1use range::Range;
2use read_token::ReadToken;
3
4use super::{
5 ret_err,
6 err_update,
7 update,
8 IndentSettings,
9 ParseResult,
10};
11use {
12 DebugId,
13 MetaData,
14 Rule,
15};
16use tokenizer::TokenizerState;
17
18#[derive(Clone, Debug, PartialEq)]
20pub struct SeparateBy {
21 pub rule: Rule,
23 pub by: Rule,
25 pub optional: bool,
27 pub allow_trail: bool,
29 pub debug_id: DebugId,
31}
32
33impl SeparateBy {
34 pub fn parse(
36 &self,
37 tokens: &mut Vec<Range<MetaData>>,
38 state: &TokenizerState,
39 read_token: &ReadToken,
40 refs: &[Rule],
41 indent_settings: &mut IndentSettings,
42 ) -> ParseResult<TokenizerState> {
43 let start = read_token;
44 let mut read_token = *start;
45 let mut state = state.clone();
46 let mut first = true;
47 let mut opt_error = None;
48 loop {
49 state = match self.rule.parse(tokens, &state, &read_token, refs, indent_settings) {
50 Err(err) => {
51 match (first, self.optional, self.allow_trail) {
52 (true, false, _)
53 | (false, _, false) => {
54 return Err(ret_err(err, opt_error));
55 }
56 (true, true, _)
57 | (false, _, true) => {
58 err_update(Some(err), &mut opt_error);
59 break;
60 }
61 }
62 }
63 Ok((range, state, err)) => {
64 update(range, err, &mut read_token, &mut opt_error);
65 state
66 }
67 };
68 state = match self.by.parse(
69 tokens, &state, &read_token, refs, indent_settings
70 ) {
71 Err(err) => {
72 err_update(Some(err), &mut opt_error);
73 break;
74 }
75 Ok((range, state, err)) => {
76 update(range, err, &mut read_token, &mut opt_error);
77 state
78 }
79 };
80 first = false;
81 }
82 Ok((read_token.subtract(start), state, opt_error))
83 }
84}
85
86#[cfg(test)]
87mod tests {
88 use all::*;
89 use all::tokenizer::*;
90 use meta_rules::{ IndentSettings, SeparateBy, Tag, UntilAnyOrWhitespace };
91 use std::sync::Arc;
92 use range::Range;
93 use read_token::ReadToken;
94
95 #[test]
96 fn required() {
97 let ref mut indent_settings = IndentSettings::default();
98 let text = "foo()";
99 let mut tokens = vec![];
100 let s = TokenizerState::new();
101 let sep = SeparateBy {
102 debug_id: 0,
103 rule: Rule::UntilAnyOrWhitespace(UntilAnyOrWhitespace {
104 debug_id: 1,
105 any_characters: Arc::new(",)".into()),
106 optional: false,
107 property: None,
108 }),
109 by: Rule::Tag(Tag {
110 debug_id: 2,
111 text: Arc::new(",".into()),
112 not: false,
113 inverted: false,
114 property: None,
115 }),
116 optional: false,
117 allow_trail: false,
118 };
119 let res = sep.parse(&mut tokens, &s,
120 &ReadToken::new(&text[4..], 4), &[], indent_settings);
121 assert_eq!(res, Err(Range::new(4, 0).wrap(
122 ParseError::ExpectedSomething(1))));
123 }
124
125 #[test]
126 fn optional() {
127 let ref mut indent_settings = IndentSettings::default();
128 let text = "foo()";
129 let mut tokens = vec![];
130 let s = TokenizerState::new();
131 let sep = SeparateBy {
132 debug_id: 0,
133 rule: Rule::UntilAnyOrWhitespace(UntilAnyOrWhitespace {
134 debug_id: 1,
135 any_characters: Arc::new(",)".into()),
136 optional: false,
137 property: None,
138 }),
139 by: Rule::Tag(Tag {
140 debug_id: 2,
141 text: Arc::new(",".into()),
142 not: false,
143 inverted: false,
144 property: None,
145 }),
146 optional: true,
147 allow_trail: false,
148 };
149 let res = sep.parse(&mut tokens, &s,
150 &ReadToken::new(&text[4..], 4), &[], indent_settings);
151 assert_eq!(res, Ok((Range::new(4, 0), s,
152 Some(Range::new(4, 0).wrap(ParseError::ExpectedSomething(1))))));
153 }
154
155 #[test]
156 fn disallow_trail() {
157 let ref mut indent_settings = IndentSettings::default();
158 let text = "foo(a,b,c,)";
159 let mut tokens = vec![];
160 let s = TokenizerState::new();
161 let arg: Arc<String> = Arc::new("arg".into());
162 let sep = SeparateBy {
163 debug_id: 0,
164 rule: Rule::UntilAnyOrWhitespace(UntilAnyOrWhitespace {
165 debug_id: 1,
166 any_characters: Arc::new(",)".into()),
167 optional: false,
168 property: Some(arg.clone()),
169 }),
170 by: Rule::Tag(Tag {
171 debug_id: 2,
172 text: Arc::new(",".into()),
173 not: false,
174 inverted: false,
175 property: None,
176 }),
177 optional: true,
178 allow_trail: false,
179 };
180 let res = sep.parse(&mut tokens, &s,
181 &ReadToken::new(&text[4..], 4), &[], indent_settings);
182 assert_eq!(res, Err(Range::new(10, 0).wrap(
183 ParseError::ExpectedSomething(1))));
184 }
185
186 #[test]
187 fn allow_trail() {
188 let ref mut indent_settings = IndentSettings::default();
189 let text = "foo(a,b,c,)";
190 let mut tokens = vec![];
191 let s = TokenizerState::new();
192 let arg: Arc<String> = Arc::new("arg".into());
193 let sep = SeparateBy {
194 debug_id: 0,
195 rule: Rule::UntilAnyOrWhitespace(UntilAnyOrWhitespace {
196 debug_id: 1,
197 any_characters: Arc::new(",)".into()),
198 optional: false,
199 property: Some(arg.clone()),
200 }),
201 by: Rule::Tag(Tag {
202 debug_id: 2,
203 text: Arc::new(",".into()),
204 not: false,
205 inverted: false,
206 property: None,
207 }),
208 optional: true,
209 allow_trail: true,
210 };
211 let res = sep.parse(&mut tokens, &s,
212 &ReadToken::new(&text[4..], 4), &[], indent_settings);
213 assert_eq!(res, Ok((Range::new(4, 6), TokenizerState(3),
214 Some(Range::new(10, 0).wrap(ParseError::ExpectedSomething(1))))));
215 assert_eq!(tokens.len(), 3);
216 assert_eq!(&tokens[0].data,
217 &MetaData::String(arg.clone(), Arc::new("a".into())));
218 assert_eq!(&tokens[1].data,
219 &MetaData::String(arg.clone(), Arc::new("b".into())));
220 assert_eq!(&tokens[2].data,
221 &MetaData::String(arg.clone(), Arc::new("c".into())));
222 }
223
224 #[test]
225 fn successful() {
226 let ref mut indent_settings = IndentSettings::default();
227 let text = "foo(a,b,c)";
228 let mut tokens = vec![];
229 let s = TokenizerState::new();
230 let arg: Arc<String> = Arc::new("arg".into());
231 let sep = SeparateBy {
232 debug_id: 0,
233 rule: Rule::UntilAnyOrWhitespace(UntilAnyOrWhitespace {
234 debug_id: 1,
235 any_characters: Arc::new(",)".into()),
236 optional: false,
237 property: Some(arg.clone()),
238 }),
239 by: Rule::Tag(Tag {
240 debug_id: 2,
241 text: Arc::new(",".into()),
242 not: false,
243 inverted: false,
244 property: None,
245 }),
246 optional: true,
247 allow_trail: false,
248 };
249 let res = sep.parse(&mut tokens, &s,
250 &ReadToken::new(&text[4..], 4), &[], indent_settings);
251 assert_eq!(res, Ok((Range::new(4, 5), TokenizerState(3),
252 Some(Range::new(9, 0).wrap(
253 ParseError::ExpectedTag(Arc::new(",".into()), 2))))));
254 assert_eq!(tokens.len(), 3);
255 assert_eq!(&tokens[0].data,
256 &MetaData::String(arg.clone(), Arc::new("a".into())));
257 assert_eq!(&tokens[1].data,
258 &MetaData::String(arg.clone(), Arc::new("b".into())));
259 assert_eq!(&tokens[2].data,
260 &MetaData::String(arg.clone(), Arc::new("c".into())));
261 }
262
263 #[test]
264 fn nested() {
265 let ref mut indent_settings = IndentSettings::default();
266 let text = "a,b,c;d,e,f;";
267 let mut tokens = vec![];
268 let s = TokenizerState::new();
269 let arg: Arc<String> = Arc::new("arg".into());
270 let sep = SeparateBy {
271 debug_id: 0,
272 rule: Rule::SeparateBy(Box::new(SeparateBy {
273 debug_id: 1,
274 rule: Rule::UntilAnyOrWhitespace(UntilAnyOrWhitespace {
275 debug_id: 2,
276 any_characters: Arc::new(",;".into()),
277 optional: false,
278 property: Some(arg.clone()),
279 }),
280 by: Rule::Tag(Tag {
281 debug_id: 3,
282 text: Arc::new(",".into()),
283 not: false,
284 inverted: false,
285 property: None,
286 }),
287 optional: false,
288 allow_trail: true,
289 })),
290 by: Rule::Tag(Tag {
291 debug_id: 4,
292 text: Arc::new(";".into()),
293 not: false,
294 inverted: false,
295 property: None,
296 }),
297 optional: false,
298 allow_trail: true,
299 };
300 let res = sep.parse(&mut tokens, &s, &ReadToken::new(&text, 0), &[], indent_settings);
301 assert_eq!(res, Ok((Range::new(0, 12), TokenizerState(6),
302 Some(Range::new(12, 0).wrap(
303 ParseError::ExpectedSomething(2))))));
304 assert_eq!(tokens.len(), 6);
305 assert_eq!(&tokens[0].data,
306 &MetaData::String(arg.clone(), Arc::new("a".into())));
307 assert_eq!(&tokens[1].data,
308 &MetaData::String(arg.clone(), Arc::new("b".into())));
309 assert_eq!(&tokens[2].data,
310 &MetaData::String(arg.clone(), Arc::new("c".into())));
311 assert_eq!(&tokens[3].data,
312 &MetaData::String(arg.clone(), Arc::new("d".into())));
313 assert_eq!(&tokens[4].data,
314 &MetaData::String(arg.clone(), Arc::new("e".into())));
315 }
316}