1#[doc(hidden)]
11#[macro_export]
12macro_rules! consumes_to {
13 ( $_rules:ident, $tokens:expr, [] ) => ();
14 ( $rules:ident, $tokens:expr, [ $name:ident ( $start:expr, $end:expr ) ] ) => {
15 let expected = format!("expected Start {{ rule: {:?}, pos: Position {{ pos: {} }} }}",
16 $rules::$name, $start);
17 match $tokens.next().expect(&format!("{} but found nothing", expected)) {
18 $crate::Token::Start { rule, pos } => {
19 if rule != $rules::$name || pos.pos() != $start {
20 panic!("{} but found Start {{ rule: {:?}, pos: Position {{ {} }} }}",
21 expected, rule, pos.pos());
22 }
23 },
24 token => panic!("{} but found {:?}", expected, token)
25 };
26
27 let expected = format!("expected End {{ rule: {:?}, pos: Position {{ pos: {} }} }}",
28 $rules::$name, $end);
29 match $tokens.next().expect(&format!("{} but found nothing", expected)) {
30 $crate::Token::End { rule, pos } => {
31 if rule != $rules::$name || pos.pos() != $end {
32 panic!("{} but found End {{ rule: {:?}, pos: Position {{ {} }} }}",
33 expected, rule, pos.pos());
34 }
35 },
36 token => panic!("{} but found {:?}", expected, token)
37 };
38 };
39 ( $rules:ident, $tokens:expr, [ $name:ident ( $start:expr, $end:expr ),
40 $( $names:ident $calls:tt ),* $(,)* ] ) => {
41
42 let expected = format!("expected Start {{ rule: {:?}, pos: Position {{ pos: {} }} }}",
43 $rules::$name, $start);
44 match $tokens.next().expect(&format!("{} but found nothing", expected)) {
45 $crate::Token::Start { rule, pos } => {
46 if rule != $rules::$name || pos.pos() != $start {
47 panic!("{} but found Start {{ rule: {:?}, pos: Position {{ {} }} }}",
48 expected, rule, pos.pos());
49 }
50 },
51 token => panic!("{} but found {:?}", expected, token)
52 };
53
54 let expected = format!("expected End {{ rule: {:?}, pos: Position {{ pos: {} }} }}",
55 $rules::$name, $end);
56 match $tokens.next().expect(&format!("{} but found nothing", expected)) {
57 $crate::Token::End { rule, pos } => {
58 if rule != $rules::$name || pos.pos() != $end {
59 panic!("{} but found End {{ rule: {:?}, pos: Position {{ {} }} }}",
60 expected, rule, pos.pos());
61 }
62 },
63 token => panic!("{} but found {:?}", expected, token)
64 };
65
66 consumes_to!($rules, $tokens, [ $( $names $calls ),* ]);
67 };
68 ( $rules:ident, $tokens:expr, [ $name:ident ( $start:expr, $end:expr,
69 [ $( $names:ident $calls:tt ),* $(,)* ] ) ] ) => {
70 let expected = format!("expected Start {{ rule: {:?}, pos: Position {{ pos: {} }} }}",
71 $rules::$name, $start);
72 match $tokens.next().expect(&format!("{} but found nothing", expected)) {
73 $crate::Token::Start { rule, pos } => {
74 if rule != $rules::$name || pos.pos() != $start {
75 panic!("{} but found Start {{ rule: {:?}, pos: Position {{ {} }} }}",
76 expected, rule, pos.pos());
77 }
78 },
79 token => panic!("{} but found {:?}", expected, token)
80 };
81
82 consumes_to!($rules, $tokens, [ $( $names $calls ),* ]);
83
84 let expected = format!("expected End {{ rule: {:?}, pos: Position {{ pos: {} }} }}",
85 $rules::$name, $end);
86 match $tokens.next().expect(&format!("{} but found nothing", expected)) {
87 $crate::Token::End { rule, pos } => {
88 if rule != $rules::$name || pos.pos() != $end {
89 panic!("{} but found End {{ rule: {:?}, pos: Position {{ {} }} }}",
90 expected, rule, pos.pos());
91 }
92 },
93 token => panic!("{} but found {:?}", expected, token)
94 };
95 };
96 ( $rules:ident, $tokens:expr, [ $name:ident ( $start:expr, $end:expr,
97 [ $( $nested_names:ident $nested_calls:tt ),*
98 $(,)* ] ),
99 $( $names:ident $calls:tt ),* ] ) => {
100
101 let expected = format!("expected Start {{ rule: {:?}, pos: Position {{ pos: {} }} }}",
102 $rules::$name, $start);
103 match $tokens.next().expect(&format!("{} but found nothing", expected)) {
104 $crate::Token::Start { rule, pos } => {
105 if rule != $rules::$name || pos.pos() != $start {
106 panic!("{} but found Start {{ rule: {:?}, pos: Position {{ {} }} }}",
107 expected, rule, pos.pos());
108 }
109 },
110 token => panic!("{} but found {:?}", expected, token)
111 };
112
113 consumes_to!($rules, $tokens, [ $( $nested_names $nested_calls ),* ]);
114
115 let expected = format!("expected End {{ rule: {:?}, pos: Position {{ pos: {} }} }}",
116 $rules::$name, $end);
117 match $tokens.next().expect(&format!("{} but found nothing", expected)) {
118 $crate::Token::End { rule, pos } => {
119 if rule != $rules::$name || pos.pos() != $end {
120 panic!("{} but found End {{ rule: {:?}, pos: Position {{ {} }} }}",
121 expected, rule, pos.pos());
122 }
123 },
124 token => panic!("{} but found {:?}", expected, token)
125 };
126
127 consumes_to!($rules, $tokens, [ $( $names $calls ),* ]);
128 };
129}
130
131#[macro_export]
191macro_rules! parses_to {
192 ( parser: $parser:ident, input: $string:expr, rule: $rules:tt :: $rule:tt,
193 tokens: [ $( $names:ident $calls:tt ),* $(,)* ] ) => {
194
195 #[allow(unused_mut)]
196 {
197 use $crate::Parser;
198
199 let mut tokens = $parser::parse($rules::$rule, $string).unwrap().tokens();
200
201 consumes_to!($rules, &mut tokens, [ $( $names $calls ),* ]);
202
203 let rest: Vec<_> = tokens.collect();
204
205 match rest.len() {
206 0 => (),
207 2 => {
208 let (first, second) = (&rest[0], &rest[1]);
209
210 match (first, second) {
211 (
212 &$crate::Token::Start { rule: ref first_rule, .. },
213 &$crate::Token::End { rule: ref second_rule, .. }
214 ) => {
215 assert!(
216 format!("{:?}", first_rule) == "EOI",
217 "expected end of input, but found {:?}", rest
218 );
219 assert!(
220 format!("{:?}", second_rule) == "EOI",
221 "expected end of input, but found {:?}", rest
222 );
223 }
224 _ => panic!("expected end of input, but found {:?}", rest)
225 }
226 }
227 _ => panic!("expected end of input, but found {:?}", rest)
228 };
229 }
230 };
231}
232
233#[macro_export]
290macro_rules! fails_with {
291 ( parser: $parser:ident, input: $string:expr, rule: $rules:tt :: $rule:tt,
292 positives: $positives:expr, negatives: $negatives:expr, pos: $pos:expr ) => {
293 #[allow(unused_mut)]
294 {
295 use $crate::Parser;
296
297 let error = $parser::parse($rules::$rule, $string).unwrap_err();
298
299 match error.variant {
300 $crate::error::ErrorVariant::ParsingError {
301 positives,
302 negatives,
303 } => {
304 assert_eq!(positives, $positives);
305 assert_eq!(negatives, $negatives);
306 }
307 _ => unreachable!(),
308 };
309
310 match error.location {
311 $crate::error::InputLocation::Pos(pos) => assert_eq!(pos, $pos),
312 _ => unreachable!(),
313 }
314 }
315 };
316}
317
318#[cfg(test)]
319pub mod tests {
320 use super::super::error::Error;
321 use super::super::iterators::Pairs;
322 use super::super::{state, Parser};
323 use alloc::format;
324 use alloc::vec;
325 use alloc::vec::Vec;
326 use std::sync::Arc;
327
328 #[allow(non_camel_case_types)]
329 #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
330 pub enum Rule {
331 a,
332 b,
333 c,
334 }
335
336 pub struct AbcParser;
337
338 impl Parser<Rule> for AbcParser {
339 fn parse(_: Rule, input: Arc<str>) -> Result<Pairs<Rule>, Error<Rule>> {
340 state(input, |state| {
341 state
342 .rule(Rule::a, |s| {
343 s.skip(1)
344 .unwrap()
345 .rule(Rule::b, |s| s.skip(1))
346 .unwrap()
347 .skip(1)
348 })
349 .and_then(|s| s.skip(1).unwrap().rule(Rule::c, |s| s.match_string("e")))
350 })
351 }
352 }
353
354 #[test]
355 fn parses_to() {
356 parses_to! {
357 parser: AbcParser,
358 input: Arc::from("abcde"),
359 rule: Rule::a,
360 tokens: [
361 a(0, 3, [
362 b(1, 2),
363 ]),
364 c(4, 5)
365 ]
366 };
367 }
368
369 #[test]
370 #[should_panic]
371 fn missing_end() {
372 parses_to! {
373 parser: AbcParser,
374 input: Arc::from("abcde"),
375 rule: Rule::a,
376 tokens: [
377 a(0, 3, [
378 b(1, 2)
379 ])
380 ]
381 };
382 }
383
384 #[test]
385 #[should_panic]
386 fn empty() {
387 parses_to! {
388 parser: AbcParser,
389 input: Arc::from("abcde"),
390 rule: Rule::a,
391 tokens: []
392 };
393 }
394
395 #[test]
396 fn fails_with() {
397 fails_with! {
398 parser: AbcParser,
399 input: Arc::from("abcdf"),
400 rule: Rule::a,
401 positives: vec![Rule::c],
402 negatives: vec![],
403 pos: 4
404 };
405 }
406
407 #[test]
408 #[should_panic]
409 fn wrong_positives() {
410 fails_with! {
411 parser: AbcParser,
412 input: Arc::from("abcdf"),
413 rule: Rule::a,
414 positives: vec![Rule::a],
415 negatives: vec![],
416 pos: 4
417 };
418 }
419
420 #[test]
421 #[should_panic]
422 fn wrong_negatives() {
423 fails_with! {
424 parser: AbcParser,
425 input: Arc::from("abcdf"),
426 rule: Rule::a,
427 positives: vec![Rule::c],
428 negatives: vec![Rule::c],
429 pos: 4
430 };
431 }
432
433 #[test]
434 #[should_panic]
435 fn wrong_pos() {
436 fails_with! {
437 parser: AbcParser,
438 input: Arc::from("abcdf"),
439 rule: Rule::a,
440 positives: vec![Rule::c],
441 negatives: vec![],
442 pos: 3
443 };
444 }
445}