Added ability to order the execution of dictionary adapter behaviors.
[castle.git] / Experiments / Attic / Rook / Castle.Rook.Compiler / Parser / antlr / TokenStreamRewriteEngine.cs
blobec0de86cd464dff2df7e94d0d220993f73a0d07a
1 namespace antlr
3 /* ANTLR Translator Generator
4 * Project led by Terence Parr at http://www.jGuru.com
5 * Software rights: http://www.antlr.org/license.html
6 */
8 //
9 // ANTLR C# Code Generator by Micheal Jordan
10 // Kunle Odutola : kunle UNDERSCORE odutola AT hotmail DOT com
11 // Anthony Oguntimehin
14 using System;
15 using IList = System.Collections.IList;
16 using IDictionary = System.Collections.IDictionary;
17 using ArrayList = System.Collections.ArrayList;
18 using Hashtable = System.Collections.Hashtable;
19 using IComparer = System.Collections.IComparer;
20 using StringBuilder = System.Text.StringBuilder;
21 using BitSet = antlr.collections.impl.BitSet;
23 /// <summary>
24 /// This token stream tracks the *entire* token stream coming from
25 /// a lexer, but does not pass on the whitespace (or whatever else
26 /// you want to discard) to the parser.
27 /// </summary>
28 /// <remarks>
29 /// <para>
30 /// This class can then be asked for the ith token in the input stream.
31 /// Useful for dumping out the input stream exactly after doing some
32 /// augmentation or other manipulations. Tokens are index from 0..n-1
33 /// </para>
34 /// <para>
35 /// You can insert stuff, replace, and delete chunks. Note that the
36 /// operations are done lazily--only if you convert the buffer to a
37 /// string. This is very efficient because you are not moving data around
38 /// all the time. As the buffer of tokens is converted to strings, the
39 /// toString() method(s) check to see if there is an operation at the
40 /// current index. If so, the operation is done and then normal string
41 /// rendering continues on the buffer. This is like having multiple Turing
42 /// machine instruction streams (programs) operating on a single input tape. :)
43 /// </para>
44 /// <para>
45 /// Since the operations are done lazily at toString-time, operations do not
46 /// screw up the token index values. That is, an insert operation at token
47 /// index i does not change the index values for tokens i+1..n-1.
48 /// </para>
49 /// <para>
50 /// Because operations never actually alter the buffer, you may always get
51 /// the original token stream back without undoing anything. Since
52 /// the instructions are queued up, you can easily simulate transactions and
53 /// roll back any changes if there is an error just by removing instructions.
54 /// For example,
55 /// </para>
56 /// <example>For example:
57 /// <code>
58 /// TokenStreamRewriteEngine rewriteEngine = new TokenStreamRewriteEngine(lexer);
59 /// JavaRecognizer parser = new JavaRecognizer(rewriteEngine);
60 /// ...
61 /// rewriteEngine.insertAfter("pass1", t, "foobar");}
62 /// rewriteEngine.insertAfter("pass2", u, "start");}
63 /// System.Console.Out.WriteLine(rewriteEngine.ToString("pass1"));
64 /// System.Console.Out.WriteLine(rewriteEngine.ToString("pass2"));
65 /// </code>
66 /// </example>
67 /// <para>
68 /// You can also have multiple "instruction streams" and get multiple
69 /// rewrites from a single pass over the input. Just name the instruction
70 /// streams and use that name again when printing the buffer. This could be
71 /// useful for generating a C file and also its header file--all from the
72 /// same buffer.
73 /// </para>
74 /// <para>
75 /// If you don't use named rewrite streams, a "default" stream is used.
76 /// </para>
77 /// <para>
78 /// Terence Parr, parrt@cs.usfca.edu
79 /// University of San Francisco
80 /// February 2004
81 /// </para>
82 /// </remarks>
83 public class TokenStreamRewriteEngine : TokenStream
85 public const int MIN_TOKEN_INDEX = 0;
87 protected class RewriteOperation
89 protected internal int index;
90 protected internal string text;
92 protected RewriteOperation(int index, string text)
94 this.index = index;
95 this.text = text;
98 /// <summary>
99 /// Execute the rewrite operation by possibly adding to the buffer.
100 /// </summary>
101 /// <param name="buf">rewrite buffer</param>
102 /// <returns>The index of the next token to operate on.</returns>
103 public virtual int execute(StringBuilder buf)
105 return index;
109 protected class InsertBeforeOp : RewriteOperation
111 public InsertBeforeOp(int index, string text) : base(index, text)
115 public override int execute(StringBuilder buf)
117 buf.Append(text);
118 return index;
122 protected class ReplaceOp : RewriteOperation
124 protected int lastIndex;
126 public ReplaceOp(int from, int to, string text) : base(from, text)
128 lastIndex = to;
131 public override int execute(StringBuilder buf)
133 if ( text != null )
135 buf.Append(text);
137 return lastIndex+1;
141 protected class DeleteOp : ReplaceOp
143 public DeleteOp(int from, int to) : base(from, to, null)
148 public const string DEFAULT_PROGRAM_NAME = "default";
149 public const int PROGRAM_INIT_SIZE = 100;
151 /// <summary>
152 /// Track the incoming list of tokens
153 /// </summary>
154 protected IList tokens;
156 /// <summary>
157 /// You may have multiple, named streams of rewrite operations.
158 /// I'm calling these things "programs."
159 /// Maps string (name) -> rewrite (List)
160 /// </summary>
161 protected IDictionary programs = null;
163 /// <summary>
164 /// Map string (program name) -> Integer index
165 /// </summary>
166 protected IDictionary lastRewriteTokenIndexes = null;
168 /// <summary>
169 /// track index of tokens
170 /// </summary>
171 protected int index = MIN_TOKEN_INDEX;
173 /// <summary>
174 /// Who do we suck tokens from?
175 /// </summary>
176 protected TokenStream stream;
178 /// <summary>
179 /// Which (whitespace) token(s) to throw out
180 /// </summary>
181 protected BitSet discardMask = new BitSet();
183 public TokenStreamRewriteEngine(TokenStream upstream) : this(upstream, 1000)
187 public TokenStreamRewriteEngine(TokenStream upstream, int initialSize)
189 stream = upstream;
190 tokens = new ArrayList(initialSize);
191 programs = new Hashtable();
192 programs[DEFAULT_PROGRAM_NAME] = new ArrayList(PROGRAM_INIT_SIZE);
193 lastRewriteTokenIndexes = new Hashtable();
196 public IToken nextToken() // throws TokenStreamException
198 TokenWithIndex t;
200 // suck tokens until end of stream or we find a non-discarded token
203 t = (TokenWithIndex) stream.nextToken();
204 if ( t != null )
206 t.setIndex(index); // what is t's index in list?
207 if ( t.Type != Token.EOF_TYPE )
209 tokens.Add(t); // track all tokens except EOF
211 index++; // move to next position
213 } while ( (t != null) && (discardMask.member(t.Type)) );
215 return t;
218 public void rollback(int instructionIndex)
220 rollback(DEFAULT_PROGRAM_NAME, instructionIndex);
223 /// <summary>
224 /// Rollback the instruction stream for a program so that
225 /// the indicated instruction (via instructionIndex) is no
226 /// longer in the stream.
227 /// </summary>
228 /// <remarks>
229 /// UNTESTED!
230 /// </remarks>
231 /// <param name="programName"></param>
232 /// <param name="instructionIndex"></param>
233 public void rollback(string programName, int instructionIndex)
235 ArrayList il = (ArrayList) programs[programName];
236 if ( il != null )
238 programs[programName] = il.GetRange(MIN_TOKEN_INDEX, (instructionIndex - MIN_TOKEN_INDEX));
242 public void deleteProgram()
244 deleteProgram(DEFAULT_PROGRAM_NAME);
247 /// <summary>
248 /// Reset the program so that no instructions exist
249 /// </summary>
250 /// <param name="programName"></param>
251 public void deleteProgram(string programName)
253 rollback(programName, MIN_TOKEN_INDEX);
256 /// <summary>
257 /// If op.index > lastRewriteTokenIndexes, just add to the end.
258 /// Otherwise, do linear
259 /// </summary>
260 /// <param name="op"></param>
261 protected void addToSortedRewriteList(RewriteOperation op)
263 addToSortedRewriteList(DEFAULT_PROGRAM_NAME, op);
266 protected void addToSortedRewriteList(string programName, RewriteOperation op)
268 ArrayList rewrites = (ArrayList) getProgram(programName);
269 // if at or beyond last op's index, just append
270 if ( op.index >= getLastRewriteTokenIndex(programName) )
272 rewrites.Add(op); // append to list of operations
273 // record the index of this operation for next time through
274 setLastRewriteTokenIndex(programName, op.index);
275 return;
277 // not after the last one, so must insert to ordered list
278 int pos = rewrites.BinarySearch(op, RewriteOperationComparer.Default);
279 if (pos < 0)
281 rewrites.Insert(-pos-1, op);
285 public void insertAfter(IToken t, string text)
287 insertAfter(DEFAULT_PROGRAM_NAME, t, text);
290 public void insertAfter(int index, string text)
292 insertAfter(DEFAULT_PROGRAM_NAME, index, text);
295 public void insertAfter(string programName, IToken t, string text)
297 insertAfter(programName,((TokenWithIndex) t).getIndex(), text);
300 public void insertAfter(string programName, int index, string text)
302 // to insert after, just insert before next index (even if past end)
303 insertBefore(programName, index+1, text);
306 public void insertBefore(IToken t, string text)
308 insertBefore(DEFAULT_PROGRAM_NAME, t, text);
311 public void insertBefore(int index, string text)
313 insertBefore(DEFAULT_PROGRAM_NAME, index, text);
316 public void insertBefore(string programName, IToken t, string text)
318 insertBefore(programName, ((TokenWithIndex) t).getIndex(), text);
321 public void insertBefore(string programName, int index, string text)
323 addToSortedRewriteList(programName, new InsertBeforeOp(index, text));
326 public void replace(int index, string text)
328 replace(DEFAULT_PROGRAM_NAME, index, index, text);
331 public void replace(int from, int to, string text)
333 replace(DEFAULT_PROGRAM_NAME, from, to, text);
336 public void replace(IToken indexT, string text)
338 replace(DEFAULT_PROGRAM_NAME, indexT, indexT, text);
341 public void replace(IToken from, IToken to, string text)
343 replace(DEFAULT_PROGRAM_NAME, from, to, text);
346 public void replace(string programName, int from, int to, string text)
348 addToSortedRewriteList(new ReplaceOp(from, to, text));
351 public void replace(string programName, IToken from, IToken to, string text)
353 replace(programName,
354 ((TokenWithIndex) from).getIndex(),
355 ((TokenWithIndex) to).getIndex(),
356 text);
359 public void delete(int index)
361 delete(DEFAULT_PROGRAM_NAME, index, index);
364 public void delete(int from, int to)
366 delete(DEFAULT_PROGRAM_NAME, from, to);
369 public void delete(IToken indexT)
371 delete(DEFAULT_PROGRAM_NAME, indexT, indexT);
374 public void delete(IToken from, IToken to)
376 delete(DEFAULT_PROGRAM_NAME, from, to);
379 public void delete(string programName, int from, int to)
381 replace(programName, from, to, null);
384 public void delete(string programName, IToken from, IToken to)
386 replace(programName, from, to, null);
389 public void discard(int ttype)
391 discardMask.add(ttype);
394 public TokenWithIndex getToken(int i)
396 return (TokenWithIndex) tokens[i];
399 public int getTokenStreamSize()
401 return tokens.Count;
404 public string ToOriginalString()
406 return ToOriginalString(MIN_TOKEN_INDEX, getTokenStreamSize()-1);
409 public string ToOriginalString(int start, int end)
411 StringBuilder buf = new StringBuilder();
412 for (int i = start; (i >= MIN_TOKEN_INDEX) && (i <= end) && (i < tokens.Count); i++)
414 buf.Append(getToken(i).getText());
416 return buf.ToString();
419 public override string ToString()
421 return ToString(MIN_TOKEN_INDEX, getTokenStreamSize());
424 public string ToString(string programName)
426 return ToString(programName, MIN_TOKEN_INDEX, getTokenStreamSize());
429 public string ToString(int start, int end)
431 return ToString(DEFAULT_PROGRAM_NAME, start, end);
434 public string ToString(string programName, int start, int end)
436 IList rewrites = (IList) programs[programName];
437 if (rewrites == null)
439 return null; // invalid program
441 StringBuilder buf = new StringBuilder();
443 // Index of first rewrite we have not done
444 int rewriteOpIndex = 0;
446 int tokenCursor = start;
447 while ( (tokenCursor >= MIN_TOKEN_INDEX) &&
448 (tokenCursor <= end) &&
449 (tokenCursor < tokens.Count) )
451 if (rewriteOpIndex < rewrites.Count)
453 RewriteOperation op = (RewriteOperation) rewrites[rewriteOpIndex];
454 while ( (tokenCursor == op.index) && (rewriteOpIndex < rewrites.Count) )
457 Console.Out.WriteLine("execute op "+rewriteOpIndex+
458 " (type "+op.GetType().FullName+")"
459 +" at index "+op.index);
461 tokenCursor = op.execute(buf);
462 rewriteOpIndex++;
463 if (rewriteOpIndex < rewrites.Count)
465 op = (RewriteOperation) rewrites[rewriteOpIndex];
469 if ( tokenCursor < end )
471 buf.Append(getToken(tokenCursor).getText());
472 tokenCursor++;
475 // now see if there are operations (append) beyond last token index
476 for (int opi = rewriteOpIndex; opi < rewrites.Count; opi++)
478 RewriteOperation op = (RewriteOperation) rewrites[opi];
479 op.execute(buf); // must be insertions if after last token
482 return buf.ToString();
485 public string ToDebugString()
487 return ToDebugString(MIN_TOKEN_INDEX, getTokenStreamSize());
490 public string ToDebugString(int start, int end)
492 StringBuilder buf = new StringBuilder();
493 for (int i = start; (i >= MIN_TOKEN_INDEX) && (i <= end) && (i < tokens.Count); i++)
495 buf.Append(getToken(i));
497 return buf.ToString();
500 public int getLastRewriteTokenIndex()
502 return getLastRewriteTokenIndex(DEFAULT_PROGRAM_NAME);
505 protected int getLastRewriteTokenIndex(string programName)
507 object i = lastRewriteTokenIndexes[programName];
508 if (i == null)
510 return -1;
512 return (int) i;
515 protected void setLastRewriteTokenIndex(string programName, int i)
517 lastRewriteTokenIndexes[programName] = (object) i;
520 protected IList getProgram(string name)
522 IList il = (IList) programs[name];
523 if ( il == null )
525 il = initializeProgram(name);
527 return il;
530 private IList initializeProgram(string name)
532 IList il = new ArrayList(PROGRAM_INIT_SIZE);
533 programs[name] = il;
534 return il;
537 public class RewriteOperationComparer : IComparer
539 public static readonly RewriteOperationComparer Default = new RewriteOperationComparer();
541 public virtual int Compare(object o1, object o2)
543 RewriteOperation rop1 = (RewriteOperation) o1;
544 RewriteOperation rop2 = (RewriteOperation) o2;
546 if (rop1.index < rop2.index) return -1;
547 if (rop1.index > rop2.index) return 1;
548 return 0;