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