antlr-ng
Version:
Next generation ANTLR Tool
183 lines (182 loc) • 5.21 kB
JavaScript
var __defProp = Object.defineProperty;
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
import { Token } from "antlr4ng";
import { TreeIterator } from "./TreeIterator.js";
class CommonTreeNodeStream {
static {
__name(this, "CommonTreeNodeStream");
}
/** If this tree (root) was created from a {@link TokenStream}, track it. */
tokens;
/** Pull nodes from which tree? */
root;
/** The {@link TreeIterator} we using. */
iterator;
/** Tree {@code (nil A B C)} trees like flat {@code A B C} streams */
hasNilRoot = false;
/** Tracks tree depth. Level=0 means we're at root node level. */
level = 0;
/** Absolute token index. It's the index of the symbol about to be read via `LT(1)`. */
currentElementIndex = 0;
/** Index of next element to fill. */
p = 0;
data = [];
/** This is the `LT(-1)` element for the first element in {@link data}. */
prevElement;
/** Track object returned by nextElement upon end of stream. */
eof = null;
/** Tracks how deep mark() calls are nested. */
markDepth = 0;
constructor(tree) {
this.root = tree;
this.iterator = new TreeIterator(this.root);
}
isEOF(o) {
return o.getType() === Token.EOF;
}
lookaheadType(k) {
if (k === 0) {
return null;
}
if (k < 0) {
return this.lookBack(-k);
}
this.syncAhead(k);
if (this.p + k - 1 > this.data.length) {
return this.eof;
}
return this.elementAt(k - 1);
}
lookahead(i) {
const tree = this.lookaheadType(i);
return tree ? tree.getType() : Token.INVALID_TYPE;
}
get index() {
return this.currentElementIndex;
}
mark() {
++this.markDepth;
return 0;
}
release(marker) {
--this.markDepth;
}
/** Make sure we have at least one element to remove, even if EOF. */
consume() {
this.syncAhead(1);
this.remove();
this.currentElementIndex++;
}
/**
* Seek to a 0-indexed absolute token index. Normally used to seek backwards in the buffer. Does not force
* loading of nodes.
*
* To preserve backward compatibility, this method allows seeking past the end of the currently buffered data.
* In this case, the input pointer will be moved but the data will only actually be loaded upon the next call to
* {@link consume} or {@link lookaheadType} for `k > 0`.
*
* @param index The absolute token index to seek to.
*/
seek(index) {
if (index < 0) {
throw new Error("can't seek before the beginning of the input");
}
const delta = this.currentElementIndex - index;
if (this.p - delta < 0) {
throw new Error("can't seek before the beginning of this stream's buffer");
}
this.p -= delta;
this.currentElementIndex = index;
}
lookBack(k) {
const index = this.p - k;
if (index === -1) {
return this.prevElement;
}
if (index >= 0) {
return this.data[index];
}
if (index < -1) {
throw new Error("can't look more than one token before the beginning of this stream's buffer");
}
throw new Error("can't look past the end of this stream's buffer using LB(int)");
}
/**
* @returns element `i` elements ahead of current element. `i == 0` gets current element. This is not an absolute
* index into `data` since `p` defines the start of the real list.
*
* @param i The index for the element.
*/
elementAt(i) {
const absIndex = this.p + i;
if (absIndex >= this.data.length) {
throw new Error("queue index " + absIndex + " > last index " + (this.data.length - 1));
}
if (absIndex < 0) {
throw new Error("queue index " + absIndex + " < 0");
}
return this.data[absIndex];
}
/**
* Makes sure we have 'need' elements from current position p. Last valid p index is data.size()-1. `p + need - 1`
* is the data index 'need' elements ahead. If we need 1 element, `(p + 1 - 1) == p` must be < data.length.
*
* @param need The number of elements to ensure are in the buffer.
*/
syncAhead(need) {
const n = this.p + need - 1 - this.data.length + 1;
if (n > 0) {
this.fill(n);
}
}
/**
* Adds n elements to buffer
*
* @param n The number of elements to add.
*/
fill(n) {
for (let i = 1; i <= n; i++) {
const o = this.nextElement();
if (this.isEOF(o)) {
this.eof = o;
}
this.data.push(o);
}
}
nextElement() {
let t = this.iterator.nextTree();
if (t === TreeIterator.up) {
this.level--;
if (this.level === 0 && this.hasNilRoot) {
return this.iterator.nextTree();
}
} else {
if (t === TreeIterator.down) {
this.level++;
}
}
if (this.level === 0 && t.isNil()) {
this.hasNilRoot = true;
t = this.iterator.nextTree();
this.level++;
t = this.iterator.nextTree();
}
return t;
}
/**
* @returns the first element in the queue.
*/
remove() {
const o = this.elementAt(0);
this.p++;
if (this.p === this.data.length && this.markDepth === 0) {
this.prevElement = o;
this.p = 0;
this.data = [];
}
return o;
}
}
export {
CommonTreeNodeStream
};