css_parse/traits/peek.rs
1use crate::{Cursor, KindSet, Parser};
2
3/// This trait allows AST nodes to indicate whether the [Parser] is in the right position to potentially
4/// [Parse][crate::Parse] the node. Returning `true` from [Peek] is not a _guarantee_ that a node will successfully
5/// parse, instead it offers an indication that the node can successfully parse the first node. This is useful for
6/// cheaply comparing a set of Nodes to see which one might viably parse, rather than calling [Parser::try_parse()] on
7/// each.
8///
9/// Nodes that implement this trait are entitled to peek any number of [Cursors][Cursor] ahead from the [Parser], to
10/// determine if those [Cursors][Cursor] are viable to begin parsing, however there is a cost involved in peeking, so
11/// it is worth being conservative; peek the minimum amount ahead to determine this. Most implementations can peek just
12/// 1 [Cursor] ahead - this is provided as the second argument. To peek further, use the [Parser::peek_n()] method.
13/// Calling `peek_n(2)` will return the [Cursor] after the provided one `peek_n(3)` will return the second [Cursor]
14/// after, and so on.
15///
16/// For simple implementations it may be sufficient to just check the [Kind][crate::Kind] of the given [Cursor].
17/// Rather than implementing [Peek::peek()], supplying [Peek::PEEK_KINDSET] and relying on the provided [Peek::peek()]
18/// method will work well.
19///
20/// However it is likely that more complex checks will be needed. In order to reason about the given [Cursor] (or other
21/// cursors ahead) an implementation might want to extract an Atom from the [Cursor] (using [Parser::to_atom]) and
22/// compare it against an [AtomSet][crate::AtomSet].
23///
24/// When peeking child nodes, implementations should _not_ call [Peek::peek()] directly. Instead - call
25/// [`Parser::peek<T>()`]. [`Parser::parse_if_peek<T>()`] also exists to conveniently parse a Node if it passes the peek
26/// test.
27///
28/// If a Node can construct itself from a single [Cursor][Cursor] it should also implement
29/// [Parse][crate::Parse].
30pub trait Peek<'a>: Sized {
31 const PEEK_KINDSET: KindSet = KindSet::ANY;
32
33 fn peek(_: &Parser<'a>, c: Cursor) -> bool {
34 c == Self::PEEK_KINDSET
35 }
36}
37
38impl<'a, T: Peek<'a>> Peek<'a> for Option<T> {
39 fn peek(p: &Parser<'a>, c: Cursor) -> bool {
40 T::peek(p, c)
41 }
42}
43
44impl<'a, T: Peek<'a>> Peek<'a> for ::bumpalo::collections::Vec<'a, T> {
45 const PEEK_KINDSET: KindSet = T::PEEK_KINDSET;
46
47 fn peek(p: &Parser<'a>, c: Cursor) -> bool {
48 T::peek(p, c)
49 }
50}
51
52macro_rules! impl_tuple {
53 ($($T:ident),*) => {
54 impl<'a, $($T),*> Peek<'a> for ($($T),*)
55 where
56 $($T: Peek<'a>,)*
57 {
58 fn peek(p: &Parser<'a>, c: Cursor) -> bool {
59 A::peek(p, c)
60 }
61 }
62 };
63}
64
65impl_tuple!(A, B);
66impl_tuple!(A, B, C);
67impl_tuple!(A, B, C, D);
68impl_tuple!(A, B, C, D, E);
69impl_tuple!(A, B, C, D, E, F);
70impl_tuple!(A, B, C, D, E, F, G);
71impl_tuple!(A, B, C, D, E, F, G, H);
72impl_tuple!(A, B, C, D, E, F, G, H, I);
73impl_tuple!(A, B, C, D, E, F, G, H, I, J);
74impl_tuple!(A, B, C, D, E, F, G, H, I, J, K);
75impl_tuple!(A, B, C, D, E, F, G, H, I, J, K, L);