diff --git a/Cargo.toml b/Cargo.toml index bd0115e6..337b07e9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,6 +25,7 @@ conv = { version = "0.3", default-features = false } # Technically a dev-dependency, but dev-dependencies are not allowed to be optional, # compiletest_rs fails to compile on stable and beta compiletest_rs = { version = "0.0.10", optional = true } +nom = { version = "1.0.0", optional = true } [features] default = ["verbose_error"] @@ -32,3 +33,4 @@ default = ["verbose_error"] nightly_test = ["compiletest_rs"] verbose_error = [] +nom_adapter = ["nom"] diff --git a/src/input.rs b/src/input.rs index a21f305c..8b29bd6f 100644 --- a/src/input.rs +++ b/src/input.rs @@ -255,6 +255,72 @@ impl<'a, I: 'a> InputBuffer<'a> for Input<'a, I> { } } +#[cfg(feature = "nom_adapter")] +impl<'a, I> Input<'a, I> { + /// Calls out to a Nom parser. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate chomp; + /// #[macro_use] + /// extern crate nom; + /// + /// use chomp::{Input, ParseResult}; + /// use chomp::{take_while1, token, take_remainder}; + /// use chomp::ascii::is_alpha; + /// + /// named!(nom_word, chain!(word: take_while1!(is_alpha) ~ tag!(b" "), || word)); + /// + /// # fn main() { + /// let i = Input::new(b"Works with Nom!"); + /// + /// let r: ParseResult<_, _, chomp::NomError<_, _>> = parse!{i; + /// let first = take_while1(is_alpha); + /// token(b' '); + /// let nom_result = i -> i.nom_parser(nom_word); + /// let remainder = take_remainder(); + /// + /// ret (first, nom_result, remainder) + /// }; + /// + /// assert_eq!(r.unwrap(), (&b"Works"[..], &b"with"[..], &b"Nom!"[..])); + /// # } + /// ``` + pub fn nom_parser(self, f: F) -> ParseResult<'a, I, T, NomError<'a, I, E>> + where F: FnOnce(&'a [I]) -> ::nom::IResult<&'a [I], T, E> { + use nom::IResult; + use nom::Needed; + + match f(self.1) { + IResult::Done(b, t) => parse_result::new(State::Data(Input(self.0, b), t)), + IResult::Error(e) => parse_result::new(State::Error(self.1, NomError::NomError(e))), + IResult::Incomplete(Needed::Unknown) => parse_result::new(State::Incomplete(1)), + IResult::Incomplete(Needed::Size(n)) => parse_result::new(State::Incomplete(n)), + } + } +} + +#[cfg(feature = "nom_adapter")] +#[derive(Debug)] +pub enum NomError<'a, I: 'a, E> { + NomError(::nom::Err<&'a [I], E>), + ChompError(::parsers::Error), +} + +#[cfg(feature = "nom_adapter")] +impl<'a, I: 'a, E> From<::nom::Err<&'a [I], E>> for NomError<'a, I, E> { + fn from(e: ::nom::Err<&'a [I], E>) -> Self { + NomError::NomError(e) + } +} + +#[cfg(feature = "nom_adapter")] +impl<'a, I, E> From<::parsers::Error> for NomError<'a, I, E> { + fn from(e: ::parsers::Error) -> Self { + NomError::ChompError(e) + } +} + #[cfg(test)] mod test { use super::{new, Input, InputBuffer, DEFAULT, END_OF_INPUT}; diff --git a/src/lib.rs b/src/lib.rs index 8ef5ad40..adc342c3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -180,6 +180,8 @@ #[macro_use] extern crate bitflags; extern crate conv; +#[cfg(feature = "nom_adapter")] +extern crate nom; #[macro_use] mod macros; @@ -261,3 +263,6 @@ pub mod primitives { pub use parse_result::new; } } + +#[cfg(feature = "nom_adapter")] +pub use input::NomError;