13447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein/*
23447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein [The "BSD license"]
33447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein Copyright (c) 2005-2009 Terence Parr
43447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein All rights reserved.
53447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein
63447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein Redistribution and use in source and binary forms, with or without
73447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein modification, are permitted provided that the following conditions
83447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein are met:
93447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein 1. Redistributions of source code must retain the above copyright
103447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein     notice, this list of conditions and the following disclaimer.
113447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein 2. Redistributions in binary form must reproduce the above copyright
123447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein     notice, this list of conditions and the following disclaimer in the
133447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein     documentation and/or other materials provided with the distribution.
143447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein 3. The name of the author may not be used to endorse or promote products
153447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein     derived from this software without specific prior written permission.
163447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein
173447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
183447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
193447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
203447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
213447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
223447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
233447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
243447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
253447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
263447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
273447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein */
283447a5916aa62f44de24cc441fc9987116ddff52Andrew Sappersteinpackage org.antlr.runtime;
293447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein
303447a5916aa62f44de24cc441fc9987116ddff52Andrew Sappersteinimport java.util.*;
313447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein
323447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein/** Useful for dumping out the input stream after doing some
333447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein *  augmentation or other manipulations.
343447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein *
353447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein *  You can insert stuff, replace, and delete chunks.  Note that the
363447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein *  operations are done lazily--only if you convert the buffer to a
373447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein *  String.  This is very efficient because you are not moving data around
383447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein *  all the time.  As the buffer of tokens is converted to strings, the
393447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein *  toString() method(s) check to see if there is an operation at the
403447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein *  current index.  If so, the operation is done and then normal String
413447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein *  rendering continues on the buffer.  This is like having multiple Turing
423447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein *  machine instruction streams (programs) operating on a single input tape. :)
433447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein *
443447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein *  Since the operations are done lazily at toString-time, operations do not
453447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein *  screw up the token index values.  That is, an insert operation at token
463447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein *  index i does not change the index values for tokens i+1..n-1.
473447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein *
483447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein *  Because operations never actually alter the buffer, you may always get
493447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein *  the original token stream back without undoing anything.  Since
503447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein *  the instructions are queued up, you can easily simulate transactions and
513447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein *  roll back any changes if there is an error just by removing instructions.
523447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein *  For example,
533447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein *
543447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein *   CharStream input = new ANTLRFileStream("input");
553447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein *   TLexer lex = new TLexer(input);
563447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein *   TokenRewriteStream tokens = new TokenRewriteStream(lex);
573447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein *   T parser = new T(tokens);
583447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein *   parser.startRule();
593447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein *
603447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein * 	 Then in the rules, you can execute
613447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein *      Token t,u;
623447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein *      ...
633447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein *      input.insertAfter(t, "text to put after t");}
643447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein * 		input.insertAfter(u, "text after u");}
653447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein * 		System.out.println(tokens.toString());
663447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein *
673447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein *  Actually, you have to cast the 'input' to a TokenRewriteStream. :(
683447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein *
693447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein *  You can also have multiple "instruction streams" and get multiple
703447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein *  rewrites from a single pass over the input.  Just name the instruction
713447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein *  streams and use that name again when printing the buffer.  This could be
723447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein *  useful for generating a C file and also its header file--all from the
733447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein *  same buffer:
743447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein *
753447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein *      tokens.insertAfter("pass1", t, "text to put after t");}
763447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein * 		tokens.insertAfter("pass2", u, "text after u");}
773447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein * 		System.out.println(tokens.toString("pass1"));
783447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein * 		System.out.println(tokens.toString("pass2"));
793447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein *
803447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein *  If you don't use named rewrite streams, a "default" stream is used as
813447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein *  the first example shows.
823447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein */
833447a5916aa62f44de24cc441fc9987116ddff52Andrew Sappersteinpublic class TokenRewriteStream extends CommonTokenStream {
843447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	public static final String DEFAULT_PROGRAM_NAME = "default";
853447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein    public static final int PROGRAM_INIT_SIZE = 100;
863447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	public static final int MIN_TOKEN_INDEX = 0;
873447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein
883447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	// Define the rewrite operation hierarchy
893447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein
903447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	class RewriteOperation {
913447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein        /** What index into rewrites List are we? */
923447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein        protected int instructionIndex;
933447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein        /** Token buffer index. */
943447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein        protected int index;
953447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein		protected Object text;
963447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein
973447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein		protected RewriteOperation(int index) {
983447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein			this.index = index;
993447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein		}
1003447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein
1013447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein		protected RewriteOperation(int index, Object text) {
1023447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein			this.index = index;
1033447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein			this.text = text;
1043447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein		}
1053447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein		/** Execute the rewrite operation by possibly adding to the buffer.
1063447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein		 *  Return the index of the next token to operate on.
1073447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein		 */
1083447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein		public int execute(StringBuffer buf) {
1093447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein			return index;
1103447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein		}
1113447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein		public String toString() {
1123447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein			String opName = getClass().getName();
1133447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein			int $index = opName.indexOf('$');
1143447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein			opName = opName.substring($index+1, opName.length());
1153447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein			return "<"+opName+"@"+tokens.get(index)+
1163447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein				   ":\""+text+"\">";
1173447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein		}
1183447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	}
1193447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein
1203447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	class InsertBeforeOp extends RewriteOperation {
1213447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein		public InsertBeforeOp(int index, Object text) {
1223447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein			super(index,text);
1233447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein		}
1243447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein		public int execute(StringBuffer buf) {
1253447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein			buf.append(text);
1263447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein			if ( tokens.get(index).getType()!=Token.EOF ) {
1273447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein				buf.append(tokens.get(index).getText());
1283447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein			}
1293447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein			return index+1;
1303447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein		}
1313447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	}
1323447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein
1333447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	/** I'm going to try replacing range from x..y with (y-x)+1 ReplaceOp
1343447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	 *  instructions.
1353447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	 */
1363447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	class ReplaceOp extends RewriteOperation {
1373447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein		protected int lastIndex;
1383447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein		public ReplaceOp(int from, int to, Object text) {
1393447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein			super(from,text);
1403447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein			lastIndex = to;
1413447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein		}
1423447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein		public int execute(StringBuffer buf) {
1433447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein			if ( text!=null ) {
1443447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein				buf.append(text);
1453447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein			}
1463447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein			return lastIndex+1;
1473447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein		}
1483447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein		public String toString() {
1493447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein			if ( text==null ) {
1503447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein				return "<DeleteOp@"+tokens.get(index)+
1513447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein					   ".."+tokens.get(lastIndex)+">";
1523447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein			}
1533447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein			return "<ReplaceOp@"+tokens.get(index)+
1543447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein				   ".."+tokens.get(lastIndex)+":\""+text+"\">";
1553447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein		}
1563447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	}
1573447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein
1583447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	/** You may have multiple, named streams of rewrite operations.
1593447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	 *  I'm calling these things "programs."
1603447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	 *  Maps String (name) -> rewrite (List)
1613447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	 */
1623447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	protected Map programs = null;
1633447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein
1643447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	/** Map String (program name) -> Integer index */
1653447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	protected Map lastRewriteTokenIndexes = null;
1663447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein
1673447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	public TokenRewriteStream() {
1683447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein		init();
1693447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	}
1703447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein
1713447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	protected void init() {
1723447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein		programs = new HashMap();
1733447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein		programs.put(DEFAULT_PROGRAM_NAME, new ArrayList(PROGRAM_INIT_SIZE));
1743447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein		lastRewriteTokenIndexes = new HashMap();
1753447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	}
1763447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein
1773447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	public TokenRewriteStream(TokenSource tokenSource) {
1783447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	    super(tokenSource);
1793447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein		init();
1803447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	}
1813447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein
1823447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	public TokenRewriteStream(TokenSource tokenSource, int channel) {
1833447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein		super(tokenSource, channel);
1843447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein		init();
1853447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	}
1863447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein
1873447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	public void rollback(int instructionIndex) {
1883447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein		rollback(DEFAULT_PROGRAM_NAME, instructionIndex);
1893447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	}
1903447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein
1913447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	/** Rollback the instruction stream for a program so that
1923447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	 *  the indicated instruction (via instructionIndex) is no
1933447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	 *  longer in the stream.  UNTESTED!
1943447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	 */
1953447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	public void rollback(String programName, int instructionIndex) {
1963447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein		List is = (List)programs.get(programName);
1973447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein		if ( is!=null ) {
1983447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein			programs.put(programName, is.subList(MIN_TOKEN_INDEX,instructionIndex));
1993447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein		}
2003447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	}
2013447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein
2023447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	public void deleteProgram() {
2033447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein		deleteProgram(DEFAULT_PROGRAM_NAME);
2043447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	}
2053447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein
2063447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	/** Reset the program so that no instructions exist */
2073447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	public void deleteProgram(String programName) {
2083447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein		rollback(programName, MIN_TOKEN_INDEX);
2093447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	}
2103447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein
2113447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	public void insertAfter(Token t, Object text) {
2123447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein		insertAfter(DEFAULT_PROGRAM_NAME, t, text);
2133447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	}
2143447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein
2153447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	public void insertAfter(int index, Object text) {
2163447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein		insertAfter(DEFAULT_PROGRAM_NAME, index, text);
2173447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	}
2183447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein
2193447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	public void insertAfter(String programName, Token t, Object text) {
2203447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein		insertAfter(programName,t.getTokenIndex(), text);
2213447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	}
2223447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein
2233447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	public void insertAfter(String programName, int index, Object text) {
2243447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein		// to insert after, just insert before next index (even if past end)
2253447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein		insertBefore(programName,index+1, text);
2263447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	}
2273447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein
2283447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	public void insertBefore(Token t, Object text) {
2293447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein		insertBefore(DEFAULT_PROGRAM_NAME, t, text);
2303447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	}
2313447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein
2323447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	public void insertBefore(int index, Object text) {
2333447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein		insertBefore(DEFAULT_PROGRAM_NAME, index, text);
2343447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	}
2353447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein
2363447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	public void insertBefore(String programName, Token t, Object text) {
2373447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein		insertBefore(programName, t.getTokenIndex(), text);
2383447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	}
2393447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein
2403447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	public void insertBefore(String programName, int index, Object text) {
2413447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein		RewriteOperation op = new InsertBeforeOp(index,text);
2423447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein		List rewrites = getProgram(programName);
2433447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein        op.instructionIndex = rewrites.size();
2443447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein        rewrites.add(op);
2453447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	}
2463447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein
2473447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	public void replace(int index, Object text) {
2483447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein		replace(DEFAULT_PROGRAM_NAME, index, index, text);
2493447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	}
2503447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein
2513447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	public void replace(int from, int to, Object text) {
2523447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein		replace(DEFAULT_PROGRAM_NAME, from, to, text);
2533447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	}
2543447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein
2553447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	public void replace(Token indexT, Object text) {
2563447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein		replace(DEFAULT_PROGRAM_NAME, indexT, indexT, text);
2573447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	}
2583447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein
2593447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	public void replace(Token from, Token to, Object text) {
2603447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein		replace(DEFAULT_PROGRAM_NAME, from, to, text);
2613447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	}
2623447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein
2633447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	public void replace(String programName, int from, int to, Object text) {
2643447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein		if ( from > to || from<0 || to<0 || to >= tokens.size() ) {
2653447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein			throw new IllegalArgumentException("replace: range invalid: "+from+".."+to+"(size="+tokens.size()+")");
2663447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein		}
2673447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein		RewriteOperation op = new ReplaceOp(from, to, text);
2683447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein		List rewrites = getProgram(programName);
2693447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein        op.instructionIndex = rewrites.size();
2703447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein        rewrites.add(op);
2713447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	}
2723447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein
2733447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	public void replace(String programName, Token from, Token to, Object text) {
2743447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein		replace(programName,
2753447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein				from.getTokenIndex(),
2763447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein				to.getTokenIndex(),
2773447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein				text);
2783447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	}
2793447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein
2803447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	public void delete(int index) {
2813447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein		delete(DEFAULT_PROGRAM_NAME, index, index);
2823447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	}
2833447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein
2843447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	public void delete(int from, int to) {
2853447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein		delete(DEFAULT_PROGRAM_NAME, from, to);
2863447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	}
2873447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein
2883447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	public void delete(Token indexT) {
2893447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein		delete(DEFAULT_PROGRAM_NAME, indexT, indexT);
2903447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	}
2913447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein
2923447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	public void delete(Token from, Token to) {
2933447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein		delete(DEFAULT_PROGRAM_NAME, from, to);
2943447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	}
2953447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein
2963447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	public void delete(String programName, int from, int to) {
2973447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein		replace(programName,from,to,null);
2983447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	}
2993447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein
3003447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	public void delete(String programName, Token from, Token to) {
3013447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein		replace(programName,from,to,null);
3023447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	}
3033447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein
3043447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	public int getLastRewriteTokenIndex() {
3053447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein		return getLastRewriteTokenIndex(DEFAULT_PROGRAM_NAME);
3063447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	}
3073447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein
3083447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	protected int getLastRewriteTokenIndex(String programName) {
3093447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein		Integer I = (Integer)lastRewriteTokenIndexes.get(programName);
3103447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein		if ( I==null ) {
3113447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein			return -1;
3123447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein		}
3133447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein		return I.intValue();
3143447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	}
3153447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein
3163447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	protected void setLastRewriteTokenIndex(String programName, int i) {
3173447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein		lastRewriteTokenIndexes.put(programName, new Integer(i));
3183447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	}
3193447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein
3203447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	protected List getProgram(String name) {
3213447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein		List is = (List)programs.get(name);
3223447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein		if ( is==null ) {
3233447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein			is = initializeProgram(name);
3243447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein		}
3253447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein		return is;
3263447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	}
3273447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein
3283447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	private List initializeProgram(String name) {
3293447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein		List is = new ArrayList(PROGRAM_INIT_SIZE);
3303447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein		programs.put(name, is);
3313447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein		return is;
3323447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	}
3333447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein
3343447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	public String toOriginalString() {
3353447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein        fill();
3363447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein		return toOriginalString(MIN_TOKEN_INDEX, size()-1);
3373447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	}
3383447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein
3393447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	public String toOriginalString(int start, int end) {
3403447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein		StringBuffer buf = new StringBuffer();
3413447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein		for (int i=start; i>=MIN_TOKEN_INDEX && i<=end && i<tokens.size(); i++) {
3423447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein			if ( get(i).getType()!=Token.EOF ) buf.append(get(i).getText());
3433447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein		}
3443447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein		return buf.toString();
3453447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	}
3463447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein
3473447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	public String toString() {
3483447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein        fill();
3493447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein		return toString(MIN_TOKEN_INDEX, size()-1);
3503447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	}
3513447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein
3523447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	public String toString(String programName) {
3533447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein        fill();
3543447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein		return toString(programName, MIN_TOKEN_INDEX, size()-1);
3553447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	}
3563447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein
3573447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	public String toString(int start, int end) {
3583447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein		return toString(DEFAULT_PROGRAM_NAME, start, end);
3593447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	}
3603447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein
3613447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	public String toString(String programName, int start, int end) {
3623447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein		List rewrites = (List)programs.get(programName);
3633447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein
3643447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein        // ensure start/end are in range
3653447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein        if ( end>tokens.size()-1 ) end = tokens.size()-1;
3663447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein        if ( start<0 ) start = 0;
3673447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein
3683447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein        if ( rewrites==null || rewrites.size()==0 ) {
3693447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein			return toOriginalString(start,end); // no instructions to execute
3703447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein		}
3713447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein		StringBuffer buf = new StringBuffer();
3723447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein
3733447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein		// First, optimize instruction stream
3743447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein		Map indexToOp = reduceToSingleOperationPerIndex(rewrites);
3753447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein
3763447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein        // Walk buffer, executing instructions and emitting tokens
3773447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein        int i = start;
3783447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein        while ( i <= end && i < tokens.size() ) {
3793447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein			RewriteOperation op = (RewriteOperation)indexToOp.get(new Integer(i));
3803447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein			indexToOp.remove(new Integer(i)); // remove so any left have index size-1
3813447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein			Token t = (Token) tokens.get(i);
3823447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein			if ( op==null ) {
3833447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein				// no operation at that index, just dump token
3843447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein				if ( t.getType()!=Token.EOF ) buf.append(t.getText());
3853447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein				i++; // move to next token
3863447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein			}
3873447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein			else {
3883447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein				i = op.execute(buf); // execute operation and skip
3893447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein			}
3903447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein		}
3913447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein
3923447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein        // include stuff after end if it's last index in buffer
3933447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein        // So, if they did an insertAfter(lastValidIndex, "foo"), include
3943447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein        // foo if end==lastValidIndex.
3953447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein        if ( end==tokens.size()-1 ) {
3963447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein            // Scan any remaining operations after last token
3973447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein            // should be included (they will be inserts).
3983447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein            Iterator it = indexToOp.values().iterator();
3993447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein            while (it.hasNext()) {
4003447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein                RewriteOperation op = (RewriteOperation)it.next();
4013447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein                if ( op.index >= tokens.size()-1 ) buf.append(op.text);
4023447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein            }
4033447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein        }
4043447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein        return buf.toString();
4053447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	}
4063447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein
4073447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	/** We need to combine operations and report invalid operations (like
4083447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	 *  overlapping replaces that are not completed nested).  Inserts to
4093447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	 *  same index need to be combined etc...   Here are the cases:
4103447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	 *
4113447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	 *  I.i.u I.j.v								leave alone, nonoverlapping
4123447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	 *  I.i.u I.i.v								combine: Iivu
4133447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	 *
4143447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	 *  R.i-j.u R.x-y.v	| i-j in x-y			delete first R
4153447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	 *  R.i-j.u R.i-j.v							delete first R
4163447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	 *  R.i-j.u R.x-y.v	| x-y in i-j			ERROR
4173447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	 *  R.i-j.u R.x-y.v	| boundaries overlap	ERROR
4183447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	 *
4193447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	 *  Delete special case of replace (text==null):
4203447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	 *  D.i-j.u D.x-y.v	| boundaries overlap	combine to max(min)..max(right)
4213447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	 *
4223447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	 *  I.i.u R.x-y.v | i in (x+1)-y			delete I (since insert before
4233447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	 *											we're not deleting i)
4243447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	 *  I.i.u R.x-y.v | i not in (x+1)-y		leave alone, nonoverlapping
4253447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	 *  R.x-y.v I.i.u | i in x-y				ERROR
4263447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	 *  R.x-y.v I.x.u 							R.x-y.uv (combine, delete I)
4273447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	 *  R.x-y.v I.i.u | i not in x-y			leave alone, nonoverlapping
4283447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	 *
4293447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	 *  I.i.u = insert u before op @ index i
4303447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	 *  R.x-y.u = replace x-y indexed tokens with u
4313447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	 *
4323447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	 *  First we need to examine replaces.  For any replace op:
4333447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	 *
4343447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	 * 		1. wipe out any insertions before op within that range.
4353447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	 *		2. Drop any replace op before that is contained completely within
4363447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	 *         that range.
4373447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	 *		3. Throw exception upon boundary overlap with any previous replace.
4383447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	 *
4393447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	 *  Then we can deal with inserts:
4403447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	 *
4413447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	 * 		1. for any inserts to same index, combine even if not adjacent.
4423447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	 * 		2. for any prior replace with same left boundary, combine this
4433447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	 *         insert with replace and delete this replace.
4443447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	 * 		3. throw exception if index in same range as previous replace
4453447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	 *
4463447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	 *  Don't actually delete; make op null in list. Easier to walk list.
4473447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	 *  Later we can throw as we add to index -> op map.
4483447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	 *
4493447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	 *  Note that I.2 R.2-2 will wipe out I.2 even though, technically, the
4503447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	 *  inserted stuff would be before the replace range.  But, if you
4513447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	 *  add tokens in front of a method body '{' and then delete the method
4523447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	 *  body, I think the stuff before the '{' you added should disappear too.
4533447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	 *
4543447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	 *  Return a map from token index to operation.
4553447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	 */
4563447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	protected Map reduceToSingleOperationPerIndex(List rewrites) {
4573447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein//		System.out.println("rewrites="+rewrites);
4583447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein
4593447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein		// WALK REPLACES
4603447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein		for (int i = 0; i < rewrites.size(); i++) {
4613447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein			RewriteOperation op = (RewriteOperation)rewrites.get(i);
4623447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein			if ( op==null ) continue;
4633447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein			if ( !(op instanceof ReplaceOp) ) continue;
4643447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein			ReplaceOp rop = (ReplaceOp)rewrites.get(i);
4653447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein			// Wipe prior inserts within range
4663447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein			List inserts = getKindOfOps(rewrites, InsertBeforeOp.class, i);
4673447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein			for (int j = 0; j < inserts.size(); j++) {
4683447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein				InsertBeforeOp iop = (InsertBeforeOp) inserts.get(j);
4693447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein				if ( iop.index == rop.index ) {
4703447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein					// E.g., insert before 2, delete 2..2; update replace
4713447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein					// text to include insert before, kill insert
4723447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein					rewrites.set(iop.instructionIndex, null);
4733447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein					rop.text = iop.text.toString() + (rop.text!=null?rop.text.toString():"");
4743447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein				}
4753447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein				else if ( iop.index > rop.index && iop.index <= rop.lastIndex ) {
4763447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein                    // delete insert as it's a no-op.
4773447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein                    rewrites.set(iop.instructionIndex, null);
4783447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein				}
4793447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein			}
4803447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein			// Drop any prior replaces contained within
4813447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein			List prevReplaces = getKindOfOps(rewrites, ReplaceOp.class, i);
4823447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein			for (int j = 0; j < prevReplaces.size(); j++) {
4833447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein				ReplaceOp prevRop = (ReplaceOp) prevReplaces.get(j);
4843447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein				if ( prevRop.index>=rop.index && prevRop.lastIndex <= rop.lastIndex ) {
4853447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein                    // delete replace as it's a no-op.
4863447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein                    rewrites.set(prevRop.instructionIndex, null);
4873447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein					continue;
4883447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein				}
4893447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein				// throw exception unless disjoint or identical
4903447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein				boolean disjoint =
4913447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein					prevRop.lastIndex<rop.index || prevRop.index > rop.lastIndex;
4923447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein				boolean same =
4933447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein					prevRop.index==rop.index && prevRop.lastIndex==rop.lastIndex;
4943447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein				// Delete special case of replace (text==null):
4953447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein				// D.i-j.u D.x-y.v	| boundaries overlap	combine to max(min)..max(right)
4963447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein				if ( prevRop.text==null && rop.text==null && !disjoint ) {
4973447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein					//System.out.println("overlapping deletes: "+prevRop+", "+rop);
4983447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein					rewrites.set(prevRop.instructionIndex, null); // kill first delete
4993447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein					rop.index = Math.min(prevRop.index, rop.index);
5003447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein					rop.lastIndex = Math.max(prevRop.lastIndex, rop.lastIndex);
5013447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein					System.out.println("new rop "+rop);
5023447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein				}
5033447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein				else if ( !disjoint && !same ) {
5043447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein					throw new IllegalArgumentException("replace op boundaries of "+rop+
5053447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein													   " overlap with previous "+prevRop);
5063447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein				}
5073447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein			}
5083447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein		}
5093447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein
5103447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein		// WALK INSERTS
5113447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein		for (int i = 0; i < rewrites.size(); i++) {
5123447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein			RewriteOperation op = (RewriteOperation)rewrites.get(i);
5133447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein			if ( op==null ) continue;
5143447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein			if ( !(op instanceof InsertBeforeOp) ) continue;
5153447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein			InsertBeforeOp iop = (InsertBeforeOp)rewrites.get(i);
5163447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein			// combine current insert with prior if any at same index
5173447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein			List prevInserts = getKindOfOps(rewrites, InsertBeforeOp.class, i);
5183447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein			for (int j = 0; j < prevInserts.size(); j++) {
5193447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein				InsertBeforeOp prevIop = (InsertBeforeOp) prevInserts.get(j);
5203447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein				if ( prevIop.index == iop.index ) { // combine objects
5213447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein					// convert to strings...we're in process of toString'ing
5223447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein					// whole token buffer so no lazy eval issue with any templates
5233447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein					iop.text = catOpText(iop.text,prevIop.text);
5243447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein                    // delete redundant prior insert
5253447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein                    rewrites.set(prevIop.instructionIndex, null);
5263447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein				}
5273447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein			}
5283447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein			// look for replaces where iop.index is in range; error
5293447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein			List prevReplaces = getKindOfOps(rewrites, ReplaceOp.class, i);
5303447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein			for (int j = 0; j < prevReplaces.size(); j++) {
5313447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein				ReplaceOp rop = (ReplaceOp) prevReplaces.get(j);
5323447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein				if ( iop.index == rop.index ) {
5333447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein					rop.text = catOpText(iop.text,rop.text);
5343447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein					rewrites.set(i, null);  // delete current insert
5353447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein					continue;
5363447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein				}
5373447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein				if ( iop.index >= rop.index && iop.index <= rop.lastIndex ) {
5383447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein					throw new IllegalArgumentException("insert op "+iop+
5393447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein													   " within boundaries of previous "+rop);
5403447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein				}
5413447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein			}
5423447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein		}
5433447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein		// System.out.println("rewrites after="+rewrites);
5443447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein		Map m = new HashMap();
5453447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein		for (int i = 0; i < rewrites.size(); i++) {
5463447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein			RewriteOperation op = (RewriteOperation)rewrites.get(i);
5473447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein			if ( op==null ) continue; // ignore deleted ops
5483447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein			if ( m.get(new Integer(op.index))!=null ) {
5493447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein				throw new Error("should only be one op per index");
5503447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein			}
5513447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein			m.put(new Integer(op.index), op);
5523447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein		}
5533447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein		//System.out.println("index to op: "+m);
5543447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein		return m;
5553447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	}
5563447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein
5573447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	protected String catOpText(Object a, Object b) {
5583447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein		String x = "";
5593447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein		String y = "";
5603447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein		if ( a!=null ) x = a.toString();
5613447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein		if ( b!=null ) y = b.toString();
5623447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein		return x+y;
5633447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	}
5643447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	protected List getKindOfOps(List rewrites, Class kind) {
5653447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein		return getKindOfOps(rewrites, kind, rewrites.size());
5663447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	}
5673447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein
5683447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein    /** Get all operations before an index of a particular kind */
5693447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein    protected List getKindOfOps(List rewrites, Class kind, int before) {
5703447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein		List ops = new ArrayList();
5713447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein		for (int i=0; i<before && i<rewrites.size(); i++) {
5723447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein			RewriteOperation op = (RewriteOperation)rewrites.get(i);
5733447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein			if ( op==null ) continue; // ignore deleted
5743447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein			if ( op.getClass() == kind ) ops.add(op);
5753447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein		}
5763447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein		return ops;
5773447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	}
5783447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein
5793447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	public String toDebugString() {
5803447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein		return toDebugString(MIN_TOKEN_INDEX, size()-1);
5813447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	}
5823447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein
5833447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	public String toDebugString(int start, int end) {
5843447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein		StringBuffer buf = new StringBuffer();
5853447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein		for (int i=start; i>=MIN_TOKEN_INDEX && i<=end && i<tokens.size(); i++) {
5863447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein			buf.append(get(i));
5873447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein		}
5883447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein		return buf.toString();
5893447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein	}
5903447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein}
591