| /* Copyright (c) 2012-2022 The ANTLR Project. All rights reserved. |
| * Use of this file is governed by the BSD 3-clause license that |
| * can be found in the LICENSE.txt file in the project root. |
| */ |
| |
| import Token from './Token.js'; |
| |
| /** |
| * If decodeToUnicodeCodePoints is true, the input is treated |
| * as a series of Unicode code points. |
| * |
| * Otherwise, the input is treated as a series of 16-bit UTF-16 code |
| * units. |
| */ |
| export default class CharStream { |
| constructor(data, decodeToUnicodeCodePoints) { |
| this.name = "<empty>"; |
| this.strdata = data; |
| this.decodeToUnicodeCodePoints = decodeToUnicodeCodePoints || false; |
| // _loadString - Vacuum all input from a string and then treat it like a buffer. |
| this._index = 0; |
| this.data = []; |
| if (this.decodeToUnicodeCodePoints) { |
| for (let i = 0; i < this.strdata.length; ) { |
| const codePoint = this.strdata.codePointAt(i); |
| this.data.push(codePoint); |
| i += codePoint <= 0xFFFF ? 1 : 2; |
| } |
| } else { |
| this.data = new Array(this.strdata.length); |
| for (let i = 0; i < this.strdata.length; i++) { |
| this.data[i] = this.strdata.charCodeAt(i); |
| } |
| } |
| this._size = this.data.length; |
| } |
| |
| /** |
| * Reset the stream so that it's in the same state it was |
| * when the object was created *except* the data array is not |
| * touched. |
| */ |
| reset() { |
| this._index = 0; |
| } |
| |
| consume() { |
| if (this._index >= this._size) { |
| // assert this.LA(1) == Token.EOF |
| throw ("cannot consume EOF"); |
| } |
| this._index += 1; |
| } |
| |
| LA(offset) { |
| if (offset === 0) { |
| return 0; // undefined |
| } |
| if (offset < 0) { |
| offset += 1; // e.g., translate LA(-1) to use offset=0 |
| } |
| const pos = this._index + offset - 1; |
| if (pos < 0 || pos >= this._size) { // invalid |
| return Token.EOF; |
| } |
| return this.data[pos]; |
| } |
| |
| LT(offset) { |
| return this.LA(offset); |
| } |
| |
| // mark/release do nothing; we have entire buffer |
| mark() { |
| return -1; |
| } |
| |
| release(marker) { |
| } |
| |
| /** |
| * consume() ahead until p==_index; can't just set p=_index as we must |
| * update line and column. If we seek backwards, just set p |
| */ |
| seek(_index) { |
| if (_index <= this._index) { |
| this._index = _index; // just jump; don't update stream state (line, |
| // ...) |
| return; |
| } |
| // seek forward |
| this._index = Math.min(_index, this._size); |
| } |
| |
| getText(start, stop) { |
| if (stop >= this._size) { |
| stop = this._size - 1; |
| } |
| if (start >= this._size) { |
| return ""; |
| } else { |
| if (this.decodeToUnicodeCodePoints) { |
| let result = ""; |
| for (let i = start; i <= stop; i++) { |
| result += String.fromCodePoint(this.data[i]); |
| } |
| return result; |
| } else { |
| return this.strdata.slice(start, stop + 1); |
| } |
| } |
| } |
| |
| toString() { |
| return this.strdata; |
| } |
| |
| get index(){ |
| return this._index; |
| } |
| |
| get size(){ |
| return this._size; |
| } |
| } |