• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * [The "BSD licence"]
3  * Copyright (c) 2005-2008 Terence Parr
4  * All rights reserved.
5  *
6  * Conversion to C#:
7  * Copyright (c) 2008-2009 Sam Harwell, Pixel Mine, Inc.
8  * All rights reserved.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. The name of the author may not be used to endorse or promote products
19  *    derived from this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32 
33 namespace Antlr.Runtime.Misc {
34     using IndexOutOfRangeException = System.IndexOutOfRangeException;
35 
36     /** <summary>
37      *  A lookahead queue that knows how to mark/release locations
38      *  in the buffer for backtracking purposes. Any markers force the FastQueue
39      *  superclass to keep all tokens until no more markers; then can reset
40      *  to avoid growing a huge buffer.
41      *  </summary>
42      */
43     public abstract class LookaheadStream<T>
44         : FastQueue<T>
45         where T : class {
46         /** Absolute token index. It's the index of the symbol about to be
47          *  read via LT(1). Goes from 0 to numtokens.
48          */
49         private int _currentElementIndex = 0;
50 
51         private T _previousElement;
52 
53         /** Track object returned by nextElement upon end of stream;
54          *  Return it later when they ask for LT passed end of input.
55          */
56         T _eof = null;
57 
58         /** <summary>Track the last mark() call result value for use in rewind().</summary> */
59         int _lastMarker;
60 
61         /** <summary>tracks how deep mark() calls are nested</summary> */
62         int _markDepth;
63 
64         public T EndOfFile {
65             get {
66                 return _eof;
67             }
68             protected set {
69                 _eof = value;
70             }
71         }
72 
Clear()73         public override void Clear() {
74             base.Clear();
75             _currentElementIndex = 0;
76             _p = 0;
77             _previousElement = null;
78         }
79 
80         /** <summary>
81          *  Implement nextElement to supply a stream of elements to this
82          *  lookahead buffer.  Return eof upon end of the stream we're pulling from.
83          *  </summary>
84          */
NextElement()85         public abstract T NextElement();
86 
IsEndOfFile(T o)87         public abstract bool IsEndOfFile(T o);
88 
89         /** <summary>Get and remove first element in queue; override FastQueue.remove()</summary> */
Dequeue()90         public override T Dequeue() {
91             T o = this[0];
92             _p++;
93             // have we hit end of buffer and not backtracking?
94             if (_p == _data.Count && _markDepth == 0) {
95                 // if so, it's an opportunity to start filling at index 0 again
96                 Clear(); // size goes to 0, but retains memory
97             }
98             return o;
99         }
100 
101         /** <summary>Make sure we have at least one element to remove, even if EOF</summary> */
Consume()102         public virtual void Consume() {
103             SyncAhead(1);
104             _previousElement = Dequeue();
105             _currentElementIndex++;
106         }
107 
108         /** <summary>
109          *  Make sure we have 'need' elements from current position p. Last valid
110          *  p index is data.size()-1.  p+need-1 is the data index 'need' elements
111          *  ahead.  If we need 1 element, (p+1-1)==p must be &lt; data.size().
112          *  </summary>
113          */
SyncAhead(int need)114         protected virtual void SyncAhead(int need) {
115             int n = (_p + need - 1) - _data.Count + 1; // how many more elements we need?
116             if (n > 0)
117                 Fill(n);                 // out of elements?
118         }
119 
120         /** <summary>add n elements to buffer</summary> */
Fill(int n)121         public virtual void Fill(int n) {
122             for (int i = 0; i < n; i++) {
123                 T o = NextElement();
124                 if (IsEndOfFile(o))
125                     _eof = o;
126 
127                 _data.Add(o);
128             }
129         }
130 
131         /** <summary>Size of entire stream is unknown; we only know buffer size from FastQueue</summary> */
132         public override int Count {
133             get {
134                 throw new System.NotSupportedException("streams are of unknown size");
135             }
136         }
137 
LT(int k)138         public virtual T LT(int k) {
139             if (k == 0) {
140                 return null;
141             }
142             if (k < 0) {
143                 return LB(-k);
144             }
145 
146             SyncAhead(k);
147             if ((_p + k - 1) > _data.Count)
148                 return _eof;
149 
150             return this[k - 1];
151         }
152 
153         public virtual int Index {
154             get {
155                 return _currentElementIndex;
156             }
157         }
158 
Mark()159         public virtual int Mark() {
160             _markDepth++;
161             _lastMarker = _p; // track where we are in buffer, not absolute token index
162             return _lastMarker;
163         }
164 
Release(int marker)165         public virtual void Release(int marker) {
166             _markDepth--;
167         }
168 
Rewind(int marker)169         public virtual void Rewind(int marker) {
170             Seek(marker);
171             Release(marker);
172         }
173 
Rewind()174         public virtual void Rewind() {
175             Seek(_lastMarker);
176         }
177 
178         /** <summary>
179          *  Seek to a 0-indexed position within data buffer.  Can't handle
180          *  case where you seek beyond end of existing buffer.  Normally used
181          *  to seek backwards in the buffer. Does not force loading of nodes.
182          *  Doesn't see to absolute position in input stream since this stream
183          *  is unbuffered. Seeks only into our moving window of elements.
184          *  </summary>
185          */
Seek(int index)186         public virtual void Seek(int index) {
187             _p = index;
188         }
189 
LB(int k)190         protected virtual T LB(int k) {
191             if (k == 1)
192                 return _previousElement;
193 
194             throw new IndexOutOfRangeException("can't look backwards more than one token in this stream");
195         }
196     }
197 }
198