Macro combine::parser[][src]

macro_rules! parser {
    (type PartialState = $partial_state : ty ; $(#[$attr : meta]) * $fn_vis : vis
 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_vis : vis struct $type_name : ident ; type
 PartialState = $partial_state : ty ; $(#[$attr : meta]) * $fn_vis : vis 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_vis : vis 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_vis : vis struct $type_name : ident ;
 $(#[$attr : meta]) * $fn_vis : vis fn $name : ident [$($type_params : tt) *]
 ($($arg : ident : $arg_type : ty), *) ($input_type : ty) -> $output_type : ty
 where [$($where_clause : tt) *] $parser : block) => { ... };
}
Expand description

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, from_str, many1, Parser, EasyParser, Stream};
use combine::error::ParseError;

parser!{
    /// `[Input]` represents a normal type parameters and lifetime declaration for the function
    /// It gets expanded to `<Input>`
    fn integer[Input]()(Input) -> i32
    where [
        Input: Stream<Token = char>,
        Input::Error: ParseError<char, Input::Range, Input::Position>,
        <Input::Error as ParseError<Input::Token, Input::Range, Input::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
        from_str(many1::<String, _, _>(digit()))
    }
}

#[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[Input]()(Input) -> IntOrString
    where [
        Input: Stream<Token = char>,
        Input::Error: ParseError<char, Input::Range, Input::Position>,
        <Input::Error as ParseError<Input::Token, Input::Range, Input::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[Input, F, P](f: F)(Input) -> (P::Output, P::Output)
        where [P: Parser<Input>,
               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")));
}