Compare commits

..

No commits in common. "master" and "v0.2.2" have entirely different histories.

6 changed files with 140 additions and 217 deletions

View File

@ -1,6 +1,6 @@
[package]
name = "abortable_parser"
version = "0.2.5"
version = "0.2.2"
authors = ["Jeremy Wall <jeremy@marzhillstudios.com>"]
description = "A parser combinator library with an emphasis on error handling"
repository = "https://github.com/zaphar/abortable_parser"
@ -8,6 +8,5 @@ documentation = "https://docs.rs/crate/abortable_parser"
readme = "README.md"
license = "Apache-2.0"
keywords = ["parsing", "combinator"]
edition = '2018'
[dependencies]

View File

@ -63,14 +63,12 @@ macro_rules! not {
}};
($i:expr, $f:ident( $( $args:tt )* ) ) => {
use $crate::run
$crate::not!($i, run!($f($($args)*)))
not!($i, run!($f($($args)*)))
};
($i:expr, $f:ident) => {{
use $crate::run;
$crate::not!($i, run!($f))
}};
($i:expr, $f:ident) => {
not!($i, run!($f))
};
}
/// Checks the given matcher without consuming the input.
@ -104,11 +102,11 @@ macro_rules! peek {
}};
($i:expr, $f:ident( $( $args:tt )* ) ) => {
$crate::peek!($i, run!($f($($args)*)))
peek!($i, run!($f($($args)*)))
};
($i:expr, $f:ident) => {
$crate::peek!($i, run!($f))
peek!($i, run!($f))
};
}
@ -163,10 +161,9 @@ macro_rules! must {
$crate::combinators::must($f!($i, $($args)*))
};
($i:expr, $f:ident) => {{
use $crate::run;
$crate::must!($i, run!($f))
}};
($i:expr, $f:ident) => {
must!($i, run!($f))
};
}
#[macro_export]
@ -182,15 +179,13 @@ macro_rules! with_err {
}
}};
($i:expr, $f:ident( $( $args:tt )* ), $e:expr ) => {{
use $crate::run;
$crate::with_err!($i, run!($f($($args)*)), $e:expr)
}};
($i:expr, $f:ident( $( $args:tt )* ), $e:expr ) => {
with_err!($i, run!($f($($args)*)), $e:expr)
};
($i:expr, $f:ident, $e:expr) => {{
use $crate::run;
$crate::with_err!($i, run!($f), $e)
}};
($i:expr, $f:ident, $e:expr) => {
with_err!($i, run!($f), $e)
};
}
/// Wraps any Error return from a subparser in another error. Stores the position at
@ -207,15 +202,13 @@ macro_rules! wrap_err {
}
}};
($i:expr, $f:ident( $( $args:tt )* ), $e:expr ) => {{
use $crate::run;
$crate::wrap_err!($i, run!($f($($args)*)), $e:expr)
}};
($i:expr, $f:ident( $( $args:tt )* ), $e:expr ) => {
wrap_err!($i, run!($f($($args)*)), $e:expr)
};
($i:expr, $f:ident, $e:expr) => {{
use $crate::run;
$crate::wrap_err!($i, run!($f), $e)
}};
($i:expr, $f:ident, $e:expr) => {
wrap_err!($i, run!($f), $e)
};
}
/// Traps a `Result::Abort` and converts it into a `Result::Fail`.
@ -255,10 +248,9 @@ macro_rules! trap {
$crate::combinators::trap($f!($i, $($args)*))
};
($i:expr, $f:ident) => {{
use $crate::run;
$crate::trap!($i, run!($f))
}};
($i:expr, $f:ident) => {
trap!($i, run!($f))
};
}
/// Turns `Result::Fail` or `Result::Incomplete` into `Result::Abort`.
@ -300,8 +292,7 @@ macro_rules! complete {
};
($i:expr, $efn:expr, $f:ident) => {
use $crate::run
$crate::complete!($i, $efn, run!($f))
complete!($i, $efn, run!($f))
};
}
@ -325,10 +316,9 @@ macro_rules! must_complete {
$crate::combinators::must_complete($f!($i.clone(), $($args)*), $e)
}};
($i:expr, $efn:expr, $f:ident) => {{
use $crate::run;
$crate::must_complete!($i, $efn, run!($f))
}};
($i:expr, $efn:expr, $f:ident) => {
must_complete!($i, $efn, run!($f))
};
}
/// Captures a sequence of sub parsers output.
@ -384,7 +374,7 @@ macro_rules! must_complete {
macro_rules! do_each {
($i:expr, $val:ident => $f:ident) => {
// This is a compile failure.
$crate::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)* ) => {
@ -392,13 +382,13 @@ macro_rules! do_each {
match $f!($i, $($args)*) {
$crate::Result::Complete(i, o) => {
let $val = o;
$crate::do_each!(i, $($rest)*)
do_each!(i, $($rest)*)
}
$crate::Result::Incomplete(ctx) => {
$crate::Result::Incomplete(ctx)
Result::Incomplete(ctx)
}
$crate::Result::Fail(e) => $crate::Result::Fail(e),
$crate::Result::Abort(e) => $crate::Result::Abort(e),
$crate::Result::Fail(e) => Result::Fail(e),
$crate::Result::Abort(e) => Result::Abort(e),
}
};
@ -406,31 +396,29 @@ macro_rules! do_each {
// If any single one of these matchers fails then all of them are failures.
match $f!($i, $($args)*) {
$crate::Result::Complete(i, _) => {
$crate::do_each!(i, $($rest)*)
do_each!(i, $($rest)*)
}
$crate::Result::Incomplete(ctx) => {
$crate::Result::Incomplete(ctx)
Result::Incomplete(ctx)
}
$crate::Result::Fail(e) => $crate::Result::Fail(e),
$crate::Result::Abort(e) => $crate::Result::Abort(e),
$crate::Result::Fail(e) => Result::Fail(e),
$crate::Result::Abort(e) => Result::Abort(e),
}
};
($i:expr, $val:ident => $f:ident, $($rest:tt)* ) => {{
use $crate::run;
($i:expr, $val:ident => $f:ident, $($rest:tt)* ) => {
// If any single one of these matchers fails then all of them are failures.
$crate::do_each!($i, $val => run!($f), $( $rest )* )
}};
do_each!($i, $val => run!($f), $( $rest )* )
};
($i:expr, _ => $f:ident, $($rest:tt)* ) => {{
use $crate::run;
($i:expr, _ => $f:ident, $($rest:tt)* ) => {
// If any single one of these matchers fails then all of them are failures.
$crate::do_each!($i, _ => run!($f), $( $rest )* )
}};
do_each!($i, _ => run!($f), $( $rest )* )
};
// Our Terminal condition
($i:expr, ( $($rest:tt)* ) ) => {
$crate::Result::Complete($i, ($($rest)*))
Result::Complete($i, ($($rest)*))
};
}
@ -455,91 +443,84 @@ macro_rules! do_each {
macro_rules! either {
// Initialization case.
($i:expr, $f:ident!( $( $args:tt )* ), $( $rest:tt)* ) => { // 0
$crate::either!(__impl $i, $f!( $($args)* ), $($rest)*)
either!(__impl $i, $f!( $($args)* ), $($rest)*)
};
// Initialization case.
($i:expr, $f:ident, $($rest:tt)* ) => {{ // 1
use $crate::run;
$crate::either!(__impl $i, run!($f), $($rest)*)
}};
// Initialization failure case.
($i:expr, $f:ident!( $( $args:tt )* )) => { // 2
$crate::compile_error!("Either requires at least two sub matchers.")
($i:expr, $f:ident, $($rest:tt)* ) => { // 1
either!(__impl $i, run!($f), $($rest)*)
};
// Initialization failure case.
($i:expr, $f:ident) => {{ // 3
use $crate::run;
$crate::either!($i, run!($f))
}};
($i:expr, $f:ident!( $( $args:tt )* )) => { // 2
compile_error!("Either requires at least two sub matchers.")
};
// Initialization failure case.
($i:expr, $f:ident) => { // 3
either!($i, run!($f))
};
// Termination clause
(__impl $i:expr, $f:ident) => {{ // 4
use $crate::run;
$crate::either!(__impl $i, run!($f))
}};
(__impl $i:expr, $f:ident) => { // 4
either!(__impl $i, run!($f))
};
// Termination clause
(__impl $i:expr, $f:ident,) => {{ // 5
use $crate::run;
$crate::either!(__impl $i, run!($f))
}};
(__impl $i:expr, $f:ident,) => { // 5
either!(__impl $i, run!($f))
};
// Termination clause
(__impl $i:expr, $f:ident!( $( $args:tt )* ),) => { // 6
$crate::either!(__impl $i, $f!($($args)*) __end)
either!(__impl $i, $f!($($args)*) __end)
};
// Termination clause
(__impl $i:expr, $f:ident!( $( $args:tt )* )) => {{ // 7
use $crate::Result;
match $f!($i, $($args)*) {
// The first one to match is our result.
Result::Complete(i, o) => {
$crate::Result::Complete(i, o) => {
Result::Complete(i, o)
}
// Incompletes may still be parseable.
Result::Incomplete(ctx) => {
$crate::Result::Incomplete(ctx) => {
Result::Incomplete(ctx)
}
// Fail means it didn't match so we are now done.
Result::Fail(e) => {
Result::Fail(e)
$crate::Result::Fail(e) => {
$crate::Result::Fail(e)
},
// Aborts are hard failures that the parser can't recover from.
Result::Abort(e) => Result::Abort(e),
$crate::Result::Abort(e) => Result::Abort(e),
}
}};
// Internal Loop Implementation
(__impl $i:expr, $f:ident!( $( $args:tt )* ), $( $rest:tt )* ) => {{ // 8
use $crate::Result;
let _i = $i.clone();
match $f!($i, $($args)*) {
// The first one to match is our result.
Result::Complete(i, o) => {
$crate::Result::Complete(i, o) => {
Result::Complete(i, o)
}
// Incompletes may still be parseable.
Result::Incomplete(ctx) => {
$crate::Result::Incomplete(ctx) => {
Result::Incomplete(ctx)
}
// Fail means it didn't match so continue to next one.
Result::Fail(_) => {
$crate::Result::Fail(_) => {
either!(__impl _i, $($rest)*)
},
// Aborts are hard failures that the parser can't recover from.
Result::Abort(e) => Result::Abort(e),
$crate::Result::Abort(e) => Result::Abort(e),
}
}};
// Internal Loop Implementation
(__impl $i:expr, $f:ident, $( $rest:tt )* ) => {{ // 9
use $crate::run;
$crate::either!(__impl $i, run!($f), $( $rest )* )
}}
(__impl $i:expr, $f:ident, $( $rest:tt )* ) => { // 9
either!(__impl $i, run!($f), $( $rest )* )
}
}
/// Maps a `Result` to be optional.
@ -585,13 +566,12 @@ where
/// # }
#[macro_export]
macro_rules! optional {
($i:expr, $f:ident) => {{
use $crate::run;
$crate::optional!(__impl $i, run!($f))
}};
($i:expr, $f:ident) => {
optional!(__impl $i, run!($f))
};
($i:expr, $f:ident!( $( $args:tt )* ) ) => {
$crate::optional!(__impl $i, $f!( $( $args )* ))
optional!(__impl $i, $f!( $( $args )* ))
};
(__impl $i:expr, $f:ident!( $( $args:tt )* )) => {{
@ -622,29 +602,28 @@ macro_rules! optional {
#[macro_export]
macro_rules! repeat {
($i:expr, $f:ident!( $( $args:tt )* ) ) => {{
use $crate::Result;
let mut _i = $i.clone();
let mut seq = Vec::new();
let mut opt_error = None;
loop {
let __i = _i.clone();
match $f!(_i, $($args)*) {
Result::Complete(i, o) => {
$crate::Result::Complete(i, o) => {
seq.push(o);
_i = i;
}
// Aborts are always a hard fail.
Result::Abort(e) => {
opt_error = Some(Result::Abort(e));
$crate::Result::Abort(e) => {
opt_error = Some($crate::Result::Abort(e));
_i = $i.clone();
break;
}
// Everything else just means we are finished parsing.
Result::Incomplete(_) => {
$crate::Result::Incomplete(_) => {
_i = __i;
break;
}
Result::Fail(_) => {
$crate::Result::Fail(_) => {
_i = __i;
break;
}
@ -652,14 +631,13 @@ macro_rules! repeat {
}
match opt_error {
Some(e) => e,
None => Result::Complete(_i, seq),
None => $crate::Result::Complete(_i, seq),
}
}};
($i:expr, $f:ident) => {{
use $crate::run;
$crate::repeat!($i, run!($f))
}};
($i:expr, $f:ident) => {
repeat!($i, run!($f))
};
}
/// Parses separated list of items.
@ -714,20 +692,17 @@ macro_rules! separated {
}
}};
($i:expr, $sep_rule:ident, $item_rule:ident ) => {{
use $crate::run;
$crate::separated!($i, run!($sep_rule), run!($item_rule))
}};
($i:expr, $sep_rule:ident, $item_rule:ident ) => {
separated!($i, run!($sep_rule), run!($item_rule))
};
($i:expr, $sep_rule:ident!( $( $args:tt )* ), $item_rule:ident ) => {{
use $crate::run;
$crate::separated!($i, $sep_rule!($($args)*), run!($item_rule))
}};
($i:expr, $sep_rule:ident!( $( $args:tt )* ), $item_rule:ident ) => {
separated!($i, $sep_rule!($($args)*), run!($item_rule))
};
($i:expr, $sep_rule:ident, $item_rule:ident!( $( $args:tt )* ) ) => {{
use $crate::run;
$crate::separated!($i, run!($sep_rule), $item_rule!($($args)*))
}};
($i:expr, $sep_rule:ident, $item_rule:ident!( $( $args:tt )* ) ) => {
separated!($i, run!($sep_rule), $item_rule!($($args)*))
};
}
/// Convenience macro for looking for a specific text token in a byte input stream.
@ -819,20 +794,18 @@ macro_rules! until {
pfn()
}};
($i:expr, $rule:ident) => {{
use $crate::run;
$crate::until!($i, run!($rule))
}};
($i:expr, $rule:ident) => {
until!($i, run!($rule))
};
}
/// Discards the output of a combinator rule when it completes and just returns `()`.
/// Leaves Failures, Aborts, and Incompletes untouched.
#[macro_export]
macro_rules! discard {
($i:expr, $rule:ident) => {{
use $crate::run;
$crate::discard!($i, run!($rule))
}};
($i:expr, $rule:ident) => {
discard!($i, run!($rule))
};
($i:expr, $rule:ident!( $( $args:tt )* ) ) => {{
use $crate::Result;
@ -913,13 +886,11 @@ macro_rules! make_fn {
};
($name:ident<$i:ty, $o:ty>, $rule:ident) => {
use $crate::run
$crate::make_fn!($name<$i, $o>, run!($rule));
make_fn!($name<$i, $o>, run!($rule));
};
(pub $name:ident<$i:ty, $o:ty>, $rule:ident) => {
use $crate::run
$crate::make_fn!(pub $name<$i, $o>, run!($rule));
make_fn!(pub $name<$i, $o>, run!($rule));
};
}
@ -930,7 +901,7 @@ macro_rules! make_fn {
#[macro_export]
macro_rules! input {
($i:expr) => {
$crate::input!($i,)
input!($i,)
};
($i:expr,) => {{
@ -985,10 +956,9 @@ macro_rules! consume_all {
pfn()
}};
($i:expr, $rule:ident) => {{
use $crate::run;
$crate::consume_all!($i, run!($rule))
}}
($i:expr, $rule:ident) => {
consume_all!($i, run!($rule))
}
}
/// ascii_digit parses a single ascii alphabetic or digit character from an InputIter of bytes.

View File

@ -11,30 +11,27 @@
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use super::{
ascii_ws, eoi,
iter::{SliceIter, StrIter},
Result,
};
use super::{ascii_ws, eoi, Result};
use iter::{SliceIter, StrIter};
make_fn!(proto<StrIter, &str>,
do_each!(
proto => until!(text_token!("://")),
_ => must!(text_token!("://")),
(proto)
)
);
do_each!(
proto => until!(text_token!("://")),
_ => must!(text_token!("://")),
(proto)
)
);
make_fn!(domain<StrIter, &str>,
until!(either!(
discard!(text_token!("/")),
discard!(ascii_ws),
eoi))
);
until!(either!(
discard!(text_token!("/")),
discard!(ascii_ws),
eoi))
);
make_fn!(path<StrIter, &str>,
until!(either!(discard!(ascii_ws), eoi))
);
until!(either!(discard!(ascii_ws), eoi))
);
make_fn!(
sliceit<SliceIter<u8>, ()>,
@ -55,14 +52,14 @@ make_fn!(
);
make_fn!(pub url<StrIter, (Option<&str>, Option<&str>, &str)>,
do_each!(
_ => input!(),
protocol => optional!(proto),
domain => optional!(domain),
path => path,
(protocol, domain, path)
)
);
do_each!(
_ => input!(),
protocol => optional!(proto),
domain => optional!(domain),
path => path,
(protocol, domain, path)
)
);
#[test]
fn test_url_parser() {

View File

@ -83,19 +83,7 @@ impl<'a, T: Debug + 'a> Clone for SliceIter<'a, T> {
}
}
impl<'a, T: Debug + 'a> InputIter for SliceIter<'a, T> {
fn curr(&self) -> Self::Item {
if self.offset >= self.source.len() {
self.source.get(self.source.len() - 1).unwrap()
} else {
if self.offset == 0 {
self.source.get(self.offset).unwrap()
} else {
self.source.get(self.offset - 1).unwrap()
}
}
}
}
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] {
@ -201,19 +189,7 @@ impl<'a> Clone for StrIter<'a> {
}
}
impl<'a> InputIter for StrIter<'a> {
fn curr(&self) -> Self::Item {
if self.offset >= self.source.len() {
self.source.as_bytes().get(self.source.len() - 1).unwrap()
} else {
if self.offset == 0 {
self.source.as_bytes().get(self.offset).unwrap()
} else {
self.source.as_bytes().get(self.offset - 1).unwrap()
}
}
}
}
impl<'a> InputIter for StrIter<'a> {}
impl<'a> From<&'a str> for StrIter<'a> {
fn from(source: &'a str) -> Self {

View File

@ -118,7 +118,7 @@ impl Offsetable for usize {
}
pub trait Seekable {
fn seek(&mut self, u: usize) -> usize;
fn seek(&mut self, usize) -> usize;
}
/// Trait for Inputs that can report current lines and columns in a text input.
@ -145,9 +145,7 @@ pub trait Peekable<O> {
}
/// A Cloneable Iterator that can report an offset as a count of processed Items.
pub trait InputIter: Iterator + Clone + Offsetable {
fn curr(&self) -> Self::Item;
}
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
@ -205,7 +203,7 @@ impl<C: Offsetable> Offsetable for Error<C> {
impl<C: Offsetable> Display for Error<C> {
fn fmt(&self, f: &mut std::fmt::Formatter) -> result::Result<(), std::fmt::Error> {
write!(f, "{}", self.msg)?;
try!(write!(f, "{}", self.msg));
match self.cause {
Some(ref c) => write!(f, "\n\tCaused By:{}", c),
None => Ok(()),

View File

@ -14,11 +14,9 @@
use std::fmt::{Debug, Display};
use super::combinators::*;
use super::{
iter::{SliceIter, StrIter},
InputIter, Offsetable, Positioned, Result,
};
use super::{InputIter, Offsetable, Positioned, Result};
use combinators::*;
use iter::{SliceIter, StrIter};
#[test]
fn test_slice_iter() {
@ -32,10 +30,8 @@ fn test_slice_iter() {
None => break,
Some(b) => b,
};
assert_eq!(*b as char, *iter.curr() as char);
out.push(b.clone());
}
assert_eq!(*iter.curr(), 'o' as u8);
assert_eq!(3, out.len());
assert_eq!('f' as u8, out[0]);
assert_eq!('o' as u8, out[1]);
@ -402,19 +398,6 @@ fn test_until() {
}
}
#[test]
fn test_until_with_function_composition() {
let input_str = "foo ";
let iter = StrIter::new(input_str);
let result = until!(iter, ascii_ws);
assert!(result.is_complete());
if let Result::Complete(i, o) = result {
assert_eq!(i.get_offset(), 3);
assert_eq!(o.len(), 3);
assert_eq!(o, "foo");
}
}
#[test]
fn test_until_abort() {
let input_str = "foo ";