generic_lexer/
input.rs

1use std::iter::Peekable;
2use std::str::Chars;
3
4pub struct BufferedInput<'a> {
5    buffer: String,
6    chars: Peekable<Chars<'a>>,
7}
8
9impl<'a> BufferedInput<'a> {
10    /// Create a new buffered lexer input
11    pub(crate) fn new(input: &'a str) -> BufferedInput<'a> {
12        BufferedInput {
13            buffer: String::new(),
14            chars: input.chars().peekable(),
15        }
16    }
17
18    /// Copy out the buffer and clear it
19    pub fn take_buffer(&mut self) -> String {
20        let buffer = self.buffer.clone();
21        self.buffer.clear();
22        buffer
23    }
24
25    /// Peek at the next character
26    #[inline(always)]
27    pub fn peek(&mut self) -> Option<char> {
28        self.chars.peek().map(|&c| c)
29    }
30
31    /// Get the next character but don't push it to the buffer
32    #[inline(always)]
33    pub fn skip(&mut self) -> Option<char> {
34        self.chars.next()
35    }
36
37    /// Skip if the given predicate is true
38    pub fn skip_if<P: Fn(&char) -> bool>(&mut self, predicate: P) -> Option<char> {
39        if let Some(c) = self.peek() {
40            if predicate(&c) {
41                self.skip();
42                return Some(c);
43            }
44        }
45        None
46    }
47
48    /// Skip while the given predicate is true
49    pub fn skip_while<P: Fn(&char) -> bool>(&mut self, predicate: P) {
50        while let Some(_) = self.skip_if(&predicate) {}
51    }
52
53    /// Retrieve the next character and increment the input position
54    pub fn accept(&mut self) -> Option<char> {
55        if let Some(c) = self.chars.next() {
56            self.buffer.push(c);
57            Some(c)
58        } else {
59            None
60        }
61    }
62
63    /// Call `self.next()` if the peeked character is identical to `b`
64    pub fn accept_if<P: Fn(&char) -> bool>(&mut self, predicate: P) -> Option<char> {
65        if let Some(c) = self.peek() {
66            if predicate(&c) {
67                self.accept().unwrap();
68                return Some(c)
69            }
70        }
71        None
72    }
73
74    /// Call `self.next()` while the peeked character fulfils `predicate`
75    pub fn accept_while<P: Fn(&char) -> bool>(&mut self, predicate: P) {
76        while let Some(_) = self.accept_if(&predicate) {}
77    }
78
79    /// Accept the given byte and return `ok`, or else return `default`
80    ///
81    /// This is useful for matching multi-character tokens:
82    /// ```rust
83    /// match c {
84    ///     '=' => input.accept_or(|&c| c == '=', TokenKind::DoubleEquals, TokenKind::Equals),
85    ///     _ => {},
86    /// }
87    /// ```
88    pub fn accept_or<P: Fn(&char) -> bool, T>(&mut self, predicate: P, ok: T, default: T) -> T {
89        if let Some(_) = self.accept_if(predicate) {
90            ok
91        } else {
92            default
93        }
94    }
95
96    /// Skip whitespace, preserving the original buffer before any whitespace was encountered
97    #[inline]
98    pub fn skip_whitespace(&mut self) {
99        self.skip_while(char::is_ascii_whitespace);
100    }
101}