1324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver/*
2324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * [The "BSD licence"]
3324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * Copyright (c) 2005-2008 Terence Parr
4324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * All rights reserved.
5324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver *
6324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * Conversion to C#:
7324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * Copyright (c) 2008-2009 Sam Harwell, Pixel Mine, Inc.
8324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * All rights reserved.
9324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver *
10324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * Redistribution and use in source and binary forms, with or without
11324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * modification, are permitted provided that the following conditions
12324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * are met:
13324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * 1. Redistributions of source code must retain the above copyright
14324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver *    notice, this list of conditions and the following disclaimer.
15324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * 2. Redistributions in binary form must reproduce the above copyright
16324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver *    notice, this list of conditions and the following disclaimer in the
17324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver *    documentation and/or other materials provided with the distribution.
18324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * 3. The name of the author may not be used to endorse or promote products
19324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver *    derived from this software without specific prior written permission.
20324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver *
21324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver */
32324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
33324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruvernamespace Antlr.Runtime
34324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver{
35324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    using System.Collections.Generic;
36324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
37324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    using ArgumentException = System.ArgumentException;
38324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    using Console = System.Console;
39324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    using Math = System.Math;
40324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    using DebuggerDisplay = System.Diagnostics.DebuggerDisplayAttribute;
41324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    using Exception = System.Exception;
42324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    using StringBuilder = System.Text.StringBuilder;
43324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    using Type = System.Type;
44324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
45324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    /** Useful for dumping out the input stream after doing some
46324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver     *  augmentation or other manipulations.
47324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver     *
48324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver     *  You can insert stuff, replace, and delete chunks.  Note that the
49324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver     *  operations are done lazily--only if you convert the buffer to a
50324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver     *  String.  This is very efficient because you are not moving data around
51324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver     *  all the time.  As the buffer of tokens is converted to strings, the
52324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver     *  toString() method(s) check to see if there is an operation at the
53324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver     *  current index.  If so, the operation is done and then normal String
54324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver     *  rendering continues on the buffer.  This is like having multiple Turing
55324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver     *  machine instruction streams (programs) operating on a single input tape. :)
56324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver     *
57324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver     *  Since the operations are done lazily at toString-time, operations do not
58324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver     *  screw up the token index values.  That is, an insert operation at token
59324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver     *  index i does not change the index values for tokens i+1..n-1.
60324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver     *
61324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver     *  Because operations never actually alter the buffer, you may always get
62324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver     *  the original token stream back without undoing anything.  Since
63324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver     *  the instructions are queued up, you can easily simulate transactions and
64324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver     *  roll back any changes if there is an error just by removing instructions.
65324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver     *  For example,
66324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver     *
67324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver     *   CharStream input = new ANTLRFileStream("input");
68324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver     *   TLexer lex = new TLexer(input);
69324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver     *   TokenRewriteStream tokens = new TokenRewriteStream(lex);
70324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver     *   T parser = new T(tokens);
71324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver     *   parser.startRule();
72324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver     *
73324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver     * 	 Then in the rules, you can execute
74324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver     *      Token t,u;
75324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver     *      ...
76324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver     *      input.insertAfter(t, "text to put after t");}
77324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver     * 		input.insertAfter(u, "text after u");}
78324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver     * 		System.out.println(tokens.toString());
79324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver     *
80324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver     *  Actually, you have to cast the 'input' to a TokenRewriteStream. :(
81324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver     *
82324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver     *  You can also have multiple "instruction streams" and get multiple
83324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver     *  rewrites from a single pass over the input.  Just name the instruction
84324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver     *  streams and use that name again when printing the buffer.  This could be
85324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver     *  useful for generating a C file and also its header file--all from the
86324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver     *  same buffer:
87324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver     *
88324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver     *      tokens.insertAfter("pass1", t, "text to put after t");}
89324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver     * 		tokens.insertAfter("pass2", u, "text after u");}
90324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver     * 		System.out.println(tokens.toString("pass1"));
91324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver     * 		System.out.println(tokens.toString("pass2"));
92324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver     *
93324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver     *  If you don't use named rewrite streams, a "default" stream is used as
94324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver     *  the first example shows.
95324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver     */
96324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    [System.Serializable]
97324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    [DebuggerDisplay( "TODO: TokenRewriteStream debugger display" )]
98324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    public class TokenRewriteStream : CommonTokenStream
99324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    {
100324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        public const string DEFAULT_PROGRAM_NAME = "default";
101324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        public const int PROGRAM_INIT_SIZE = 100;
102324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        public const int MIN_TOKEN_INDEX = 0;
103324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
104324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        // Define the rewrite operation hierarchy
105324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
106324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        protected class RewriteOperation
107324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        {
108324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            /** <summary>What index into rewrites List are we?</summary> */
109324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            public int instructionIndex;
110324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            /** <summary>Token buffer index.</summary> */
111324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            public int index;
112324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            public object text;
113324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            // outer
114324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            protected TokenRewriteStream stream;
115324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
116324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            protected RewriteOperation(TokenRewriteStream stream, int index)
117324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            {
118324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                this.stream = stream;
119324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                this.index = index;
120324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            }
121324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
122324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            protected RewriteOperation( TokenRewriteStream stream, int index, object text )
123324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            {
124324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                this.index = index;
125324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                this.text = text;
126324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                this.stream = stream;
127324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            }
128324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
129324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            /** <summary>
130324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver             *  Execute the rewrite operation by possibly adding to the buffer.
131324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver             *  Return the index of the next token to operate on.
132324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver             *  </summary>
133324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver             */
134324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            public virtual int Execute( StringBuilder buf )
135324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            {
136324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                return index;
137324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            }
138324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
139324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            public override string ToString()
140324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            {
141324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                string opName = this.GetType().Name;
142324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                int dindex = opName.IndexOf( '$' );
143324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                opName = opName.Substring( dindex + 1 );
144324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                return string.Format("<{0}@{1}:\"{2}\">", opName, stream._tokens[index], text);
145324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            }
146324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        }
147324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
148324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        private class InsertBeforeOp : RewriteOperation
149324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        {
150324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            public InsertBeforeOp( TokenRewriteStream stream, int index, object text ) :
151324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                base( stream, index, text )
152324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            {
153324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            }
154324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
155324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            public override int Execute( StringBuilder buf )
156324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            {
157324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                buf.Append( text );
158324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                if (stream._tokens[index].Type != CharStreamConstants.EndOfFile)
159324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                    buf.Append(stream._tokens[index].Text);
160324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                return index + 1;
161324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            }
162324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        }
163324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
164324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        /** <summary>
165324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver         *  I'm going to try replacing range from x..y with (y-x)+1 ReplaceOp
166324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver         *  instructions.
167324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver         *  </summary>
168324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver         */
169324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        private class ReplaceOp : RewriteOperation
170324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        {
171324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            public int lastIndex;
172324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            public ReplaceOp( TokenRewriteStream stream, int from, int to, object text )
173324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                : base( stream, from, text )
174324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            {
175324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                lastIndex = to;
176324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            }
177324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
178324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            public override int Execute( StringBuilder buf )
179324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            {
180324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                if ( text != null )
181324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                {
182324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                    buf.Append( text );
183324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                }
184324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                return lastIndex + 1;
185324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            }
186324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
187324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            public override string ToString()
188324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            {
189324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                if (text == null)
190324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                {
191324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                    return string.Format("<DeleteOp@{0}..{1}>", stream._tokens[index], stream._tokens[lastIndex]);
192324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                }
193324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
194324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                return string.Format("<ReplaceOp@{0}..{1}:\"{2}\">", stream._tokens[index], stream._tokens[lastIndex], text);
195324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            }
196324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        }
197324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
198324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        /** <summary>
199324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver         *  You may have multiple, named streams of rewrite operations.
200324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver         *  I'm calling these things "programs."
201324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver         *  Maps String (name) -> rewrite (List)
202324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver         *  </summary>
203324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver         */
204324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        protected IDictionary<string, IList<RewriteOperation>> programs = null;
205324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
206324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        /** <summary>Map String (program name) -> Integer index</summary> */
207324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        protected IDictionary<string, int> lastRewriteTokenIndexes = null;
208324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
209324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        public TokenRewriteStream()
210324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        {
211324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            Init();
212324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        }
213324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
214324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        protected void Init()
215324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        {
216324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            programs = new Dictionary<string, IList<RewriteOperation>>();
217324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            programs[DEFAULT_PROGRAM_NAME] = new List<RewriteOperation>( PROGRAM_INIT_SIZE );
218324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            lastRewriteTokenIndexes = new Dictionary<string, int>();
219324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        }
220324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
221324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        public TokenRewriteStream( ITokenSource tokenSource )
222324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            : base( tokenSource )
223324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        {
224324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            Init();
225324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        }
226324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
227324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        public TokenRewriteStream( ITokenSource tokenSource, int channel )
228324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            : base( tokenSource, channel )
229324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        {
230324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            Init();
231324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        }
232324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
233324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        public virtual void Rollback( int instructionIndex )
234324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        {
235324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            Rollback( DEFAULT_PROGRAM_NAME, instructionIndex );
236324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        }
237324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
238324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        /** <summary>
239324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver         *  Rollback the instruction stream for a program so that
240324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver         *  the indicated instruction (via instructionIndex) is no
241324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver         *  longer in the stream.  UNTESTED!
242324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver         *  </summary>
243324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver         */
244324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        public virtual void Rollback( string programName, int instructionIndex )
245324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        {
246324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            IList<RewriteOperation> @is;
247324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            if ( programs.TryGetValue( programName, out @is ) && @is != null )
248324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            {
249324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                List<RewriteOperation> sublist = new List<RewriteOperation>();
250324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                for ( int i = MIN_TOKEN_INDEX; i <= instructionIndex; i++ )
251324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                    sublist.Add( @is[i] );
252324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
253324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                programs[programName] = sublist;
254324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            }
255324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        }
256324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
257324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        public virtual void DeleteProgram()
258324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        {
259324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            DeleteProgram( DEFAULT_PROGRAM_NAME );
260324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        }
261324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
262324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        /** <summary>Reset the program so that no instructions exist</summary> */
263324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        public virtual void DeleteProgram( string programName )
264324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        {
265324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            Rollback( programName, MIN_TOKEN_INDEX );
266324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        }
267324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
268324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        public virtual void InsertAfter( IToken t, object text )
269324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        {
270324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            InsertAfter( DEFAULT_PROGRAM_NAME, t, text );
271324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        }
272324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
273324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        public virtual void InsertAfter( int index, object text )
274324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        {
275324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            InsertAfter( DEFAULT_PROGRAM_NAME, index, text );
276324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        }
277324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
278324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        public virtual void InsertAfter( string programName, IToken t, object text )
279324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        {
280324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            InsertAfter( programName, t.TokenIndex, text );
281324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        }
282324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
283324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        public virtual void InsertAfter( string programName, int index, object text )
284324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        {
285324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            // to insert after, just insert before next index (even if past end)
286324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            InsertBefore( programName, index + 1, text );
287324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        }
288324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
289324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        public virtual void InsertBefore( IToken t, object text )
290324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        {
291324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            InsertBefore( DEFAULT_PROGRAM_NAME, t, text );
292324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        }
293324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
294324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        public virtual void InsertBefore( int index, object text )
295324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        {
296324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            InsertBefore( DEFAULT_PROGRAM_NAME, index, text );
297324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        }
298324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
299324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        public virtual void InsertBefore( string programName, IToken t, object text )
300324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        {
301324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            InsertBefore( programName, t.TokenIndex, text );
302324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        }
303324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
304324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        public virtual void InsertBefore( string programName, int index, object text )
305324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        {
306324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            RewriteOperation op = new InsertBeforeOp( this, index, text );
307324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            IList<RewriteOperation> rewrites = GetProgram( programName );
308324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            op.instructionIndex = rewrites.Count;
309324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            rewrites.Add( op );
310324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        }
311324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
312324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        public virtual void Replace( int index, object text )
313324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        {
314324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            Replace( DEFAULT_PROGRAM_NAME, index, index, text );
315324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        }
316324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
317324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        public virtual void Replace( int from, int to, object text )
318324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        {
319324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            Replace( DEFAULT_PROGRAM_NAME, from, to, text );
320324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        }
321324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
322324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        public virtual void Replace( IToken indexT, object text )
323324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        {
324324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            Replace( DEFAULT_PROGRAM_NAME, indexT, indexT, text );
325324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        }
326324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
327324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        public virtual void Replace( IToken from, IToken to, object text )
328324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        {
329324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            Replace( DEFAULT_PROGRAM_NAME, from, to, text );
330324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        }
331324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
332324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        public virtual void Replace( string programName, int from, int to, object text )
333324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        {
334324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            if ( from > to || from < 0 || to < 0 || to >= _tokens.Count )
335324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            {
336324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                throw new ArgumentException( "replace: range invalid: " + from + ".." + to + "(size=" + _tokens.Count + ")" );
337324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            }
338324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            RewriteOperation op = new ReplaceOp( this, from, to, text );
339324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            IList<RewriteOperation> rewrites = GetProgram( programName );
340324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            op.instructionIndex = rewrites.Count;
341324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            rewrites.Add( op );
342324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        }
343324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
344324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        public virtual void Replace( string programName, IToken from, IToken to, object text )
345324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        {
346324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            Replace( programName,
347324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                    from.TokenIndex,
348324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                    to.TokenIndex,
349324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                    text );
350324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        }
351324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
352324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        public virtual void Delete( int index )
353324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        {
354324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            Delete( DEFAULT_PROGRAM_NAME, index, index );
355324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        }
356324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
357324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        public virtual void Delete( int from, int to )
358324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        {
359324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            Delete( DEFAULT_PROGRAM_NAME, from, to );
360324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        }
361324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
362324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        public virtual void Delete( IToken indexT )
363324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        {
364324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            Delete( DEFAULT_PROGRAM_NAME, indexT, indexT );
365324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        }
366324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
367324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        public virtual void Delete( IToken from, IToken to )
368324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        {
369324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            Delete( DEFAULT_PROGRAM_NAME, from, to );
370324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        }
371324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
372324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        public virtual void Delete( string programName, int from, int to )
373324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        {
374324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            Replace( programName, from, to, null );
375324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        }
376324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
377324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        public virtual void Delete( string programName, IToken from, IToken to )
378324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        {
379324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            Replace( programName, from, to, null );
380324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        }
381324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
382324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        public virtual int GetLastRewriteTokenIndex()
383324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        {
384324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            return GetLastRewriteTokenIndex( DEFAULT_PROGRAM_NAME );
385324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        }
386324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
387324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        protected virtual int GetLastRewriteTokenIndex( string programName )
388324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        {
389324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            int value;
390324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            if ( lastRewriteTokenIndexes.TryGetValue( programName, out value ) )
391324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                return value;
392324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
393324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            return -1;
394324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        }
395324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
396324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        protected virtual void SetLastRewriteTokenIndex( string programName, int i )
397324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        {
398324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            lastRewriteTokenIndexes[programName] = i;
399324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        }
400324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
401324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        protected virtual IList<RewriteOperation> GetProgram( string name )
402324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        {
403324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            IList<RewriteOperation> @is;
404324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            if ( !programs.TryGetValue( name, out @is ) || @is == null )
405324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            {
406324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                @is = InitializeProgram( name );
407324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            }
408324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            return @is;
409324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        }
410324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
411324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        private IList<RewriteOperation> InitializeProgram( string name )
412324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        {
413324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            IList<RewriteOperation> @is = new List<RewriteOperation>( PROGRAM_INIT_SIZE );
414324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            programs[name] = @is;
415324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            return @is;
416324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        }
417324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
418324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        public virtual string ToOriginalString()
419324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        {
420324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            Fill();
421324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            return ToOriginalString( MIN_TOKEN_INDEX, Count - 1 );
422324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        }
423324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
424324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        public virtual string ToOriginalString( int start, int end )
425324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        {
426324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            StringBuilder buf = new StringBuilder();
427324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            for ( int i = start; i >= MIN_TOKEN_INDEX && i <= end && i < _tokens.Count; i++ )
428324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            {
429324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                if (Get(i).Type != CharStreamConstants.EndOfFile)
430324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                    buf.Append(Get(i).Text);
431324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            }
432324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            return buf.ToString();
433324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        }
434324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
435324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        public override string ToString()
436324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        {
437324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            Fill();
438324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            return ToString( MIN_TOKEN_INDEX, Count - 1 );
439324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        }
440324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
441324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        public virtual string ToString( string programName )
442324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        {
443324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            Fill();
444324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            return ToString(programName, MIN_TOKEN_INDEX, Count - 1);
445324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        }
446324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
447324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        public override string ToString( int start, int end )
448324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        {
449324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            return ToString( DEFAULT_PROGRAM_NAME, start, end );
450324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        }
451324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
452324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        public virtual string ToString( string programName, int start, int end )
453324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        {
454324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            IList<RewriteOperation> rewrites;
455324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            if ( !programs.TryGetValue( programName, out rewrites ) )
456324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                rewrites = null;
457324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
458324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            // ensure start/end are in range
459324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            if ( end > _tokens.Count - 1 )
460324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                end = _tokens.Count - 1;
461324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            if ( start < 0 )
462324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                start = 0;
463324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
464324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            if ( rewrites == null || rewrites.Count == 0 )
465324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            {
466324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                return ToOriginalString( start, end ); // no instructions to execute
467324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            }
468324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            StringBuilder buf = new StringBuilder();
469324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
470324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            // First, optimize instruction stream
471324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            IDictionary<int, RewriteOperation> indexToOp = ReduceToSingleOperationPerIndex( rewrites );
472324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
473324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            // Walk buffer, executing instructions and emitting tokens
474324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            int i = start;
475324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            while ( i <= end && i < _tokens.Count )
476324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            {
477324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                RewriteOperation op;
478324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                bool exists = indexToOp.TryGetValue( i, out op );
479324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
480324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                if ( exists )
481324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                {
482324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                    // remove so any left have index size-1
483324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                    indexToOp.Remove( i );
484324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                }
485324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
486324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                if ( !exists || op == null )
487324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                {
488324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                    IToken t = _tokens[i];
489324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                    // no operation at that index, just dump token
490324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                    if (t.Type != CharStreamConstants.EndOfFile)
491324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                        buf.Append(t.Text);
492324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                    i++; // move to next token
493324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                }
494324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                else
495324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                {
496324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                    i = op.Execute( buf ); // execute operation and skip
497324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                }
498324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            }
499324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
500324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            // include stuff after end if it's last index in buffer
501324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            // So, if they did an insertAfter(lastValidIndex, "foo"), include
502324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            // foo if end==lastValidIndex.
503324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            if ( end == _tokens.Count - 1 )
504324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            {
505324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                // Scan any remaining operations after last token
506324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                // should be included (they will be inserts).
507324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                foreach ( RewriteOperation op in indexToOp.Values )
508324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                {
509324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                    if ( op.index >= _tokens.Count - 1 )
510324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                        buf.Append( op.text );
511324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                }
512324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            }
513324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            return buf.ToString();
514324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        }
515324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
516324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        /** We need to combine operations and report invalid operations (like
517324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver         *  overlapping replaces that are not completed nested).  Inserts to
518324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver         *  same index need to be combined etc...   Here are the cases:
519324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver         *
520324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver         *  I.i.u I.j.v								leave alone, nonoverlapping
521324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver         *  I.i.u I.i.v								combine: Iivu
522324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver         *
523324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver         *  R.i-j.u R.x-y.v	| i-j in x-y			delete first R
524324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver         *  R.i-j.u R.i-j.v							delete first R
525324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver         *  R.i-j.u R.x-y.v	| x-y in i-j			ERROR
526324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver         *  R.i-j.u R.x-y.v	| boundaries overlap	ERROR
527324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver         *
528324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver         *  Delete special case of replace (text==null):
529324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver         *  D.i-j.u D.x-y.v	| boundaries overlap	combine to max(min)..max(right)
530324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver         *
531324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver         *  I.i.u R.x-y.v | i in (x+1)-y			delete I (since insert before
532324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver         *											we're not deleting i)
533324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver         *  I.i.u R.x-y.v | i not in (x+1)-y		leave alone, nonoverlapping
534324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver         *  R.x-y.v I.i.u | i in x-y				ERROR
535324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver         *  R.x-y.v I.x.u 							R.x-y.uv (combine, delete I)
536324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver         *  R.x-y.v I.i.u | i not in x-y			leave alone, nonoverlapping
537324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver         *
538324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver         *  I.i.u = insert u before op @ index i
539324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver         *  R.x-y.u = replace x-y indexed tokens with u
540324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver         *
541324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver         *  First we need to examine replaces.  For any replace op:
542324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver         *
543324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver         * 		1. wipe out any insertions before op within that range.
544324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver         *		2. Drop any replace op before that is contained completely within
545324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver         *         that range.
546324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver         *		3. Throw exception upon boundary overlap with any previous replace.
547324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver         *
548324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver         *  Then we can deal with inserts:
549324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver         *
550324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver         * 		1. for any inserts to same index, combine even if not adjacent.
551324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver         * 		2. for any prior replace with same left boundary, combine this
552324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver         *         insert with replace and delete this replace.
553324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver         * 		3. throw exception if index in same range as previous replace
554324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver         *
555324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver         *  Don't actually delete; make op null in list. Easier to walk list.
556324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver         *  Later we can throw as we add to index -> op map.
557324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver         *
558324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver         *  Note that I.2 R.2-2 will wipe out I.2 even though, technically, the
559324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver         *  inserted stuff would be before the replace range.  But, if you
560324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver         *  add tokens in front of a method body '{' and then delete the method
561324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver         *  body, I think the stuff before the '{' you added should disappear too.
562324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver         *
563324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver         *  Return a map from token index to operation.
564324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver         */
565324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        protected virtual IDictionary<int, RewriteOperation> ReduceToSingleOperationPerIndex( IList<RewriteOperation> rewrites )
566324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        {
567324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            //System.out.println("rewrites="+rewrites);
568324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
569324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            // WALK REPLACES
570324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            for ( int i = 0; i < rewrites.Count; i++ )
571324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            {
572324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                RewriteOperation op = rewrites[i];
573324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                if ( op == null )
574324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                    continue;
575324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                if ( !( op is ReplaceOp ) )
576324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                    continue;
577324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                ReplaceOp rop = (ReplaceOp)rewrites[i];
578324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                // Wipe prior inserts within range
579324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                var inserts = GetKindOfOps( rewrites, typeof( InsertBeforeOp ), i );
580324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                for ( int j = 0; j < inserts.Count; j++ )
581324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                {
582324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                    InsertBeforeOp iop = (InsertBeforeOp)inserts[j];
583324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                    if (iop.index == rop.index)
584324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                    {
585324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                        // E.g., insert before 2, delete 2..2; update replace
586324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                        // text to include insert before, kill insert
587324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                        rewrites[iop.instructionIndex] = null;
588324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                        rop.text = iop.text.ToString() + (rop.text != null ? rop.text.ToString() : string.Empty);
589324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                    }
590324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                    else if (iop.index > rop.index && iop.index <= rop.lastIndex)
591324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                    {
592324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                        // delete insert as it's a no-op.
593324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                        rewrites[iop.instructionIndex] = null;
594324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                    }
595324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                }
596324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                // Drop any prior replaces contained within
597324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                var prevReplaces = GetKindOfOps( rewrites, typeof( ReplaceOp ), i );
598324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                for ( int j = 0; j < prevReplaces.Count; j++ )
599324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                {
600324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                    ReplaceOp prevRop = (ReplaceOp)prevReplaces[j];
601324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                    if ( prevRop.index >= rop.index && prevRop.lastIndex <= rop.lastIndex )
602324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                    {
603324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                        // delete replace as it's a no-op.
604324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                        rewrites[prevRop.instructionIndex] = null;
605324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                        continue;
606324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                    }
607324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                    // throw exception unless disjoint or identical
608324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                    bool disjoint =
609324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                        prevRop.lastIndex < rop.index || prevRop.index > rop.lastIndex;
610324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                    bool same =
611324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                        prevRop.index == rop.index && prevRop.lastIndex == rop.lastIndex;
612324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                    // Delete special case of replace (text==null):
613324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                    // D.i-j.u D.x-y.v	| boundaries overlap	combine to max(min)..max(right)
614324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                    if (prevRop.text == null && rop.text == null && !disjoint)
615324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                    {
616324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                        //System.out.println("overlapping deletes: "+prevRop+", "+rop);
617324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                        rewrites[prevRop.instructionIndex] = null; // kill first delete
618324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                        rop.index = Math.Min(prevRop.index, rop.index);
619324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                        rop.lastIndex = Math.Max(prevRop.lastIndex, rop.lastIndex);
620324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                        Console.WriteLine("new rop " + rop);
621324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                    }
622324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                    else if ( !disjoint && !same )
623324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                    {
624324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                        throw new ArgumentException( "replace op boundaries of " + rop +
625324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                                                           " overlap with previous " + prevRop );
626324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                    }
627324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                }
628324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            }
629324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
630324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            // WALK INSERTS
631324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            for ( int i = 0; i < rewrites.Count; i++ )
632324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            {
633324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                RewriteOperation op = (RewriteOperation)rewrites[i];
634324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                if ( op == null )
635324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                    continue;
636324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                if ( !( op is InsertBeforeOp ) )
637324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                    continue;
638324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                InsertBeforeOp iop = (InsertBeforeOp)rewrites[i];
639324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                // combine current insert with prior if any at same index
640324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                var prevInserts = GetKindOfOps( rewrites, typeof( InsertBeforeOp ), i );
641324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                for ( int j = 0; j < prevInserts.Count; j++ )
642324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                {
643324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                    InsertBeforeOp prevIop = (InsertBeforeOp)prevInserts[j];
644324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                    if ( prevIop.index == iop.index )
645324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                    { // combine objects
646324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                        // convert to strings...we're in process of toString'ing
647324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                        // whole token buffer so no lazy eval issue with any templates
648324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                        iop.text = CatOpText( iop.text, prevIop.text );
649324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                        // delete redundant prior insert
650324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                        rewrites[prevIop.instructionIndex] = null;
651324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                    }
652324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                }
653324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                // look for replaces where iop.index is in range; error
654324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                var prevReplaces = GetKindOfOps( rewrites, typeof( ReplaceOp ), i );
655324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                for ( int j = 0; j < prevReplaces.Count; j++ )
656324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                {
657324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                    ReplaceOp rop = (ReplaceOp)prevReplaces[j];
658324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                    if ( iop.index == rop.index )
659324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                    {
660324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                        rop.text = CatOpText( iop.text, rop.text );
661324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                        rewrites[i] = null;  // delete current insert
662324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                        continue;
663324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                    }
664324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                    if ( iop.index >= rop.index && iop.index <= rop.lastIndex )
665324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                    {
666324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                        throw new ArgumentException( "insert op " + iop +
667324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                                                           " within boundaries of previous " + rop );
668324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                    }
669324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                }
670324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            }
671324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            // System.out.println("rewrites after="+rewrites);
672324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            IDictionary<int, RewriteOperation> m = new Dictionary<int, RewriteOperation>();
673324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            for ( int i = 0; i < rewrites.Count; i++ )
674324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            {
675324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                RewriteOperation op = (RewriteOperation)rewrites[i];
676324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                if ( op == null )
677324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                    continue; // ignore deleted ops
678324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
679324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                RewriteOperation existing;
680324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                if ( m.TryGetValue( op.index, out existing ) && existing != null )
681324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                {
682324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                    throw new Exception( "should only be one op per index" );
683324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                }
684324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                m[op.index] = op;
685324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            }
686324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            //System.out.println("index to op: "+m);
687324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            return m;
688324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        }
689324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
690324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        protected virtual string CatOpText( object a, object b )
691324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        {
692324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            return string.Concat( a, b );
693324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        }
694324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        protected virtual IList<RewriteOperation> GetKindOfOps( IList<RewriteOperation> rewrites, Type kind )
695324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        {
696324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            return GetKindOfOps( rewrites, kind, rewrites.Count );
697324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        }
698324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
699324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        /** <summary>Get all operations before an index of a particular kind</summary> */
700324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        protected virtual IList<RewriteOperation> GetKindOfOps( IList<RewriteOperation> rewrites, Type kind, int before )
701324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        {
702324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            IList<RewriteOperation> ops = new List<RewriteOperation>();
703324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            for ( int i = 0; i < before && i < rewrites.Count; i++ )
704324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            {
705324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                RewriteOperation op = rewrites[i];
706324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                if ( op == null )
707324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                    continue; // ignore deleted
708324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                if ( op.GetType() == kind )
709324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                    ops.Add( op );
710324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            }
711324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            return ops;
712324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        }
713324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
714324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        public virtual string ToDebugString()
715324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        {
716324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            return ToDebugString( MIN_TOKEN_INDEX, Count - 1 );
717324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        }
718324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
719324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        public virtual string ToDebugString( int start, int end )
720324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        {
721324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            StringBuilder buf = new StringBuilder();
722324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            for ( int i = start; i >= MIN_TOKEN_INDEX && i <= end && i < _tokens.Count; i++ )
723324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            {
724324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                buf.Append( Get( i ) );
725324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            }
726324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            return buf.ToString();
727324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        }
728324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    }
729324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver}
730