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);
        }
Beispiel #2
0
 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);
 }