forked from rust-bakery/nom
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy patharithmetic.rs
84 lines (75 loc) · 1.87 KB
/
arithmetic.rs
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
#[macro_use]
extern crate criterion;
#[global_allocator]
static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;
use criterion::Criterion;
use nom::{
branch::alt,
character::complete::{char, digit1, one_of, space0},
combinator::map_res,
multi::fold_many0,
sequence::{delimited, pair},
IResult,
};
// Parser definition
// We transform an integer string into a i64, ignoring surrounding whitespaces
// We look for a digit suite, and try to convert it.
// If there are no digits, we look for a parenthesized expression.
fn factor(input: &[u8]) -> IResult<&[u8], i64> {
delimited(
space0,
alt((
map_res(digit1, |digits| {
unsafe { std::str::from_utf8_unchecked(digits) }.parse()
}),
delimited(char('('), expr, char(')')),
)),
space0,
)(input)
}
// We read an initial factor and for each time we find
// a * or / operator followed by another factor, we do
// the math by folding everything
fn term(input: &[u8]) -> IResult<&[u8], i64> {
let (input, init) = factor(input)?;
fold_many0(
pair(one_of("*/"), factor),
move || init,
|acc, (op, val)| {
if op == '*' {
acc * val
} else {
acc / val
}
},
)(input)
}
fn expr(input: &[u8]) -> IResult<&[u8], i64> {
let (input, init) = term(input)?;
fold_many0(
pair(one_of("+-"), term),
move || init,
|acc, (op, val)| {
if op == '+' {
acc + val
} else {
acc - val
}
},
)(input)
}
fn arithmetic(c: &mut Criterion) {
let data = b" 2*2 / ( 5 - 1) + 3 / 4 * (2 - 7 + 567 *12 /2) + 3*(1+2*( 45 /2));";
assert_eq!(
expr(data),
Ok((
&b";"[..],
2 * 2 / (5 - 1) + 3 / 4 * (2 - 7 + 567 * 12 / 2) + 3 * (1 + 2 * (45 / 2)),
))
);
c.bench_function("arithmetic", |b| {
b.iter(|| expr(data).unwrap());
});
}
criterion_group!(benches, arithmetic);
criterion_main!(benches);