public virtual void InsertBefore(string programName, int index, object text) { RewriteOperation op = new InsertBeforeOp(index, text, this); IList rewrites = GetProgram(programName); rewrites.Add(op); }
public virtual void InsertBefore(string programName, int index, object text) { RewriteOperation op = new InsertBeforeOp(this, index, text); IList <RewriteOperation> rewrites = GetProgram(programName); op.instructionIndex = rewrites.Count; rewrites.Add(op); }
/** We need to combine operations and report invalid operations (like * overlapping replaces that are not completed nested). Inserts to * same index need to be combined etc... Here are the cases: * * I.i.u I.j.v leave alone, nonoverlapping * I.i.u I.i.v combine: Iivu * * R.i-j.u R.x-y.v | i-j in x-y delete first R * R.i-j.u R.i-j.v delete first R * R.i-j.u R.x-y.v | x-y in i-j ERROR * R.i-j.u R.x-y.v | boundaries overlap ERROR * * Delete special case of replace (text==null): * D.i-j.u D.x-y.v | boundaries overlap combine to max(min)..max(right) * * I.i.u R.x-y.v | i in (x+1)-y delete I (since insert before * we're not deleting i) * I.i.u R.x-y.v | i not in (x+1)-y leave alone, nonoverlapping * R.x-y.v I.i.u | i in x-y ERROR * R.x-y.v I.x.u R.x-y.uv (combine, delete I) * R.x-y.v I.i.u | i not in x-y leave alone, nonoverlapping * * I.i.u = insert u before op @ index i * R.x-y.u = replace x-y indexed tokens with u * * First we need to examine replaces. For any replace op: * * 1. wipe out any insertions before op within that range. * 2. Drop any replace op before that is contained completely within * that range. * 3. Throw exception upon boundary overlap with any previous replace. * * Then we can deal with inserts: * * 1. for any inserts to same index, combine even if not adjacent. * 2. for any prior replace with same left boundary, combine this * insert with replace and delete this replace. * 3. throw exception if index in same range as previous replace * * Don't actually delete; make op null in list. Easier to walk list. * Later we can throw as we add to index -> op map. * * Note that I.2 R.2-2 will wipe out I.2 even though, technically, the * inserted stuff would be before the replace range. But, if you * add tokens in front of a method body '{' and then delete the method * body, I think the stuff before the '{' you added should disappear too. * * Return a map from token index to operation. */ protected virtual IDictionary <int, RewriteOperation> ReduceToSingleOperationPerIndex(IList <RewriteOperation> rewrites) { //System.out.println("rewrites="+rewrites); // WALK REPLACES for (int i = 0; i < rewrites.Count; i++) { RewriteOperation op = rewrites[i]; if (op == null) { continue; } if (!(op is ReplaceOp)) { continue; } ReplaceOp rop = (ReplaceOp)rewrites[i]; // Wipe prior inserts within range var inserts = GetKindOfOps(rewrites, typeof(InsertBeforeOp), i); for (int j = 0; j < inserts.Count; j++) { InsertBeforeOp iop = (InsertBeforeOp)inserts[j]; if (iop.index == rop.index) { // E.g., insert before 2, delete 2..2; update replace // text to include insert before, kill insert rewrites[iop.instructionIndex] = null; rop.text = iop.text.ToString() + (rop.text != null ? rop.text.ToString() : string.Empty); } else if (iop.index > rop.index && iop.index <= rop.lastIndex) { // delete insert as it's a no-op. rewrites[iop.instructionIndex] = null; } } // Drop any prior replaces contained within var prevReplaces = GetKindOfOps(rewrites, typeof(ReplaceOp), i); for (int j = 0; j < prevReplaces.Count; j++) { ReplaceOp prevRop = (ReplaceOp)prevReplaces[j]; if (prevRop.index >= rop.index && prevRop.lastIndex <= rop.lastIndex) { // delete replace as it's a no-op. rewrites[prevRop.instructionIndex] = null; continue; } // throw exception unless disjoint or identical bool disjoint = prevRop.lastIndex <rop.index || prevRop.index> rop.lastIndex; bool same = prevRop.index == rop.index && prevRop.lastIndex == rop.lastIndex; // Delete special case of replace (text==null): // D.i-j.u D.x-y.v | boundaries overlap combine to max(min)..max(right) if (prevRop.text == null && rop.text == null && !disjoint) { //System.out.println("overlapping deletes: "+prevRop+", "+rop); rewrites[prevRop.instructionIndex] = null; // kill first delete rop.index = Math.Min(prevRop.index, rop.index); rop.lastIndex = Math.Max(prevRop.lastIndex, rop.lastIndex); #if !PORTABLE Console.WriteLine("new rop " + rop); #endif } else if (!disjoint && !same) { throw new ArgumentException("replace op boundaries of " + rop + " overlap with previous " + prevRop); } } } // WALK INSERTS for (int i = 0; i < rewrites.Count; i++) { RewriteOperation op = (RewriteOperation)rewrites[i]; if (op == null) { continue; } if (!(op is InsertBeforeOp)) { continue; } InsertBeforeOp iop = (InsertBeforeOp)rewrites[i]; // combine current insert with prior if any at same index var prevInserts = GetKindOfOps(rewrites, typeof(InsertBeforeOp), i); for (int j = 0; j < prevInserts.Count; j++) { InsertBeforeOp prevIop = (InsertBeforeOp)prevInserts[j]; if (prevIop.index == iop.index) { // combine objects // convert to strings...we're in process of toString'ing // whole token buffer so no lazy eval issue with any templates iop.text = CatOpText(iop.text, prevIop.text); // delete redundant prior insert rewrites[prevIop.instructionIndex] = null; } } // look for replaces where iop.index is in range; error var prevReplaces = GetKindOfOps(rewrites, typeof(ReplaceOp), i); for (int j = 0; j < prevReplaces.Count; j++) { ReplaceOp rop = (ReplaceOp)prevReplaces[j]; if (iop.index == rop.index) { rop.text = CatOpText(iop.text, rop.text); rewrites[i] = null; // delete current insert continue; } if (iop.index >= rop.index && iop.index <= rop.lastIndex) { throw new ArgumentException("insert op " + iop + " within boundaries of previous " + rop); } } } // System.out.println("rewrites after="+rewrites); IDictionary <int, RewriteOperation> m = new Dictionary <int, RewriteOperation>(); for (int i = 0; i < rewrites.Count; i++) { RewriteOperation op = (RewriteOperation)rewrites[i]; if (op == null) { continue; // ignore deleted ops } RewriteOperation existing; if (m.TryGetValue(op.index, out existing) && existing != null) { throw new Exception("should only be one op per index"); } m[op.index] = op; } //System.out.println("index to op: "+m); return(m); }
public virtual void InsertBefore( string programName, int index, object text ) { //addToSortedRewriteList(programName, new InsertBeforeOp(index,text)); RewriteOperation op = new InsertBeforeOp( this, index, text ); IList<RewriteOperation> rewrites = GetProgram( programName ); op.instructionIndex = rewrites.Count; rewrites.Add( op ); }
/// <summary> /// Return a map from token index to operation. /// </summary> /// <remarks>We need to combine operations and report invalid operations (like /// overlapping replaces that are not completed nested). Inserts to /// same index need to be combined etc... Here are the cases: /// /// I.i.u I.j.v leave alone, nonoverlapping /// I.i.u I.i.v combine: Iivu /// /// R.i-j.u R.x-y.v | i-j in x-y delete first R /// R.i-j.u R.i-j.v delete first R /// R.i-j.u R.x-y.v | x-y in i-j ERROR /// R.i-j.u R.x-y.v | boundaries overlap ERROR /// /// I.i.u R.x-y.v | i in x-y delete I /// I.i.u R.x-y.v | i not in x-y leave alone, nonoverlapping /// R.x-y.v I.i.u | i in x-y ERROR /// R.x-y.v I.x.u R.x-y.uv (combine, delete I) /// R.x-y.v I.i.u | i not in x-y leave alone, nonoverlapping /// /// I.i.u = insert u before op @ index i /// R.x-y.u = replace x-y indexed tokens with u /// /// First we need to examine replaces. For any replace op: /// /// 1. wipe out any insertions before op within that range. /// 2. Drop any replace op before that is contained completely within /// that range. /// 3. Throw exception upon boundary overlap with any previous replace. /// /// Then we can deal with inserts: /// /// 1. for any inserts to same index, combine even if not adjacent. /// 2. for any prior replace with same left boundary, combine this /// insert with replace and delete this replace. /// 3. throw exception if index in same range as previous replace /// /// Don't actually delete; make op null in list. Easier to walk list. /// Later we can throw as we add to index -> op map. /// /// Note that I.2 R.2-2 will wipe out I.2 even though, technically, the /// inserted stuff would be before the replace range. But, if you /// add tokens in front of a method body '{' and then delete the method /// body, I think the stuff before the '{' you added should disappear too. /// </remarks> protected IDictionary ReduceToSingleOperationPerIndex(IList rewrites) { // WALK REPLACES for (int i = 0; i < rewrites.Count; i++) { RewriteOperation op = (RewriteOperation)rewrites[i]; if (op == null) { continue; } if (!(op is ReplaceOp)) { continue; } ReplaceOp rop = (ReplaceOp)rewrites[i]; // Wipe prior inserts within range IList inserts = GetKindOfOps(rewrites, typeof(InsertBeforeOp), i); for (int j = 0; j < inserts.Count; j++) { InsertBeforeOp iop = (InsertBeforeOp)inserts[j]; if (iop.index >= rop.index && iop.index <= rop.lastIndex) { // delete insert as it's a no-op. rewrites[iop.instructionIndex] = null; } } // Drop any prior replaces contained within IList prevReplaces = GetKindOfOps(rewrites, typeof(ReplaceOp), i); for (int j = 0; j < prevReplaces.Count; j++) { ReplaceOp prevRop = (ReplaceOp)prevReplaces[j]; if (prevRop.index >= rop.index && prevRop.lastIndex <= rop.lastIndex) { // delete replace as it's a no-op. rewrites[prevRop.instructionIndex] = null; continue; } // throw exception unless disjoint or identical bool disjoint = prevRop.lastIndex <rop.index || prevRop.index> rop.lastIndex; bool same = prevRop.index == rop.index && prevRop.lastIndex == rop.lastIndex; if (!disjoint && !same) { throw new ArgumentOutOfRangeException("replace op boundaries of " + rop + " overlap with previous " + prevRop); } } } // WALK INSERTS for (int i = 0; i < rewrites.Count; i++) { RewriteOperation op = (RewriteOperation)rewrites[i]; if (op == null) { continue; } if (!(op is InsertBeforeOp)) { continue; } InsertBeforeOp iop = (InsertBeforeOp)rewrites[i]; // combine current insert with prior if any at same index IList prevInserts = GetKindOfOps(rewrites, typeof(InsertBeforeOp), i); for (int j = 0; j < prevInserts.Count; j++) { InsertBeforeOp prevIop = (InsertBeforeOp)prevInserts[j]; if (prevIop.index == iop.index) // combine objects // convert to strings...we're in process of toString'ing // whole token buffer so no lazy eval issue with any templates { iop.text = CatOpText(iop.text, prevIop.text); // delete redundant prior insert rewrites[prevIop.instructionIndex] = null; } } // look for replaces where iop.index is in range; error IList prevReplaces = GetKindOfOps(rewrites, typeof(ReplaceOp), i); for (int j = 0; j < prevReplaces.Count; j++) { ReplaceOp rop = (ReplaceOp)prevReplaces[j]; if (iop.index == rop.index) { rop.text = CatOpText(iop.text, rop.text); rewrites[i] = null; // delete current insert continue; } if (iop.index >= rop.index && iop.index <= rop.lastIndex) { throw new ArgumentOutOfRangeException("insert op " + iop + " within boundaries of previous " + rop); } } } // System.out.println("rewrites after="+rewrites); IDictionary m = new Hashtable(); for (int i = 0; i < rewrites.Count; i++) { RewriteOperation op = (RewriteOperation)rewrites[i]; if (op == null) { continue; // ignore deleted ops } if (m[op.index] != null) { throw new Exception("should only be one op per index"); } m[op.index] = op; } //System.out.println("index to op: "+m); return(m); }
public virtual string ToString(string programName, int start, int end) { IList rewrites = (IList)programs[programName]; // ensure start/end are in range if (end > tokens.Count - 1) { end = tokens.Count - 1; } if (start < 0) { start = 0; } if ((rewrites == null) || (rewrites.Count == 0)) { return(ToOriginalString(start, end)); // no instructions to execute } StringBuilder buf = new StringBuilder(); // First, optimize instruction stream IDictionary indexToOp = ReduceToSingleOperationPerIndex(rewrites); // Walk buffer, executing instructions and emitting tokens int i = start; while (i <= end && i < tokens.Count) { RewriteOperation op = (RewriteOperation)indexToOp[i]; indexToOp.Remove(i); // remove so any left have index size-1 IToken t = (IToken)tokens[i]; if (op == null) { // no operation at that index, just dump token buf.Append(t.Text); 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.Count - 1) { // Scan any remaining operations after last token // should be included (they will be inserts). IEnumerator iter = indexToOp.Values.GetEnumerator(); while (iter.MoveNext()) { InsertBeforeOp iop = (InsertBeforeOp)iter.Current; if (iop.index >= tokens.Count - 1) { buf.Append(iop.text); } } } return(buf.ToString()); }
public virtual void InsertBefore(string programName, int index, object text) { RewriteOperation item = new InsertBeforeOp(this, index, text); IList<RewriteOperation> program = this.GetProgram(programName); item.instructionIndex = program.Count; program.Add(item); }