1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
//! <ost generic stream of symbols

/// `IntStream::la` must return EOF in the end of stream
pub const EOF: isize = -1;

/// A simple stream of symbols whose values are represented as integers. This
/// interface provides *marked ranges* with support for a minimum level
/// of buffering necessary to implement arbitrary lookahead during prediction.
pub trait IntStream {
    /// Consumes the current symbol in the stream.
    /// Advances this stream to the next element.
    ///
    ///	This method has the following
    /// effects:
    ///
    ///  - Forward movement: The value of `index`
    ///		before calling this method is less than the value of `index`
    ///		after calling this method.
    ///  - Ordered lookahead: The value of {@code LA(1)} before
    ///		calling this method becomes the value of {@code LA(-1)} after calling
    ///		this method.
    ///
    /// Note that calling this method does not guarantee that `index()` is
    /// incremented by exactly 1.
    ///
    /// Allowed to panic if trying to consume EOF
    fn consume(&mut self);

    /// Lookaheads (or loopbacks if `i` is negative)
    ///
    /// Gets the value of the symbol at offset {@code i} from the current
    /// position. When {@code i==1}, this method returns the value of the current
    /// symbol in the stream (which is the next symbol to be consumed). When
    /// {@code i==-1}, this method returns the value of the previously read
    /// symbol in the stream. It is not valid to call this method with
    /// {@code i==0}, but the specific behavior is unspecified because this
    /// method is frequently called from performance-critical code.
    ///
    /// Note that default Lexer does not call this method with anything other than `-1`
    /// so it can be used for optimizations in downstream implementations.
    ///
    /// Must return `EOF` if `i` points to position at or beyond the end of the stream
    fn la(&mut self, i: isize) -> isize;

    /// After this call subsequent calls to seek must succeed if seek index is greater than mark index
    ///
    /// Returns marker that should be used later by `release` call to release this stream from
    fn mark(&mut self) -> isize;

    /// Releases `marker`
    fn release(&mut self, marker: isize);

    /// Returns current position of the input stream
    ///
    /// If there is active marker from `mark` then calling `seek` later with result of this call
    /// should put stream in same state it is currently in.
    fn index(&self) -> isize;
    /// Put stream back in state it was when it was in `index` position
    ///
    /// Allowed to panic if `index` does not belong to marked region(via `mark`-`release` calls)
    fn seek(&mut self, index: isize);

    /// Returns the total number of symbols in the stream.
    fn size(&self) -> isize;

    /// Returns name of the source this stream operates over if any
    fn get_source_name(&self) -> String;
}

/// Iterator over `IntStream`
#[derive(Debug)]
pub struct IterWrapper<'a, T: IntStream>(pub &'a mut T);

impl<'a, T: IntStream> Iterator for IterWrapper<'a, T> {
    type Item = isize;

    fn next(&mut self) -> Option<Self::Item> {
        let result = self.0.la(1);
        self.0.consume();
        match result {
            EOF => None,
            x => Some(x),
        }
    }
}