Skip to main content

antlr4_runtime/
token_stream.rs

1use crate::int_stream::{EOF, IntStream, UNKNOWN_SOURCE_NAME};
2use crate::token::{CommonToken, DEFAULT_CHANNEL, TOKEN_EOF, Token, TokenSource, TokenSourceError};
3
4#[derive(Debug)]
5pub struct CommonTokenStream<S> {
6    source: S,
7    tokens: Vec<CommonToken>,
8    next_visible_after: Vec<usize>,
9    cursor: usize,
10    fetched_eof: bool,
11    channel: i32,
12    source_errors: Vec<TokenSourceError>,
13}
14
15const UNKNOWN_NEXT_VISIBLE: usize = usize::MAX;
16
17impl<S> CommonTokenStream<S>
18where
19    S: TokenSource,
20{
21    /// Creates a token stream that filters lookahead to the default channel.
22    pub const fn new(source: S) -> Self {
23        Self::with_channel(source, DEFAULT_CHANNEL)
24    }
25
26    /// Creates a token stream whose `LT/LA` operations see only `channel`.
27    pub const fn with_channel(source: S, channel: i32) -> Self {
28        Self {
29            source,
30            tokens: Vec::new(),
31            next_visible_after: Vec::new(),
32            cursor: 0,
33            fetched_eof: false,
34            channel,
35            source_errors: Vec::new(),
36        }
37    }
38
39    /// Reads tokens from the source until EOF is buffered.
40    pub fn fill(&mut self) {
41        while !self.fetched_eof {
42            self.fetch_one();
43        }
44        self.cursor = self.adjust_seek_index(self.cursor);
45    }
46
47    /// Returns the token at an absolute buffered index, fetching from the source
48    /// as needed.
49    pub fn get(&mut self, index: usize) -> Option<&CommonToken> {
50        self.sync(index);
51        self.tokens.get(index)
52    }
53
54    /// Returns the token at one-based lookahead/lookbehind offset, skipping
55    /// tokens outside the configured channel for positive offsets.
56    pub fn lt(&mut self, offset: isize) -> Option<&CommonToken> {
57        if offset == 0 {
58            return None;
59        }
60        if offset < 0 {
61            return offset
62                .checked_neg()
63                .map(isize::cast_unsigned)
64                .and_then(|offset| self.lb(offset));
65        }
66
67        let mut index = self.next_token_on_channel(self.cursor, self.channel);
68        let mut remaining = offset;
69        while remaining > 1 {
70            index = self.next_token_on_channel(index + 1, self.channel);
71            remaining -= 1;
72        }
73        self.sync(index);
74        self.tokens.get(index)
75    }
76
77    pub fn lb(&self, offset: usize) -> Option<&CommonToken> {
78        if offset == 0 || self.cursor == 0 {
79            return None;
80        }
81        let mut index = self.cursor;
82        let mut remaining = offset;
83        while remaining > 0 {
84            index = self.previous_token_on_channel(index, self.channel)?;
85            remaining -= 1;
86        }
87        self.tokens.get(index)
88    }
89
90    pub const fn token_source(&self) -> &S {
91        &self.source
92    }
93
94    pub fn tokens(&self) -> &[CommonToken] {
95        &self.tokens
96    }
97
98    /// Ensures the buffer contains `index`, unless EOF has already been fetched.
99    fn sync(&mut self, index: usize) -> bool {
100        if index < self.tokens.len() {
101            return true;
102        }
103        let needed = index + 1 - self.tokens.len();
104        self.fetch(needed) >= needed
105    }
106
107    /// Fetches up to `count` more tokens, stopping early at EOF.
108    fn fetch(&mut self, count: usize) -> usize {
109        let mut fetched = 0;
110        while fetched < count && !self.fetched_eof {
111            self.fetch_one();
112            fetched += 1;
113        }
114        fetched
115    }
116
117    fn fetch_one(&mut self) {
118        let mut token = self.source.next_token();
119        self.source_errors.extend(self.source.drain_errors());
120        let token_index = isize::try_from(self.tokens.len()).unwrap_or(isize::MAX);
121        token.set_token_index(token_index);
122        self.fetched_eof = token.token_type() == TOKEN_EOF;
123        self.tokens.push(token);
124        self.next_visible_after.push(UNKNOWN_NEXT_VISIBLE);
125    }
126
127    /// Moves a raw token index to the next token visible on this stream's
128    /// channel.
129    fn adjust_seek_index(&mut self, index: usize) -> usize {
130        self.next_token_on_channel(index, self.channel)
131    }
132
133    /// Finds the next buffered token on `channel`, fetching as needed.
134    fn next_token_on_channel(&mut self, mut index: usize, channel: i32) -> usize {
135        self.sync(index);
136        while let Some(token) = self.tokens.get(index) {
137            if token.token_type() == TOKEN_EOF || token.channel() == channel {
138                return index;
139            }
140            index += 1;
141            self.sync(index);
142        }
143        index
144    }
145
146    /// Finds the previous buffered token on `channel`.
147    fn previous_token_on_channel(&self, mut index: usize, channel: i32) -> Option<usize> {
148        while index > 0 {
149            index -= 1;
150            let token = self.tokens.get(index)?;
151            if token.token_type() == TOKEN_EOF || token.channel() == channel {
152                return Some(index);
153            }
154        }
155        None
156    }
157
158    /// Finds the previous buffered token visible to this stream before
159    /// `index`.
160    ///
161    /// Parser rule intervals and `$text` actions are defined in terms of
162    /// visible tokens, but their rendered source text still includes hidden
163    /// tokens between the visible start and stop. Returning the previous token
164    /// on the stream channel avoids accidentally using trailing hidden
165    /// whitespace as the stop token.
166    pub fn previous_visible_token_index(&mut self, index: usize) -> Option<usize> {
167        if index > 0 {
168            self.sync(index - 1);
169        }
170        self.previous_token_on_channel(index, self.channel)
171    }
172}
173
174impl<S> IntStream for CommonTokenStream<S>
175where
176    S: TokenSource,
177{
178    fn consume(&mut self) {
179        if self.la(1) == EOF {
180            return;
181        }
182        let current = self.next_token_on_channel(self.cursor, self.channel);
183        self.cursor = self.adjust_seek_index(current + 1);
184    }
185
186    fn la(&mut self, offset: isize) -> i32 {
187        self.la_token(offset)
188    }
189
190    fn index(&self) -> usize {
191        self.cursor
192    }
193
194    fn seek(&mut self, index: usize) {
195        self.cursor = self.adjust_seek_index(index);
196    }
197
198    fn size(&self) -> usize {
199        self.tokens.len()
200    }
201
202    fn source_name(&self) -> &str {
203        let source_name = self.source.source_name();
204        if source_name.is_empty() {
205            UNKNOWN_SOURCE_NAME
206        } else {
207            source_name
208        }
209    }
210}
211
212impl<S> CommonTokenStream<S>
213where
214    S: TokenSource,
215{
216    pub fn la_token(&mut self, offset: isize) -> i32 {
217        self.lt(offset).map_or(TOKEN_EOF, Token::token_type)
218    }
219
220    /// Returns the token type at a buffered absolute index, fetching from the
221    /// source on demand. Past-EOF reads are reported as `TOKEN_EOF` so the
222    /// caller does not need to special-case the buffer's stop. The cursor is
223    /// not modified, which lets hot speculative loops avoid the seek
224    /// round-trip when they only need lookahead types.
225    pub fn token_type_at_index(&mut self, index: usize) -> i32 {
226        self.sync(index);
227        self.tokens.get(index).map_or(TOKEN_EOF, Token::token_type)
228    }
229
230    /// Returns the next parser-visible token index after consuming the token
231    /// at `index`, skipping hidden-channel tokens. The parser's stream cursor
232    /// is not modified. Used by speculative recognition that simulates token
233    /// consumption thousands of times without committing it.
234    pub fn next_visible_after(&mut self, index: usize) -> usize {
235        self.sync(index);
236        if let Some(cached) = self
237            .next_visible_after
238            .get(index)
239            .copied()
240            .filter(|cached| *cached != UNKNOWN_NEXT_VISIBLE)
241        {
242            return cached;
243        }
244
245        let mut next = index + 1;
246        let found = loop {
247            self.sync(next);
248            match self.tokens.get(next) {
249                Some(token)
250                    if token.token_type() != TOKEN_EOF && token.channel() != self.channel =>
251                {
252                    next += 1;
253                    continue;
254                }
255                _ => break next,
256            }
257        };
258        if let Some(slot) = self.next_visible_after.get_mut(index) {
259            *slot = found;
260        }
261        found
262    }
263
264    pub fn text(&mut self, start: usize, stop: usize) -> String {
265        self.sync(stop);
266        if start > stop || start >= self.tokens.len() {
267            return String::new();
268        }
269        self.tokens[start..=stop.min(self.tokens.len().saturating_sub(1))]
270            .iter()
271            .filter_map(Token::text)
272            .collect::<Vec<_>>()
273            .join("")
274    }
275
276    /// Returns and clears diagnostics emitted by the underlying token source
277    /// while this stream was fetching tokens.
278    pub fn drain_source_errors(&mut self) -> Vec<TokenSourceError> {
279        std::mem::take(&mut self.source_errors)
280    }
281
282    pub const fn is_filled(&self) -> bool {
283        self.fetched_eof
284    }
285}
286
287#[cfg(test)]
288mod tests {
289    use super::*;
290    use crate::token::{CommonToken, HIDDEN_CHANNEL};
291
292    #[derive(Debug)]
293    struct VecTokenSource {
294        tokens: Vec<CommonToken>,
295        index: usize,
296    }
297
298    impl TokenSource for VecTokenSource {
299        fn next_token(&mut self) -> CommonToken {
300            let token = self
301                .tokens
302                .get(self.index)
303                .cloned()
304                .unwrap_or_else(|| CommonToken::eof("vec", self.index, 1, self.index));
305            self.index += 1;
306            token
307        }
308
309        fn line(&self) -> usize {
310            1
311        }
312
313        fn column(&self) -> usize {
314            self.index
315        }
316
317        fn source_name(&self) -> &'static str {
318            "vec"
319        }
320    }
321
322    #[test]
323    fn stream_skips_hidden_channel_for_lookahead() {
324        let source = VecTokenSource {
325            tokens: vec![
326                CommonToken::new(1).with_text("a"),
327                CommonToken::new(2)
328                    .with_text(" ")
329                    .with_channel(HIDDEN_CHANNEL),
330                CommonToken::new(3).with_text("b"),
331                CommonToken::eof("vec", 3, 1, 3),
332            ],
333            index: 0,
334        };
335        let mut stream = CommonTokenStream::new(source);
336        assert_eq!(stream.la_token(1), 1);
337        stream.consume();
338        assert_eq!(stream.la_token(1), 3);
339        assert_eq!(
340            stream
341                .lt(-1)
342                .expect("look-behind token should be buffered")
343                .token_type(),
344            1
345        );
346    }
347
348    #[test]
349    fn lookahead_skips_hidden_token_at_initial_cursor() {
350        let source = VecTokenSource {
351            tokens: vec![
352                CommonToken::new(2)
353                    .with_text(" ")
354                    .with_channel(HIDDEN_CHANNEL),
355                CommonToken::new(1).with_text("a"),
356                CommonToken::eof("vec", 2, 1, 2),
357            ],
358            index: 0,
359        };
360        let mut stream = CommonTokenStream::new(source);
361
362        assert_eq!(stream.la_token(1), 1);
363        assert_eq!(stream.lt(1).and_then(Token::text), Some("a"));
364        stream.consume();
365        assert_eq!(stream.la_token(1), TOKEN_EOF);
366    }
367
368    #[test]
369    fn text_returns_empty_when_start_is_past_buffer() {
370        let source = VecTokenSource {
371            tokens: vec![
372                CommonToken::new(1).with_text("a"),
373                CommonToken::eof("vec", 1, 1, 1),
374            ],
375            index: 0,
376        };
377        let mut stream = CommonTokenStream::new(source);
378
379        assert_eq!(stream.text(10, 12), "");
380    }
381}