proc_macro_rules/
match_set.rs

1use proc_macro2::Span;
2use std::collections::HashSet;
3use syn::parse::{Error, ParseBuffer, ParseStream};
4
5pub struct MatchSet<'a, M: Fork> {
6    positions: Vec<Position<'a, M>>,
7    garbage: HashSet<usize>,
8}
9
10pub trait Fork {
11    type Parent;
12
13    fn fork(&self) -> Self;
14    fn new() -> Self;
15    fn hoist(&self, outer: &mut Self::Parent);
16}
17
18pub struct Position<'a, M: Fork> {
19    pub input: ParseBuffer<'a>,
20    pub matches: M,
21    state: FragmentState,
22}
23
24#[derive(Clone, Copy, Eq, PartialEq, Debug)]
25enum FragmentState {
26    Ready,
27    Exhausted,
28}
29
30pub struct MatchHandler<'a, 'b: 'a, M: Fork> {
31    outer_position: &'a mut Position<'b, M>,
32    forked: Vec<Position<'b, M>>,
33}
34
35impl<'a, M: Fork> MatchSet<'a, M> {
36    pub fn new(initial: ParseBuffer<'a>) -> MatchSet<'a, M> {
37        MatchSet {
38            positions: vec![Position {
39                input: initial,
40                matches: M::new(),
41                state: FragmentState::Ready,
42            }],
43            garbage: HashSet::new(),
44        }
45    }
46
47    pub fn finalise(self) -> syn::parse::Result<Vec<Position<'a, M>>> {
48        if self.positions.is_empty() {
49            return Err(Error::new(Span::call_site(), "No match"));
50        }
51        Ok(self.positions)
52    }
53
54    // return value = if any positions were forked
55    pub fn fork<F>(&mut self, mut f: F) -> bool
56    where
57        for<'b> F: FnMut(ParseBuffer<'a>, &mut MatchHandler<'b, 'a, M>) -> Result<(), Error>,
58    {
59        debug_assert!(self.garbage.is_empty());
60
61        let mut forked = vec![];
62        for p in self.positions.iter_mut() {
63            if p.state != FragmentState::Ready {
64                continue;
65            }
66            p.state = FragmentState::Exhausted;
67            let forked_input = p.input.fork();
68            let mut match_handler = MatchHandler {
69                outer_position: p,
70                forked: vec![],
71            };
72            if f(forked_input, &mut match_handler).is_ok() {
73                forked.append(&mut match_handler.forked);
74            }
75        }
76
77        self.positions
78            .iter()
79            .filter(|p| p.state == FragmentState::Ready)
80            .count()
81            > 0
82    }
83
84    pub fn reset_states(&mut self) {
85        for p in self.positions.iter_mut() {
86            p.state = FragmentState::Ready;
87        }
88    }
89
90    // returns err if the set is non-empty
91    pub fn expect<F>(&mut self, mut f: F) -> Result<(), Error>
92    where
93        for<'b> F: FnMut(ParseStream<'b>, &'b mut M) -> Result<(), Error>,
94    {
95        debug_assert!(self.garbage.is_empty());
96
97        for (i, p) in self.positions.iter_mut().enumerate() {
98            match f(&p.input, &mut p.matches) {
99                Ok(_) => {}
100                Err(_) => {
101                    self.garbage.insert(i);
102                }
103            }
104        }
105
106        self.compact();
107
108        if self.positions.is_empty() {
109            Err(Error::new(Span::call_site(), "no positions passed expect"))
110        } else {
111            Ok(())
112        }
113    }
114
115    fn compact(&mut self) {
116        if self.garbage.is_empty() {
117            return;
118        }
119
120        let mut new = Vec::with_capacity(self.positions.len() - self.garbage.len());
121        for (i, p) in self.positions.drain(..).enumerate() {
122            if !self.garbage.contains(&i) {
123                new.push(p);
124            }
125        }
126
127        self.positions = new;
128        self.garbage = HashSet::new();
129    }
130}
131
132impl<'a, M: Fork> Position<'a, M> {
133    pub fn stream(&'a self) -> ParseStream<'a> {
134        &self.input
135    }
136
137    pub fn fork(&self) -> Position<'a, M> {
138        Position {
139            input: self.input.fork(),
140            matches: self.matches.fork(),
141            state: FragmentState::Ready,
142        }
143    }
144}
145
146impl<'a, 'b: 'a, M: Fork> MatchHandler<'a, 'b, M> {
147    pub fn hoist<MM: Fork<Parent = M>>(&mut self, positions: &[Position<'b, MM>]) {
148        assert!(!positions.is_empty());
149
150        for p in &positions[1..] {
151            let mut new = Position {
152                input: p.input.fork(),
153                matches: self.outer_position.matches.fork(),
154                state: FragmentState::Ready,
155            };
156            p.matches.hoist(&mut new.matches);
157            self.forked.push(new);
158        }
159
160        positions[0].matches.hoist(&mut self.outer_position.matches);
161        let _: Result<proc_macro2::TokenStream, _> = self.outer_position.input.parse();
162        self.outer_position.state = FragmentState::Ready;
163        self.outer_position.input = positions[0].input.fork();
164    }
165
166    pub fn matches(&mut self) -> &mut M {
167        &mut self.outer_position.matches
168    }
169}