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 {
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]
289macro_rules! fails_with {
290 ( parser: $parser:ident, input: $string:expr, rule: $rules:tt :: $rule:tt,
291 positives: $positives:expr, negatives: $negatives:expr, pos: $pos:expr ) => {
292 #[allow(unused_mut)]
293 {
294 use $crate::Parser;
295
296 let error = $parser::parse($rules::$rule, $string).unwrap_err();
297
298 match error.variant {
299 $crate::error::ErrorVariant::ParsingError {
300 positives,
301 negatives,
302 } => {
303 assert_eq!(positives, $positives, "positives");
304 assert_eq!(negatives, $negatives, "negatives");
305 }
306 _ => unreachable!(),
307 };
308
309 match error.location {
310 $crate::error::InputLocation::Pos(pos) => assert_eq!(pos, $pos, "pos"),
311 _ => unreachable!(),
312 }
313 }
314 };
315}
316
317#[cfg(test)]
318pub mod tests {
319 use super::super::error::Error;
320 use super::super::iterators::Pairs;
321 use super::super::{state, Parser};
322 use alloc::format;
323 use alloc::vec;
324 use alloc::vec::Vec;
325
326 #[allow(non_camel_case_types)]
327 #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
328 pub enum Rule {
329 a,
330 b,
331 c,
332 d,
333 }
334
335 pub struct AbcParser;
336
337 impl Parser<Rule> for AbcParser {
338 fn parse(_: Rule, input: &str) -> Result<Pairs<'_, Rule>, Error<Rule>> {
339 state(input, |state| {
340 state
341 .rule(Rule::a, |s| {
342 s.skip(1)
343 .unwrap()
344 .rule(Rule::b, |s| s.skip(1))
345 .unwrap()
346 .skip(1)
347 })
348 .and_then(|s| s.skip(1).unwrap().rule(Rule::c, |s| s.match_string("e")))
349 .and_then(|s| s.optional(|s| s.rule(Rule::d, |s| s.match_string("fgh"))))
350 })
351 }
352 }
353
354 #[test]
355 fn parses_to() {
356 parses_to! {
357 parser: AbcParser,
358 input: "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: "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: "abcde",
390 rule: Rule::a,
391 tokens: []
392 };
393 }
394
395 #[test]
396 fn fails_with() {
397 fails_with! {
398 parser: AbcParser,
399 input: "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: "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: "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: "abcdf",
439 rule: Rule::a,
440 positives: vec![Rule::c],
441 negatives: vec![],
442 pos: 3
443 };
444 }
445}