public void insertBefore(String programName, int index, Object text) {
   // addToSortedRewriteList(programName, new InsertBeforeOp(index,text));
   RewriteOperation op = new InsertBeforeOp(index, text);
   List rewrites = getProgram(programName);
   op.instructionIndex = rewrites.size();
   rewrites.add(op);
 }
 /** Get all operations before an index of a particular kind */
 protected List getKindOfOps(List rewrites, Class kind, int before) {
   List ops = new ArrayList();
   for (int i = 0; i < before && i < rewrites.size(); i++) {
     RewriteOperation op = (RewriteOperation) rewrites.get(i);
     if (op == null) continue; // ignore deleted
     if (op.getClass() == kind) ops.add(op);
   }
   return ops;
 }
 public void replace(String programName, int from, int to, Object text) {
   if (from > to || from < 0 || to < 0 || to >= tokens.size()) {
     throw new IllegalArgumentException(
         "replace: range invalid: " + from + ".." + to + "(size=" + tokens.size() + ")");
   }
   RewriteOperation op = new ReplaceOp(from, to, text);
   List rewrites = getProgram(programName);
   op.instructionIndex = rewrites.size();
   rewrites.add(op);
 }
  public String toString(String programName, int start, int end) {
    List rewrites = (List) programs.get(programName);

    // ensure start/end are in range
    if (end > tokens.size() - 1) end = tokens.size() - 1;
    if (start < 0) start = 0;

    if (rewrites == null || rewrites.size() == 0) {
      return toOriginalString(start, end); // no instructions to execute
    }
    StringBuffer buf = new StringBuffer();

    // First, optimize instruction stream
    Map indexToOp = reduceToSingleOperationPerIndex(rewrites);

    // Walk buffer, executing instructions and emitting tokens
    int i = start;
    while (i <= end && i < tokens.size()) {
      RewriteOperation op = (RewriteOperation) indexToOp.get(new Integer(i));
      indexToOp.remove(new Integer(i)); // remove so any left have index size-1
      Token t = (Token) tokens.get(i);
      if (op == null) {
        // no operation at that index, just dump token
        if (t.getType() != Token.EOF) buf.append(t.getText());
        i++; // move to next token
      } else {
        i = op.execute(buf); // execute operation and skip
      }
    }

    // include stuff after end if it's last index in buffer
    // So, if they did an insertAfter(lastValidIndex, "foo"), include
    // foo if end==lastValidIndex.
    if (end == tokens.size() - 1) {
      // Scan any remaining operations after last token
      // should be included (they will be inserts).
      Iterator it = indexToOp.values().iterator();
      while (it.hasNext()) {
        RewriteOperation op = (RewriteOperation) it.next();
        if (op.index >= tokens.size() - 1) buf.append(op.text);
      }
    }
    return buf.toString();
  }