UNPKG

antlr-ng

Version:

Next generation ANTLR Tool

183 lines (182 loc) 5.21 kB
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 };