Skip to main content

moxy_token/parser/
stream.rs

1use super::{ParseError, Peek};
2use crate::span::DelimSpan;
3use crate::{Delim, LexError, Parse, Span, TokenStream, TokenTree};
4
5pub struct ParseStream<'a> {
6    input: &'a TokenStream,
7    index: usize,
8    depth: usize,
9    config: ParseConfig,
10    pending: Option<TokenTree>,
11}
12
13impl<'a> ParseStream<'a> {
14    pub fn new(input: &'a TokenStream) -> Self {
15        Self {
16            input,
17            index: 0,
18            depth: 0,
19            config: Default::default(),
20            pending: None,
21        }
22    }
23
24    pub fn from_config(input: &'a TokenStream, config: ParseConfig) -> Self {
25        Self {
26            input,
27            index: 0,
28            depth: 0,
29            config,
30            pending: None,
31        }
32    }
33
34    pub fn config(&self) -> &ParseConfig {
35        &self.config
36    }
37
38    pub fn is_empty(&self) -> bool {
39        self.pending.is_none() && self.index >= self.input.len()
40    }
41
42    pub fn span(&self) -> Span {
43        if let Some(t) = &self.pending {
44            return t.span();
45        }
46
47        self.input.get(self.index).map(|t| t.span()).unwrap_or_default()
48    }
49
50    pub fn fork(&self) -> Self {
51        Self {
52            input: self.input,
53            index: self.index,
54            depth: self.depth + 1,
55            config: self.config,
56            pending: self.pending.clone(),
57        }
58    }
59
60    /// Create a non-consuming fork whose parser activity is omitted from traces.
61    ///
62    /// This is intended for grammar lookahead that needs more information than
63    /// [`peek`](Self::peek)'s boolean result.
64    pub fn lookahead(&self) -> Self {
65        let mut fork = self.fork();
66        fork.config.trace = false;
67        fork
68    }
69
70    pub fn seek(&mut self, other: &Self) {
71        self.index = other.index;
72        self.pending = other.pending.clone();
73    }
74}
75
76impl<'a> ParseStream<'a> {
77    pub fn remaining(&self) -> usize {
78        self.input.len().saturating_sub(self.index)
79    }
80
81    pub fn curr(&self) -> Option<&TokenTree> {
82        if let Some(t) = &self.pending {
83            return Some(t);
84        }
85
86        self.input.get(self.index)
87    }
88
89    /// Look ahead `n` tokens without consuming (`nth(0)` == `curr`). When a glued
90    /// punct has been split, the pending half is `nth(0)` and the real stream
91    /// follows it.
92    pub fn nth(&self, n: usize) -> Option<&TokenTree> {
93        if let Some(t) = &self.pending {
94            return if n == 0 { Some(t) } else { self.input.get(self.index + n - 1) };
95        }
96
97        self.input.get(self.index + n)
98    }
99
100    pub fn prev(&self) -> Option<&TokenTree> {
101        self.input.get(self.index - 1)
102    }
103
104    pub fn peek<T: Peek>(&mut self) -> bool {
105        T::peek(&mut self.lookahead())
106    }
107
108    pub fn parse<T: Parse>(&mut self) -> Result<T, ParseError> {
109        let name = std::any::type_name::<T>();
110
111        if self.config.trace {
112            println!(
113                "{}{}-> {} @ ln {}, col {}{}",
114                " ".repeat(self.depth),
115                Ansi::Blue,
116                name,
117                self.span().start().line(),
118                self.span().start().column(),
119                Ansi::Reset,
120            );
121        }
122
123        let mut fork = self.fork();
124        let value = match T::parse(&mut fork) {
125            Err(err) => {
126                if self.config.trace {
127                    println!(
128                        "{}{}<- {} @ ln {}, col {}{}",
129                        " ".repeat(self.depth),
130                        Ansi::Red,
131                        name,
132                        self.span().end().line(),
133                        self.span().end().column(),
134                        Ansi::Reset,
135                    );
136                }
137
138                Err(err)
139            }
140            Ok(v) => {
141                if self.config.trace {
142                    println!(
143                        "{}{}<- {} @ ln {}, col {}{}",
144                        " ".repeat(self.depth),
145                        Ansi::Green,
146                        name,
147                        self.span().end().line(),
148                        self.span().end().column(),
149                        Ansi::Reset,
150                    );
151                }
152
153                Ok(v)
154            }
155        }?;
156
157        self.seek(&fork);
158        Ok(value)
159    }
160
161    /// Parse `T` if it matches; leave the stream unchanged otherwise.
162    pub fn parse_if<T: Parse>(&mut self) -> Option<T> {
163        if self.peek::<T>() { self.parse().ok() } else { None }
164    }
165
166    /// Parse `T` repeatedly while it matches, collecting results. Never errors.
167    pub fn parse_while<T: Parse>(&mut self) -> Vec<T> {
168        let mut items = Vec::new();
169
170        while let Some(item) = self.parse_if::<T>() {
171            items.push(item);
172        }
173
174        items
175    }
176
177    /// Parse `T` until the stream is empty, propagating the first error.
178    pub fn parse_until_empty<T: Parse>(&mut self) -> Result<Vec<T>, ParseError> {
179        let mut items = Vec::new();
180
181        while !self.is_empty() {
182            items.push(self.parse()?);
183        }
184
185        Ok(items)
186    }
187
188    /// Discard leading `T` tokens while they match. Returns `self` for chaining.
189    pub fn skip_while<T: Parse>(&mut self) -> &mut Self {
190        while self.parse_if::<T>().is_some() {}
191        self
192    }
193
194    /// Discard one `T` if it matches. Returns `self` for chaining.
195    pub fn skip_if<T: Parse>(&mut self) -> &mut Self {
196        self.parse_if::<T>();
197        self
198    }
199
200    /// Advance past tokens until `pred(curr())` is true (does NOT consume the matching token).
201    /// Returns `self` for chaining.
202    pub fn skip_until<F: Fn(Option<&TokenTree>) -> bool>(&mut self, pred: F) -> &mut Self {
203        while !self.is_empty() && !pred(self.curr()) {
204            self.advance();
205        }
206
207        self
208    }
209
210    pub fn advance_by(&mut self, n: usize) -> Option<&[TokenTree]> {
211        if self.index + n > self.input.len() {
212            return None;
213        }
214
215        let start = self.index;
216        self.index += n;
217        Some(&self.input[start..self.index])
218    }
219
220    /// move the iterator forward and return the token. Consumes a pending split
221    /// half first if one is present.
222    pub fn advance(&mut self) -> Option<&TokenTree> {
223        if self.pending.is_some() {
224            self.pending = None;
225            // The split half has been consumed; report the real token it came from.
226            return self.input.get(self.index - 1);
227        }
228
229        self.advance_by(1)?.first()
230    }
231
232    /// Consume the next token as the single-char punct spelled `head`. If the
233    /// next token is a longer glued punct that starts with `head` (e.g. `>>`,
234    /// `>=`, `>>=`), peel off the first char and leave the remainder as a pending
235    /// split token. Returns the span for the consumed head punct, or `None` if
236    /// the next token isn't a punct starting with `head`.
237    pub fn eat_punct_head(&mut self, head: &str) -> Option<Span> {
238        let punct = match self.curr() {
239            Some(TokenTree::Punct(p)) => *p,
240            _ => return None,
241        };
242
243        let text = punct.as_str();
244
245        if text == head {
246            let span = punct.span();
247            self.advance();
248            return Some(span);
249        }
250
251        if !text.starts_with(head) {
252            return None;
253        }
254
255        let rest = &text[head.len()..];
256        let mut remainder = Self::scan_punct(rest)?;
257        let full = punct.span();
258        let (head_span, rest_span) = full.split(head.len());
259        remainder.set_span(rest_span);
260
261        self.advance();
262        self.pending = Some(TokenTree::Punct(remainder));
263        Some(head_span)
264    }
265
266    /// Lex a single punctuation token from `text` (must be exactly one punct).
267    fn scan_punct(text: &str) -> Option<crate::Punctuation> {
268        use crate::Punctuation;
269        use crate::lex::{Cursor, Scan};
270
271        let cursor = Cursor::new(text, 0);
272        Punctuation::scan(cursor).ok().map(|(_, op)| op)
273    }
274
275    /// Consume a group with the given delimiter and return its inner token stream.
276    /// The caller can then create a new ParseStream over the returned stream.
277    pub fn parse_group(&mut self, delim: Delim) -> Result<TokenStream, ParseError> {
278        let at = self.span();
279
280        match self.curr() {
281            Some(TokenTree::Group(g)) if g.delim() == delim => {
282                let stream = g.stream();
283                self.advance();
284                Ok(stream)
285            }
286            _ => Err(LexError::new(at)
287                .message(format!("expected `{}` delimiter", delim.as_str()))
288                .into()),
289        }
290    }
291
292    /// Like [`parse_group`](Self::parse_group), but also returns the group's
293    /// `DelimSpan` (the open/close spans of its delimiters).
294    pub fn parse_group_spanned(&mut self, delim: Delim) -> Result<(DelimSpan, TokenStream), ParseError> {
295        let at = self.span();
296
297        match self.curr() {
298            Some(TokenTree::Group(g)) if g.delim() == delim => {
299                let span = g.span();
300                let stream = g.stream();
301                self.advance();
302                Ok((span, stream))
303            }
304            _ => Err(LexError::new(at)
305                .message(format!("expected `{}` delimiter", delim.as_str()))
306                .into()),
307        }
308    }
309}
310
311#[derive(Debug, Default, Copy, Clone, PartialOrd, Ord, PartialEq, Eq, Hash)]
312#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
313pub struct ParseConfig {
314    pub trace: bool,
315}
316
317enum Ansi {
318    Blue,
319    Green,
320    Red,
321    Reset,
322}
323
324impl std::fmt::Display for Ansi {
325    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
326        match self {
327            Self::Blue => write!(f, "\x1b[34m"),
328            Self::Green => write!(f, "\x1b[32m"),
329            Self::Red => write!(f, "\x1b[31m"),
330            Self::Reset => write!(f, "\x1b[0m"),
331        }
332    }
333}