📄 unbufferedtreenodestream.java
字号:
state.absoluteNodeIndex = absoluteNodeIndex; state.currentChildIndex = currentChildIndex; state.currentNode = currentNode; state.previousNode = previousNode; state.nodeStackSize = nodeStack.size(); state.indexStackSize = indexStack.size(); // take snapshot of lookahead buffer int n = getLookaheadSize(); int i=0; state.lookahead = new Object[n]; for (int k=1; k<=n; k++,i++) { state.lookahead[i] = LT(k); } lastMarker = markDepth; return markDepth; } public void release(int marker) { // unwind any other markers made after marker and release marker markDepth = marker; // release this marker markDepth--; } /** Rewind the current state of the tree walk to the state it * was in when mark() was called and it returned marker. Also, * wipe out the lookahead which will force reloading a few nodes * but it is better than making a copy of the lookahead buffer * upon mark(). */ public void rewind(int marker) { if ( markers==null ) { return; } TreeWalkState state = (TreeWalkState)markers.get(marker); absoluteNodeIndex = state.absoluteNodeIndex; currentChildIndex = state.currentChildIndex; currentNode = state.currentNode; previousNode = state.previousNode; // drop node and index stacks back to old size nodeStack.setSize(state.nodeStackSize); indexStack.setSize(state.indexStackSize); head = tail = 0; // wack lookahead buffer and then refill for (; tail<state.lookahead.length; tail++) { lookahead[tail] = state.lookahead[tail]; } release(marker); } public void rewind() { rewind(lastMarker); } /** consume() ahead until we hit index. Can't just jump ahead--must * spit out the navigation nodes. */ public void seek(int index) { if ( index<this.index() ) { throw new IllegalArgumentException("can't seek backwards in node stream"); } // seek forward, consume until we hit index while ( this.index()<index ) { consume(); } } public int index() { return absoluteNodeIndex+1; } /** Expensive to compute; recursively walk tree to find size; * include navigation nodes and EOF. Reuse functionality * in CommonTreeNodeStream as we only really use this * for testing. */ public int size() { CommonTreeNodeStream s = new CommonTreeNodeStream(root); return s.size(); } /** Return the next node found during a depth-first walk of root. * Also, add these nodes and DOWN/UP imaginary nodes into the lokoahead * buffer as a side-effect. Normally side-effects are bad, but because * we can emit many tokens for every next() call, it's pretty hard to * use a single return value for that. We must add these tokens to * the lookahead buffer. * * This does *not* return the DOWN/UP nodes; those are only returned * by the LT() method. * * Ugh. This mechanism is much more complicated than a recursive * solution, but it's the only way to provide nodes on-demand instead * of walking once completely through and buffering up the nodes. :( */ public Object next() { // already walked entire tree; nothing to return if ( currentNode==null ) { addLookahead(eof); // this is infinite stream returning EOF at end forever // so don't throw NoSuchElementException return null; } // initial condition (first time method is called) if ( currentChildIndex==-1 ) { return handleRootNode(); } // index is in the child list? if ( currentChildIndex<adaptor.getChildCount(currentNode) ) { return visitChild(currentChildIndex); } // hit end of child list, return to parent node or its parent ... walkBackToMostRecentNodeWithUnvisitedChildren(); if ( currentNode!=null ) { return visitChild(currentChildIndex); } return null; } protected Object handleRootNode() { Object node; node = currentNode; // point to first child in prep for subsequent next() currentChildIndex = 0; if ( adaptor.isNil(node) ) { // don't count this root nil node node = visitChild(currentChildIndex); } else { addLookahead(node); if ( adaptor.getChildCount(currentNode)==0 ) { // single node case currentNode = null; // say we're done } } return node; } protected Object visitChild(int child) { Object node = null; // save state nodeStack.push(currentNode); indexStack.push(new Integer(child)); if ( child==0 && !adaptor.isNil(currentNode) ) { addNavigationNode(Token.DOWN); } // visit child currentNode = adaptor.getChild(currentNode,child); currentChildIndex = 0; node = currentNode; // record node to return addLookahead(node); walkBackToMostRecentNodeWithUnvisitedChildren(); return node; } /** 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 = null; 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; } } addLookahead(navNode); } /** Walk upwards looking for a node with more children to walk. */ protected void walkBackToMostRecentNodeWithUnvisitedChildren() { while ( currentNode!=null && currentChildIndex>=adaptor.getChildCount(currentNode) ) { currentNode = nodeStack.pop(); if ( currentNode==null ) { // hit the root? return; } currentChildIndex = ((Integer)indexStack.pop()).intValue(); currentChildIndex++; // move to next child if ( currentChildIndex>=adaptor.getChildCount(currentNode) ) { if ( !adaptor.isNil(currentNode) ) { addNavigationNode(Token.UP); } if ( currentNode==root ) { // we done yet? currentNode = null; } } } } public TreeAdaptor getTreeAdaptor() { return adaptor; } public boolean hasUniqueNavigationNodes() { return uniqueNavigationNodes; } public void setUniqueNavigationNodes(boolean uniqueNavigationNodes) { this.uniqueNavigationNodes = uniqueNavigationNodes; } /** Print out the entire tree including DOWN/UP nodes. Uses * a recursive walk. Mostly useful for testing as it yields * the token types not text. */ public String toString() { return toString(root, null); } protected int getLookaheadSize() { return tail<head?(lookahead.length-head+tail):(tail-head); } public String toString(Object start, Object stop) { if ( start==null ) { return null; } // if we have the token stream, use that to dump text in order if ( tokens!=null ) { // don't trust stop node as it's often an UP node etc... // walk backwards until you find a non-UP, non-DOWN node // and ask for it's token index. int beginTokenIndex = adaptor.getTokenStartIndex(start); int endTokenIndex = adaptor.getTokenStopIndex(stop); if ( stop!=null && adaptor.getType(stop)==Token.UP ) { endTokenIndex = adaptor.getTokenStopIndex(start); } else { endTokenIndex = size()-1; } return tokens.toString(beginTokenIndex, endTokenIndex); } StringBuffer buf = new StringBuffer(); toStringWork(start, stop, buf); return buf.toString(); } protected void toStringWork(Object p, Object stop, StringBuffer buf) { if ( !adaptor.isNil(p) ) { String text = adaptor.getText(p); if ( text==null ) { text = " "+String.valueOf(adaptor.getType(p)); } buf.append(text); // ask the node to go to string } if ( p==stop ) { return; } int n = adaptor.getChildCount(p); if ( n>0 && !adaptor.isNil(p) ) { buf.append(" "); buf.append(Token.DOWN); } for (int c=0; c<n; c++) { Object child = adaptor.getChild(p,c); toStringWork(child, stop, buf); } if ( n>0 && !adaptor.isNil(p) ) { buf.append(" "); buf.append(Token.UP); } }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -