/runtime/Java/src/main/java/org/antlr/runtime/tree/BufferedTreeNodeStream.java
Java | 500 lines | 327 code | 53 blank | 120 comment | 51 complexity | 551df2424ce5cb3ac6030e8f32264e1f MD5 | raw file
- /*
- [The "BSD license"]
- Copyright (c) 2005-2009 Terence Parr
- All rights reserved.
- Redistribution and use in source and binary forms, with or without
- modification, are permitted provided that the following conditions
- are met:
- 1. Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
- 2. Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
- 3. The name of the author may not be used to endorse or promote products
- derived from this software without specific prior written permission.
- THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
- package org.antlr.runtime.tree;
- import org.antlr.runtime.Token;
- import org.antlr.runtime.TokenStream;
- import org.antlr.runtime.misc.IntArray;
- import java.util.*;
- /** A buffered stream of tree nodes. Nodes can be from a tree of ANY kind.
- *
- * This node stream sucks all nodes out of the tree specified in
- * the constructor during construction and makes pointers into
- * the tree using an array of Object pointers. The stream necessarily
- * includes pointers to DOWN and UP and EOF nodes.
- *
- * This stream knows how to mark/release for backtracking.
- *
- * This stream is most suitable for tree interpreters that need to
- * jump around a lot or for tree parsers requiring speed (at cost of memory).
- * There is some duplicated functionality here with UnBufferedTreeNodeStream
- * but just in bookkeeping, not tree walking etc...
- *
- * TARGET DEVELOPERS:
- *
- * This is the old CommonTreeNodeStream that buffered up entire node stream.
- * No need to implement really as new CommonTreeNodeStream is much better
- * and covers what we need.
- *
- * @see CommonTreeNodeStream
- */
- public class BufferedTreeNodeStream implements TreeNodeStream {
- public static final int DEFAULT_INITIAL_BUFFER_SIZE = 100;
- public static final int INITIAL_CALL_STACK_SIZE = 10;
- protected class StreamIterator implements Iterator<Object> {
- int i = 0;
- @Override
- public boolean hasNext() {
- return i<nodes.size();
- }
- @Override
- public Object next() {
- int current = i;
- i++;
- if ( current < nodes.size() ) {
- return nodes.get(current);
- }
- return eof;
- }
- @Override
- public void remove() {
- throw new RuntimeException("cannot remove nodes from stream");
- }
- }
- // all these navigation nodes are shared and hence they
- // cannot contain any line/column info
- protected Object down;
- protected Object up;
- protected Object eof;
- /** The complete mapping from stream index to tree node.
- * This buffer includes pointers to DOWN, UP, and EOF nodes.
- * It is built upon ctor invocation. The elements are type
- * Object as we don't what the trees look like.
- *
- * Load upon first need of the buffer so we can set token types
- * of interest for reverseIndexing. Slows us down a wee bit to
- * do all of the if p==-1 testing everywhere though.
- */
- protected List<Object> nodes;
- /** Pull nodes from which tree? */
- protected Object root;
- /** IF this tree (root) was created from a token stream, track it. */
- protected TokenStream tokens;
- /** What tree adaptor was used to build these trees */
- TreeAdaptor adaptor;
- /** Reuse same DOWN, UP navigation nodes unless this is true */
- protected boolean uniqueNavigationNodes = false;
- /** The index into the nodes list of the current node (next node
- * to consume). If -1, nodes array not filled yet.
- */
- protected int p = -1;
- /** Track the last mark() call result value for use in rewind(). */
- protected int lastMarker;
- /** Stack of indexes used for push/pop calls */
- protected IntArray calls;
- public BufferedTreeNodeStream(Object tree) {
- this(new CommonTreeAdaptor(), tree);
- }
- public BufferedTreeNodeStream(TreeAdaptor adaptor, Object tree) {
- this(adaptor, tree, DEFAULT_INITIAL_BUFFER_SIZE);
- }
- public BufferedTreeNodeStream(TreeAdaptor adaptor, Object tree, int initialBufferSize) {
- this.root = tree;
- this.adaptor = adaptor;
- nodes = new ArrayList<Object>(initialBufferSize);
- down = adaptor.create(Token.DOWN, "DOWN");
- up = adaptor.create(Token.UP, "UP");
- eof = adaptor.create(Token.EOF, "EOF");
- }
- /** Walk tree with depth-first-search and fill nodes buffer.
- * Don't do DOWN, UP nodes if its a list (t is isNil).
- */
- protected void fillBuffer() {
- fillBuffer(root);
- //System.out.println("revIndex="+tokenTypeToStreamIndexesMap);
- p = 0; // buffer of nodes intialized now
- }
- public void fillBuffer(Object t) {
- boolean nil = adaptor.isNil(t);
- if ( !nil ) {
- nodes.add(t); // add this node
- }
- // add DOWN node if t has children
- int n = adaptor.getChildCount(t);
- if ( !nil && n>0 ) {
- addNavigationNode(Token.DOWN);
- }
- // and now add all its children
- for (int c=0; c<n; c++) {
- Object child = adaptor.getChild(t,c);
- fillBuffer(child);
- }
- // add UP node if t has children
- if ( !nil && n>0 ) {
- addNavigationNode(Token.UP);
- }
- }
- /** What is the stream index for node? 0..n-1
- * Return -1 if node not found.
- */
- protected int getNodeIndex(Object node) {
- if ( p==-1 ) {
- fillBuffer();
- }
- for (int i = 0; i < nodes.size(); i++) {
- Object t = nodes.get(i);
- if ( t==node ) {
- return i;
- }
- }
- return -1;
- }
- /** As we flatten the tree, we use UP, DOWN nodes to represent
- * the tree structure. When debugging we need unique nodes
- * so instantiate new ones when uniqueNavigationNodes is true.
- */
- protected void addNavigationNode(final int ttype) {
- Object navNode;
- if ( ttype==Token.DOWN ) {
- if ( hasUniqueNavigationNodes() ) {
- navNode = adaptor.create(Token.DOWN, "DOWN");
- }
- else {
- navNode = down;
- }
- }
- else {
- if ( hasUniqueNavigationNodes() ) {
- navNode = adaptor.create(Token.UP, "UP");
- }
- else {
- navNode = up;
- }
- }
- nodes.add(navNode);
- }
- @Override
- public Object get(int i) {
- if ( p==-1 ) {
- fillBuffer();
- }
- return nodes.get(i);
- }
- @Override
- public Object LT(int k) {
- if ( p==-1 ) {
- fillBuffer();
- }
- if ( k==0 ) {
- return null;
- }
- if ( k<0 ) {
- return LB(-k);
- }
- //System.out.print("LT(p="+p+","+k+")=");
- if ( (p+k-1) >= nodes.size() ) {
- return eof;
- }
- return nodes.get(p+k-1);
- }
- public Object getCurrentSymbol() { return LT(1); }
- /*
- public Object getLastTreeNode() {
- int i = index();
- if ( i>=size() ) {
- i--; // if at EOF, have to start one back
- }
- System.out.println("start last node: "+i+" size=="+nodes.size());
- while ( i>=0 &&
- (adaptor.getType(get(i))==Token.EOF ||
- adaptor.getType(get(i))==Token.UP ||
- adaptor.getType(get(i))==Token.DOWN) )
- {
- i--;
- }
- System.out.println("stop at node: "+i+" "+nodes.get(i));
- return nodes.get(i);
- }
- */
-
- /** Look backwards k nodes */
- protected Object LB(int k) {
- if ( k==0 ) {
- return null;
- }
- if ( (p-k)<0 ) {
- return null;
- }
- return nodes.get(p-k);
- }
- @Override
- public Object getTreeSource() {
- return root;
- }
- @Override
- public String getSourceName() {
- return getTokenStream().getSourceName();
- }
- @Override
- public TokenStream getTokenStream() {
- return tokens;
- }
- public void setTokenStream(TokenStream tokens) {
- this.tokens = tokens;
- }
- @Override
- public TreeAdaptor getTreeAdaptor() {
- return adaptor;
- }
- public void setTreeAdaptor(TreeAdaptor adaptor) {
- this.adaptor = adaptor;
- }
- public boolean hasUniqueNavigationNodes() {
- return uniqueNavigationNodes;
- }
- @Override
- public void setUniqueNavigationNodes(boolean uniqueNavigationNodes) {
- this.uniqueNavigationNodes = uniqueNavigationNodes;
- }
- @Override
- public void consume() {
- if ( p==-1 ) {
- fillBuffer();
- }
- p++;
- }
- @Override
- public int LA(int i) {
- return adaptor.getType(LT(i));
- }
- @Override
- public int mark() {
- if ( p==-1 ) {
- fillBuffer();
- }
- lastMarker = index();
- return lastMarker;
- }
- @Override
- public void release(int marker) {
- // no resources to release
- }
- @Override
- public int index() {
- return p;
- }
- @Override
- public void rewind(int marker) {
- seek(marker);
- }
- @Override
- public void rewind() {
- seek(lastMarker);
- }
- @Override
- public void seek(int index) {
- if ( p==-1 ) {
- fillBuffer();
- }
- p = index;
- }
- /** Make stream jump to a new location, saving old location.
- * Switch back with pop().
- */
- public void push(int index) {
- if ( calls==null ) {
- calls = new IntArray();
- }
- calls.push(p); // save current index
- seek(index);
- }
- /** Seek back to previous index saved during last push() call.
- * Return top of stack (return index).
- */
- public int pop() {
- int ret = calls.pop();
- seek(ret);
- return ret;
- }
- @Override
- public void reset() {
- p = 0;
- lastMarker = 0;
- if (calls != null) {
- calls.clear();
- }
- }
- @Override
- public int size() {
- if ( p==-1 ) {
- fillBuffer();
- }
- return nodes.size();
- }
- public Iterator<Object> iterator() {
- if ( p==-1 ) {
- fillBuffer();
- }
- return new StreamIterator();
- }
- // TREE REWRITE INTERFACE
- @Override
- public void replaceChildren(Object parent, int startChildIndex, int stopChildIndex, Object t) {
- if ( parent!=null ) {
- adaptor.replaceChildren(parent, startChildIndex, stopChildIndex, t);
- }
- }
- /** Used for testing, just return the token type stream */
- public String toTokenTypeString() {
- if ( p==-1 ) {
- fillBuffer();
- }
- StringBuilder buf = new StringBuilder();
- for (int i = 0; i < nodes.size(); i++) {
- Object t = nodes.get(i);
- buf.append(" ");
- buf.append(adaptor.getType(t));
- }
- return buf.toString();
- }
- /** Debugging */
- public String toTokenString(int start, int stop) {
- if ( p==-1 ) {
- fillBuffer();
- }
- StringBuilder buf = new StringBuilder();
- for (int i = start; i < nodes.size() && i <= stop; i++) {
- Object t = nodes.get(i);
- buf.append(" ");
- buf.append(adaptor.getToken(t));
- }
- return buf.toString();
- }
- @Override
- public String toString(Object start, Object stop) {
- System.out.println("toString");
- if ( start==null || stop==null ) {
- return null;
- }
- if ( p==-1 ) {
- fillBuffer();
- }
- //System.out.println("stop: "+stop);
- if ( start instanceof CommonTree )
- System.out.print("toString: "+((CommonTree)start).getToken()+", ");
- else
- System.out.println(start);
- if ( stop instanceof CommonTree )
- System.out.println(((CommonTree)stop).getToken());
- else
- System.out.println(stop);
- // if we have the token stream, use that to dump text in order
- if ( tokens!=null ) {
- int beginTokenIndex = adaptor.getTokenStartIndex(start);
- int endTokenIndex = adaptor.getTokenStopIndex(stop);
- // if it's a tree, use start/stop index from start node
- // else use token range from start/stop nodes
- if ( adaptor.getType(stop)==Token.UP ) {
- endTokenIndex = adaptor.getTokenStopIndex(start);
- }
- else if ( adaptor.getType(stop)==Token.EOF ) {
- endTokenIndex = size()-2; // don't use EOF
- }
- return tokens.toString(beginTokenIndex, endTokenIndex);
- }
- // walk nodes looking for start
- Object t;
- int i = 0;
- for (; i < nodes.size(); i++) {
- t = nodes.get(i);
- if ( t==start ) {
- break;
- }
- }
- // now walk until we see stop, filling string buffer with text
- StringBuilder buf = new StringBuilder();
- t = nodes.get(i);
- while ( t!=stop ) {
- String text = adaptor.getText(t);
- if ( text==null ) {
- text = " "+String.valueOf(adaptor.getType(t));
- }
- buf.append(text);
- i++;
- t = nodes.get(i);
- }
- // include stop node too
- String text = adaptor.getText(stop);
- if ( text==null ) {
- text = " "+String.valueOf(adaptor.getType(stop));
- }
- buf.append(text);
- return buf.toString();
- }
- }