• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/**
2 * A stream of characters created from a JavaScript string that in turn gets
3 * fed to a lexer.
4 * @class
5 * @extends org.antlr.runtime.CharStream
6 * @param {String} data the string from which this stream will be created.
7 */
8org.antlr.runtime.ANTLRStringStream = function(data) {
9    /**
10     * Location in the stream.
11     * Ranges from 0 to (stream length - 1).
12     * @private
13     * @type Number
14     */
15    this.p = 0;
16
17    /**
18     * The current line in the input.
19     * Ranges from 1 to (number of lines).
20     * @private
21     * @type Number
22     */
23    this.line = 1;
24
25    /**
26     * The index of the character relative to the beginning of the line.
27     * Ranges from 0 to (length of line - 1).
28     * @private
29     * @type Number
30     */
31    this.charPositionInLine = 0;
32
33    /**
34     * Tracks how deep mark() calls are nested
35     * @private
36     * @type Number
37     */
38    this.markDepth = 0;
39
40    /**
41     * An Array of objects that tracks the stream state
42     * values line, charPositionInLine, and p that can change as you
43     * move through the input stream.  Indexed from 1..markDepth.
44     * A null is kept at index 0.  Created upon first call to mark().
45     * @private
46     * @type Array
47     */
48    this.markers = null;
49
50    /**
51     * Track the last mark() call result value for use in rewind().
52     * @private
53     * @type Number
54     */
55    this.lastMarker = null;
56
57    /**
58     * The data being scanned.
59     * @private
60     * @type String
61     */
62    this.data = data;
63
64    /**
65     * The number of characters in the stream.
66     * @private
67     * @type Number
68     */
69    this.n = data.length;
70};
71
72org.antlr.lang.extend(org.antlr.runtime.ANTLRStringStream,
73                      org.antlr.runtime.CharStream,
74/** @lends org.antlr.runtime.ANTLRStringStream.prototype */
75{
76    /**
77     * Reset the stream so that it's in the same state it was
78     * when the object was created *except* the data array is not
79     * touched.
80     */
81    reset: function() {
82       this.p = 0;
83       this.line = 1;
84       this.charPositionInLine = 0;
85       this.markDepth = 0;
86    },
87
88    /**
89     * Consume the next character of data in the stream.
90     */
91    consume: function() {
92        if ( this.p < this.n ) {
93            this.charPositionInLine++;
94            if ( this.data.charAt(this.p)==="\n" ) {
95                this.line++;
96                this.charPositionInLine=0;
97            }
98            this.p++;
99        }
100    },
101
102    /**
103     * Get character at current input pointer + i ahead where i=1 is next int.
104     * Negative indexes are allowed.  LA(-1) is previous token (token
105     * just matched).  LA(-i) where i is before first token should
106     * yield -1, invalid char / EOF.
107     * @param {Number} i non-zero amount of lookahead or lookback
108     * @returns {String|Number} The charcter at the specified position or -1 if
109     *      you fell off either end of the stream.
110     */
111    LA: function(i) {
112        if ( i<0 ) {
113            i++; // e.g., translate LA(-1) to use offset i=0; then data[p+0-1]
114        }
115
116        var new_pos = this.p+i-1;
117        if (new_pos>=this.n || new_pos<0) {
118            return org.antlr.runtime.CharStream.EOF;
119        }
120        return this.data.charAt(new_pos);
121    },
122
123
124    /**
125     * Return the current input symbol index 0..n where n indicates the
126     * last symbol has been read.  The index is the index of char to
127     * be returned from LA(1) (i.e. the one about to be consumed).
128     * @returns {Number} the index of the current input symbol
129     */
130    index: function() {
131        return this.p;
132    },
133
134    /**
135     * The length of this stream.
136     * @returns {Number} the length of this stream.
137     */
138    size: function() {
139        return this.n;
140    },
141
142    /**
143     * Tell the stream to start buffering if it hasn't already.  Return
144     * current input position, index(), or some other marker so that
145     * when passed to rewind() you get back to the same spot.
146     * rewind(mark()) should not affect the input cursor.  The Lexer
147     * tracks line/col info as well as input index so its markers are
148     * not pure input indexes.  Same for tree node streams.
149     *
150     * <p>Marking is a mechanism for storing the current position of a stream
151     * in a stack.  This corresponds with the predictive look-ahead mechanism
152     * used in Lexers.</p>
153     * @returns {Number} the current size of the mark stack.
154     */
155    mark: function() {
156        if ( !this.markers ) {
157            this.markers = [];
158            this.markers.push(null); // depth 0 means no backtracking, leave blank
159        }
160        this.markDepth++;
161        var state = null;
162        if ( this.markDepth>=this.markers.length ) {
163            state = {};
164            this.markers.push(state);
165        }
166        else {
167            state = this.markers[this.markDepth];
168        }
169        state.p = this.p;
170        state.line = this.line;
171        state.charPositionInLine = this.charPositionInLine;
172        this.lastMarker = this.markDepth;
173        return this.markDepth;
174    },
175
176    /**
177     * Rewind to the input position of the last marker.
178     * Used currently only after a cyclic DFA and just
179     * before starting a sem/syn predicate to get the
180     * input position back to the start of the decision.
181     * Do not "pop" the marker off the state.  mark(i)
182     * and rewind(i) should balance still. It is
183     * like invoking rewind(last marker) but it should not "pop"
184     * the marker off.  It's like seek(last marker's input position).
185     * @param {Number} [m] the index in the mark stack to load instead of the
186     *      last.
187     */
188    rewind: function(m) {
189        if (!org.antlr.lang.isNumber(m)) {
190            m = this.lastMarker;
191        }
192
193        var state = this.markers[m];
194        // restore stream state
195        this.seek(state.p);
196        this.line = state.line;
197        this.charPositionInLine = state.charPositionInLine;
198        this.release(m);
199    },
200
201    /**
202     * You may want to commit to a backtrack but don't want to force the
203     * stream to keep bookkeeping objects around for a marker that is
204     * no longer necessary.  This will have the same behavior as
205     * rewind() except it releases resources without the backward seek.
206     * This must throw away resources for all markers back to the marker
207     * argument.  So if you're nested 5 levels of mark(), and then release(2)
208     * you have to release resources for depths 2..5.
209     * @param {Number} marker the mark depth above which all mark states will
210     *      be released.
211     */
212    release: function(marker) {
213        // unwind any other markers made after m and release m
214        this.markDepth = marker;
215        // release this marker
216        this.markDepth--;
217    },
218
219    /**
220     * Set the input cursor to the position indicated by index.  This is
221     * normally used to seek ahead in the input stream.  No buffering is
222     * required to do this unless you know your stream will use seek to
223     * move backwards such as when backtracking.
224     *
225     * <p>This is different from rewind in its multi-directional
226     * requirement and in that its argument is strictly an input cursor
227     * (index).</p>
228     *
229     * <p>For char streams, seeking forward must update the stream state such
230     * as line number.  For seeking backwards, you will be presumably
231     * backtracking using the mark/rewind mechanism that restores state and
232     * so this method does not need to update state when seeking backwards.</p>
233     *
234     * <p>Currently, this method is only used for efficient backtracking using
235     * memoization, but in the future it may be used for incremental
236     * parsing.</p>
237     *
238     * <p>The index is 0..n-1.  A seek to position i means that LA(1) will
239     * return the ith symbol.  So, seeking to 0 means LA(1) will return the
240     * first element in the stream.</p>
241     *
242     * <p>Esentially this method method moves the input position,
243     * {@link #consume}-ing data if necessary.</p>
244     *
245     * @param {Number} index the position to seek to.
246     */
247    seek: function(index) {
248        if ( index<=this.p ) {
249            this.p = index; // just jump; don't update stream state (line, ...)
250            return;
251        }
252        // seek forward, consume until p hits index
253        while ( this.p<index ) {
254            this.consume();
255        }
256    },
257
258    /**
259     * Retrieve a substring from this stream.
260     * @param {Number} start the starting index of the substring (inclusive).
261     * @param {Number} stop the last index of the substring (inclusive).
262     * @returns {String}
263     */
264    substring: function(start, stop) {
265        return this.data.substr(start,stop-start+1);
266    },
267
268    /**
269     * Return the current line position in the stream.
270     * @returns {Number} the current line position in the stream (1..numlines).
271     */
272    getLine: function() {
273        return this.line;
274    },
275
276    /**
277     * Get the index of the character relative to the beginning of the line.
278     * Ranges from 0 to (length of line - 1).
279     * @returns {Number}
280     */
281    getCharPositionInLine: function() {
282        return this.charPositionInLine;
283    },
284
285    /**
286     * Set the current line in the input stream.
287     * This is used internally when performing rewinds.
288     * @param {Number} line
289     * @private
290     */
291    setLine: function(line) {
292        this.line = line;
293    },
294
295    /**
296     * Set the index of the character relative to the beginning of the line.
297     * Ranges from 0 to (length of line - 1).
298     * @param {Number} pos
299     * @private
300     */
301    setCharPositionInLine: function(pos) {
302        this.charPositionInLine = pos;
303    },
304
305    /** Where are you getting symbols from? Normally, implementations will
306     *  pass the buck all the way to the lexer who can ask its input stream
307     *  for the file name or whatever.
308     */
309    getSourceName: function() {
310        return null;
311    }
312});
313
314/**
315 * Alias for {@link #LA}.
316 * @methodOf org.antlr.runtime.ANTLRStringStream.prototype
317 */
318org.antlr.runtime.ANTLRStringStream.prototype.LT = org.antlr.runtime.ANTLRStringStream.prototype.LA;
319