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, from_str, many1, Parser, Stream};
use combine::error::ParseError;
parser!{
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>,
]
{
from_str(many1::<String, _>(digit()))
}
}
#[derive(Debug, PartialEq)]
pub enum IntOrString {
Int(i32),
String(String),
}
parser!{
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!{
#[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")));
}