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")));
}