aboutsummaryrefslogtreecommitdiff
path: root/antlr-3.4/runtime/ActionScript/project/src/org/antlr/runtime/tree/CommonTreeNodeStream.as
diff options
context:
space:
mode:
Diffstat (limited to 'antlr-3.4/runtime/ActionScript/project/src/org/antlr/runtime/tree/CommonTreeNodeStream.as')
-rw-r--r--antlr-3.4/runtime/ActionScript/project/src/org/antlr/runtime/tree/CommonTreeNodeStream.as438
1 files changed, 438 insertions, 0 deletions
diff --git a/antlr-3.4/runtime/ActionScript/project/src/org/antlr/runtime/tree/CommonTreeNodeStream.as b/antlr-3.4/runtime/ActionScript/project/src/org/antlr/runtime/tree/CommonTreeNodeStream.as
new file mode 100644
index 0000000..a6fd778
--- /dev/null
+++ b/antlr-3.4/runtime/ActionScript/project/src/org/antlr/runtime/tree/CommonTreeNodeStream.as
@@ -0,0 +1,438 @@
+/*
+[The "BSD licence"]
+Copyright (c) 2005-2006 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.TokenConstants;
+ import org.antlr.runtime.TokenStream;
+
+
+ /** 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...
+ *
+ * @see UnBufferedTreeNodeStream
+ */
+ public class CommonTreeNodeStream implements TreeNodeStream {
+ public static const DEFAULT_INITIAL_BUFFER_SIZE:int = 100;
+ public static const INITIAL_CALL_STACK_SIZE:int = 10;
+
+ // all these navigation nodes are shared and hence they
+ // cannot contain any line/column info
+
+ protected var down:Object;
+ protected var up:Object;
+ protected var eof:Object;
+
+ /** 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 var nodes:Array;
+
+ /** Pull nodes from which tree? */
+ protected var root:Object;
+
+ /** IF this tree (root) was created from a token stream, track it. */
+ protected var tokens:TokenStream;
+
+ /** What tree adaptor was used to build these trees */
+ internal var adaptor:TreeAdaptor;
+
+ /** Reuse same DOWN, UP navigation nodes unless this is true */
+ protected var uniqueNavigationNodes:Boolean = false;
+
+ /** The index into the nodes list of the current node (next node
+ * to consume). If -1, nodes array not filled yet.
+ */
+ protected var p:int = -1;
+
+ /** Track the last mark() call result value for use in rewind(). */
+ protected var lastMarker:int;
+
+ /** Stack of indexes used for push/pop calls */
+ protected var calls:Array;
+
+ public function CommonTreeNodeStream(tree:Object, adaptor:TreeAdaptor = null, initialBufferSize:int = DEFAULT_INITIAL_BUFFER_SIZE) {
+ if (tree == null) {
+ // return uninitalized for static resuse function
+ return;
+ }
+ this.root = tree;
+ this.adaptor = adaptor == null ? new CommonTreeAdaptor() : adaptor;
+
+ nodes = new Array();
+ down = this.adaptor.createFromType(TokenConstants.DOWN, "DOWN");
+ up = this.adaptor.createFromType(TokenConstants.UP, "UP");
+ eof = this.adaptor.createFromType(TokenConstants.EOF, "EOF");
+ }
+
+ /** Reuse an existing node stream's buffer of nodes. Do not point at a
+ * node stream that can change. Must have static node list. start/stop
+ * are indexes into the parent.nodes stream. We avoid making a new
+ * list of nodes like this.
+ */
+ public static function reuse(parent:CommonTreeNodeStream, start:int, stop:int):CommonTreeNodeStream {
+ var stream:CommonTreeNodeStream = new CommonTreeNodeStream(null);
+ stream.root = parent.root;
+ stream.adaptor = parent.adaptor;
+ stream.nodes = parent.nodes.slice(start, stop);
+ stream.down = parent.down;
+ stream.up = parent.up;
+ stream.eof = parent.eof;
+ return stream;
+ }
+
+ /** Walk tree with depth-first-search and fill nodes buffer.
+ * Don't do DOWN, UP nodes if its a list (t is isNil).
+ */
+ protected function fillBuffer():void {
+ fillBufferTo(root);
+ //System.out.println("revIndex="+tokenTypeToStreamIndexesMap);
+ p = 0; // buffer of nodes intialized now
+ }
+
+ public function fillBufferTo(t:Object):void {
+ var nil:Boolean = adaptor.isNil(t);
+ if ( !nil ) {
+ nodes.push(t); // add this node
+ }
+ // add DOWN node if t has children
+ var n:int = adaptor.getChildCount(t);
+ if ( !nil && n>0 ) {
+ addNavigationNode(TokenConstants.DOWN);
+ }
+ // and now add all its children
+ for (var c:int=0; c<n; c++) {
+ var child:Object = adaptor.getChild(t,c);
+ fillBufferTo(child);
+ }
+ // add UP node if t has children
+ if ( !nil && n>0 ) {
+ addNavigationNode(TokenConstants.UP);
+ }
+ }
+
+ /** What is the stream index for node? 0..n-1
+ * Return -1 if node not found.
+ */
+ protected function getNodeIndex(node:Object):int {
+ if ( p==-1 ) {
+ fillBuffer();
+ }
+ for (var i:int = 0; i < nodes.length; i++) {
+ var t:Object = nodes[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 function addNavigationNode(ttype:int):void {
+ var navNode:Object = null;
+ if ( ttype==TokenConstants.DOWN ) {
+ if ( hasUniqueNavigationNodes) {
+ navNode = adaptor.createFromType(TokenConstants.DOWN, "DOWN");
+ }
+ else {
+ navNode = down;
+ }
+ }
+ else {
+ if ( hasUniqueNavigationNodes ) {
+ navNode = adaptor.createFromType(TokenConstants.UP, "UP");
+ }
+ else {
+ navNode = up;
+ }
+ }
+ nodes.push(navNode);
+ }
+
+ public function getNode(i:int):Object {
+ if ( p==-1 ) {
+ fillBuffer();
+ }
+ return nodes[i];
+ }
+
+ public function LT(k:int):Object {
+ 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.length ) {
+ return eof;
+ }
+ return nodes[p+k-1];
+ }
+
+ public function get currentSymbol():Object { return LT(1); }
+
+ /** Look backwards k nodes */
+ protected function LB(k:int):Object {
+ if ( k==0 ) {
+ return null;
+ }
+ if ( (p-k)<0 ) {
+ return null;
+ }
+ return nodes[p-k];
+ }
+
+ public function get treeSource():Object {
+ return root;
+ }
+
+ public function get sourceName():String {
+ return tokenStream.sourceName;
+ }
+
+ public function get tokenStream():TokenStream {
+ return tokens;
+ }
+
+ public function set tokenStream(tokens:TokenStream):void {
+ this.tokens = tokens;
+ }
+
+ public function get treeAdaptor():TreeAdaptor {
+ return adaptor;
+ }
+
+ public function set treeAdaptor(adaptor:TreeAdaptor):void {
+ this.adaptor = adaptor;
+ }
+
+ public function get hasUniqueNavigationNodes():Boolean {
+ return uniqueNavigationNodes;
+ }
+
+ public function set hasUniqueNavigationNodes(uniqueNavigationNodes:Boolean):void {
+ this.uniqueNavigationNodes = uniqueNavigationNodes;
+ }
+
+ public function consume():void {
+ if ( p==-1 ) {
+ fillBuffer();
+ }
+ p++;
+ }
+
+ public function LA(i:int):int {
+ return adaptor.getType(LT(i));
+ }
+
+ public function mark():int {
+ if ( p==-1 ) {
+ fillBuffer();
+ }
+ lastMarker = index;
+ return lastMarker;
+ }
+
+ public function release(marker:int):void {
+ // no resources to release
+ }
+
+ public function get index():int {
+ return p;
+ }
+
+ public function rewindTo(marker:int):void {
+ seek(marker);
+ }
+
+ public function rewind():void {
+ seek(lastMarker);
+ }
+
+ public function seek(index:int):void {
+ if ( p==-1 ) {
+ fillBuffer();
+ }
+ p = index;
+ }
+
+ /** Make stream jump to a new location, saving old location.
+ * Switch back with pop().
+ */
+ public function push(index:int):void {
+ if ( calls==null ) {
+ calls = new Array();
+ }
+ 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 function pop():int {
+ var ret:int = calls.pop();
+ seek(ret);
+ return ret;
+ }
+
+ public function reset():void {
+ p = 0;
+ lastMarker = 0;
+ if (calls != null) {
+ calls = new Array();
+ }
+ }
+
+ public function get size():int {
+ if ( p==-1 ) {
+ fillBuffer();
+ }
+ return nodes.length;
+ }
+
+ // TREE REWRITE INTERFACE
+ public function replaceChildren(parent:Object, startChildIndex:int, stopChildIndex:int, t:Object):void {
+ if ( parent!=null ) {
+ adaptor.replaceChildren(parent, startChildIndex, stopChildIndex, t);
+ }
+ }
+
+ /** Used for testing, just return the token type stream */
+ public function toString():String {
+ if ( p==-1 ) {
+ fillBuffer();
+ }
+ var buf:String = "";
+ for (var i:int = 0; i < nodes.length; i++) {
+ var t:Object = nodes[i];
+ buf += " ";
+ buf += (adaptor.getType(t));
+ }
+ return buf.toString();
+ }
+
+ /** Debugging */
+ public function toTokenString(start:int, stop:int):String {
+ if ( p==-1 ) {
+ fillBuffer();
+ }
+ var buf:String = "";
+ for (var i:int = start; i < nodes.length && i <= stop; i++) {
+ var t:Object = nodes[i];
+ buf += " ";
+ buf += adaptor.getToken(t);
+ }
+ return buf;
+ }
+
+ public function toStringWithRange(start:Object, stop:Object):String {
+ if ( start==null || stop==null ) {
+ return null;
+ }
+ if ( p==-1 ) {
+ fillBuffer();
+ }
+ trace("stop: "+stop);
+ if ( start is CommonTree )
+ trace("toString: "+CommonTree(start).token+", ");
+ else
+ trace(start);
+ if ( stop is CommonTree )
+ trace(CommonTree(stop).token);
+ else
+ trace(stop);
+ // if we have the token stream, use that to dump text in order
+ if ( tokens!=null ) {
+ var beginTokenIndex:int = adaptor.getTokenStartIndex(start);
+ var endTokenIndex:int = 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)==TokenConstants.UP ) {
+ endTokenIndex = adaptor.getTokenStopIndex(start);
+ }
+ else if ( adaptor.getType(stop)==TokenConstants.EOF ) {
+ endTokenIndex = size-2; // don't use EOF
+ }
+ return tokens.toStringWithRange(beginTokenIndex, endTokenIndex);
+ }
+ // walk nodes looking for start
+ var t:Object = null;
+ var i:int = 0;
+ for (; i < nodes.length; i++) {
+ t = nodes[i];
+ if ( t==start ) {
+ break;
+ }
+ }
+ // now walk until we see stop, filling string buffer with text
+ var buf:String = "";
+ t = nodes[i];
+ while ( t!=stop ) {
+ var text:String = adaptor.getText(t);
+ if ( text==null ) {
+ text = " "+ adaptor.getType(t);
+ }
+ buf += text;
+ i++;
+ t = nodes[i];
+ }
+ // include stop node too
+ text = adaptor.getText(stop);
+ if ( text==null ) {
+ text = " " + adaptor.getType(stop);
+ }
+ buf += text;
+ return buf.toString();
+ }
+ }
+
+} \ No newline at end of file