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<String, Integer> 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<Integer, List> 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<Integer token type,ArrayList<Integer stream index>> 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<Integertoken type,Map<Object tree node,Integer stream index>> 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