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
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
pub use crate::core::complete::*;
pub use crate::core::*;
pub fn read_line(s: &str) -> IResult<&str, &str> {
use nom::combinator::recognize;
let (rest, line_opt) = opt(recognize(pair(take_until("\n"), tag("\n"))))(s)?;
match line_opt {
None => nom::combinator::rest(rest),
Some(line) => Ok((rest, line)),
}
}
#[test]
fn test_read_line() {
let txt = "first line\nsecond line\r\nthird line\n";
let (rest, line) = read_line(txt).unwrap();
assert_eq!(line, "first line\n");
let (rest, line) = read_line(rest).unwrap();
assert_eq!(line, "second line\r\n");
let (rest, line) = read_line(rest).unwrap();
assert_eq!(line, "third line\n");
assert_eq!(rest, "");
let txt = "no newline at the end";
let (rest, line) = read_line(txt).unwrap();
assert_eq!(line, txt);
assert_eq!(rest, "");
}
pub fn read_until_eol(s: &str) -> IResult<&str, &str> {
use nom::character::complete::line_ending;
use nom::character::complete::not_line_ending;
nom::sequence::terminated(not_line_ending, line_ending)(s)
}
pub fn eol(s: &str) -> IResult<&str, &str> {
use nom::character::complete::line_ending;
nom::sequence::terminated(space0, line_ending)(s)
}
pub fn not_space(s: &str) -> IResult<&str, &str> {
is_not(" \t\r\n")(s)
}
pub fn unsigned_digit(s: &str) -> IResult<&str, usize> {
map(digit1, |s: &str| s.parse().unwrap())(s)
}
pub fn signed_digit(s: &str) -> IResult<&str, isize> {
use nom::combinator::recognize;
let sign = opt(alt((tag("-"), tag("+"))));
map_res(recognize(pair(sign, digit1)), |x: &str| x.parse::<isize>())(s)
}
#[test]
fn test_signed_digit() {
let (_, x) = signed_digit("-123").expect("signed digit, minus");
assert_eq!(x, -123);
let (_, x) = signed_digit("123").expect("signed digit, normal");
assert_eq!(x, 123);
let (_, x) = signed_digit("+123").expect("signed digit, plus");
assert_eq!(x, 123);
}
pub fn read_usize(s: &str) -> IResult<&str, usize> {
use nom::character::complete::line_ending;
let p = nom::sequence::delimited(space0, unsigned_digit, space0);
nom::sequence::terminated(p, line_ending)(s)
}
#[test]
fn test_numbers() {
let s = "12x";
let (r, n) = unsigned_digit(s).unwrap();
assert_eq!(n, 12);
assert_eq!(r, "x");
let (r, n) = read_usize(" 12 \n").unwrap();
assert_eq!(n, 12);
assert_eq!(r, "");
}
pub fn xyz_array(s: &str) -> IResult<&str, [f64; 3]> {
let (r, (x, _, y, _, z)) = tuple((double, space1, double, space1, double))(s)?;
Ok((r, [x, y, z]))
}
pub fn jump_to<'a>(token: &'a str) -> impl Fn(&'a str) -> IResult<&str, ()> {
map(pair(take_until(token), tag(token)), |_| ())
}
#[test]
fn test_take() {
let x = "xxbcc aa cc";
let (r, _) = jump_to("aa")(x).unwrap();
assert_eq!(r, " cc");
}
pub fn take_s<'a>(n: usize) -> impl Fn(&'a str) -> IResult<&'a str, &'a str> {
take(n)
}