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
#[macro_export]
macro_rules! repeat {
($visibility:vis $name:ident { $to_repeat:ident; { $lower:expr , } } )=> {
repeat!($visibility $name { $to_repeat; { 1 , usize::MAX } } );
};
($visibility:vis $name:ident { $to_repeat:ident; { , $upper:expr } } )=> {
repeat!($visibility $name { $to_repeat; { 0 , $upper }});
};
($visibility:vis $name:ident { $to_repeat:ident; { , } } )=> {
repeat!($visibility $name { $to_repeat; { 0 , usize::MAX }});
};
($visibility:vis $name:ident { $to_repeat:ident; { $amount:expr } } )=> {
repeat!($visibility $name { $to_repeat; { $amount , $amount }});
};
($visibility:vis $name:ident { $to_repeat:ident; { $lower:expr , $upper:expr } } ) => {
$visibility fn $name ( string: String, index: usize ) -> $crate::parse_result::ParseResult {
use $crate::Parser;
use $crate::Progress;
use $crate::ParseError;
use $crate::Done;
use std::rc::Rc;
let lower: usize = $lower;
let upper: usize = $upper;
let to_repeat: Parser = $to_repeat;
let name: &'static str = stringify!($name);
let mut offset = 0;
let mut children: Vec<Rc<Done>> = vec![];
#[allow(unused_assignments)]
let mut parse_error = ParseError {
offset,
name_stack: vec![],
message: ""
};
loop {
let result = to_repeat(string.clone(), index + offset);
if let Ok(progress) = result {
children.push(Rc::from(progress.done));
offset += progress.offset;
continue;
}
if let Err(new_parse_error) = result {
parse_error = new_parse_error;
break;
}
}
if children.len() < lower || children.len() > upper {
let mut result = parse_error.clone();
result.offset = offset;
result.name_stack.push(name);
result.message = concat!("Couldn't parse '", stringify!($name) ,"' enough times.");
return Err(result.clone());
}
Ok( Progress { offset, done: Done::Nonterminal {
name,
children
}})
}
};
}