Macro combine::parser [] [src]

macro_rules! parser {
    (
        $(#[$attr:meta])*
        pub fn $name: ident [$($type_params: tt)*]( $($arg: ident :  $arg_type: ty),* )
            ($input_type: ty) -> $output_type: ty
        $parser: block
    ) => { ... };
    (
        $(#[$attr:meta])*
        fn $name: ident [$($type_params: tt)*]( $($arg: ident :  $arg_type: ty),* )
            ($input_type: ty) -> $output_type: ty
        $parser: block
    ) => { ... };
    (
        $(#[$attr:meta])*
        pub fn $name: ident [$($type_params: tt)*]( $($arg: ident :  $arg_type: ty),* )
            ($input_type: ty) -> $output_type: ty
            where [$($where_clause: tt)*]
        $parser: block
    ) => { ... };
    (
        $(#[$attr:meta])*
        fn $name: ident [$($type_params: tt)*]( $($arg: ident :  $arg_type: ty),*)
            ($input_type: ty) -> $output_type: ty
            where [$($where_clause: tt)*]
        $parser: block
    ) => { ... };
    (
        $(#[$derive:meta])*
        pub struct $type_name: ident;
        $(#[$attr:meta])*
        pub fn $name: ident [$($type_params: tt)*]( $($arg: ident :  $arg_type: ty),* )
            ($input_type: ty) -> $output_type: ty
            where [$($where_clause: tt)*]
        $parser: block
    ) => { ... };
    (
        $(#[$derive:meta])*
        struct $type_name: ident;
        $(#[$attr:meta])*
        fn $name: ident [$($type_params: tt)*]( $($arg: ident :  $arg_type: ty),*)
            ($input_type: ty) -> $output_type: ty
            where [$($where_clause: tt)*]
        $parser: block
    ) => { ... };
    (
        type PartialState = $partial_state: ty;
        $(#[$attr:meta])*
        pub fn $name: ident [$($type_params: tt)*]( $($arg: ident :  $arg_type: ty),* )
            ($input_type: ty) -> $output_type: ty
            $parser: block
    ) => { ... };
    (
        type PartialState = $partial_state: ty;
        $(#[$attr:meta])*
        fn $name: ident [$($type_params: tt)*]( $($arg: ident :  $arg_type: ty),* )
            ($input_type: ty) -> $output_type: ty
            $parser: block
    ) => { ... };
    (
        type PartialState = $partial_state: ty;
        $(#[$attr:meta])*
        pub fn $name: ident [$($type_params: tt)*]( $($arg: ident :  $arg_type: ty),* )
            ($input_type: ty) -> $output_type: ty
            where [$($where_clause: tt)*]
        $parser: block
    ) => { ... };
    (
        type PartialState = $partial_state: ty;
        $(#[$attr:meta])*
        fn $name: ident [$($type_params: tt)*]( $($arg: ident :  $arg_type: ty),*)
            ($input_type: ty) -> $output_type: ty
            where [$($where_clause: tt)*]
        $parser: block
    ) => { ... };
    (
        $(#[$derive:meta])*
        pub struct $type_name: ident;
        type PartialState = $partial_state: ty;
        $(#[$attr:meta])*
        pub fn $name: ident [$($type_params: tt)*]( $($arg: ident :  $arg_type: ty),* )
            ($input_type: ty) -> $output_type: ty
            where [$($where_clause: tt)*]
        $parser: block
    ) => { ... };
    (
        $(#[$derive:meta])*
        struct $type_name: ident;
        type PartialState = $partial_state: ty;
        $(#[$attr:meta])*
        fn $name: ident [$($type_params: tt)*]( $($arg: ident :  $arg_type: ty),*)
            ($input_type: ty) -> $output_type: ty
            where [$($where_clause: tt)*]
        $parser: block
    ) => { ... };
}

Declares a named parser which can easily be reused.

The expression which creates the parser should have no side effects as it may be called multiple times even during a single parse attempt.

NOTE: If you are using rust nightly you can use impl Trait instead. See the json parser for an example.

#[macro_use]
extern crate combine;
use combine::parser::char::digit;
use combine::{any, choice, many1, Parser, Stream};
use combine::error::ParseError;

parser!{
    /// `[I]` represents a normal type parameters and lifetime declaration for the function
    /// It gets expanded to `<I>`
    fn integer[I]()(I) -> i32
    where [
        I: Stream<Item = char>,
        I::Error: ParseError<char, I::Range, I::Position>,
        <I::Error as ParseError<I::Item, I::Range, I::Position>>::StreamError:
            From<::std::num::ParseIntError>,
    ]
    {
        // The body must be a block body ( `{ <block body> }`) which ends with an expression
        // which evaluates to a parser
        let digits = many1(digit());
        digits.and_then(|s: String| s.parse())
    }
}

#[derive(Debug, PartialEq)]
pub enum IntOrString {
    Int(i32),
    String(String),
}
// prefix with `pub` to declare a public parser
parser!{
    // Documentation comments works as well

    /// Parses an integer or a string (any characters)
    pub fn integer_or_string[I]()(I) -> IntOrString
    where [
        I: Stream<Item = char>,
        I::Error: ParseError<char, I::Range, I::Position>,
        <I::Error as ParseError<I::Item, I::Range, I::Position>>::StreamError:
            From<::std::num::ParseIntError>,
    ]
    {
        choice!(
            integer().map(IntOrString::Int),
            many1(any()).map(IntOrString::String)
        )
    }
}

parser!{
    // Give the created type a unique name
    #[derive(Clone)]
    pub struct Twice;
    pub fn twice[F, P](f: F)(P::Input) -> (P::Output, P::Output)
        where [P: Parser,
               F: FnMut() -> P]
    {
        (f(), f())
    }
}

fn main() {
    assert_eq!(integer().easy_parse("123"), Ok((123, "")));
    assert!(integer().easy_parse("!").is_err());

    assert_eq!(
        integer_or_string().easy_parse("123"),
        Ok((IntOrString::Int(123), ""))
    );
    assert_eq!(
        integer_or_string().easy_parse("abc"),
        Ok((IntOrString::String("abc".to_string()), ""))
    );
    assert_eq!(twice(|| digit()).parse("123"), Ok((('1', '2'), "3")));
}