diff --git a/src/combinators.rs b/src/combinators.rs index ce64d75..ea5fd0c 100644 --- a/src/combinators.rs +++ b/src/combinators.rs @@ -65,7 +65,7 @@ macro_rules! not { ($i:expr, $f:ident( $( $args:tt )* ) ) => { not!($i, run!($f($($args)*))) }; - + ($i:expr, $f:ident) => { not!($i, run!($f)) }; @@ -104,7 +104,7 @@ macro_rules! peek { ($i:expr, $f:ident( $( $args:tt )* ) ) => { peek!($i, run!($f($($args)*))) }; - + ($i:expr, $f:ident) => { peek!($i, run!($f)) }; @@ -160,7 +160,7 @@ macro_rules! must { ($i:expr, $f:ident!( $( $args:tt )* ) ) => { $crate::combinators::must($f!($i, $($args)*)) }; - + ($i:expr, $f:ident) => { must!($i, run!($f)) }; @@ -179,11 +179,11 @@ macro_rules! wrap_err { $crate::Result::Abort(e) => $crate::Result::Abort($crate::Error::caused_by($e, Box::new(e), Box::new(_i.clone()))), } }}; - + ($i:expr, $f:ident( $( $args:tt )* ), $e:expr ) => { wrap_err!($i, run!($f($($args)*)), $e:expr) }; - + ($i:expr, $f:ident, $e:expr) => { wrap_err!($i, run!($f), $e) }; @@ -225,7 +225,7 @@ macro_rules! trap { ($i:expr, $f:ident!( $( $args:tt )* ) ) => { $crate::combinators::trap($f!($i, $($args)*)) }; - + ($i:expr, $f:ident) => { trap!($i, run!($f)) }; @@ -250,7 +250,7 @@ where /// Turns `Result::Incomplete` into `Result::Fail`. pub fn complete(result: Result, msg: S) -> Result -where +where I: InputIter, S: Into, { @@ -268,7 +268,7 @@ macro_rules! complete { ($i:expr, $e:expr, $f:ident!( $( $args:tt )* ) ) => { $crate::combinators::complete($f!($i, $($args)*), $e) }; - + ($i:expr, $efn:expr, $f:ident) => { complete!($i, $efn, run!($f)) }; @@ -293,7 +293,7 @@ macro_rules! must_complete { ($i:expr, $e:expr, $f:ident!( $( $args:tt )* ) ) => {{ $crate::combinators::must_complete($f!($i.clone(), $($args)*), $e) }}; - + ($i:expr, $efn:expr, $f:ident) => { must_complete!($i, $efn, run!($f)) }; @@ -354,7 +354,7 @@ macro_rules! do_each { // This is a compile failure. compile_error!("do_each! must end with a tuple capturing the results") }; - + ($i:expr, $val:ident => $f:ident!($( $args:tt )* ), $($rest:tt)* ) => { // If any single one of these matchers fails then all of them are failures. match $f!($i, $($args)*) { @@ -369,7 +369,7 @@ macro_rules! do_each { $crate::Result::Abort(e) => Result::Abort(e), } }; - + ($i:expr, _ => $f:ident!($( $args:tt )* ), $($rest:tt)* ) => { // If any single one of these matchers fails then all of them are failures. match $f!($i, $($args)*) { @@ -383,7 +383,7 @@ macro_rules! do_each { $crate::Result::Abort(e) => Result::Abort(e), } }; - + ($i:expr, $val:ident => $f:ident, $($rest:tt)* ) => { // If any single one of these matchers fails then all of them are failures. do_each!($i, $val => run!($f), $( $rest )* ) @@ -612,14 +612,14 @@ macro_rules! repeat { None => $crate::Result::Complete(_i, seq), } }}; - + ($i:expr, $f:ident) => { repeat!($i, run!($f)) }; } /// Parses separated list of items. -/// +/// /// ``` /// # #[macro_use] extern crate abortable_parser; /// use abortable_parser::iter; @@ -803,10 +803,16 @@ pub fn ascii_ws<'a, I: InputIter>(mut i: I) -> Result { if (*b as char).is_whitespace() { Result::Complete(i, *b) } else { - Result::Fail(Error::new("Not whitespace".to_string(), Box::new(i.clone()))) + Result::Fail(Error::new( + "Not whitespace".to_string(), + Box::new(i.clone()), + )) } - }, - None => Result::Fail(Error::new("Unexpected End Of Input".to_string(), Box::new(i.clone()))), + } + None => Result::Fail(Error::new( + "Unexpected End Of Input".to_string(), + Box::new(i.clone()), + )), } } @@ -815,7 +821,10 @@ pub fn ascii_ws<'a, I: InputIter>(mut i: I) -> Result { pub fn eoi(i: I) -> Result { let mut _i = i.clone(); match _i.next() { - Some(_) => Result::Fail(Error::new("Expected End Of Input".to_string(), Box::new(i.clone()))), + Some(_) => Result::Fail(Error::new( + "Expected End Of Input".to_string(), + Box::new(i.clone()), + )), None => Result::Complete(i, ()), } } @@ -847,7 +856,7 @@ macro_rules! make_fn { $rule!(i, $($body)*) } }; - + (pub $name:ident<$i:ty, $o:ty>, $rule:ident!($( $body:tt )* )) => { pub fn $name(i: $i) -> $crate::Result<$i, $o> { $rule!(i, $($body)*) @@ -864,7 +873,7 @@ macro_rules! make_fn { } /// Helper macro that returns the input without consuming it. -/// +/// /// Useful when you need to get the input and use it to retrieve /// positional information like offset or line and column. #[macro_export] @@ -881,7 +890,7 @@ macro_rules! input { /// Consumes the input until the $rule fails and then returns the consumed input as /// a slice. -/// +/// /// ``` /// # #[macro_use] extern crate abortable_parser; /// use abortable_parser::iter; @@ -932,17 +941,23 @@ macro_rules! consume_all { /// ascii_digit parses a single ascii alphabetic or digit character from an InputIter of bytes. #[inline(always)] -pub fn ascii_alphanumeric<'a, I: InputIter>(mut i: I) -> Result { +pub fn ascii_alphanumeric<'a, I: InputIter>(mut i: I) -> Result { match i.next() { Some(b) => { let c = *b as char; if c.is_ascii_alphabetic() || c.is_ascii_digit() { Result::Complete(i, *b) } else { - Result::Fail(Error::new("Not an alphanumeric character".to_string(), Box::new(i.clone()))) + Result::Fail(Error::new( + "Not an alphanumeric character".to_string(), + Box::new(i.clone()), + )) } - }, - None => Result::Fail(Error::new("Unexpected End Of Input.".to_string(), Box::new(i.clone()))), + } + None => Result::Fail(Error::new( + "Unexpected End Of Input.".to_string(), + Box::new(i.clone()), + )), } } @@ -954,10 +969,16 @@ pub fn ascii_digit<'a, I: InputIter>(mut i: I) -> Result { if (*b as char).is_ascii_digit() { Result::Complete(i, *b) } else { - Result::Fail(Error::new("Not an digit character".to_string(), Box::new(i.clone()))) + Result::Fail(Error::new( + "Not an digit character".to_string(), + Box::new(i.clone()), + )) } - }, - None => Result::Fail(Error::new("Unexpected End Of Input.".to_string(), Box::new(i.clone()))), + } + None => Result::Fail(Error::new( + "Unexpected End Of Input.".to_string(), + Box::new(i.clone()), + )), } } @@ -969,12 +990,18 @@ pub fn ascii_alpha<'a, I: InputIter>(mut i: I) -> Result { if (*b as char).is_ascii_alphabetic() { Result::Complete(i, *b) } else { - Result::Fail(Error::new("Not an alpha character".to_string(), Box::new(i.clone()))) + Result::Fail(Error::new( + "Not an alpha character".to_string(), + Box::new(i.clone()), + )) } - }, - None => Result::Fail(Error::new("Unexpected End Of Input.".to_string(), Box::new(i.clone()))), + } + None => Result::Fail(Error::new( + "Unexpected End Of Input.".to_string(), + Box::new(i.clone()), + )), } } // TODO(jwall): We need a helper to convert Optional into failures. -// TODO(jwall): We need a helper to convert std::result::Result into failures. \ No newline at end of file +// TODO(jwall): We need a helper to convert std::result::Result into failures. diff --git a/src/integration_tests.rs b/src/integration_tests.rs index 9543566..68ec772 100644 --- a/src/integration_tests.rs +++ b/src/integration_tests.rs @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. use super::{ascii_ws, eoi, Result}; -use iter::{StrIter, SliceIter}; +use iter::{SliceIter, StrIter}; make_fn!(proto, do_each!( @@ -33,7 +33,8 @@ make_fn!(path, until!(either!(discard!(ascii_ws), eoi)) ); -make_fn!(sliceit, ()>, +make_fn!( + sliceit, ()>, do_each!( _ => input!(), end_of_input => eoi, @@ -41,7 +42,8 @@ make_fn!(sliceit, ()>, ) ); -make_fn!(long_string_path, ()>, +make_fn!( + long_string_path, ()>, do_each!( _ => input!(), end_of_input => eoi, diff --git a/src/iter.rs b/src/iter.rs index 98def77..bed36fc 100644 --- a/src/iter.rs +++ b/src/iter.rs @@ -16,7 +16,7 @@ use std::fmt::Debug; use std::iter::Iterator; -use super::{InputIter, Offsetable, Seekable, Span, SpanRange, TextPositionTracker}; +use super::{InputIter, Offsetable, Positioned, Seekable, Span, SpanRange}; /// Implements `InputIter` for any slice of T. #[derive(Debug)] @@ -55,6 +55,25 @@ impl<'a, T: Debug + 'a> Offsetable for SliceIter<'a, T> { } } +impl<'a, It> Positioned for SliceIter<'a, It> +where + It: Positioned + Debug, +{ + fn line(&self) -> usize { + match self.peek_next() { + Some(i) => i.line(), + None => 0, + } + } + + fn column(&self) -> usize { + match self.peek_next() { + Some(i) => i.column(), + None => 0, + } + } +} + impl<'a, T: Debug + 'a> Clone for SliceIter<'a, T> { fn clone(&self) -> Self { SliceIter { @@ -149,7 +168,7 @@ impl<'a> Offsetable for StrIter<'a> { } } -impl<'a> TextPositionTracker for StrIter<'a> { +impl<'a> Positioned for StrIter<'a> { fn line(&self) -> usize { self.line } @@ -194,11 +213,7 @@ impl<'a> Span<&'a str> for StrIter<'a> { impl<'a> Seekable for StrIter<'a> { fn seek(&mut self, to: usize) -> usize { let self_len = self.source.len(); - let offset = if self_len > to { - to - } else { - self_len - }; + let offset = if self_len > to { to } else { self_len }; self.offset = offset; self.offset } @@ -210,4 +225,4 @@ impl<'a> Peekable<&'a u8> for StrIter<'a> { fn peek_next(&self) -> Option<&'a u8> { self.source.as_bytes().get(self.offset) } -} \ No newline at end of file +} diff --git a/src/lib.rs b/src/lib.rs index 85cc679..137a7ec 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -102,7 +102,7 @@ //! assert!(bad_result.is_abort()); //! # } //! ``` -use std::fmt::{Display,Debug}; +use std::fmt::{Debug, Display}; use std::iter::Iterator; use std::result; @@ -121,8 +121,8 @@ pub trait Seekable { fn seek(&mut self, usize) -> usize; } -/// Trait for Inputs that can track lines and columns in a text input. -pub trait TextPositionTracker { +/// Trait for Inputs that can report current lines and columns in a text input. +pub trait Positioned { fn line(&self) -> usize; fn column(&self) -> usize; } @@ -150,20 +150,16 @@ pub trait InputIter: Iterator + Clone + Offsetable {} /// The custom error type for use in `Result::{Fail, Abort}`. /// Stores a wrapped err that must implement Display as well as an offset and /// an optional cause. -#[derive(Debug,Clone)] -pub struct Error -where - C: InputIter, -{ +#[derive(Debug, Clone)] +pub struct Error { msg: String, cause: Option>>, context: Box, } -impl Error { +impl Error { /// Constructs a new Error with an offset and no cause. - pub fn new>(msg: D, ctx: Box) -> Self - { + pub fn new>(msg: D, ctx: Box) -> Self { Error { msg: msg.into(), cause: None, @@ -172,8 +168,7 @@ impl Error { } /// Constructs a new Error with an offset and a cause. - pub fn caused_by<'a, D: Into>(msg: D, cause: Box, ctx: Box) -> Self - { + pub fn caused_by<'a, D: Into>(msg: D, cause: Box, ctx: Box) -> Self { Error { msg: msg.into(), cause: Some(cause), @@ -182,32 +177,31 @@ impl Error { } /// Returns the msg. - pub fn get_msg<'a>(&'a self) -> String { - format!("{}", &self.msg) + pub fn get_msg<'a>(&'a self) -> &str { + &self.msg } /// Returns `Some(cause)` if there is one, None otherwise. pub fn get_cause<'a>(&'a self) -> Option<&'a Error> { match self.cause { Some(ref e) => Some(e), - None => None + None => None, } } - // Returns the offset at which this Error happened. - pub fn get_offset(&self) -> usize { - self.context.get_offset() - } - - pub fn get_context(&self) -> &C - where - C: InputIter, - { + pub fn get_context(&self) -> &C { self.context.as_ref() } } -impl Display for Error { +impl Offsetable for Error { + // Returns the offset at which this Error happened. + fn get_offset(&self) -> usize { + self.context.get_offset() + } +} + +impl Display for Error { fn fmt(&self, f: &mut std::fmt::Formatter) -> result::Result<(), std::fmt::Error> { try!(write!(f, "{}", self.msg)); match self.cause { @@ -217,12 +211,11 @@ impl Display for Error { } } -impl std::error::Error for Error {} +impl std::error::Error for Error {} /// The result of a parsing attempt. #[derive(Debug)] -pub enum Result -{ +pub enum Result { /// Complete represents a successful match. Complete(I, O), /// Incomplete indicates input ended before a match could be completed. @@ -234,8 +227,7 @@ pub enum Result Abort(Error), } -impl Result -{ +impl Result { /// Returns true if the Result is Complete. pub fn is_complete(&self) -> bool { if let &Result::Complete(_, _) = self { diff --git a/src/test.rs b/src/test.rs index 0d49384..391d431 100644 --- a/src/test.rs +++ b/src/test.rs @@ -14,7 +14,7 @@ use std::fmt::{Debug, Display}; -use super::{InputIter, Offsetable, Result, TextPositionTracker}; +use super::{InputIter, Offsetable, Positioned, Result}; use combinators::*; use iter::{SliceIter, StrIter}; @@ -53,7 +53,10 @@ where I: InputIter, C: Debug + Display, { - Result::Fail(super::Error::new("AAAAHHH!!!".to_string(), Box::new(i.clone()))) + Result::Fail(super::Error::new( + "AAAAHHH!!!".to_string(), + Box::new(i.clone()), + )) } fn parse_byte<'a, I>(mut i: I) -> Result @@ -574,7 +577,7 @@ fn test_ascii_alphanumeric() { let iter = StrIter::new(input_str); let result = repeat!(iter, ascii_alphanumeric); assert!(result.is_complete()); - if let Result::Complete(i,list) = result { + if let Result::Complete(i, list) = result { assert_eq!(list.len(), 2); assert_eq!(list[0], b'a'); assert_eq!(list[1], b'1'); @@ -596,7 +599,7 @@ fn test_ascii_digit() { let iter = StrIter::new(input_str); let result = repeat!(iter, ascii_digit); assert!(result.is_complete()); - if let Result::Complete(i,list) = result { + if let Result::Complete(i, list) = result { assert_eq!(list.len(), 2); assert_eq!(list[0], b'1'); assert_eq!(list[1], b'2'); @@ -618,7 +621,7 @@ fn test_ascii_alpha() { let iter = StrIter::new(input_str); let result = repeat!(iter, ascii_alpha); assert!(result.is_complete()); - if let Result::Complete(i,list) = result { + if let Result::Complete(i, list) = result { assert_eq!(list.len(), 2); assert_eq!(list[0], b'a'); assert_eq!(list[1], b'b'); @@ -645,4 +648,4 @@ fn test_consume_all() { assert_eq!(o, "foo"); assert!(text_token!(i, ";").is_complete()); } -} \ No newline at end of file +}