File: complete_arithmetic.rs

package info (click to toggle)
rust-nom-4 4.2.3-3
  • links: PTS, VCS
  • area: main
  • in suites: bookworm, bullseye
  • size: 820 kB
  • sloc: makefile: 2
file content (95 lines) | stat: -rw-r--r-- 2,158 bytes parent folder | download | duplicates (4)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
#[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
    )))
  );
}