pest3_core/typed/
traits.rs

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
6/// A trait which parser rules must implement.
7///
8/// See [pest2::RuleType].
9pub trait RuleType: Copy + Debug + Eq + Hash + Ord {
10    /// End of input.
11    const EOI: Self;
12}
13
14/// Node of a typed syntax tree.
15pub trait TypedNode<'i, R: RuleType>: Sized {
16    /// Try parse a part of or all of remained string into a node.
17    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    /// Try parse remained string into a node.
23    #[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    /// Try parsing leading part of string into a node.
38    #[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    /// Try parsing given string into a node.
47    #[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    /// Check whether the some leading part of the result can be accepted.
55    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    /// Check whether the some leading part of the result can be accepted.
61    #[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    /// Try parsing leading part of string into a node.
82    #[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    /// Try parsing given string into a node.
90    #[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    // /// Whether this node will modify the stack.
101    // /// Must be evaluated correctly,
102    // /// otherwise the stack won't be restored correctly.
103    // const MODIFY_STACK: bool;
104
105    // /// Whether this node accepts null input.
106    // const NULLABLE: bool;
107    // /// Leading characters that this node accepts.
108    // const FIRST: &'static [char];
109}
110
111/// The super rule of `R`.
112pub trait SuperRule<R: RuleType>: RuleType {
113    /// Convert from.
114    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
122/// A sub rule of `Self::Super`.
123pub trait SubRule: RuleType {
124    /// Super rule.
125    type Super: RuleType;
126    /// Convert into.
127    fn cvt_into(self) -> Self::Super;
128}
129
130#[macro_export]
131/// Struct for rules with full capacity.
132macro_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
172/// A container of pairs.
173pub trait PairContainer<R> {
174    /// for `Self` as a pair if it is, otherwise for each child pair.
175    fn for_self_or_for_each_child_pair(&self, f: &mut impl FnMut(Pair<R>)) {
176        self.for_each_child_pair(f)
177    }
178    /// For each child pair.
179    fn for_each_child_pair(&self, f: &mut impl FnMut(Pair<R>));
180    /// Convert children pairs into a [Vec].
181    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
197/// Contains no pair.
198pub 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
203/// A pair that can be converted to a pair tree.
204pub trait PairTree<R: RuleType>: PairContainer<R> {
205    /// Wrapped rule.
206    fn get_rule() -> R;
207    /// Get pair span.
208    fn get_span(&self) -> (usize, usize);
209    /// Convert `Self` to a pair tree.
210    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
262/// Parser that can produce typed syntax tree.
263pub trait TypedParser<R: RuleType> {
264    /// See [TypedNode::try_parse_with].
265    #[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    /// See [TypedNode::try_parse_with_partial].
274    #[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    /// See [TypedNode::try_parse].
283    #[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    /// See [TypedNode::try_parse_partial].
288    #[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
296/// Node of concrete syntax tree that never fails.
297pub trait NeverFailedTypedNode<'i, R: RuleType>
298where
299    Self: Sized + Debug + Clone + PartialEq + Default,
300{
301    /// Parse leading part of given input into a typed node.
302    fn parse_with_partial(input: Position<'i>, stack: &mut Stack<Span<'i>>)
303        -> (Position<'i>, Self);
304    /// Parse leading part of given input into a typed node.
305    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}