syntax_rs/
parse.rs

1#[cfg(feature = "debug")]
2use crate::debug::DebugTap;
3#[cfg(feature = "span")]
4use crate::Span;
5use crate::{cursor::Cursor, snapshot::Snapshot, spec, Result};
6
7pub trait Parse: Sized {
8    fn parse(stream: &mut ParseStream) -> Result<Self>;
9}
10
11pub struct ParseStream<'a> {
12    cursor: Cursor<'a>,
13}
14
15impl<'a> ParseStream<'a> {
16    pub fn new(slice: &'a str) -> ParseStream<'a> {
17        ParseStream {
18            cursor: Cursor::new(slice),
19        }
20    }
21
22    pub fn empty() -> ParseStream<'a> {
23        ParseStream {
24            cursor: Cursor::new(""),
25        }
26    }
27
28    #[inline]
29    pub fn snapshot(&self) -> Snapshot {
30        Snapshot(self.cursor.index())
31    }
32
33    #[inline]
34    #[cfg(feature = "span")]
35    pub fn since(&self, snapshot: Snapshot) -> Span {
36        Span {
37            begin: snapshot.index(),
38            end: self.cursor.index(),
39        }
40    }
41
42    #[inline]
43    #[cfg(feature = "debug")]
44    pub fn parse<P: Parse>(&mut self) -> Result<P> {
45        P::parse(self).debug_tap(|result| {
46            if result.is_ok() {
47                eprintln!(
48                    "[P] at {}:{}    | Sucessfully parsed item {}.",
49                    file!(),
50                    line!(),
51                    std::any::type_name::<P>()
52                )
53            } else {
54                eprintln!(
55                    "[P] at {}:{}    | Failed to parse item {}.",
56                    file!(),
57                    line!(),
58                    std::any::type_name::<P>()
59                )
60            }
61        })
62    }
63
64    #[inline]
65    #[cfg(not(feature = "debug"))]
66    pub fn parse<P: Parse>(&mut self) -> Result<P> {
67        P::parse(self)
68    }
69
70    #[inline]
71    pub fn cur(&mut self) -> &mut Cursor<'a> {
72        &mut self.cursor
73    }
74
75    #[inline]
76    pub fn is_empty(&self) -> bool {
77        self.cursor.is_empty()
78    }
79
80    pub fn is_only_whitespaces(&self) -> bool {
81        for c in self.cursor.iter() {
82            if !spec::is_whitespace(c) {
83                return false;
84            }
85        }
86        true
87    }
88
89    pub fn skip_all(&mut self, mut pred: impl FnMut(char) -> bool) -> bool {
90        let mut has_moved = false;
91        while !self.is_empty() && pred(self.cursor.peek0().unwrap()) {
92            has_moved = true;
93            self.cursor.advance();
94        }
95        has_moved
96    }
97
98    /// Tries to parse something using the `parse_fn` parameter.
99    /// On failure; the cursor is reset to it's original value.<br>
100    /// **NOTE: This function is generally much more expensive than just doing a simple check before parsing.**
101    pub fn try_parse<R>(
102        &mut self,
103        parse_fn: impl FnOnce(&mut ParseStream<'a>) -> Result<R>,
104    ) -> Result<R> {
105        // FIXME: Do i need to reset the spans on error?
106        // TODO: Maybe we can do something clever here to avoid expensive cloning?
107        let original = self.cursor;
108        match parse_fn(self) {
109            ok @ Ok(_) => {
110                #[cfg(feature = "debug")]
111                eprintln!(
112                    "[P&R] at {}:{} | Successfully parsed item {}.",
113                    file!(),
114                    line!(),
115                    std::any::type_name::<R>()
116                );
117                ok
118            }
119            e @ Err(_) => {
120                #[cfg(feature = "debug")]
121                eprintln!(
122                    "[P&R] at {}:{} | Failed to parse item {}. Reversed the cursor to {:?}",
123                    file!(),
124                    line!(),
125                    std::any::type_name::<R>(),
126                    self.cursor
127                );
128                self.cursor = original;
129                e
130            }
131        }
132    }
133}