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