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