1324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver/*
2324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver [The "BSD licence"]
3324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver Copyright (c) 2005-2006 Terence Parr
4324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver All rights reserved.
5324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
6324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver Redistribution and use in source and binary forms, with or without
7324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver modification, are permitted provided that the following conditions
8324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver are met:
9324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 1. Redistributions of source code must retain the above copyright
10324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    notice, this list of conditions and the following disclaimer.
11324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 2. Redistributions in binary form must reproduce the above copyright
12324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    notice, this list of conditions and the following disclaimer in the
13324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    documentation and/or other materials provided with the distribution.
14324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver 3. The name of the author may not be used to endorse or promote products
15324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    derived from this software without specific prior written permission.
16324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
17324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver*/
28324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruverpackage org.antlr.runtime {
29324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	import flash.utils.getQualifiedClassName;
30324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
31324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
32324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	/** Useful for dumping out the input stream after doing some
33324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	 *  augmentation or other manipulations.
34324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	 *
35324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	 *  You can insert stuff, replace, and delete chunks.  Note that the
36324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	 *  operations are done lazily--only if you convert the buffer to a
37324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	 *  String.  This is very efficient because you are not moving data around
38324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	 *  all the time.  As the buffer of tokens is converted to strings, the
39324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	 *  toString() method(s) check to see if there is an operation at the
40324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	 *  current index.  If so, the operation is done and then normal String
41324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	 *  rendering continues on the buffer.  This is like having multiple Turing
42324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	 *  machine instruction streams (programs) operating on a single input tape. :)
43324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	 *
44324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	 *  Since the operations are done lazily at toString-time, operations do not
45324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	 *  screw up the token index values.  That is, an insert operation at token
46324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	 *  index i does not change the index values for tokens i+1..n-1.
47324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	 *
48324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	 *  Because operations never actually alter the buffer, you may always get
49324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	 *  the original token stream back without undoing anything.  Since
50324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	 *  the instructions are queued up, you can easily simulate transactions and
51324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	 *  roll back any changes if there is an error just by removing instructions.
52324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	 *  For example,
53324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	 *
54324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	 *   var input:CharStream = new ANTLRFileStream("input");
55324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	 *   var lex:TLexer = new TLexer(input);
56324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	 *   var tokens:TokenRewriteStream = new TokenRewriteStream(lex);
57324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	 *   var parser:T = new T(tokens);
58324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	 *   parser.startRule();
59324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	 *
60324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	 * 	 Then in the rules, you can execute
61324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	 *      var t:Token t, u:Token;
62324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	 *      ...
63324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	 *      input.insertAfter(t, "text to put after t");}
64324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	 * 		input.insertAfter(u, "text after u");}
65324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	 * 		trace(tokens.toString());
66324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	 *
67324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	 *  Actually, you have to cast the 'input' to a TokenRewriteStream. :(
68324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	 *
69324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	 *  You can also have multiple "instruction streams" and get multiple
70324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	 *  rewrites from a single pass over the input.  Just name the instruction
71324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	 *  streams and use that name again when printing the buffer.  This could be
72324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	 *  useful for generating a C file and also its header file--all from the
73324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	 *  same buffer:
74324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	 *
75324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	 *      tokens.insertAfter("pass1", t, "text to put after t");}
76324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	 * 		tokens.insertAfter("pass2", u, "text after u");}
77324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	 * 		trace(tokens.toString("pass1"));
78324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	 * 		trace(tokens.toString("pass2"));
79324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	 *
80324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	 *  If you don't use named rewrite streams, a "default" stream is used as
81324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	 *  the first example shows.
82324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	 */
83324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	public class TokenRewriteStream extends CommonTokenStream {
84324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver		public static const DEFAULT_PROGRAM_NAME:String = "default";
85324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver		public static const MIN_TOKEN_INDEX:int = 0;
86324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
87324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver		/** You may have multiple, named streams of rewrite operations.
88324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver		 *  I'm calling these things "programs."
89324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver		 *  Maps String (name) -> rewrite (List)
90324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver		 */
91324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver		protected var programs:Object = new Object();
92324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
93324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver		/** Map String (program name) -> Integer index */
94324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver		protected var lastRewriteTokenIndexes:Object = new Object();
95324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
96324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver		public function TokenRewriteStream(tokenSource:TokenSource = null, channel:int = TokenConstants.DEFAULT_CHANNEL) {
97324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver			super(tokenSource, channel);
98324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver			programs[DEFAULT_PROGRAM_NAME] = new Array();
99324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver		}
100324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
101324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	    /** Rollback the instruction stream for a program so that
102324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver		 *  the indicated instruction (via instructionIndex) is no
103324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver		 *  longer in the stream.  UNTESTED!
104324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver		 */
105324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver		public function rollback(instructionIndex:int, programName:String = DEFAULT_PROGRAM_NAME):void {
106324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver			var isn:Array = programs[programName] as Array;
107324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver			if ( isn != null ) {
108324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver				programs[programName] = isn.slice(MIN_TOKEN_INDEX,instructionIndex);
109324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver			}
110324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver		}
111324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
112324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver		/** Reset the program so that no instructions exist */
113324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver		public function deleteProgram(programName:String = DEFAULT_PROGRAM_NAME):void {
114324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver			rollback(MIN_TOKEN_INDEX, programName);
115324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver		}
116324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
117324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver		public function insertAfterToken(t:Token, text:Object, programName:String = DEFAULT_PROGRAM_NAME):void {
118324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver			insertAfter(t.tokenIndex, text, programName);
119324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver		}
120324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
121324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver		public function insertAfter(index:int, text:Object, programName:String = DEFAULT_PROGRAM_NAME):void {
122324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver			// to insert after, just insert before next index (even if past end)
123324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver			insertBefore(index+1, text, programName);
124324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver		}
125324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
126324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver		public function insertBeforeToken(t:Token, text:Object, programName:String = DEFAULT_PROGRAM_NAME):void {
127324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver			insertBefore(t.tokenIndex, text, programName);
128324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver		}
129324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
130324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver		public function insertBefore(index:int, text:Object, programName:String = DEFAULT_PROGRAM_NAME):void {
131324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver			var op:RewriteOperation = new InsertBeforeOp(index,text);
132324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver			var rewrites:Array = getProgram(programName);
133324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver			op.instructionIndex = rewrites.length;
134324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver			rewrites.push(op);
135324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver		}
136324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
137324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver		public function replace(index:int, text:Object, programName:String = DEFAULT_PROGRAM_NAME):void {
138324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver			replaceRange(index, index, text, programName);
139324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver		}
140324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
141324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver		public function replaceRange(fromIndex:int, toIndex:int, text:Object, programName:String = DEFAULT_PROGRAM_NAME):void {
142324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver			if ( fromIndex > toIndex || fromIndex<0 || toIndex<0 || toIndex >= tokens.length ) {
143324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver				throw new Error("replace: range invalid: "+fromIndex+".."+toIndex+"(size="+tokens.length+")");
144324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver			}
145324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver			var op:RewriteOperation = new ReplaceOp(fromIndex, toIndex, text);
146324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver			var rewrites:Array = getProgram(programName);
147324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver			op.instructionIndex = rewrites.length;
148324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver			rewrites.push(op);
149324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver		}
150324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
151324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver		public function replaceToken(indexT:Token, text:Object, programName:String = DEFAULT_PROGRAM_NAME):void {
152324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver			replaceTokenRange(indexT, indexT, text, programName);
153324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver		}
154324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
155324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver		public function replaceTokenRange(fromToken:Token, toToken:Token, text:Object, programName:String = DEFAULT_PROGRAM_NAME):void {
156324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver			replaceRange(fromToken.tokenIndex, toToken.tokenIndex, text, programName);
157324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver		}
158324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
159324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver		public function remove(index:int, programName:String = DEFAULT_PROGRAM_NAME):void {
160324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver			removeRange(index, index, programName);
161324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver		}
162324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
163324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver		public function removeRange(fromIndex:int, toIndex:int, programName:String = DEFAULT_PROGRAM_NAME):void {
164324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver			replaceRange(fromIndex, toIndex, null, programName);
165324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver		}
166324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
167324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver		public function removeToken(token:Token, programName:String = DEFAULT_PROGRAM_NAME):void {
168324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver			removeTokenRange(token, token, programName);
169324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver		}
170324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
171324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver		public function removeTokenRange(fromToken:Token, toToken:Token, programName:String = DEFAULT_PROGRAM_NAME):void {
172324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver			replaceTokenRange(fromToken, toToken, null, programName);
173324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver		}
174324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
175324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver		public function getLastRewriteTokenIndex(programName:String = DEFAULT_PROGRAM_NAME):int {
176324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver			var i:* = lastRewriteTokenIndexes[programName];
177324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver			if ( i == undefined ) {
178324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver				return -1;
179324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver			}
180324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver			return i as int;
181324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver		}
182324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
183324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver		protected function setLastRewriteTokenIndex(programName:String, i:int):void {
184324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver			lastRewriteTokenIndexes[programName] = i;
185324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver		}
186324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
187324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver		protected function getProgram(name:String):Array {
188324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver			var isn:Array = programs[name] as Array;
189324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver			if ( isn==null ) {
190324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver				isn = initializeProgram(name);
191324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver			}
192324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver			return isn;
193324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver		}
194324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
195324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver		private function initializeProgram(name:String):Array {
196324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver			var isn:Array = new Array();
197324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver			programs[name] =  isn;
198324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver			return isn;
199324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver		}
200324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
201324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver		public function toOriginalString():String {
202324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver			return toOriginalStringWithRange(MIN_TOKEN_INDEX, size-1);
203324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver		}
204324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
205324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver		public function toOriginalStringWithRange(start:int, end:int):String {
206324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver			var buf:String = new String();
207324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver			for (var i:int=start; i>=MIN_TOKEN_INDEX && i<=end && i<tokens.length; i++) {
208324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver				buf += getToken(i).text;
209324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver			}
210324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver			return buf.toString();
211324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver		}
212324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
213324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver		public override function toString():String {
214324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver			return toStringWithRange(MIN_TOKEN_INDEX, size-1);
215324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver		}
216324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
217324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver		public override function toStringWithRange(start:int, end:int):String {
218324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver			return toStringWithRangeAndProgram(start, end, DEFAULT_PROGRAM_NAME);
219324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver		}
220324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
221324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver		public function toStringWithRangeAndProgram(start:int, end:int, programName:String):String {
222324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver			var rewrites:Array = programs[programName] as Array;
223324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
224324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver			// ensure start/end are in range
225324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	        if ( end > tokens.length-1 ) end = tokens.length-1;
226324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	        if ( start < 0 ) start = 0;
227324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
228324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver			if ( rewrites==null || rewrites.length==0 ) {
229324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver				return toOriginalStringWithRange(start,end); // no instructions to execute
230324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver			}
231324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver			var state:RewriteState = new RewriteState();
232324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver			state.tokens = tokens;
233324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
234324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver			// First, optimize instruction stream
235324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	        var indexToOp:Array = reduceToSingleOperationPerIndex(rewrites);
236324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
237324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	        // Walk buffer, executing instructions and emitting tokens
238324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	        var i:int = start;
239324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	        while ( i <= end && i < tokens.length ) {
240324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	            var op:RewriteOperation = RewriteOperation(indexToOp[i]);
241324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	            indexToOp[i] = undefined; // remove so any left have index size-1
242324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	            var t:Token = Token(tokens[i]);
243324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	            if ( op==null ) {
244324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	                // no operation at that index, just dump token
245324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	                state.buf += t.text;
246324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	                i++; // move to next token
247324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	            }
248324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	            else {
249324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	                i = op.execute(state); // execute operation and skip
250324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	            }
251324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	        }
252324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
253324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	        // include stuff after end if it's last index in buffer
254324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	        // So, if they did an insertAfter(lastValidIndex, "foo"), include
255324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	        // foo if end==lastValidIndex.
256324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	        if ( end==tokens.length-1 ) {
257324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	            // Scan any remaining operations after last token
258324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	            // should be included (they will be inserts).
259324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	            for each (op in indexToOp) {
260324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	            	if (op == null) continue;
261324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	                if ( op.index >= tokens.length-1 ) state.buf += op.text;
262324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	            }
263324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	        }
264324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
265324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	        return state.buf;
266324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver		}
267324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
268324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	    /** We need to combine operations and report invalid operations (like
269324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	     *  overlapping replaces that are not completed nested).  Inserts to
270324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	     *  same index need to be combined etc...   Here are the cases:
271324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	     *
272324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	     *  I.i.u I.j.v                             leave alone, nonoverlapping
273324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	     *  I.i.u I.i.v                             combine: Iivu
274324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	     *
275324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	     *  R.i-j.u R.x-y.v | i-j in x-y            delete first R
276324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	     *  R.i-j.u R.i-j.v                         delete first R
277324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	     *  R.i-j.u R.x-y.v | x-y in i-j            ERROR
278324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	     *  R.i-j.u R.x-y.v | boundaries overlap    ERROR
279324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	     *
280324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	     *  I.i.u R.x-y.v | i in x-y                delete I
281324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	     *  I.i.u R.x-y.v | i not in x-y            leave alone, nonoverlapping
282324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	     *  R.x-y.v I.i.u | i in x-y                ERROR
283324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	     *  R.x-y.v I.x.u                           R.x-y.uv (combine, delete I)
284324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	     *  R.x-y.v I.i.u | i not in x-y            leave alone, nonoverlapping
285324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	     *
286324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	     *  I.i.u = insert u before op @ index i
287324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	     *  R.x-y.u = replace x-y indexed tokens with u
288324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	     *
289324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	     *  First we need to examine replaces.  For any replace op:
290324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	     *
291324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	     *      1. wipe out any insertions before op within that range.
292324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	     *      2. Drop any replace op before that is contained completely within
293324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	     *         that range.
294324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	     *      3. Throw exception upon boundary overlap with any previous replace.
295324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	     *
296324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	     *  Then we can deal with inserts:
297324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	     *
298324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	     *      1. for any inserts to same index, combine even if not adjacent.
299324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	     *      2. for any prior replace with same left boundary, combine this
300324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	     *         insert with replace and delete this replace.
301324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	     *      3. throw exception if index in same range as previous replace
302324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	     *
303324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	     *  Don't actually delete; make op null in list. Easier to walk list.
304324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	     *  Later we can throw as we add to index -> op map.
305324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	     *
306324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	     *  Note that I.2 R.2-2 will wipe out I.2 even though, technically, the
307324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	     *  inserted stuff would be before the replace range.  But, if you
308324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	     *  add tokens in front of a method body '{' and then delete the method
309324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	     *  body, I think the stuff before the '{' you added should disappear too.
310324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	     *
311324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	     *  Return a map from token index to operation.
312324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	     */
313324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	    protected function reduceToSingleOperationPerIndex(rewrites:Array):Array {
314324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	        //System.out.println("rewrites="+rewrites);
315324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
316324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	        // WALK REPLACES
317324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	        for (var i:int = 0; i < rewrites.length; i++) {
318324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	            var op:RewriteOperation = RewriteOperation(rewrites[i]);
319324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	            if ( op==null ) continue;
320324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	            if ( !(op is ReplaceOp) ) continue;
321324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	            var rop:ReplaceOp = ReplaceOp(rewrites[i]);
322324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	            // Wipe prior inserts within range
323324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	            var inserts:Array = getKindOfOps(rewrites, InsertBeforeOp, i);
324324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	            for (var j:int = 0; j < inserts.length; j++) {
325324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	                var iop:InsertBeforeOp = InsertBeforeOp(inserts[j]);
326324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	                if ( iop.index >= rop.index && iop.index <= rop.lastIndex ) {
327324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	                    rewrites[iop.instructionIndex] = null;  // delete insert as it's a no-op.
328324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	                }
329324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	            }
330324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	            // Drop any prior replaces contained within
331324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	            var prevReplaces:Array = getKindOfOps(rewrites, ReplaceOp, i);
332324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	            for (j = 0; j < prevReplaces.length; j++) {
333324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	                var prevRop:ReplaceOp = ReplaceOp(prevReplaces[j]);
334324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	                if ( prevRop.index>=rop.index && prevRop.lastIndex <= rop.lastIndex ) {
335324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	                    rewrites[prevRop.instructionIndex] = null;  // delete replace as it's a no-op.
336324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	                    continue;
337324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	                }
338324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	                // throw exception unless disjoint or identical
339324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	                var disjoint:Boolean =
340324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	                    prevRop.lastIndex<rop.index || prevRop.index > rop.lastIndex;
341324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	                var same:Boolean =
342324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	                    prevRop.index==rop.index && prevRop.lastIndex==rop.lastIndex;
343324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	                if ( !disjoint && !same ) {
344324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	                    throw new Error("replace op boundaries of "+rop+
345324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	                                                       " overlap with previous "+prevRop);
346324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	                }
347324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	            }
348324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	        }
349324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
350324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	        // WALK INSERTS
351324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	        for (i = 0; i < rewrites.length; i++) {
352324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	            op = RewriteOperation(rewrites[i]);
353324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	            if ( op==null ) continue;
354324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	            if ( !(op is InsertBeforeOp) ) continue;
355324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	            iop = InsertBeforeOp(rewrites[i]);
356324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	            // combine current insert with prior if any at same index
357324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	            var prevInserts:Array = getKindOfOps(rewrites, InsertBeforeOp, i);
358324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	            for (j = 0; j < prevInserts.length; j++) {
359324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	                var prevIop:InsertBeforeOp = InsertBeforeOp(prevInserts[j]);
360324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	                if ( prevIop.index == iop.index ) { // combine objects
361324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	                    // convert to strings...we're in process of toString'ing
362324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	                    // whole token buffer so no lazy eval issue with any templates
363324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	                    iop.text = catOpText(iop.text,prevIop.text);
364324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	                    rewrites[prevIop.instructionIndex] = null;  // delete redundant prior insert
365324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	                }
366324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	            }
367324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	            // look for replaces where iop.index is in range; error
368324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	            prevReplaces = getKindOfOps(rewrites, ReplaceOp, i);
369324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	            for (j = 0; j < prevReplaces.length; j++) {
370324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	                rop = ReplaceOp(prevReplaces[j]);
371324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	                if ( iop.index == rop.index ) {
372324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	                    rop.text = catOpText(iop.text,rop.text);
373324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	                    rewrites[i] = null;  // delete current insert
374324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	                    continue;
375324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	                }
376324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	                if ( iop.index >= rop.index && iop.index <= rop.lastIndex ) {
377324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	                    throw new Error("insert op "+iop+
378324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	                                                       " within boundaries of previous "+rop);
379324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	                }
380324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	            }
381324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	        }
382324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	        // System.out.println("rewrites after="+rewrites);
383324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	        var m:Array = new Array();
384324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	        for (i = 0; i < rewrites.length; i++) {
385324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	            op = RewriteOperation(rewrites[i]);
386324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	            if ( op==null ) continue; // ignore deleted ops
387324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	            if ( m[op.index] != undefined ) {
388324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	                throw new Error("should only be one op per index");
389324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	            }
390324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	            m[op.index] = op;
391324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	        }
392324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	        //System.out.println("index to op: "+m);
393324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	        return m;
394324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	    }
395324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
396324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	    protected function catOpText(a:Object, b:Object):String {
397324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	        var x:String = "";
398324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	        var y:String = "";
399324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	        if ( a!=null ) x = a.toString();
400324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	        if ( b!=null ) y = b.toString();
401324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	        return x+y;
402324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	    }
403324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
404324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	    /** Get all operations before an index of a particular kind */
405324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	    protected function getKindOfOps(rewrites:Array, kind:Class, before:int = -1):Array {
406324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	    	if (before == -1) {
407324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	    		before = rewrites.length;
408324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	    	}
409324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	    	var ops:Array = new Array();
410324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	        for (var i:int=0; i<before && i<rewrites.length; i++) {
411324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	            var op:RewriteOperation = RewriteOperation(rewrites[i]);
412324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	            if ( op==null ) continue; // ignore deleted
413324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	            if ( getQualifiedClassName(op) == getQualifiedClassName(kind) ) ops.push(op);
414324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	        }
415324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	        return ops;
416324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	    }
417324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
418324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
419324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver		public function toDebugString():String {
420324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver			return toDebugStringWithRange(MIN_TOKEN_INDEX, size-1);
421324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver		}
422324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
423324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver		public function toDebugStringWithRange(start:int, end:int):String {
424324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver			var buf:String = new String();
425324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver			for (var i:int=start; i>=MIN_TOKEN_INDEX && i<=end && i<tokens.length; i++) {
426324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver				buf += getToken(i);
427324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver			}
428324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver			return buf;
429324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver		}
430324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
431324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
432324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	}
433324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver}
434324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	import org.antlr.runtime.Token;
435324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
436324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
437324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver// Define the rewrite operation hierarchy
438324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
439324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruverclass RewriteState {
440324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	public var buf:String = new String();
441324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	public var tokens:Array;
442324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver}
443324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
444324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruverclass RewriteOperation {
445324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	/** What index into rewrites List are we? */
446324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    internal var instructionIndex:int;
447324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    /** Token buffer index. */
448324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	public var index:int;
449324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	internal var text:Object;
450324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	public function RewriteOperation(index:int, text:Object) {
451324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver		this.index = index;
452324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver		this.text = text;
453324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	}
454324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	/** Execute the rewrite operation by possibly adding to the buffer.
455324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	 *  Return the index of the next token to operate on.
456324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	 */
457324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	public function execute(state:RewriteState):int {
458324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver		return index;
459324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	}
460324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver}
461324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
462324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruverclass InsertBeforeOp extends RewriteOperation {
463324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	public function InsertBeforeOp(index:int, text:Object) {
464324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver		super(index,text);
465324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	}
466324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
467324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	public override function execute(state:RewriteState):int {
468324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver		state.buf += text;
469324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver		state.buf += Token(state.tokens[index]).text;
470324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver		return index + 1;
471324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	}
472324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
473324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	public function toString():String {
474324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver		return "<InsertBeforeOp@" + index + ":\"" + text + "\">";
475324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver	}
476324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver}
477