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    using System.Collections.Generic;
35324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
36324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    using ArgumentException = System.ArgumentException;
37324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    using DebuggerDisplay = System.Diagnostics.DebuggerDisplayAttribute;
38324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    using Exception = System.Exception;
39324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    using StringBuilder = System.Text.StringBuilder;
40324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    using Type = System.Type;
41324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
42324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    /** Useful for dumping out the input stream after doing some
43324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver     *  augmentation or other manipulations.
44324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver     *
45324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver     *  You can insert stuff, replace, and delete chunks.  Note that the
46324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver     *  operations are done lazily--only if you convert the buffer to a
47324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver     *  String.  This is very efficient because you are not moving data around
48324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver     *  all the time.  As the buffer of tokens is converted to strings, the
49324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver     *  toString() method(s) check to see if there is an operation at the
50324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver     *  current index.  If so, the operation is done and then normal String
51324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver     *  rendering continues on the buffer.  This is like having multiple Turing
52324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver     *  machine instruction streams (programs) operating on a single input tape. :)
53324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver     *
54324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver     *  Since the operations are done lazily at toString-time, operations do not
55324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver     *  screw up the token index values.  That is, an insert operation at token
56324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver     *  index i does not change the index values for tokens i+1..n-1.
57324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver     *
58324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver     *  Because operations never actually alter the buffer, you may always get
59324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver     *  the original token stream back without undoing anything.  Since
60324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver     *  the instructions are queued up, you can easily simulate transactions and
61324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver     *  roll back any changes if there is an error just by removing instructions.
62324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver     *  For example,
63324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver     *
64324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver     *   CharStream input = new ANTLRFileStream("input");
65324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver     *   TLexer lex = new TLexer(input);
66324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver     *   TokenRewriteStream tokens = new TokenRewriteStream(lex);
67324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver     *   T parser = new T(tokens);
68324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver     *   parser.startRule();
69324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver     *
70324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver     * 	 Then in the rules, you can execute
71324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver     *      Token t,u;
72324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver     *      ...
73324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver     *      input.insertAfter(t, "text to put after t");}
74324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver     * 		input.insertAfter(u, "text after u");}
75324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver     * 		System.out.println(tokens.toString());
76324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver     *
77324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver     *  Actually, you have to cast the 'input' to a TokenRewriteStream. :(
78324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver     *
79324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver     *  You can also have multiple "instruction streams" and get multiple
80324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver     *  rewrites from a single pass over the input.  Just name the instruction
81324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver     *  streams and use that name again when printing the buffer.  This could be
82324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver     *  useful for generating a C file and also its header file--all from the
83324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver     *  same buffer:
84324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver     *
85324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver     *      tokens.insertAfter("pass1", t, "text to put after t");}
86324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver     * 		tokens.insertAfter("pass2", u, "text after u");}
87324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver     * 		System.out.println(tokens.toString("pass1"));
88324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver     * 		System.out.println(tokens.toString("pass2"));
89324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver     *
90324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver     *  If you don't use named rewrite streams, a "default" stream is used as
91324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver     *  the first example shows.
92324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver     */
93324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    [System.Serializable]
94324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    [DebuggerDisplay("TODO: TokenRewriteStream debugger display")]
95324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    public class TokenRewriteStream : CommonTokenStream {
96324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        public const string DEFAULT_PROGRAM_NAME = "default";
97324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        public const int PROGRAM_INIT_SIZE = 100;
98324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        public const int MIN_TOKEN_INDEX = 0;
99324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
100324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        // Define the rewrite operation hierarchy
101324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
102324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        protected class RewriteOperation {
103324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            /** <summary>What index into rewrites List are we?</summary> */
104324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            public int instructionIndex;
105324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            /** <summary>Token buffer index.</summary> */
106324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            public int index;
107324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            public object text;
108324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            // outer
109324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            protected TokenRewriteStream stream;
110324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
111324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            protected RewriteOperation(TokenRewriteStream stream, int index, object text) {
112324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                this.index = index;
113324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                this.text = text;
114324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                this.stream = stream;
115324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            }
116324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            /** <summary>
117324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver             *  Execute the rewrite operation by possibly adding to the buffer.
118324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver             *  Return the index of the next token to operate on.
119324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver             *  </summary>
120324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver             */
121324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            public virtual int Execute(StringBuilder buf) {
122324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                return index;
123324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            }
124324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            public override string ToString() {
125324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                string opName = this.GetType().Name;
126324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                int index = opName.IndexOf('$');
127324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                opName = opName.Substring(index + 1);
128324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                return "<" + opName + "@" + this.index + ":\"" + text + "\">";
129324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            }
130324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        }
131324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
132324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        class InsertBeforeOp : RewriteOperation {
133324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            public InsertBeforeOp(TokenRewriteStream stream, int index, object text) :
134324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                base(stream, index, text) {
135324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            }
136324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
137324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            public override int Execute(StringBuilder buf) {
138324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                buf.Append(text);
139324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                if (stream._tokens[index].Type != CharStreamConstants.EndOfFile)
140324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                    buf.Append(stream._tokens[index].Text);
141324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                return index + 1;
142324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            }
143324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        }
144324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
145324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        /** <summary>
146324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver         *  I'm going to try replacing range from x..y with (y-x)+1 ReplaceOp
147324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver         *  instructions.
148324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver         *  </summary>
149324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver         */
150324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        class ReplaceOp : RewriteOperation {
151324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            public int lastIndex;
152324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            public ReplaceOp(TokenRewriteStream stream, int from, int to, object text)
153324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                : base(stream, from, text) {
154324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                lastIndex = to;
155324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            }
156324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            public override int Execute(StringBuilder buf) {
157324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                if (text != null) {
158324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                    buf.Append(text);
159324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                }
160324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                return lastIndex + 1;
161324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            }
162324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            public override string ToString() {
163324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                return "<ReplaceOp@" + index + ".." + lastIndex + ":\"" + text + "\">";
164324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            }
165324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        }
166324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
167324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        class DeleteOp : ReplaceOp {
168324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            public DeleteOp(TokenRewriteStream stream, int from, int to) :
169324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                base(stream, from, to, null) {
170324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            }
171324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            public override string ToString() {
172324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                return "<DeleteOp@" + index + ".." + lastIndex + ">";
173324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            }
174324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        }
175324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
176324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        /** <summary>
177324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver         *  You may have multiple, named streams of rewrite operations.
178324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver         *  I'm calling these things "programs."
179324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver         *  Maps String (name) -> rewrite (List)
180324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver         *  </summary>
181324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver         */
182324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        protected IDictionary<string, IList<RewriteOperation>> programs = null;
183324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
184324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        /** <summary>Map String (program name) -> Integer index</summary> */
185324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        protected IDictionary<string, int> lastRewriteTokenIndexes = null;
186324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
187324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        public TokenRewriteStream() {
188324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            Init();
189324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        }
190324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
191324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        protected void Init() {
192324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            programs = new Dictionary<string, IList<RewriteOperation>>();
193324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            programs[DEFAULT_PROGRAM_NAME] = new List<RewriteOperation>(PROGRAM_INIT_SIZE);
194324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            lastRewriteTokenIndexes = new Dictionary<string, int>();
195324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        }
196324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
197324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        public TokenRewriteStream(ITokenSource tokenSource)
198324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            : base(tokenSource) {
199324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            Init();
200324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        }
201324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
202324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        public TokenRewriteStream(ITokenSource tokenSource, int channel)
203324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            : base(tokenSource, channel) {
204324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            Init();
205324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        }
206324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
207324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        public virtual void Rollback(int instructionIndex) {
208324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            Rollback(DEFAULT_PROGRAM_NAME, instructionIndex);
209324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        }
210324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
211324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        /** <summary>
212324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver         *  Rollback the instruction stream for a program so that
213324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver         *  the indicated instruction (via instructionIndex) is no
214324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver         *  longer in the stream.  UNTESTED!
215324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver         *  </summary>
216324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver         */
217324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        public virtual void Rollback(string programName, int instructionIndex) {
218324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            IList<RewriteOperation> @is;
219324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            if (programs.TryGetValue(programName, out @is) && @is != null) {
220324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                List<RewriteOperation> sublist = new List<RewriteOperation>();
221324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                for (int i = MIN_TOKEN_INDEX; i <= instructionIndex; i++)
222324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                    sublist.Add(@is[i]);
223324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
224324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                programs[programName] = sublist;
225324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            }
226324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        }
227324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
228324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        public virtual void DeleteProgram() {
229324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            DeleteProgram(DEFAULT_PROGRAM_NAME);
230324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        }
231324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
232324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        /** <summary>Reset the program so that no instructions exist</summary> */
233324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        public virtual void DeleteProgram(string programName) {
234324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            Rollback(programName, MIN_TOKEN_INDEX);
235324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        }
236324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
237324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        public virtual void InsertAfter(IToken t, object text) {
238324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            InsertAfter(DEFAULT_PROGRAM_NAME, t, text);
239324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        }
240324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
241324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        public virtual void InsertAfter(int index, object text) {
242324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            InsertAfter(DEFAULT_PROGRAM_NAME, index, text);
243324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        }
244324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
245324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        public virtual void InsertAfter(string programName, IToken t, object text) {
246324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            InsertAfter(programName, t.TokenIndex, text);
247324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        }
248324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
249324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        public virtual void InsertAfter(string programName, int index, object text) {
250324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            // to insert after, just insert before next index (even if past end)
251324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            InsertBefore(programName, index + 1, text);
252324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            //addToSortedRewriteList(programName, new InsertAfterOp(index,text));
253324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        }
254324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
255324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        public virtual void InsertBefore(IToken t, object text) {
256324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            InsertBefore(DEFAULT_PROGRAM_NAME, t, text);
257324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        }
258324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
259324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        public virtual void InsertBefore(int index, object text) {
260324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            InsertBefore(DEFAULT_PROGRAM_NAME, index, text);
261324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        }
262324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
263324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        public virtual void InsertBefore(string programName, IToken t, object text) {
264324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            InsertBefore(programName, t.TokenIndex, text);
265324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        }
266324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
267324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        public virtual void InsertBefore(string programName, int index, object text) {
268324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            //addToSortedRewriteList(programName, new InsertBeforeOp(index,text));
269324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            RewriteOperation op = new InsertBeforeOp(this, index, text);
270324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            IList<RewriteOperation> rewrites = GetProgram(programName);
271324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            op.instructionIndex = rewrites.Count;
272324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            rewrites.Add(op);
273324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        }
274324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
275324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        public virtual void Replace(int index, object text) {
276324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            Replace(DEFAULT_PROGRAM_NAME, index, index, text);
277324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        }
278324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
279324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        public virtual void Replace(int from, int to, object text) {
280324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            Replace(DEFAULT_PROGRAM_NAME, from, to, text);
281324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        }
282324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
283324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        public virtual void Replace(IToken indexT, object text) {
284324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            Replace(DEFAULT_PROGRAM_NAME, indexT, indexT, text);
285324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        }
286324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
287324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        public virtual void Replace(IToken from, IToken to, object text) {
288324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            Replace(DEFAULT_PROGRAM_NAME, from, to, text);
289324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        }
290324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
291324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        public virtual void Replace(string programName, int from, int to, object text) {
292324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            if (from > to || from < 0 || to < 0 || to >= _tokens.Count) {
293324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                throw new ArgumentException("replace: range invalid: " + from + ".." + to + "(size=" + _tokens.Count + ")");
294324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            }
295324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            RewriteOperation op = new ReplaceOp(this, from, to, text);
296324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            IList<RewriteOperation> rewrites = GetProgram(programName);
297324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            op.instructionIndex = rewrites.Count;
298324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            rewrites.Add(op);
299324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        }
300324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
301324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        public virtual void Replace(string programName, IToken from, IToken to, object text) {
302324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            Replace(programName,
303324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                    from.TokenIndex,
304324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                    to.TokenIndex,
305324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                    text);
306324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        }
307324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
308324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        public virtual void Delete(int index) {
309324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            Delete(DEFAULT_PROGRAM_NAME, index, index);
310324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        }
311324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
312324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        public virtual void Delete(int from, int to) {
313324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            Delete(DEFAULT_PROGRAM_NAME, from, to);
314324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        }
315324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
316324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        public virtual void Delete(IToken indexT) {
317324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            Delete(DEFAULT_PROGRAM_NAME, indexT, indexT);
318324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        }
319324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
320324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        public virtual void Delete(IToken from, IToken to) {
321324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            Delete(DEFAULT_PROGRAM_NAME, from, to);
322324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        }
323324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
324324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        public virtual void Delete(string programName, int from, int to) {
325324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            Replace(programName, from, to, null);
326324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        }
327324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
328324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        public virtual void Delete(string programName, IToken from, IToken to) {
329324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            Replace(programName, from, to, null);
330324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        }
331324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
332324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        public virtual int GetLastRewriteTokenIndex() {
333324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            return GetLastRewriteTokenIndex(DEFAULT_PROGRAM_NAME);
334324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        }
335324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
336324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        protected virtual int GetLastRewriteTokenIndex(string programName) {
337324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            int value;
338324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            if (lastRewriteTokenIndexes.TryGetValue(programName, out value))
339324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                return value;
340324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
341324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            return -1;
342324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        }
343324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
344324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        protected virtual void SetLastRewriteTokenIndex(string programName, int i) {
345324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            lastRewriteTokenIndexes[programName] = i;
346324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        }
347324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
348324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        protected virtual IList<RewriteOperation> GetProgram(string name) {
349324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            IList<RewriteOperation> @is;
350324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            if (!programs.TryGetValue(name, out @is) || @is == null) {
351324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                @is = InitializeProgram(name);
352324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            }
353324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            return @is;
354324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        }
355324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
356324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        private IList<RewriteOperation> InitializeProgram(string name) {
357324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            IList<RewriteOperation> @is = new List<RewriteOperation>(PROGRAM_INIT_SIZE);
358324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            programs[name] = @is;
359324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            return @is;
360324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        }
361324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
362324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        public virtual string ToOriginalString() {
363324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            Fill();
364324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            return ToOriginalString(MIN_TOKEN_INDEX, Count - 1);
365324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        }
366324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
367324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        public virtual string ToOriginalString(int start, int end) {
368324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            StringBuilder buf = new StringBuilder();
369324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            for (int i = start; i >= MIN_TOKEN_INDEX && i <= end && i < _tokens.Count; i++) {
370324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                if (Get(i).Type != CharStreamConstants.EndOfFile)
371324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                    buf.Append(Get(i).Text);
372324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            }
373324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            return buf.ToString();
374324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        }
375324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
376324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        public override string ToString() {
377324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            Fill();
378324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            return ToString(MIN_TOKEN_INDEX, Count - 1);
379324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        }
380324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
381324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        public virtual string ToString(string programName) {
382324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            Fill();
383324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            return ToString(programName, MIN_TOKEN_INDEX, Count - 1);
384324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        }
385324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
386324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        public override string ToString(int start, int end) {
387324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            return ToString(DEFAULT_PROGRAM_NAME, start, end);
388324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        }
389324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
390324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        public virtual string ToString(string programName, int start, int end) {
391324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            IList<RewriteOperation> rewrites;
392324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            if (!programs.TryGetValue(programName, out rewrites))
393324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                rewrites = null;
394324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
395324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            // ensure start/end are in range
396324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            if (end > _tokens.Count - 1)
397324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                end = _tokens.Count - 1;
398324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            if (start < 0)
399324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                start = 0;
400324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
401324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            if (rewrites == null || rewrites.Count == 0) {
402324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                return ToOriginalString(start, end); // no instructions to execute
403324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            }
404324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            StringBuilder buf = new StringBuilder();
405324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
406324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            // First, optimize instruction stream
407324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            IDictionary<int, RewriteOperation> indexToOp = ReduceToSingleOperationPerIndex(rewrites);
408324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
409324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            // Walk buffer, executing instructions and emitting tokens
410324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            int i = start;
411324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            while (i <= end && i < _tokens.Count) {
412324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                RewriteOperation op;
413324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                bool exists = indexToOp.TryGetValue(i, out op);
414324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
415324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                if (exists) {
416324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                    // remove so any left have index size-1
417324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                    indexToOp.Remove(i);
418324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                }
419324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
420324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                if (!exists || op == null) {
421324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                    IToken t = _tokens[i];
422324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                    // no operation at that index, just dump token
423324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                    if (t.Type != CharStreamConstants.EndOfFile)
424324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                        buf.Append(t.Text);
425324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                    i++; // move to next token
426324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                } else {
427324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                    i = op.Execute(buf); // execute operation and skip
428324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                }
429324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            }
430324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
431324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            // include stuff after end if it's last index in buffer
432324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            // So, if they did an insertAfter(lastValidIndex, "foo"), include
433324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            // foo if end==lastValidIndex.
434324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            if (end == _tokens.Count - 1) {
435324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                // Scan any remaining operations after last token
436324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                // should be included (they will be inserts).
437324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                foreach (RewriteOperation op in indexToOp.Values) {
438324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                    if (op.index >= _tokens.Count - 1)
439324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                        buf.Append(op.text);
440324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                }
441324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            }
442324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            return buf.ToString();
443324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        }
444324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
445324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        /** We need to combine operations and report invalid operations (like
446324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver         *  overlapping replaces that are not completed nested).  Inserts to
447324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver         *  same index need to be combined etc...   Here are the cases:
448324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver         *
449324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver         *  I.i.u I.j.v								leave alone, nonoverlapping
450324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver         *  I.i.u I.i.v								combine: Iivu
451324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver         *
452324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver         *  R.i-j.u R.x-y.v	| i-j in x-y			delete first R
453324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver         *  R.i-j.u R.i-j.v							delete first R
454324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver         *  R.i-j.u R.x-y.v	| x-y in i-j			ERROR
455324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver         *  R.i-j.u R.x-y.v	| boundaries overlap	ERROR
456324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver         *
457324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver         *  I.i.u R.x-y.v | i in x-y				delete I
458324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver         *  I.i.u R.x-y.v | i not in x-y			leave alone, nonoverlapping
459324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver         *  R.x-y.v I.i.u | i in x-y				ERROR
460324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver         *  R.x-y.v I.x.u 							R.x-y.uv (combine, delete I)
461324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver         *  R.x-y.v I.i.u | i not in x-y			leave alone, nonoverlapping
462324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver         *
463324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver         *  I.i.u = insert u before op @ index i
464324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver         *  R.x-y.u = replace x-y indexed tokens with u
465324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver         *
466324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver         *  First we need to examine replaces.  For any replace op:
467324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver         *
468324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver         * 		1. wipe out any insertions before op within that range.
469324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver         *		2. Drop any replace op before that is contained completely within
470324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver         *         that range.
471324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver         *		3. Throw exception upon boundary overlap with any previous replace.
472324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver         *
473324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver         *  Then we can deal with inserts:
474324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver         *
475324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver         * 		1. for any inserts to same index, combine even if not adjacent.
476324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver         * 		2. for any prior replace with same left boundary, combine this
477324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver         *         insert with replace and delete this replace.
478324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver         * 		3. throw exception if index in same range as previous replace
479324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver         *
480324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver         *  Don't actually delete; make op null in list. Easier to walk list.
481324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver         *  Later we can throw as we add to index -> op map.
482324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver         *
483324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver         *  Note that I.2 R.2-2 will wipe out I.2 even though, technically, the
484324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver         *  inserted stuff would be before the replace range.  But, if you
485324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver         *  add tokens in front of a method body '{' and then delete the method
486324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver         *  body, I think the stuff before the '{' you added should disappear too.
487324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver         *
488324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver         *  Return a map from token index to operation.
489324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver         */
490324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        protected virtual IDictionary<int, RewriteOperation> ReduceToSingleOperationPerIndex(IList<RewriteOperation> rewrites) {
491324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            //System.out.println("rewrites="+rewrites);
492324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
493324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            // WALK REPLACES
494324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            for (int i = 0; i < rewrites.Count; i++) {
495324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                RewriteOperation op = rewrites[i];
496324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                if (op == null)
497324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                    continue;
498324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                if (!(op is ReplaceOp))
499324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                    continue;
500324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                ReplaceOp rop = (ReplaceOp)rewrites[i];
501324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                // Wipe prior inserts within range
502324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                var inserts = GetKindOfOps(rewrites, typeof(InsertBeforeOp), i);
503324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                for (int j = 0; j < inserts.Count; j++) {
504324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                    InsertBeforeOp iop = (InsertBeforeOp)inserts[j];
505324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                    if (iop.index >= rop.index && iop.index <= rop.lastIndex) {
506324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                        // delete insert as it's a no-op.
507324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                        rewrites[iop.instructionIndex] = null;
508324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                    }
509324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                }
510324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                // Drop any prior replaces contained within
511324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                var prevReplaces = GetKindOfOps(rewrites, typeof(ReplaceOp), i);
512324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                for (int j = 0; j < prevReplaces.Count; j++) {
513324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                    ReplaceOp prevRop = (ReplaceOp)prevReplaces[j];
514324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                    if (prevRop.index >= rop.index && prevRop.lastIndex <= rop.lastIndex) {
515324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                        // delete replace as it's a no-op.
516324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                        rewrites[prevRop.instructionIndex] = null;
517324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                        continue;
518324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                    }
519324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                    // throw exception unless disjoint or identical
520324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                    bool disjoint =
521324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                        prevRop.lastIndex < rop.index || prevRop.index > rop.lastIndex;
522324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                    bool same =
523324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                        prevRop.index == rop.index && prevRop.lastIndex == rop.lastIndex;
524324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                    if (!disjoint && !same) {
525324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                        throw new ArgumentException("replace op boundaries of " + rop +
526324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                                                           " overlap with previous " + prevRop);
527324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                    }
528324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                }
529324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            }
530324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
531324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            // WALK INSERTS
532324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            for (int i = 0; i < rewrites.Count; i++) {
533324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                RewriteOperation op = (RewriteOperation)rewrites[i];
534324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                if (op == null)
535324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                    continue;
536324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                if (!(op is InsertBeforeOp))
537324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                    continue;
538324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                InsertBeforeOp iop = (InsertBeforeOp)rewrites[i];
539324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                // combine current insert with prior if any at same index
540324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                var prevInserts = GetKindOfOps(rewrites, typeof(InsertBeforeOp), i);
541324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                for (int j = 0; j < prevInserts.Count; j++) {
542324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                    InsertBeforeOp prevIop = (InsertBeforeOp)prevInserts[j];
543324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                    if (prevIop.index == iop.index) { // combine objects
544324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                        // convert to strings...we're in process of toString'ing
545324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                        // whole token buffer so no lazy eval issue with any templates
546324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                        iop.text = CatOpText(iop.text, prevIop.text);
547324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                        // delete redundant prior insert
548324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                        rewrites[prevIop.instructionIndex] = null;
549324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                    }
550324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                }
551324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                // look for replaces where iop.index is in range; error
552324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                var prevReplaces = GetKindOfOps(rewrites, typeof(ReplaceOp), i);
553324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                for (int j = 0; j < prevReplaces.Count; j++) {
554324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                    ReplaceOp rop = (ReplaceOp)prevReplaces[j];
555324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                    if (iop.index == rop.index) {
556324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                        rop.text = CatOpText(iop.text, rop.text);
557324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                        rewrites[i] = null;  // delete current insert
558324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                        continue;
559324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                    }
560324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                    if (iop.index >= rop.index && iop.index <= rop.lastIndex) {
561324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                        throw new ArgumentException("insert op " + iop +
562324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                                                           " within boundaries of previous " + rop);
563324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                    }
564324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                }
565324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            }
566324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            // System.out.println("rewrites after="+rewrites);
567324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            IDictionary<int, RewriteOperation> m = new Dictionary<int, RewriteOperation>();
568324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            for (int i = 0; i < rewrites.Count; i++) {
569324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                RewriteOperation op = (RewriteOperation)rewrites[i];
570324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                if (op == null)
571324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                    continue; // ignore deleted ops
572324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
573324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                RewriteOperation existing;
574324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                if (m.TryGetValue(op.index, out existing) && existing != null) {
575324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                    throw new Exception("should only be one op per index");
576324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                }
577324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                m[op.index] = op;
578324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            }
579324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            //System.out.println("index to op: "+m);
580324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            return m;
581324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        }
582324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
583324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        protected virtual string CatOpText(object a, object b) {
584324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            return string.Concat(a, b);
585324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        }
586324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        protected virtual IList<RewriteOperation> GetKindOfOps(IList<RewriteOperation> rewrites, Type kind) {
587324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            return GetKindOfOps(rewrites, kind, rewrites.Count);
588324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        }
589324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
590324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        /** <summary>Get all operations before an index of a particular kind</summary> */
591324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        protected virtual IList<RewriteOperation> GetKindOfOps(IList<RewriteOperation> rewrites, Type kind, int before) {
592324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            IList<RewriteOperation> ops = new List<RewriteOperation>();
593324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            for (int i = 0; i < before && i < rewrites.Count; i++) {
594324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                RewriteOperation op = rewrites[i];
595324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                if (op == null)
596324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                    continue; // ignore deleted
597324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                if (op.GetType() == kind)
598324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                    ops.Add(op);
599324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            }
600324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            return ops;
601324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        }
602324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
603324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        public virtual string ToDebugString() {
604324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            return ToDebugString(MIN_TOKEN_INDEX, Count - 1);
605324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        }
606324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver
607324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        public virtual string ToDebugString(int start, int end) {
608324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            StringBuilder buf = new StringBuilder();
609324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            for (int i = start; i >= MIN_TOKEN_INDEX && i <= end && i < _tokens.Count; i++) {
610324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver                buf.Append(Get(i));
611324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            }
612324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver            return buf.ToString();
613324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver        }
614324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver    }
615324c4644fee44b9898524c09511bd33c3f12e2dfBen Gruver}
616