1use super::template::eoi;
2use crate::{error::Error, token::Pair, typed::tracker::Tracker, Position, Span};
3use core::{fmt::Debug, hash::Hash};
4use pest2::Stack;
5
6pub trait RuleType: Copy + Debug + Eq + Hash + Ord {
10 const EOI: Self;
12}
13
14pub trait TypedNode<'i, R: RuleType>: Sized {
16 fn try_parse_with_partial(
18 input: Position<'i>,
19 stack: &mut Stack<Span<'i>>,
20 tracker: &mut Tracker<'i, R>,
21 ) -> Option<(Position<'i>, Self)>;
22 #[inline]
24 fn try_parse_with(
25 input: Position<'i>,
26 stack: &mut Stack<Span<'i>>,
27 tracker: &mut Tracker<'i, R>,
28 ) -> Option<Self> {
29 let (input, res) = Self::try_parse_with_partial(input, stack, tracker)?;
30 let (_input, _eoi) = tracker.record_option_during_with(
31 input,
32 |tracker| eoi::try_parse_with_partial(input, stack, tracker),
33 <R as RuleType>::EOI,
34 )?;
35 Some(res)
36 }
37 #[inline]
39 fn try_parse_partial(input: &'i str) -> Result<(Position<'i>, Self), Box<Error<R>>> {
40 let mut stack = Stack::new();
41 let input = Position::from_start(input);
42 let mut tracker = Tracker::new(input);
43 Self::try_parse_with_partial(input, &mut stack, &mut tracker)
44 .ok_or_else(|| tracker.collect())
45 }
46 #[inline]
48 fn try_parse(input: &'i str) -> Result<Self, Box<Error<R>>> {
49 let mut stack = Stack::new();
50 let input = Position::from_start(input);
51 let mut tracker = Tracker::new(input);
52 Self::try_parse_with(input, &mut stack, &mut tracker).ok_or_else(|| tracker.collect())
53 }
54 fn check_with_partial(
56 input: Position<'i>,
57 stack: &mut Stack<Span<'i>>,
58 tracker: &mut Tracker<'i, R>,
59 ) -> Option<Position<'i>>;
60 #[inline]
62 fn check_with(
63 input: Position<'i>,
64 stack: &mut Stack<Span<'i>>,
65 tracker: &mut Tracker<'i, R>,
66 ) -> bool {
67 let input = match Self::check_with_partial(input, stack, tracker) {
68 Some(input) => input,
69 None => return false,
70 };
71 let _input = match tracker.record_option_during_with(
72 input,
73 |tracker| eoi::check_with_partial(input, stack, tracker),
74 <R as RuleType>::EOI,
75 ) {
76 Some(input) => input,
77 None => return false,
78 };
79 true
80 }
81 #[inline]
83 fn check_partial(input: &'i str) -> Result<Position<'i>, Box<Error<R>>> {
84 let mut stack = Stack::new();
85 let input = Position::from_start(input);
86 let mut tracker = Tracker::new(input);
87 Self::check_with_partial(input, &mut stack, &mut tracker).ok_or_else(|| tracker.collect())
88 }
89 #[inline]
91 fn check(input: &'i str) -> Result<(), Box<Error<R>>> {
92 let mut stack = Stack::new();
93 let input = Position::from_start(input);
94 let mut tracker = Tracker::new(input);
95 match Self::check_with(input, &mut stack, &mut tracker) {
96 true => Ok(()),
97 false => Err(tracker.collect()),
98 }
99 }
100 }
110
111pub trait SuperRule<R: RuleType>: RuleType {
113 fn cvt_from(rule: R) -> Self;
115}
116impl<R: RuleType> SuperRule<R> for R {
117 fn cvt_from(rule: R) -> Self {
118 rule
119 }
120}
121
122pub trait SubRule: RuleType {
124 type Super: RuleType;
126 fn cvt_into(self) -> Self::Super;
128}
129
130#[macro_export]
131macro_rules! full_rule_struct {
133 ($name:ident, ( $($args:ident ),* ), $Rule:ty, $rule:expr, $inner:ty, $content:ty, $(,)?) => {
134 #[allow(non_camel_case_types)]
135 impl<'i, $($args: $crate::typed::TypedNode<'i, $Rule>, )*> $crate::typed::TypedNode<'i, $Rule> for $name<'i, $($args, )*> {
136 fn try_parse_with_partial(
137 input: $crate::Position<'i>,
138 stack: &mut $crate::Stack<$crate::Span<'i>>,
139 tracker: &mut $crate::typed::Tracker<'i, $Rule>,
140 ) -> Option<($crate::Position<'i>, Self)> {
141 tracker.record_option_during(
142 input,
143 |tracker| {
144 let (pos, content) = <$inner as $crate::typed::TypedNode<'i, $Rule>>::try_parse_with_partial(input, stack, tracker)?;
145 let content = content.into();
146 let span = input.span(&pos);
147 Some((pos, Self { content, span }))
148 },
149 $rule
150 )
151 }
152 fn check_with_partial(
153 input: $crate::Position<'i>,
154 stack: &mut $crate::Stack<$crate::Span<'i>>,
155 tracker: &mut $crate::typed::Tracker<'i, $Rule>,
156 ) -> Option<$crate::Position<'i>> {
157 tracker.record_empty_during::<Self>(
158 input,
159 |tracker| {
160 let pos = <$inner>::check_with_partial(input, stack, tracker)?;
161 Some(pos)
162 },
163 $rule
164 )
165 }
166 }
167 };
168}
169
170pub use full_rule_struct;
171
172pub trait PairContainer<R> {
174 fn for_self_or_for_each_child_pair(&self, f: &mut impl FnMut(Pair<R>)) {
176 self.for_each_child_pair(f)
177 }
178 fn for_each_child_pair(&self, f: &mut impl FnMut(Pair<R>));
180 fn vec_children_pairs(&self) -> Vec<Pair<R>> {
182 let mut vec = vec![];
183 self.for_each_child_pair(&mut |token| vec.push(token));
184 vec
185 }
186}
187
188impl<R, T: PairContainer<R>> PairContainer<R> for Option<T> {
189 fn for_each_child_pair(&self, f: &mut impl FnMut(Pair<R>)) {
190 match self {
191 Some(val) => val.for_self_or_for_each_child_pair(f),
192 None => (),
193 }
194 }
195}
196
197pub trait EmptyPairContainer {}
199impl<R, T: EmptyPairContainer> PairContainer<R> for T {
200 fn for_each_child_pair(&self, _f: &mut impl FnMut(Pair<R>)) {}
201}
202
203pub trait PairTree<R: RuleType>: PairContainer<R> {
205 fn get_rule() -> R;
207 fn get_span(&self) -> (usize, usize);
209 fn as_pair_tree(&self) -> Pair<R> {
211 let rule = Self::get_rule();
212 let (start, end) = self.get_span();
213 let children = self.vec_children_pairs();
214 Pair {
215 rule,
216 start,
217 end,
218 children,
219 }
220 }
221}
222
223impl<'i, R: RuleType, T: TypedNode<'i, R>> TypedNode<'i, R> for Option<T> {
224 #[inline]
225 fn try_parse_with_partial(
226 input: Position<'i>,
227 stack: &mut Stack<Span<'i>>,
228 tracker: &mut Tracker<'i, R>,
229 ) -> Option<(Position<'i>, Self)> {
230 stack.snapshot();
231 match T::try_parse_with_partial(input, stack, tracker) {
232 Some((pos, res)) => {
233 stack.clear_snapshot();
234 Some((pos, Some(res)))
235 }
236 None => {
237 stack.restore();
238 Some((input, None))
239 }
240 }
241 }
242 #[inline]
243 fn check_with_partial(
244 input: Position<'i>,
245 stack: &mut Stack<Span<'i>>,
246 tracker: &mut Tracker<'i, R>,
247 ) -> Option<Position<'i>> {
248 stack.snapshot();
249 match T::check_with_partial(input, stack, tracker) {
250 Some(pos) => {
251 stack.clear_snapshot();
252 Some(pos)
253 }
254 None => {
255 stack.restore();
256 Some(input)
257 }
258 }
259 }
260}
261
262pub trait TypedParser<R: RuleType> {
264 #[inline]
266 fn try_parse_with<'i, T: TypedNode<'i, R>>(
267 input: Position<'i>,
268 stack: &mut Stack<Span<'i>>,
269 tracker: &mut Tracker<'i, R>,
270 ) -> Option<T> {
271 T::try_parse_with(input, stack, tracker)
272 }
273 #[inline]
275 fn try_parse_with_partial<'i, T: TypedNode<'i, R>>(
276 input: Position<'i>,
277 stack: &mut Stack<Span<'i>>,
278 tracker: &mut Tracker<'i, R>,
279 ) -> Option<(Position<'i>, T)> {
280 T::try_parse_with_partial(input, stack, tracker)
281 }
282 #[inline]
284 fn try_parse<'i, T: TypedNode<'i, R>>(input: &'i str) -> Result<T, Box<Error<R>>> {
285 T::try_parse(input)
286 }
287 #[inline]
289 fn try_parse_partial<'i, T: TypedNode<'i, R>>(
290 input: &'i str,
291 ) -> Result<(Position<'i>, T), Box<Error<R>>> {
292 T::try_parse_partial(input)
293 }
294}
295
296pub trait NeverFailedTypedNode<'i, R: RuleType>
298where
299 Self: Sized + Debug + Clone + PartialEq + Default,
300{
301 fn parse_with_partial(input: Position<'i>, stack: &mut Stack<Span<'i>>)
303 -> (Position<'i>, Self);
304 fn parse_partial(input: &'i str) -> (Position<'i>, Self) {
306 let input = Position::from_start(input);
307 let mut stack = Stack::new();
308 Self::parse_with_partial(input, &mut stack)
309 }
310}