extern crate nom; use nom::combinator::map_res; use nom::{ branch::alt, bytes::complete::tag, character::complete::{digit1, multispace0}, combinator::map, error::{VerboseError, VerboseErrorKind}, map_res, sequence::{preceded, tuple}, IResult, }; #[derive(Debug, PartialEq)] pub enum Op { Add, } #[derive(Debug, PartialEq)] pub enum Expr { Num(i32), BinOp(Box<Expr>, Op, Box<Expr>), } pub fn parse_i32(i: &str) -> IResult<&str, Expr, VerboseError<&str>> { map_res(digit1, |digit_str: &str| match digit_str.parse::<i32>() { Err(e) => Err(VerboseError { errors: vec![(digit_str, VerboseErrorKind::Context("not a 32-bit integer"))], }), Ok(x) => Ok(Expr::Num(x)), })(i) } fn parse_expr(input: &str) -> IResult<&str, Expr, VerboseError<&str>> { preceded( multispace0, alt(( map( tuple((parse_i32, preceded(multispace0, tag("+")), parse_expr)), |(l, _, r)| Expr::BinOp(Box::new(l), Op::Add, Box::new(r)), ), parse_i32, )), )(input) } fn main() { println!("{:?}", parse_expr("1")); println!("{:?}", parse_expr("1+1a")); println!("{:?}", parse_expr("11111111111111111111111111")); }