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 if let Some(val) = self {
191 val.for_self_or_for_each_child_pair(f)
192 }
193 }
194}
195
196pub trait EmptyPairContainer {}
198impl<R, T: EmptyPairContainer> PairContainer<R> for T {
199 fn for_each_child_pair(&self, _f: &mut impl FnMut(Pair<R>)) {}
200}
201
202pub trait PairTree<R: RuleType>: PairContainer<R> {
204 fn get_rule() -> R;
206 fn get_span(&self) -> (usize, usize);
208 fn as_pair_tree(&self) -> Pair<R> {
210 let rule = Self::get_rule();
211 let (start, end) = self.get_span();
212 let children = self.vec_children_pairs();
213 Pair {
214 rule,
215 start,
216 end,
217 children,
218 }
219 }
220}
221
222impl<'i, R: RuleType, T: TypedNode<'i, R>> TypedNode<'i, R> for Option<T> {
223 #[inline]
224 fn try_parse_with_partial(
225 input: Position<'i>,
226 stack: &mut Stack<Span<'i>>,
227 tracker: &mut Tracker<'i, R>,
228 ) -> Option<(Position<'i>, Self)> {
229 stack.snapshot();
230 match T::try_parse_with_partial(input, stack, tracker) {
231 Some((pos, res)) => {
232 stack.clear_snapshot();
233 Some((pos, Some(res)))
234 }
235 None => {
236 stack.restore();
237 Some((input, None))
238 }
239 }
240 }
241 #[inline]
242 fn check_with_partial(
243 input: Position<'i>,
244 stack: &mut Stack<Span<'i>>,
245 tracker: &mut Tracker<'i, R>,
246 ) -> Option<Position<'i>> {
247 stack.snapshot();
248 match T::check_with_partial(input, stack, tracker) {
249 Some(pos) => {
250 stack.clear_snapshot();
251 Some(pos)
252 }
253 None => {
254 stack.restore();
255 Some(input)
256 }
257 }
258 }
259}
260
261pub trait TypedParser<R: RuleType> {
263 #[inline]
265 fn try_parse_with<'i, T: TypedNode<'i, R>>(
266 input: Position<'i>,
267 stack: &mut Stack<Span<'i>>,
268 tracker: &mut Tracker<'i, R>,
269 ) -> Option<T> {
270 T::try_parse_with(input, stack, tracker)
271 }
272 #[inline]
274 fn try_parse_with_partial<'i, T: TypedNode<'i, R>>(
275 input: Position<'i>,
276 stack: &mut Stack<Span<'i>>,
277 tracker: &mut Tracker<'i, R>,
278 ) -> Option<(Position<'i>, T)> {
279 T::try_parse_with_partial(input, stack, tracker)
280 }
281 #[inline]
283 fn try_parse<'i, T: TypedNode<'i, R>>(input: &'i str) -> Result<T, Box<Error<R>>> {
284 T::try_parse(input)
285 }
286 #[inline]
288 fn try_parse_partial<'i, T: TypedNode<'i, R>>(
289 input: &'i str,
290 ) -> Result<(Position<'i>, T), Box<Error<R>>> {
291 T::try_parse_partial(input)
292 }
293}
294
295pub trait NeverFailedTypedNode<'i, R: RuleType>
297where
298 Self: Sized + Debug + Clone + PartialEq + Default,
299{
300 fn parse_with_partial(input: Position<'i>, stack: &mut Stack<Span<'i>>)
302 -> (Position<'i>, Self);
303 fn parse_partial(input: &'i str) -> (Position<'i>, Self) {
305 let input = Position::from_start(input);
306 let mut stack = Stack::new();
307 Self::parse_with_partial(input, &mut stack)
308 }
309}