public virtual void Replace(string programName, int from, int to, object text) { if (from > to || from < 0 || to < 0 || to >= _tokens.Count) { throw new ArgumentException("replace: range invalid: " + from + ".." + to + "(size=" + _tokens.Count + ")"); } RewriteOperation op = new ReplaceOp(this, from, to, text); IList <RewriteOperation> rewrites = GetProgram(programName); op.instructionIndex = rewrites.Count; rewrites.Add(op); }
public virtual void Replace(string programName, int from, int to, object text) { if (from > to || from < 0 || to < 0 || to >= tokens.Count) { throw new ArgumentOutOfRangeException("replace: range invalid: " + from + ".." + to + "(size=" + tokens.Count + ")"); } RewriteOperation op = new ReplaceOp(from, to, text, this); IList 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); }
/// <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 void Replace(string programName, int from, int to, object text) { if (((from > to) || (from < 0)) || ((to < 0) || (to >= base._tokens.Count))) { throw new ArgumentException(string.Concat(new object[] { "replace: range invalid: ", from, "..", to, "(size=", base._tokens.Count, ")" })); } RewriteOperation item = new ReplaceOp(this, from, to, text); IList<RewriteOperation> program = this.GetProgram(programName); item.instructionIndex = program.Count; program.Add(item); }