mirror of
https://github.com/zaphar/abortable_parser.git
synced 2025-07-21 20:29:49 -04:00
Refactor: Make traits more composable and eliminate some redundancy.
This commit is contained in:
parent
5cb8effcca
commit
374212aecd
@ -65,7 +65,7 @@ macro_rules! not {
|
|||||||
($i:expr, $f:ident( $( $args:tt )* ) ) => {
|
($i:expr, $f:ident( $( $args:tt )* ) ) => {
|
||||||
not!($i, run!($f($($args)*)))
|
not!($i, run!($f($($args)*)))
|
||||||
};
|
};
|
||||||
|
|
||||||
($i:expr, $f:ident) => {
|
($i:expr, $f:ident) => {
|
||||||
not!($i, run!($f))
|
not!($i, run!($f))
|
||||||
};
|
};
|
||||||
@ -104,7 +104,7 @@ macro_rules! peek {
|
|||||||
($i:expr, $f:ident( $( $args:tt )* ) ) => {
|
($i:expr, $f:ident( $( $args:tt )* ) ) => {
|
||||||
peek!($i, run!($f($($args)*)))
|
peek!($i, run!($f($($args)*)))
|
||||||
};
|
};
|
||||||
|
|
||||||
($i:expr, $f:ident) => {
|
($i:expr, $f:ident) => {
|
||||||
peek!($i, run!($f))
|
peek!($i, run!($f))
|
||||||
};
|
};
|
||||||
@ -160,7 +160,7 @@ macro_rules! must {
|
|||||||
($i:expr, $f:ident!( $( $args:tt )* ) ) => {
|
($i:expr, $f:ident!( $( $args:tt )* ) ) => {
|
||||||
$crate::combinators::must($f!($i, $($args)*))
|
$crate::combinators::must($f!($i, $($args)*))
|
||||||
};
|
};
|
||||||
|
|
||||||
($i:expr, $f:ident) => {
|
($i:expr, $f:ident) => {
|
||||||
must!($i, run!($f))
|
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()))),
|
$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 ) => {
|
($i:expr, $f:ident( $( $args:tt )* ), $e:expr ) => {
|
||||||
wrap_err!($i, run!($f($($args)*)), $e:expr)
|
wrap_err!($i, run!($f($($args)*)), $e:expr)
|
||||||
};
|
};
|
||||||
|
|
||||||
($i:expr, $f:ident, $e:expr) => {
|
($i:expr, $f:ident, $e:expr) => {
|
||||||
wrap_err!($i, run!($f), $e)
|
wrap_err!($i, run!($f), $e)
|
||||||
};
|
};
|
||||||
@ -225,7 +225,7 @@ macro_rules! trap {
|
|||||||
($i:expr, $f:ident!( $( $args:tt )* ) ) => {
|
($i:expr, $f:ident!( $( $args:tt )* ) ) => {
|
||||||
$crate::combinators::trap($f!($i, $($args)*))
|
$crate::combinators::trap($f!($i, $($args)*))
|
||||||
};
|
};
|
||||||
|
|
||||||
($i:expr, $f:ident) => {
|
($i:expr, $f:ident) => {
|
||||||
trap!($i, run!($f))
|
trap!($i, run!($f))
|
||||||
};
|
};
|
||||||
@ -250,7 +250,7 @@ where
|
|||||||
|
|
||||||
/// Turns `Result::Incomplete` into `Result::Fail`.
|
/// Turns `Result::Incomplete` into `Result::Fail`.
|
||||||
pub fn complete<I, O, S>(result: Result<I, O>, msg: S) -> Result<I, O>
|
pub fn complete<I, O, S>(result: Result<I, O>, msg: S) -> Result<I, O>
|
||||||
where
|
where
|
||||||
I: InputIter,
|
I: InputIter,
|
||||||
S: Into<String>,
|
S: Into<String>,
|
||||||
{
|
{
|
||||||
@ -268,7 +268,7 @@ macro_rules! complete {
|
|||||||
($i:expr, $e:expr, $f:ident!( $( $args:tt )* ) ) => {
|
($i:expr, $e:expr, $f:ident!( $( $args:tt )* ) ) => {
|
||||||
$crate::combinators::complete($f!($i, $($args)*), $e)
|
$crate::combinators::complete($f!($i, $($args)*), $e)
|
||||||
};
|
};
|
||||||
|
|
||||||
($i:expr, $efn:expr, $f:ident) => {
|
($i:expr, $efn:expr, $f:ident) => {
|
||||||
complete!($i, $efn, run!($f))
|
complete!($i, $efn, run!($f))
|
||||||
};
|
};
|
||||||
@ -293,7 +293,7 @@ macro_rules! must_complete {
|
|||||||
($i:expr, $e:expr, $f:ident!( $( $args:tt )* ) ) => {{
|
($i:expr, $e:expr, $f:ident!( $( $args:tt )* ) ) => {{
|
||||||
$crate::combinators::must_complete($f!($i.clone(), $($args)*), $e)
|
$crate::combinators::must_complete($f!($i.clone(), $($args)*), $e)
|
||||||
}};
|
}};
|
||||||
|
|
||||||
($i:expr, $efn:expr, $f:ident) => {
|
($i:expr, $efn:expr, $f:ident) => {
|
||||||
must_complete!($i, $efn, run!($f))
|
must_complete!($i, $efn, run!($f))
|
||||||
};
|
};
|
||||||
@ -354,7 +354,7 @@ macro_rules! do_each {
|
|||||||
// This is a compile failure.
|
// This is a compile failure.
|
||||||
compile_error!("do_each! must end with a tuple capturing the results")
|
compile_error!("do_each! must end with a tuple capturing the results")
|
||||||
};
|
};
|
||||||
|
|
||||||
($i:expr, $val:ident => $f:ident!($( $args:tt )* ), $($rest:tt)* ) => {
|
($i:expr, $val:ident => $f:ident!($( $args:tt )* ), $($rest:tt)* ) => {
|
||||||
// If any single one of these matchers fails then all of them are failures.
|
// If any single one of these matchers fails then all of them are failures.
|
||||||
match $f!($i, $($args)*) {
|
match $f!($i, $($args)*) {
|
||||||
@ -369,7 +369,7 @@ macro_rules! do_each {
|
|||||||
$crate::Result::Abort(e) => Result::Abort(e),
|
$crate::Result::Abort(e) => Result::Abort(e),
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
($i:expr, _ => $f:ident!($( $args:tt )* ), $($rest:tt)* ) => {
|
($i:expr, _ => $f:ident!($( $args:tt )* ), $($rest:tt)* ) => {
|
||||||
// If any single one of these matchers fails then all of them are failures.
|
// If any single one of these matchers fails then all of them are failures.
|
||||||
match $f!($i, $($args)*) {
|
match $f!($i, $($args)*) {
|
||||||
@ -383,7 +383,7 @@ macro_rules! do_each {
|
|||||||
$crate::Result::Abort(e) => Result::Abort(e),
|
$crate::Result::Abort(e) => Result::Abort(e),
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
($i:expr, $val:ident => $f:ident, $($rest:tt)* ) => {
|
($i:expr, $val:ident => $f:ident, $($rest:tt)* ) => {
|
||||||
// If any single one of these matchers fails then all of them are failures.
|
// If any single one of these matchers fails then all of them are failures.
|
||||||
do_each!($i, $val => run!($f), $( $rest )* )
|
do_each!($i, $val => run!($f), $( $rest )* )
|
||||||
@ -612,14 +612,14 @@ macro_rules! repeat {
|
|||||||
None => $crate::Result::Complete(_i, seq),
|
None => $crate::Result::Complete(_i, seq),
|
||||||
}
|
}
|
||||||
}};
|
}};
|
||||||
|
|
||||||
($i:expr, $f:ident) => {
|
($i:expr, $f:ident) => {
|
||||||
repeat!($i, run!($f))
|
repeat!($i, run!($f))
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parses separated list of items.
|
/// Parses separated list of items.
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// # #[macro_use] extern crate abortable_parser;
|
/// # #[macro_use] extern crate abortable_parser;
|
||||||
/// use abortable_parser::iter;
|
/// use abortable_parser::iter;
|
||||||
@ -803,10 +803,16 @@ pub fn ascii_ws<'a, I: InputIter<Item = &'a u8>>(mut i: I) -> Result<I, u8> {
|
|||||||
if (*b as char).is_whitespace() {
|
if (*b as char).is_whitespace() {
|
||||||
Result::Complete(i, *b)
|
Result::Complete(i, *b)
|
||||||
} else {
|
} 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<Item = &'a u8>>(mut i: I) -> Result<I, u8> {
|
|||||||
pub fn eoi<I: InputIter>(i: I) -> Result<I, ()> {
|
pub fn eoi<I: InputIter>(i: I) -> Result<I, ()> {
|
||||||
let mut _i = i.clone();
|
let mut _i = i.clone();
|
||||||
match _i.next() {
|
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, ()),
|
None => Result::Complete(i, ()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -847,7 +856,7 @@ macro_rules! make_fn {
|
|||||||
$rule!(i, $($body)*)
|
$rule!(i, $($body)*)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
(pub $name:ident<$i:ty, $o:ty>, $rule:ident!($( $body:tt )* )) => {
|
(pub $name:ident<$i:ty, $o:ty>, $rule:ident!($( $body:tt )* )) => {
|
||||||
pub fn $name(i: $i) -> $crate::Result<$i, $o> {
|
pub fn $name(i: $i) -> $crate::Result<$i, $o> {
|
||||||
$rule!(i, $($body)*)
|
$rule!(i, $($body)*)
|
||||||
@ -864,7 +873,7 @@ macro_rules! make_fn {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Helper macro that returns the input without consuming it.
|
/// Helper macro that returns the input without consuming it.
|
||||||
///
|
///
|
||||||
/// Useful when you need to get the input and use it to retrieve
|
/// Useful when you need to get the input and use it to retrieve
|
||||||
/// positional information like offset or line and column.
|
/// positional information like offset or line and column.
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
@ -881,7 +890,7 @@ macro_rules! input {
|
|||||||
|
|
||||||
/// Consumes the input until the $rule fails and then returns the consumed input as
|
/// Consumes the input until the $rule fails and then returns the consumed input as
|
||||||
/// a slice.
|
/// a slice.
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// # #[macro_use] extern crate abortable_parser;
|
/// # #[macro_use] extern crate abortable_parser;
|
||||||
/// use abortable_parser::iter;
|
/// 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.
|
/// ascii_digit parses a single ascii alphabetic or digit character from an InputIter of bytes.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn ascii_alphanumeric<'a, I: InputIter<Item=&'a u8>>(mut i: I) -> Result<I, u8> {
|
pub fn ascii_alphanumeric<'a, I: InputIter<Item = &'a u8>>(mut i: I) -> Result<I, u8> {
|
||||||
match i.next() {
|
match i.next() {
|
||||||
Some(b) => {
|
Some(b) => {
|
||||||
let c = *b as char;
|
let c = *b as char;
|
||||||
if c.is_ascii_alphabetic() || c.is_ascii_digit() {
|
if c.is_ascii_alphabetic() || c.is_ascii_digit() {
|
||||||
Result::Complete(i, *b)
|
Result::Complete(i, *b)
|
||||||
} else {
|
} 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<Item = &'a u8>>(mut i: I) -> Result<I, u8> {
|
|||||||
if (*b as char).is_ascii_digit() {
|
if (*b as char).is_ascii_digit() {
|
||||||
Result::Complete(i, *b)
|
Result::Complete(i, *b)
|
||||||
} else {
|
} 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<Item = &'a u8>>(mut i: I) -> Result<I, u8> {
|
|||||||
if (*b as char).is_ascii_alphabetic() {
|
if (*b as char).is_ascii_alphabetic() {
|
||||||
Result::Complete(i, *b)
|
Result::Complete(i, *b)
|
||||||
} else {
|
} 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 Optional into failures.
|
||||||
// TODO(jwall): We need a helper to convert std::result::Result into failures.
|
// TODO(jwall): We need a helper to convert std::result::Result into failures.
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
use super::{ascii_ws, eoi, Result};
|
use super::{ascii_ws, eoi, Result};
|
||||||
use iter::{StrIter, SliceIter};
|
use iter::{SliceIter, StrIter};
|
||||||
|
|
||||||
make_fn!(proto<StrIter, &str>,
|
make_fn!(proto<StrIter, &str>,
|
||||||
do_each!(
|
do_each!(
|
||||||
@ -33,7 +33,8 @@ make_fn!(path<StrIter, &str>,
|
|||||||
until!(either!(discard!(ascii_ws), eoi))
|
until!(either!(discard!(ascii_ws), eoi))
|
||||||
);
|
);
|
||||||
|
|
||||||
make_fn!(sliceit<SliceIter<u8>, ()>,
|
make_fn!(
|
||||||
|
sliceit<SliceIter<u8>, ()>,
|
||||||
do_each!(
|
do_each!(
|
||||||
_ => input!(),
|
_ => input!(),
|
||||||
end_of_input => eoi,
|
end_of_input => eoi,
|
||||||
@ -41,7 +42,8 @@ make_fn!(sliceit<SliceIter<u8>, ()>,
|
|||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
make_fn!(long_string_path<SliceIter<u8>, ()>,
|
make_fn!(
|
||||||
|
long_string_path<SliceIter<u8>, ()>,
|
||||||
do_each!(
|
do_each!(
|
||||||
_ => input!(),
|
_ => input!(),
|
||||||
end_of_input => eoi,
|
end_of_input => eoi,
|
||||||
|
31
src/iter.rs
31
src/iter.rs
@ -16,7 +16,7 @@
|
|||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
use std::iter::Iterator;
|
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.
|
/// Implements `InputIter` for any slice of T.
|
||||||
#[derive(Debug)]
|
#[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> {
|
impl<'a, T: Debug + 'a> Clone for SliceIter<'a, T> {
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self {
|
||||||
SliceIter {
|
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 {
|
fn line(&self) -> usize {
|
||||||
self.line
|
self.line
|
||||||
}
|
}
|
||||||
@ -194,11 +213,7 @@ impl<'a> Span<&'a str> for StrIter<'a> {
|
|||||||
impl<'a> Seekable for StrIter<'a> {
|
impl<'a> Seekable for StrIter<'a> {
|
||||||
fn seek(&mut self, to: usize) -> usize {
|
fn seek(&mut self, to: usize) -> usize {
|
||||||
let self_len = self.source.len();
|
let self_len = self.source.len();
|
||||||
let offset = if self_len > to {
|
let offset = if self_len > to { to } else { self_len };
|
||||||
to
|
|
||||||
} else {
|
|
||||||
self_len
|
|
||||||
};
|
|
||||||
self.offset = offset;
|
self.offset = offset;
|
||||||
self.offset
|
self.offset
|
||||||
}
|
}
|
||||||
@ -210,4 +225,4 @@ impl<'a> Peekable<&'a u8> for StrIter<'a> {
|
|||||||
fn peek_next(&self) -> Option<&'a u8> {
|
fn peek_next(&self) -> Option<&'a u8> {
|
||||||
self.source.as_bytes().get(self.offset)
|
self.source.as_bytes().get(self.offset)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
54
src/lib.rs
54
src/lib.rs
@ -102,7 +102,7 @@
|
|||||||
//! assert!(bad_result.is_abort());
|
//! assert!(bad_result.is_abort());
|
||||||
//! # }
|
//! # }
|
||||||
//! ```
|
//! ```
|
||||||
use std::fmt::{Display,Debug};
|
use std::fmt::{Debug, Display};
|
||||||
use std::iter::Iterator;
|
use std::iter::Iterator;
|
||||||
use std::result;
|
use std::result;
|
||||||
|
|
||||||
@ -121,8 +121,8 @@ pub trait Seekable {
|
|||||||
fn seek(&mut self, usize) -> usize;
|
fn seek(&mut self, usize) -> usize;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Trait for Inputs that can track lines and columns in a text input.
|
/// Trait for Inputs that can report current lines and columns in a text input.
|
||||||
pub trait TextPositionTracker {
|
pub trait Positioned {
|
||||||
fn line(&self) -> usize;
|
fn line(&self) -> usize;
|
||||||
fn column(&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}`.
|
/// The custom error type for use in `Result::{Fail, Abort}`.
|
||||||
/// Stores a wrapped err that must implement Display as well as an offset and
|
/// Stores a wrapped err that must implement Display as well as an offset and
|
||||||
/// an optional cause.
|
/// an optional cause.
|
||||||
#[derive(Debug,Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Error<C>
|
pub struct Error<C> {
|
||||||
where
|
|
||||||
C: InputIter,
|
|
||||||
{
|
|
||||||
msg: String,
|
msg: String,
|
||||||
cause: Option<Box<Error<C>>>,
|
cause: Option<Box<Error<C>>>,
|
||||||
context: Box<C>,
|
context: Box<C>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<C: InputIter> Error<C> {
|
impl<C> Error<C> {
|
||||||
/// Constructs a new Error with an offset and no cause.
|
/// Constructs a new Error with an offset and no cause.
|
||||||
pub fn new<D: Into<String>>(msg: D, ctx: Box<C>) -> Self
|
pub fn new<D: Into<String>>(msg: D, ctx: Box<C>) -> Self {
|
||||||
{
|
|
||||||
Error {
|
Error {
|
||||||
msg: msg.into(),
|
msg: msg.into(),
|
||||||
cause: None,
|
cause: None,
|
||||||
@ -172,8 +168,7 @@ impl<C: InputIter> Error<C> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Constructs a new Error with an offset and a cause.
|
/// Constructs a new Error with an offset and a cause.
|
||||||
pub fn caused_by<'a, D: Into<String>>(msg: D, cause: Box<Self>, ctx: Box<C>) -> Self
|
pub fn caused_by<'a, D: Into<String>>(msg: D, cause: Box<Self>, ctx: Box<C>) -> Self {
|
||||||
{
|
|
||||||
Error {
|
Error {
|
||||||
msg: msg.into(),
|
msg: msg.into(),
|
||||||
cause: Some(cause),
|
cause: Some(cause),
|
||||||
@ -182,32 +177,31 @@ impl<C: InputIter> Error<C> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the msg.
|
/// Returns the msg.
|
||||||
pub fn get_msg<'a>(&'a self) -> String {
|
pub fn get_msg<'a>(&'a self) -> &str {
|
||||||
format!("{}", &self.msg)
|
&self.msg
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns `Some(cause)` if there is one, None otherwise.
|
/// Returns `Some(cause)` if there is one, None otherwise.
|
||||||
pub fn get_cause<'a>(&'a self) -> Option<&'a Error<C>> {
|
pub fn get_cause<'a>(&'a self) -> Option<&'a Error<C>> {
|
||||||
match self.cause {
|
match self.cause {
|
||||||
Some(ref e) => Some(e),
|
Some(ref e) => Some(e),
|
||||||
None => None
|
None => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns the offset at which this Error happened.
|
pub fn get_context(&self) -> &C {
|
||||||
pub fn get_offset(&self) -> usize {
|
|
||||||
self.context.get_offset()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_context(&self) -> &C
|
|
||||||
where
|
|
||||||
C: InputIter,
|
|
||||||
{
|
|
||||||
self.context.as_ref()
|
self.context.as_ref()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<C: InputIter> Display for Error<C> {
|
impl<C: Offsetable> Offsetable for Error<C> {
|
||||||
|
// Returns the offset at which this Error happened.
|
||||||
|
fn get_offset(&self) -> usize {
|
||||||
|
self.context.get_offset()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<C: Offsetable> Display for Error<C> {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> result::Result<(), std::fmt::Error> {
|
fn fmt(&self, f: &mut std::fmt::Formatter) -> result::Result<(), std::fmt::Error> {
|
||||||
try!(write!(f, "{}", self.msg));
|
try!(write!(f, "{}", self.msg));
|
||||||
match self.cause {
|
match self.cause {
|
||||||
@ -217,12 +211,11 @@ impl<C: InputIter> Display for Error<C> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<C: InputIter + Debug> std::error::Error for Error<C> {}
|
impl<C: Offsetable + Debug> std::error::Error for Error<C> {}
|
||||||
|
|
||||||
/// The result of a parsing attempt.
|
/// The result of a parsing attempt.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum Result<I: InputIter, O>
|
pub enum Result<I: InputIter, O> {
|
||||||
{
|
|
||||||
/// Complete represents a successful match.
|
/// Complete represents a successful match.
|
||||||
Complete(I, O),
|
Complete(I, O),
|
||||||
/// Incomplete indicates input ended before a match could be completed.
|
/// Incomplete indicates input ended before a match could be completed.
|
||||||
@ -234,8 +227,7 @@ pub enum Result<I: InputIter, O>
|
|||||||
Abort(Error<I>),
|
Abort(Error<I>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<I: InputIter, O> Result<I, O>
|
impl<I: InputIter, O> Result<I, O> {
|
||||||
{
|
|
||||||
/// Returns true if the Result is Complete.
|
/// Returns true if the Result is Complete.
|
||||||
pub fn is_complete(&self) -> bool {
|
pub fn is_complete(&self) -> bool {
|
||||||
if let &Result::Complete(_, _) = self {
|
if let &Result::Complete(_, _) = self {
|
||||||
|
15
src/test.rs
15
src/test.rs
@ -14,7 +14,7 @@
|
|||||||
|
|
||||||
use std::fmt::{Debug, Display};
|
use std::fmt::{Debug, Display};
|
||||||
|
|
||||||
use super::{InputIter, Offsetable, Result, TextPositionTracker};
|
use super::{InputIter, Offsetable, Positioned, Result};
|
||||||
use combinators::*;
|
use combinators::*;
|
||||||
use iter::{SliceIter, StrIter};
|
use iter::{SliceIter, StrIter};
|
||||||
|
|
||||||
@ -53,7 +53,10 @@ where
|
|||||||
I: InputIter<Item = C>,
|
I: InputIter<Item = C>,
|
||||||
C: Debug + Display,
|
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<I, u8>
|
fn parse_byte<'a, I>(mut i: I) -> Result<I, u8>
|
||||||
@ -574,7 +577,7 @@ fn test_ascii_alphanumeric() {
|
|||||||
let iter = StrIter::new(input_str);
|
let iter = StrIter::new(input_str);
|
||||||
let result = repeat!(iter, ascii_alphanumeric);
|
let result = repeat!(iter, ascii_alphanumeric);
|
||||||
assert!(result.is_complete());
|
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.len(), 2);
|
||||||
assert_eq!(list[0], b'a');
|
assert_eq!(list[0], b'a');
|
||||||
assert_eq!(list[1], b'1');
|
assert_eq!(list[1], b'1');
|
||||||
@ -596,7 +599,7 @@ fn test_ascii_digit() {
|
|||||||
let iter = StrIter::new(input_str);
|
let iter = StrIter::new(input_str);
|
||||||
let result = repeat!(iter, ascii_digit);
|
let result = repeat!(iter, ascii_digit);
|
||||||
assert!(result.is_complete());
|
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.len(), 2);
|
||||||
assert_eq!(list[0], b'1');
|
assert_eq!(list[0], b'1');
|
||||||
assert_eq!(list[1], b'2');
|
assert_eq!(list[1], b'2');
|
||||||
@ -618,7 +621,7 @@ fn test_ascii_alpha() {
|
|||||||
let iter = StrIter::new(input_str);
|
let iter = StrIter::new(input_str);
|
||||||
let result = repeat!(iter, ascii_alpha);
|
let result = repeat!(iter, ascii_alpha);
|
||||||
assert!(result.is_complete());
|
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.len(), 2);
|
||||||
assert_eq!(list[0], b'a');
|
assert_eq!(list[0], b'a');
|
||||||
assert_eq!(list[1], b'b');
|
assert_eq!(list[1], b'b');
|
||||||
@ -645,4 +648,4 @@ fn test_consume_all() {
|
|||||||
assert_eq!(o, "foo");
|
assert_eq!(o, "foo");
|
||||||
assert!(text_token!(i, ";").is_complete());
|
assert!(text_token!(i, ";").is_complete());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user