parsing_utils/
lib.rs

1//! Common code for pest-based parsers.
2//!
3//! This crate provides [`PairsHelper`], which lets you
4//! write code to traverse pest `Pairs` easily.
5
6use pest::iterators::{ Pairs, Pair };
7use pest::RuleType;
8use std::thread;
9
10/// A useful wrapper around pest Pairs, that provide
11/// several convenient shortcuts to read the Pair's inside it.
12///
13/// It is intended to be used in exhaustive parsing, and
14/// will assert that all Pair's have been read out when
15/// this wrapper is dropped.
16pub struct PairsHelper<'i, Rule: RuleType>(pub Pairs<'i, Rule>);
17
18/// Iterator generated by [`PairsHelper::iter_while`].
19pub struct PairPartialIter<'i, 'j, Rule: RuleType>(&'j mut PairsHelper<'i, Rule>, Rule);
20
21impl<'i, Rule: RuleType> Drop for PairsHelper<'i, Rule> {
22    /// An error message will be printed when
23    /// this PairsHelper is dropped.
24    ///
25    /// We handled the "double panic" issue by not asserting
26    /// when the drop is already initiated by another
27    /// panic.
28    #[inline]
29    fn drop(&mut self) {
30        if !thread::panicking() {
31            assert_eq!(self.0.peek(), None,
32                       "iterator not exhausted after use.")
33        }
34    }
35}
36
37impl<'i, Rule: RuleType> PairsHelper<'i, Rule> {
38    /// Get next Pair. Panics if there is not one.
39    #[inline]
40    pub fn next(&mut self) -> Pair<'i, Rule> {
41        self.0.next().unwrap()
42    }
43
44    /// Get next Pair and assert its rule type.
45    /// Panics if there is not one, or the rule type
46    /// does not match.
47    #[inline]
48    pub fn next_rule(&mut self, rule: Rule) -> Pair<'i, Rule> {
49        let p = self.0.next().unwrap();
50        assert_eq!(p.as_rule(), rule);
51        p
52    }
53
54    /// Get the next Pair if it matches the given Rule.
55    /// This will not panic.
56    #[inline]
57    pub fn next_rule_opt(&mut self, rule: Rule) -> Option<Pair<'i, Rule>> {
58        if self.0.peek()?.as_rule() == rule {
59            return self.0.next()
60        }
61        None
62    }
63
64    /// Create an iterator of the first consecutive Pair's
65    /// that match a given Rule.
66    #[inline]
67    pub fn iter_while<'j>(&'j mut self, rule: Rule) -> PairPartialIter<'i, 'j, Rule> {
68        PairPartialIter(self, rule)
69    }
70}
71
72impl<'i, 'j, Rule: RuleType> Iterator for PairPartialIter<'i, 'j, Rule> {
73    type Item = Pair<'i, Rule>;
74
75    #[inline]
76    fn next(&mut self) -> Option<Pair<'i, Rule>> {
77        self.0.next_rule_opt(self.1)
78    }
79
80    #[inline]
81    fn size_hint(&self) -> (usize, Option<usize>) {
82        (0, self.0.0.size_hint().1)
83    }
84}
85