public string ToString(string programName, int start, int end) { IList rewrites = (IList)programs[programName]; if (rewrites == null) { return(null); // invalid program } StringBuilder buf = new StringBuilder(); // Index of first rewrite we have not done int rewriteOpIndex = 0; int tokenCursor = start; while ((tokenCursor >= MIN_TOKEN_INDEX) && (tokenCursor <= end) && (tokenCursor < tokens.Count)) { if (rewriteOpIndex < rewrites.Count) { RewriteOperation op = (RewriteOperation)rewrites[rewriteOpIndex]; while ((tokenCursor == op.index) && (rewriteOpIndex < rewrites.Count)) { /* * Console.Out.WriteLine("execute op "+rewriteOpIndex+ * " (type "+op.GetType().FullName+")" +" at index "+op.index); */ tokenCursor = op.execute(buf); rewriteOpIndex++; if (rewriteOpIndex < rewrites.Count) { op = (RewriteOperation)rewrites[rewriteOpIndex]; } } } if (tokenCursor < end) { buf.Append(getToken(tokenCursor).getText()); tokenCursor++; } } // now see if there are operations (append) beyond last token index for (int opi = rewriteOpIndex; opi < rewrites.Count; opi++) { RewriteOperation op = (RewriteOperation)rewrites[opi]; op.execute(buf); // must be insertions if after last token } return(buf.ToString()); }
public virtual int Compare(object o1, object o2) { RewriteOperation rop1 = (RewriteOperation)o1; RewriteOperation rop2 = (RewriteOperation)o2; if (rop1.index < rop2.index) { return(-1); } if (rop1.index > rop2.index) { return(1); } return(0); }
/** <summary>Get all operations before an index of a particular kind</summary> */ protected virtual IList <RewriteOperation> GetKindOfOps(IList <RewriteOperation> rewrites, Type kind, int before) { IList <RewriteOperation> ops = new List <RewriteOperation>(); for (int i = 0; i < before && i < rewrites.Count; i++) { RewriteOperation op = rewrites[i]; if (op == null) { continue; // ignore deleted } if (op.GetType() == kind) { ops.Add(op); } } return(ops); }
/// <summary> /// Get all operations before an index of a particular kind /// </summary> protected IList GetKindOfOps(IList rewrites, Type kind, int before) { IList ops = new ArrayList(); for (int i = 0; i < before && i < rewrites.Count; i++) { RewriteOperation op = (RewriteOperation)rewrites[i]; if (op == null) { continue; // ignore deleted } if (op.GetType() == kind) { ops.Add(op); } } return(ops); }
protected void addToSortedRewriteList(string programName, RewriteOperation op) { ArrayList rewrites = (ArrayList)getProgram(programName); // if at or beyond last op's index, just append if (op.index >= getLastRewriteTokenIndex(programName)) { rewrites.Add(op); // append to list of operations // record the index of this operation for next time through setLastRewriteTokenIndex(programName, op.index); return; } // not after the last one, so must insert to ordered list int pos = rewrites.BinarySearch(op, RewriteOperationComparer.Default); if (pos < 0) { rewrites.Insert(-pos - 1, op); } }
public static void AssertRewrite(Action <RewriteContext> preAssertions, Action <RewriteContext> postAssertions) { var context = RewriteContext.For( "Test.Target.dll", DebugSymbolFormat.None, "Test.Support.dll", string.Empty, new string[] { Path.GetDirectoryName(typeof(object).Assembly.Location) }, string.Empty, new string[] {}, string.Empty, new string[0], new string[0], new Dictionary <string, IList <string> >(), new Dictionary <string, IList <string> >()); var operation = RewriteOperation.Create(ns => ns.StartsWith("System") ? "Test.Support" + ns.Substring("System".Length) : ns); preAssertions(context); operation.Execute(context); postAssertions(context); }
/** 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); }
protected void addToSortedRewriteList(string programName, RewriteOperation op) { var rewrites = (ArrayList) getProgram(programName); // if at or beyond last op's index, just append if ( op.index >= getLastRewriteTokenIndex(programName) ) { rewrites.Add(op); // append to list of operations // record the index of this operation for next time through setLastRewriteTokenIndex(programName, op.index); return; } // not after the last one, so must insert to ordered list var pos = rewrites.BinarySearch(op, RewriteOperationComparer.Default); if (pos < 0) { rewrites.Insert(-pos-1, op); } }
/// <summary> /// If op.index > lastRewriteTokenIndexes, just add to the end. /// Otherwise, do linear /// </summary> /// <param name="op"></param> protected void addToSortedRewriteList(RewriteOperation op) { addToSortedRewriteList(DEFAULT_PROGRAM_NAME, 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()); }