16855e09eSopenharmony_ciuse std::fmt;
26855e09eSopenharmony_ciuse std::fmt::{Debug, Display, Formatter};
36855e09eSopenharmony_ci
46855e09eSopenharmony_ciuse std::str::FromStr;
56855e09eSopenharmony_ci
66855e09eSopenharmony_ciuse nom::{
76855e09eSopenharmony_ci  branch::alt,
86855e09eSopenharmony_ci  bytes::complete::tag,
96855e09eSopenharmony_ci  character::complete::{digit1 as digit, multispace0 as multispace},
106855e09eSopenharmony_ci  combinator::{map, map_res},
116855e09eSopenharmony_ci  multi::many0,
126855e09eSopenharmony_ci  sequence::{delimited, preceded},
136855e09eSopenharmony_ci  IResult,
146855e09eSopenharmony_ci};
156855e09eSopenharmony_ci
166855e09eSopenharmony_cipub enum Expr {
176855e09eSopenharmony_ci  Value(i64),
186855e09eSopenharmony_ci  Add(Box<Expr>, Box<Expr>),
196855e09eSopenharmony_ci  Sub(Box<Expr>, Box<Expr>),
206855e09eSopenharmony_ci  Mul(Box<Expr>, Box<Expr>),
216855e09eSopenharmony_ci  Div(Box<Expr>, Box<Expr>),
226855e09eSopenharmony_ci  Paren(Box<Expr>),
236855e09eSopenharmony_ci}
246855e09eSopenharmony_ci
256855e09eSopenharmony_ci#[derive(Debug)]
266855e09eSopenharmony_cipub enum Oper {
276855e09eSopenharmony_ci  Add,
286855e09eSopenharmony_ci  Sub,
296855e09eSopenharmony_ci  Mul,
306855e09eSopenharmony_ci  Div,
316855e09eSopenharmony_ci}
326855e09eSopenharmony_ci
336855e09eSopenharmony_ciimpl Display for Expr {
346855e09eSopenharmony_ci  fn fmt(&self, format: &mut Formatter<'_>) -> fmt::Result {
356855e09eSopenharmony_ci    use self::Expr::*;
366855e09eSopenharmony_ci    match *self {
376855e09eSopenharmony_ci      Value(val) => write!(format, "{}", val),
386855e09eSopenharmony_ci      Add(ref left, ref right) => write!(format, "{} + {}", left, right),
396855e09eSopenharmony_ci      Sub(ref left, ref right) => write!(format, "{} - {}", left, right),
406855e09eSopenharmony_ci      Mul(ref left, ref right) => write!(format, "{} * {}", left, right),
416855e09eSopenharmony_ci      Div(ref left, ref right) => write!(format, "{} / {}", left, right),
426855e09eSopenharmony_ci      Paren(ref expr) => write!(format, "({})", expr),
436855e09eSopenharmony_ci    }
446855e09eSopenharmony_ci  }
456855e09eSopenharmony_ci}
466855e09eSopenharmony_ci
476855e09eSopenharmony_ciimpl Debug for Expr {
486855e09eSopenharmony_ci  fn fmt(&self, format: &mut Formatter<'_>) -> fmt::Result {
496855e09eSopenharmony_ci    use self::Expr::*;
506855e09eSopenharmony_ci    match *self {
516855e09eSopenharmony_ci      Value(val) => write!(format, "{}", val),
526855e09eSopenharmony_ci      Add(ref left, ref right) => write!(format, "({:?} + {:?})", left, right),
536855e09eSopenharmony_ci      Sub(ref left, ref right) => write!(format, "({:?} - {:?})", left, right),
546855e09eSopenharmony_ci      Mul(ref left, ref right) => write!(format, "({:?} * {:?})", left, right),
556855e09eSopenharmony_ci      Div(ref left, ref right) => write!(format, "({:?} / {:?})", left, right),
566855e09eSopenharmony_ci      Paren(ref expr) => write!(format, "[{:?}]", expr),
576855e09eSopenharmony_ci    }
586855e09eSopenharmony_ci  }
596855e09eSopenharmony_ci}
606855e09eSopenharmony_ci
616855e09eSopenharmony_cifn parens(i: &str) -> IResult<&str, Expr> {
626855e09eSopenharmony_ci  delimited(
636855e09eSopenharmony_ci    multispace,
646855e09eSopenharmony_ci    delimited(tag("("), map(expr, |e| Expr::Paren(Box::new(e))), tag(")")),
656855e09eSopenharmony_ci    multispace,
666855e09eSopenharmony_ci  )(i)
676855e09eSopenharmony_ci}
686855e09eSopenharmony_ci
696855e09eSopenharmony_cifn factor(i: &str) -> IResult<&str, Expr> {
706855e09eSopenharmony_ci  alt((
716855e09eSopenharmony_ci    map(
726855e09eSopenharmony_ci      map_res(delimited(multispace, digit, multispace), FromStr::from_str),
736855e09eSopenharmony_ci      Expr::Value,
746855e09eSopenharmony_ci    ),
756855e09eSopenharmony_ci    parens,
766855e09eSopenharmony_ci  ))(i)
776855e09eSopenharmony_ci}
786855e09eSopenharmony_ci
796855e09eSopenharmony_cifn fold_exprs(initial: Expr, remainder: Vec<(Oper, Expr)>) -> Expr {
806855e09eSopenharmony_ci  remainder.into_iter().fold(initial, |acc, pair| {
816855e09eSopenharmony_ci    let (oper, expr) = pair;
826855e09eSopenharmony_ci    match oper {
836855e09eSopenharmony_ci      Oper::Add => Expr::Add(Box::new(acc), Box::new(expr)),
846855e09eSopenharmony_ci      Oper::Sub => Expr::Sub(Box::new(acc), Box::new(expr)),
856855e09eSopenharmony_ci      Oper::Mul => Expr::Mul(Box::new(acc), Box::new(expr)),
866855e09eSopenharmony_ci      Oper::Div => Expr::Div(Box::new(acc), Box::new(expr)),
876855e09eSopenharmony_ci    }
886855e09eSopenharmony_ci  })
896855e09eSopenharmony_ci}
906855e09eSopenharmony_ci
916855e09eSopenharmony_cifn term(i: &str) -> IResult<&str, Expr> {
926855e09eSopenharmony_ci  let (i, initial) = factor(i)?;
936855e09eSopenharmony_ci  let (i, remainder) = many0(alt((
946855e09eSopenharmony_ci    |i| {
956855e09eSopenharmony_ci      let (i, mul) = preceded(tag("*"), factor)(i)?;
966855e09eSopenharmony_ci      Ok((i, (Oper::Mul, mul)))
976855e09eSopenharmony_ci    },
986855e09eSopenharmony_ci    |i| {
996855e09eSopenharmony_ci      let (i, div) = preceded(tag("/"), factor)(i)?;
1006855e09eSopenharmony_ci      Ok((i, (Oper::Div, div)))
1016855e09eSopenharmony_ci    },
1026855e09eSopenharmony_ci  )))(i)?;
1036855e09eSopenharmony_ci
1046855e09eSopenharmony_ci  Ok((i, fold_exprs(initial, remainder)))
1056855e09eSopenharmony_ci}
1066855e09eSopenharmony_ci
1076855e09eSopenharmony_cifn expr(i: &str) -> IResult<&str, Expr> {
1086855e09eSopenharmony_ci  let (i, initial) = term(i)?;
1096855e09eSopenharmony_ci  let (i, remainder) = many0(alt((
1106855e09eSopenharmony_ci    |i| {
1116855e09eSopenharmony_ci      let (i, add) = preceded(tag("+"), term)(i)?;
1126855e09eSopenharmony_ci      Ok((i, (Oper::Add, add)))
1136855e09eSopenharmony_ci    },
1146855e09eSopenharmony_ci    |i| {
1156855e09eSopenharmony_ci      let (i, sub) = preceded(tag("-"), term)(i)?;
1166855e09eSopenharmony_ci      Ok((i, (Oper::Sub, sub)))
1176855e09eSopenharmony_ci    },
1186855e09eSopenharmony_ci  )))(i)?;
1196855e09eSopenharmony_ci
1206855e09eSopenharmony_ci  Ok((i, fold_exprs(initial, remainder)))
1216855e09eSopenharmony_ci}
1226855e09eSopenharmony_ci
1236855e09eSopenharmony_ci#[test]
1246855e09eSopenharmony_cifn factor_test() {
1256855e09eSopenharmony_ci  assert_eq!(
1266855e09eSopenharmony_ci    factor("  3  ").map(|(i, x)| (i, format!("{:?}", x))),
1276855e09eSopenharmony_ci    Ok(("", String::from("3")))
1286855e09eSopenharmony_ci  );
1296855e09eSopenharmony_ci}
1306855e09eSopenharmony_ci
1316855e09eSopenharmony_ci#[test]
1326855e09eSopenharmony_cifn term_test() {
1336855e09eSopenharmony_ci  assert_eq!(
1346855e09eSopenharmony_ci    term(" 3 *  5   ").map(|(i, x)| (i, format!("{:?}", x))),
1356855e09eSopenharmony_ci    Ok(("", String::from("(3 * 5)")))
1366855e09eSopenharmony_ci  );
1376855e09eSopenharmony_ci}
1386855e09eSopenharmony_ci
1396855e09eSopenharmony_ci#[test]
1406855e09eSopenharmony_cifn expr_test() {
1416855e09eSopenharmony_ci  assert_eq!(
1426855e09eSopenharmony_ci    expr(" 1 + 2 *  3 ").map(|(i, x)| (i, format!("{:?}", x))),
1436855e09eSopenharmony_ci    Ok(("", String::from("(1 + (2 * 3))")))
1446855e09eSopenharmony_ci  );
1456855e09eSopenharmony_ci  assert_eq!(
1466855e09eSopenharmony_ci    expr(" 1 + 2 *  3 / 4 - 5 ").map(|(i, x)| (i, format!("{:?}", x))),
1476855e09eSopenharmony_ci    Ok(("", String::from("((1 + ((2 * 3) / 4)) - 5)")))
1486855e09eSopenharmony_ci  );
1496855e09eSopenharmony_ci  assert_eq!(
1506855e09eSopenharmony_ci    expr(" 72 / 2 / 3 ").map(|(i, x)| (i, format!("{:?}", x))),
1516855e09eSopenharmony_ci    Ok(("", String::from("((72 / 2) / 3)")))
1526855e09eSopenharmony_ci  );
1536855e09eSopenharmony_ci}
1546855e09eSopenharmony_ci
1556855e09eSopenharmony_ci#[test]
1566855e09eSopenharmony_cifn parens_test() {
1576855e09eSopenharmony_ci  assert_eq!(
1586855e09eSopenharmony_ci    expr(" ( 1 + 2 ) *  3 ").map(|(i, x)| (i, format!("{:?}", x))),
1596855e09eSopenharmony_ci    Ok(("", String::from("([(1 + 2)] * 3)")))
1606855e09eSopenharmony_ci  );
1616855e09eSopenharmony_ci}
162