• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * [The "BSD licence"]
3  * Copyright (c) 2005-2008 Terence Parr
4  * All rights reserved.
5  *
6  * Conversion to C#:
7  * Copyright (c) 2008-2009 Sam Harwell, Pixel Mine, Inc.
8  * All rights reserved.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. The name of the author may not be used to endorse or promote products
19  *    derived from this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32 
33 // TODO: build indexes for wizard
34 //#define BUILD_INDEXES
35 
36 namespace Antlr.Runtime.Tree
37 {
38     using System.Collections.Generic;
39 
40     using IList = System.Collections.IList;
41 #if BUILD_INDEXES
42     using IDictionary = System.Collections.IDictionary;
43 #endif
44 
45     /** <summary>
46      *  Build and navigate trees with this object.  Must know about the names
47      *  of tokens so you have to pass in a map or array of token names (from which
48      *  this class can build the map).  I.e., Token DECL means nothing unless the
49      *  class can translate it to a token type.
50      *  </summary>
51      *
52      *  <remarks>
53      *  In order to create nodes and navigate, this class needs a TreeAdaptor.
54      *
55      *  This class can build a token type -> node index for repeated use or for
56      *  iterating over the various nodes with a particular type.
57      *
58      *  This class works in conjunction with the TreeAdaptor rather than moving
59      *  all this functionality into the adaptor.  An adaptor helps build and
60      *  navigate trees using methods.  This class helps you do it with string
61      *  patterns like "(A B C)".  You can create a tree from that pattern or
62      *  match subtrees against it.
63      *  </remarks>
64      */
65     public class TreeWizard
66     {
67         protected ITreeAdaptor adaptor;
68         protected IDictionary<string, int> tokenNameToTypeMap;
69 
70         public interface IContextVisitor
71         {
72             // TODO: should this be called visit or something else?
Visit( object t, object parent, int childIndex, IDictionary<string, object> labels )73             void Visit( object t, object parent, int childIndex, IDictionary<string, object> labels );
74         }
75 
76         public abstract class Visitor : IContextVisitor
77         {
Visit( object t, object parent, int childIndex, IDictionary<string, object> labels )78             public virtual void Visit( object t, object parent, int childIndex, IDictionary<string, object> labels )
79             {
80                 Visit( t );
81             }
Visit( object t )82             public abstract void Visit( object t );
83         }
84 
85         class ActionVisitor : Visitor
86         {
87             System.Action<object> _action;
88 
ActionVisitor( System.Action<object> action )89             public ActionVisitor( System.Action<object> action )
90             {
91                 _action = action;
92             }
93 
Visit( object t )94             public override void Visit( object t )
95             {
96                 _action( t );
97             }
98         }
99 
100         /** <summary>
101          *  When using %label:TOKENNAME in a tree for parse(), we must
102          *  track the label.
103          *  </summary>
104          */
105         public class TreePattern : CommonTree
106         {
107             public string label;
108             public bool hasTextArg;
TreePattern( IToken payload )109             public TreePattern( IToken payload ) :
110                 base( payload )
111             {
112             }
ToString()113             public override string ToString()
114             {
115                 if ( label != null )
116                 {
117                     return "%" + label + ":"; //+ base.ToString();
118                 }
119                 else
120                 {
121                     return base.ToString();
122                 }
123             }
124         }
125 
126         public class WildcardTreePattern : TreePattern
127         {
WildcardTreePattern( IToken payload )128             public WildcardTreePattern( IToken payload ) :
129                 base( payload )
130             {
131             }
132         }
133 
134         /** <summary>This adaptor creates TreePattern objects for use during scan()</summary> */
135         public class TreePatternTreeAdaptor : CommonTreeAdaptor
136         {
Create( IToken payload )137             public override object Create( IToken payload )
138             {
139                 return new TreePattern( payload );
140             }
141         }
142 
143 #if BUILD_INDEXES
144         // TODO: build indexes for the wizard
145 
146         /** <summary>
147          *  During fillBuffer(), we can make a reverse index from a set
148          *  of token types of interest to the list of indexes into the
149          *  node stream.  This lets us convert a node pointer to a
150          *  stream index semi-efficiently for a list of interesting
151          *  nodes such as function definition nodes (you'll want to seek
152          *  to their bodies for an interpreter).  Also useful for doing
153          *  dynamic searches; i.e., go find me all PLUS nodes.
154          *  </summary>
155          */
156         protected IDictionary<int, IList<int>> tokenTypeToStreamIndexesMap;
157 
158         /** <summary>
159          *  If tokenTypesToReverseIndex set to INDEX_ALL then indexing
160          *  occurs for all token types.
161          *  </summary>
162          */
163         public static readonly HashSet<int> INDEX_ALL = new HashSet<int>();
164 
165         /** <summary>
166          *  A set of token types user would like to index for faster lookup.
167          *  If this is INDEX_ALL, then all token types are tracked.  If null,
168          *  then none are indexed.
169          *  </summary>
170          */
171         protected HashSet<int> tokenTypesToReverseIndex = null;
172 #endif
173 
TreeWizard( ITreeAdaptor adaptor )174         public TreeWizard( ITreeAdaptor adaptor )
175         {
176             this.adaptor = adaptor;
177         }
178 
TreeWizard( ITreeAdaptor adaptor, IDictionary<string, int> tokenNameToTypeMap )179         public TreeWizard( ITreeAdaptor adaptor, IDictionary<string, int> tokenNameToTypeMap )
180         {
181             this.adaptor = adaptor;
182             this.tokenNameToTypeMap = tokenNameToTypeMap;
183         }
184 
TreeWizard( ITreeAdaptor adaptor, string[] tokenNames )185         public TreeWizard( ITreeAdaptor adaptor, string[] tokenNames )
186         {
187             this.adaptor = adaptor;
188             this.tokenNameToTypeMap = ComputeTokenTypes( tokenNames );
189         }
190 
TreeWizard( string[] tokenNames )191         public TreeWizard( string[] tokenNames )
192             : this( new CommonTreeAdaptor(), tokenNames )
193         {
194         }
195 
196         /** <summary>
197          *  Compute a Map&lt;String, Integer&gt; that is an inverted index of
198          *  tokenNames (which maps int token types to names).
199          *  </summary>
200          */
ComputeTokenTypes( string[] tokenNames )201         public virtual IDictionary<string, int> ComputeTokenTypes( string[] tokenNames )
202         {
203             IDictionary<string, int> m = new Dictionary<string, int>();
204             if ( tokenNames == null )
205             {
206                 return m;
207             }
208             for ( int ttype = TokenTypes.Min; ttype < tokenNames.Length; ttype++ )
209             {
210                 string name = tokenNames[ttype];
211                 m[name] = ttype;
212             }
213             return m;
214         }
215 
216         /** <summary>Using the map of token names to token types, return the type.</summary> */
GetTokenType( string tokenName )217         public virtual int GetTokenType( string tokenName )
218         {
219             if ( tokenNameToTypeMap == null )
220             {
221                 return TokenTypes.Invalid;
222             }
223 
224             int value;
225             if ( tokenNameToTypeMap.TryGetValue( tokenName, out value ) )
226                 return value;
227 
228             return TokenTypes.Invalid;
229         }
230 
231         /** <summary>
232          *  Walk the entire tree and make a node name to nodes mapping.
233          *  For now, use recursion but later nonrecursive version may be
234          *  more efficient.  Returns Map&lt;Integer, List&gt; where the List is
235          *  of your AST node type.  The Integer is the token type of the node.
236          *  </summary>
237          *
238          *  <remarks>
239          *  TODO: save this index so that find and visit are faster
240          *  </remarks>
241          */
Index( object t )242         public IDictionary<int, IList> Index( object t )
243         {
244             IDictionary<int, IList> m = new Dictionary<int, IList>();
245             IndexCore( t, m );
246             return m;
247         }
248 
249         /** <summary>Do the work for index</summary> */
IndexCore( object t, IDictionary<int, IList> m )250         protected virtual void IndexCore( object t, IDictionary<int, IList> m )
251         {
252             if ( t == null )
253             {
254                 return;
255             }
256             int ttype = adaptor.GetType( t );
257             IList elements;
258             if ( !m.TryGetValue( ttype, out elements ) || elements == null )
259             {
260                 elements = new List<object>();
261                 m[ttype] = elements;
262             }
263             elements.Add( t );
264             int n = adaptor.GetChildCount( t );
265             for ( int i = 0; i < n; i++ )
266             {
267                 object child = adaptor.GetChild( t, i );
268                 IndexCore( child, m );
269             }
270         }
271 
272         class FindTreeWizardVisitor : TreeWizard.Visitor
273         {
274             IList _nodes;
FindTreeWizardVisitor( IList nodes )275             public FindTreeWizardVisitor( IList nodes )
276             {
277                 _nodes = nodes;
278             }
Visit( object t )279             public override void Visit( object t )
280             {
281                 _nodes.Add( t );
282             }
283         }
284         class FindTreeWizardContextVisitor : TreeWizard.IContextVisitor
285         {
286             TreeWizard _outer;
287             TreePattern _tpattern;
288             IList _subtrees;
FindTreeWizardContextVisitor( TreeWizard outer, TreePattern tpattern, IList subtrees )289             public FindTreeWizardContextVisitor( TreeWizard outer, TreePattern tpattern, IList subtrees )
290             {
291                 _outer = outer;
292                 _tpattern = tpattern;
293                 _subtrees = subtrees;
294             }
295 
Visit( object t, object parent, int childIndex, IDictionary<string, object> labels )296             public void Visit( object t, object parent, int childIndex, IDictionary<string, object> labels )
297             {
298                 if ( _outer.ParseCore( t, _tpattern, null ) )
299                 {
300                     _subtrees.Add( t );
301                 }
302             }
303         }
304 
305         /** <summary>Return a List of tree nodes with token type ttype</summary> */
Find( object t, int ttype )306         public virtual IList Find( object t, int ttype )
307         {
308             IList nodes = new List<object>();
309             Visit( t, ttype, new FindTreeWizardVisitor( nodes ) );
310             return nodes;
311         }
312 
313         /** <summary>Return a List of subtrees matching pattern.</summary> */
Find( object t, string pattern )314         public virtual IList Find( object t, string pattern )
315         {
316             IList subtrees = new List<object>();
317             // Create a TreePattern from the pattern
318             TreePatternLexer tokenizer = new TreePatternLexer( pattern );
319             TreePatternParser parser =
320                 new TreePatternParser( tokenizer, this, new TreePatternTreeAdaptor() );
321             TreePattern tpattern = (TreePattern)parser.Pattern();
322             // don't allow invalid patterns
323             if ( tpattern == null ||
324                  tpattern.IsNil ||
325                  tpattern.GetType() == typeof( WildcardTreePattern ) )
326             {
327                 return null;
328             }
329             int rootTokenType = tpattern.Type;
330             Visit( t, rootTokenType, new FindTreeWizardContextVisitor( this, tpattern, subtrees ) );
331             return subtrees;
332         }
333 
FindFirst( object t, int ttype )334         public virtual object FindFirst( object t, int ttype )
335         {
336             return null;
337         }
338 
FindFirst( object t, string pattern )339         public virtual object FindFirst( object t, string pattern )
340         {
341             return null;
342         }
343 
344         /** <summary>
345          *  Visit every ttype node in t, invoking the visitor.  This is a quicker
346          *  version of the general visit(t, pattern) method.  The labels arg
347          *  of the visitor action method is never set (it's null) since using
348          *  a token type rather than a pattern doesn't let us set a label.
349          *  </summary>
350          */
Visit( object t, int ttype, IContextVisitor visitor )351         public void Visit( object t, int ttype, IContextVisitor visitor )
352         {
353             VisitCore( t, null, 0, ttype, visitor );
354         }
355 
Visit( object t, int ttype, System.Action<object> action )356         public void Visit( object t, int ttype, System.Action<object> action )
357         {
358             Visit( t, ttype, new ActionVisitor( action ) );
359         }
360 
361         /** <summary>Do the recursive work for visit</summary> */
VisitCore( object t, object parent, int childIndex, int ttype, IContextVisitor visitor )362         protected virtual void VisitCore( object t, object parent, int childIndex, int ttype, IContextVisitor visitor )
363         {
364             if ( t == null )
365             {
366                 return;
367             }
368             if ( adaptor.GetType( t ) == ttype )
369             {
370                 visitor.Visit( t, parent, childIndex, null );
371             }
372             int n = adaptor.GetChildCount( t );
373             for ( int i = 0; i < n; i++ )
374             {
375                 object child = adaptor.GetChild( t, i );
376                 VisitCore( child, t, i, ttype, visitor );
377             }
378         }
379 
380         class VisitTreeWizardContextVisitor : TreeWizard.IContextVisitor
381         {
382             TreeWizard _outer;
383             IContextVisitor _visitor;
384             IDictionary<string, object> _labels;
385             TreePattern _tpattern;
386 
VisitTreeWizardContextVisitor( TreeWizard outer, IContextVisitor visitor, IDictionary<string, object> labels, TreePattern tpattern )387             public VisitTreeWizardContextVisitor( TreeWizard outer, IContextVisitor visitor, IDictionary<string, object> labels, TreePattern tpattern )
388             {
389                 _outer = outer;
390                 _visitor = visitor;
391                 _labels = labels;
392                 _tpattern = tpattern;
393             }
394 
Visit( object t, object parent, int childIndex, IDictionary<string, object> unusedlabels )395             public void Visit( object t, object parent, int childIndex, IDictionary<string, object> unusedlabels )
396             {
397                 // the unusedlabels arg is null as visit on token type doesn't set.
398                 _labels.Clear();
399                 if ( _outer.ParseCore( t, _tpattern, _labels ) )
400                 {
401                     _visitor.Visit( t, parent, childIndex, _labels );
402                 }
403             }
404         }
405 
406         /** <summary>
407          *  For all subtrees that match the pattern, execute the visit action.
408          *  The implementation uses the root node of the pattern in combination
409          *  with visit(t, ttype, visitor) so nil-rooted patterns are not allowed.
410          *  Patterns with wildcard roots are also not allowed.
411          *  </summary>
412          */
Visit( object t, string pattern, IContextVisitor visitor )413         public void Visit( object t, string pattern, IContextVisitor visitor )
414         {
415             // Create a TreePattern from the pattern
416             TreePatternLexer tokenizer = new TreePatternLexer( pattern );
417             TreePatternParser parser =
418                 new TreePatternParser( tokenizer, this, new TreePatternTreeAdaptor() );
419             TreePattern tpattern = (TreePattern)parser.Pattern();
420             // don't allow invalid patterns
421             if ( tpattern == null ||
422                  tpattern.IsNil ||
423                  tpattern.GetType() == typeof( WildcardTreePattern ) )
424             {
425                 return;
426             }
427             IDictionary<string, object> labels = new Dictionary<string, object>(); // reused for each _parse
428             int rootTokenType = tpattern.Type;
429             Visit( t, rootTokenType, new VisitTreeWizardContextVisitor( this, visitor, labels, tpattern ) );
430         }
431 
432         /** <summary>
433          *  Given a pattern like (ASSIGN %lhs:ID %rhs:.) with optional labels
434          *  on the various nodes and '.' (dot) as the node/subtree wildcard,
435          *  return true if the pattern matches and fill the labels Map with
436          *  the labels pointing at the appropriate nodes.  Return false if
437          *  the pattern is malformed or the tree does not match.
438          *  </summary>
439          *
440          *  <remarks>
441          *  If a node specifies a text arg in pattern, then that must match
442          *  for that node in t.
443          *
444          *  TODO: what's a better way to indicate bad pattern? Exceptions are a hassle
445          *  </remarks>
446          */
Parse( object t, string pattern, IDictionary<string, object> labels )447         public bool Parse( object t, string pattern, IDictionary<string, object> labels )
448         {
449             TreePatternLexer tokenizer = new TreePatternLexer( pattern );
450             TreePatternParser parser =
451                 new TreePatternParser( tokenizer, this, new TreePatternTreeAdaptor() );
452             TreePattern tpattern = (TreePattern)parser.Pattern();
453             /*
454             System.out.println("t="+((Tree)t).toStringTree());
455             System.out.println("scant="+tpattern.toStringTree());
456             */
457             bool matched = ParseCore( t, tpattern, labels );
458             return matched;
459         }
460 
Parse( object t, string pattern )461         public bool Parse( object t, string pattern )
462         {
463             return Parse( t, pattern, null );
464         }
465 
466         /** <summary>
467          *  Do the work for parse. Check to see if the t2 pattern fits the
468          *  structure and token types in t1.  Check text if the pattern has
469          *  text arguments on nodes.  Fill labels map with pointers to nodes
470          *  in tree matched against nodes in pattern with labels.
471          *  </summary>
472          */
ParseCore( object t1, TreePattern tpattern, IDictionary<string, object> labels )473         protected virtual bool ParseCore( object t1, TreePattern tpattern, IDictionary<string, object> labels )
474         {
475             // make sure both are non-null
476             if ( t1 == null || tpattern == null )
477             {
478                 return false;
479             }
480             // check roots (wildcard matches anything)
481             if ( tpattern.GetType() != typeof( WildcardTreePattern ) )
482             {
483                 if ( adaptor.GetType( t1 ) != tpattern.Type )
484                 {
485                     return false;
486                 }
487                 // if pattern has text, check node text
488                 if ( tpattern.hasTextArg && !adaptor.GetText( t1 ).Equals( tpattern.Text ) )
489                 {
490                     return false;
491                 }
492             }
493             if ( tpattern.label != null && labels != null )
494             {
495                 // map label in pattern to node in t1
496                 labels[tpattern.label] = t1;
497             }
498             // check children
499             int n1 = adaptor.GetChildCount( t1 );
500             int n2 = tpattern.ChildCount;
501             if ( n1 != n2 )
502             {
503                 return false;
504             }
505             for ( int i = 0; i < n1; i++ )
506             {
507                 object child1 = adaptor.GetChild( t1, i );
508                 TreePattern child2 = (TreePattern)tpattern.GetChild( i );
509                 if ( !ParseCore( child1, child2, labels ) )
510                 {
511                     return false;
512                 }
513             }
514             return true;
515         }
516 
517         /** <summary>
518          *  Create a tree or node from the indicated tree pattern that closely
519          *  follows ANTLR tree grammar tree element syntax:
520          *
521          *      (root child1 ... child2).
522          *  </summary>
523          *
524          *  <remarks>
525          *  You can also just pass in a node: ID
526          *
527          *  Any node can have a text argument: ID[foo]
528          *  (notice there are no quotes around foo--it's clear it's a string).
529          *
530          *  nil is a special name meaning "give me a nil node".  Useful for
531          *  making lists: (nil A B C) is a list of A B C.
532          *  </remarks>
533          */
Create( string pattern )534         public virtual object Create( string pattern )
535         {
536             TreePatternLexer tokenizer = new TreePatternLexer( pattern );
537             TreePatternParser parser = new TreePatternParser( tokenizer, this, adaptor );
538             object t = parser.Pattern();
539             return t;
540         }
541 
542         /** <summary>
543          *  Compare t1 and t2; return true if token types/text, structure match exactly.
544          *  The trees are examined in their entirety so that (A B) does not match
545          *  (A B C) nor (A (B C)).
546          *  </summary>
547          *
548          *  <remarks>
549          *  TODO: allow them to pass in a comparator
550          *  TODO: have a version that is nonstatic so it can use instance adaptor
551          *
552          *  I cannot rely on the tree node's equals() implementation as I make
553          *  no constraints at all on the node types nor interface etc...
554          *  </remarks>
555          */
Equals( object t1, object t2, ITreeAdaptor adaptor )556         public static bool Equals( object t1, object t2, ITreeAdaptor adaptor )
557         {
558             return EqualsCore( t1, t2, adaptor );
559         }
560 
561         /** <summary>
562          *  Compare type, structure, and text of two trees, assuming adaptor in
563          *  this instance of a TreeWizard.
564          *  </summary>
565          */
Equals( object t1, object t2 )566         public new bool Equals( object t1, object t2 )
567         {
568             return EqualsCore( t1, t2, adaptor );
569         }
570 
EqualsCore( object t1, object t2, ITreeAdaptor adaptor )571         protected static bool EqualsCore( object t1, object t2, ITreeAdaptor adaptor )
572         {
573             // make sure both are non-null
574             if ( t1 == null || t2 == null )
575             {
576                 return false;
577             }
578             // check roots
579             if ( adaptor.GetType( t1 ) != adaptor.GetType( t2 ) )
580             {
581                 return false;
582             }
583             if ( !adaptor.GetText( t1 ).Equals( adaptor.GetText( t2 ) ) )
584             {
585                 return false;
586             }
587             // check children
588             int n1 = adaptor.GetChildCount( t1 );
589             int n2 = adaptor.GetChildCount( t2 );
590             if ( n1 != n2 )
591             {
592                 return false;
593             }
594             for ( int i = 0; i < n1; i++ )
595             {
596                 object child1 = adaptor.GetChild( t1, i );
597                 object child2 = adaptor.GetChild( t2, i );
598                 if ( !EqualsCore( child1, child2, adaptor ) )
599                 {
600                     return false;
601                 }
602             }
603             return true;
604         }
605 
606 #if BUILD_INDEXES
607         // TODO: next stuff taken from CommonTreeNodeStream
608 
609         /** <summary>
610          *  Given a node, add this to the reverse index tokenTypeToStreamIndexesMap.
611          *  You can override this method to alter how indexing occurs.  The
612          *  default is to create a
613          *
614          *    Map&lt;Integer token type,ArrayList&lt;Integer stream index&gt;&gt;
615          *  </summary>
616          *
617          *  <remarks>
618          *  This data structure allows you to find all nodes with type INT in order.
619          *
620          *  If you really need to find a node of type, say, FUNC quickly then perhaps
621          *
622          *    Map&lt;Integertoken type,Map&lt;Object tree node,Integer stream index&gt;&gt;
623          *
624          *  would be better for you.  The interior maps map a tree node to
625          *  the index so you don't have to search linearly for a specific node.
626          *
627          *  If you change this method, you will likely need to change
628          *  getNodeIndex(), which extracts information.
629          *  </remarks>
630          */
fillReverseIndex( object node, int streamIndex )631         protected void fillReverseIndex( object node, int streamIndex )
632         {
633             //System.out.println("revIndex "+node+"@"+streamIndex);
634             if ( tokenTypesToReverseIndex == null )
635             {
636                 return; // no indexing if this is empty (nothing of interest)
637             }
638             if ( tokenTypeToStreamIndexesMap == null )
639             {
640                 tokenTypeToStreamIndexesMap = new Dictionary<int, IList<int>>(); // first indexing op
641             }
642             int tokenType = adaptor.getType( node );
643             if ( !( tokenTypesToReverseIndex == INDEX_ALL ||
644                    tokenTypesToReverseIndex.Contains( tokenType ) ) )
645             {
646                 return; // tokenType not of interest
647             }
648             IList<int> indexes;
649 
650             if ( !tokenTypeToStreamIndexesMap.TryGetValue( tokenType, out indexes ) || indexes == null )
651             {
652                 indexes = new List<int>(); // no list yet for this token type
653                 indexes.Add( streamIndex ); // not there yet, add
654                 tokenTypeToStreamIndexesMap[tokenType] = indexes;
655             }
656             else
657             {
658                 if ( !indexes.Contains( streamIndex ) )
659                 {
660                     indexes.Add( streamIndex ); // not there yet, add
661                 }
662             }
663         }
664 
665         /** <summary>
666          *  Track the indicated token type in the reverse index.  Call this
667          *  repeatedly for each type or use variant with Set argument to
668          *  set all at once.
669          *  </summary>
670          *
671          *  <param name="tokenType" />
672          */
reverseIndex( int tokenType )673         public void reverseIndex( int tokenType )
674         {
675             if ( tokenTypesToReverseIndex == null )
676             {
677                 tokenTypesToReverseIndex = new HashSet<int>();
678             }
679             else if ( tokenTypesToReverseIndex == INDEX_ALL )
680             {
681                 return;
682             }
683             tokenTypesToReverseIndex.add( tokenType );
684         }
685 
686         /** <summary>
687          *  Track the indicated token types in the reverse index. Set
688          *  to INDEX_ALL to track all token types.
689          *  </summary>
690          */
reverseIndex( HashSet<int> tokenTypes )691         public void reverseIndex( HashSet<int> tokenTypes )
692         {
693             tokenTypesToReverseIndex = tokenTypes;
694         }
695 
696         /** <summary>
697          *  Given a node pointer, return its index into the node stream.
698          *  This is not its Token stream index.  If there is no reverse map
699          *  from node to stream index or the map does not contain entries
700          *  for node's token type, a linear search of entire stream is used.
701          *  </summary>
702          *
703          *  <remarks>
704          *  Return -1 if exact node pointer not in stream.
705          *  </remarks>
706          */
getNodeIndex( object node )707         public int getNodeIndex( object node )
708         {
709             //System.out.println("get "+node);
710             if ( tokenTypeToStreamIndexesMap == null )
711             {
712                 return getNodeIndexLinearly( node );
713             }
714             int tokenType = adaptor.getType( node );
715             IList<int> indexes;
716             if ( !tokenTypeToStreamIndexesMap.TryGetValue( tokenType, out indexes ) || indexes == null )
717             {
718                 //System.out.println("found linearly; stream index = "+getNodeIndexLinearly(node));
719                 return getNodeIndexLinearly( node );
720             }
721             for ( int i = 0; i < indexes.size(); i++ )
722             {
723                 int streamIndex = indexes[i];
724                 object n = get( streamIndex );
725                 if ( n == node )
726                 {
727                     //System.out.println("found in index; stream index = "+streamIndexI);
728                     return streamIndex; // found it!
729                 }
730             }
731             return -1;
732         }
733 #endif
734 
735     }
736 }
737