#[macro_use]
extern crate nom;
use nom::types::CompleteStr;
use std::str::FromStr;
#[macro_export]
macro_rules! complete_named (
($name:ident, $submac:ident!( $($args:tt)* )) => (
fn $name( i: CompleteStr ) -> nom::IResult<CompleteStr, CompleteStr, u32> {
$submac!(i, $($args)*)
}
);
($name:ident<$o:ty>, $submac:ident!( $($args:tt)* )) => (
fn $name( i: CompleteStr ) -> nom::IResult<CompleteStr, $o, u32> {
$submac!(i, $($args)*)
}
);
);
complete_named!(digit, is_a!("0123456789"));
complete_named!(parens<i64>, ws!(delimited!( tag!("("), expr, tag!(")") )) );
complete_named!(factor<i64>, alt!(
map_res!(
ws!(digit),
to_i64
)
| parens
)
);
complete_named!(term <i64>, do_parse!(
init: factor >>
res: fold_many0!(
pair!(alt!(tag!("*") | tag!("/")), factor),
init,
|acc, (op, val): (CompleteStr, i64)| {
if (op.0.chars().next().unwrap() as char) == '*' { acc * val } else { acc / val }
}
) >>
(res)
)
);
complete_named!(expr <i64>, do_parse!(
init: term >>
res: fold_many0!(
pair!(alt!(tag!("+") | tag!("-")), term),
init,
|acc, (op, val): (CompleteStr, i64)| {
if (op.0.chars().next().unwrap() as char) == '+' { acc + val } else { acc - val }
}
) >>
(res)
)
);
complete_named!(root_expr<i64>,
terminated!(expr, eof!())
);
fn to_i64(input: CompleteStr) -> Result<i64, ()> {
match FromStr::from_str(input.0) {
Err(_) => Err(()),
Ok(i) => Ok(i),
}
}
#[test]
fn factor_test() {
let a = CompleteStr("3");
println!("calculated: {:?}", factor(a));
}
#[test]
fn parens_test() {
use nom::ErrorKind;
let input1 = CompleteStr(" 2* ( 3 + 4 ) ");
assert_eq!(expr(input1), Ok((CompleteStr(""), 14)));
let input2 = CompleteStr(" 2*2 / ( 5 - 1) + 3");
assert_eq!(expr(input2), Ok((CompleteStr(""), 4)));
let input3 = CompleteStr(" 2*2 / ( 5 - 1) + ");
assert_eq!(root_expr(input3), Err(nom::Err::Error(error_position!(CompleteStr("+ "), ErrorKind::Eof))));
}