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 pub fn try_parse<R>(
102 &mut self,
103 parse_fn: impl FnOnce(&mut ParseStream<'a>) -> Result<R>,
104 ) -> Result<R> {
105 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}