diff --git a/src/combinators.rs b/src/combinators.rs index bd76baf..967cf01 100644 --- a/src/combinators.rs +++ b/src/combinators.rs @@ -760,11 +760,13 @@ macro_rules! make_fn { } +/// For inputs that implement the TextPositionTracker trait returns the current +/// line and column position for this input. #[macro_export] macro_rules! pos { ($i:expr) => {{ let _i = $i.clone(); use $crate::TextPositionTracker; $crate::Result::Complete($i, (_i.line(), _i.column())) - }} -} \ No newline at end of file + }}; +} diff --git a/src/integration_tests.rs b/src/integration_tests.rs index f76d454..fa8c12a 100644 --- a/src/integration_tests.rs +++ b/src/integration_tests.rs @@ -1,4 +1,3 @@ - use super::{ascii_ws, eoi, Result}; use iter::StrIter; diff --git a/src/lib.rs b/src/lib.rs index 3a34c63..5c136af 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,6 +1,13 @@ //! An opinionated parser combinator library with a focus on fully abortable parsing and error handling. //! -//! # Example +//! The approach to macro composition is heavily inspired by nom. However we emphasize error +//! handling as a first class citizen. abortable_parser has the concept of an unrecoverable +//! parsing error as distinct from a general failure to match. +//! +//! We have a numner of macros that assist in the gneration or handling of each type +//! of error. +//! +//! # Simple parsing of a url. //! //! ``` //! #[macro_use] @@ -17,22 +24,46 @@ //! ); //! //! make_fn!(domain, -//! until!(either!( -//! discard!(text_token!("/")), -//! discard!(ascii_ws), -//! eoi)) +//! do_each!( +//! // domains do not start with a slash +//! _ => peek!(not!(text_token!("/"))), +//! domain => until!(either!( +//! discard!(text_token!("/")), +//! discard!(ascii_ws), +//! eoi)), +//! (domain) +//! ) //! ); //! //! make_fn!(path, //! until!(either!(discard!(ascii_ws), eoi)) //! ); //! -//! make_fn!(url, Option<&str>, &str)>, +//! make_fn!(full_url, Option<&str>, Option<&str>)>, //! do_each!( -//! protocol => optional!(proto), -//! domain => optional!(domain), +//! protocol => proto, +//! // If we match the protocol then we must have a domain. +//! // This is an example of an unrecoverable parsing error so we +//! // abort with the must! macro if it doesn't match. +//! domain => must!(domain), +//! path => optional!(path), +//! (Some(protocol), Some(domain), path) +//! ) +//! ); +//! +//! make_fn!(relative_url, Option<&str>, Option<&str>)>, +//! do_each!( +//! _ => not!(either!(text_token!("//"), proto)), +//! // we require a valid path for relative urls. //! path => path, -//! (protocol, domain, path) +//! (None, None, Some(path)) +//! ) +//! ); +//! +//! make_fn!(url, Option<&str>, Option<&str>)>, +//! either!( +//! full_url, +//! relative_url, //! ) //! ); //! @@ -43,8 +74,18 @@ //! if let Result::Complete(_, (proto, domain, path)) = result { //! assert!(proto.is_some()); //! assert!(domain.is_some()); -//! assert_eq!(path, "/some/path"); +//! if let Some(domain) = domain { +//! assert_eq!(domain, "example.com"); +//! } +//! assert!(path.is_some()); +//! if let Some(path) = path { +//! assert_eq!(path, "/some/path"); +//! } //! } +//! +//! let bad_input = StrIter::new("http:///some/path"); +//! let bad_result = url(bad_input); +//! assert!(bad_result.is_abort()); //! # } //! ``` use std::fmt::Display; @@ -67,6 +108,7 @@ pub trait TextPositionTracker { fn column(&self) -> usize; } +/// SpanRange encompasses the valid Ops::Range types for use with the Span trait. pub enum SpanRange { Range(std::ops::Range), RangeTo(std::ops::RangeTo), @@ -74,7 +116,7 @@ pub enum SpanRange { RangeFull(std::ops::RangeFull), } -// An input that can provide a span of a range of the input. +/// An input that can provide a span of a range of the input. pub trait Span { fn span(&self, idx: SpanRange) -> O; }