PageRenderTime 47ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 1ms

/antlr-3.4/runtime/CSharp2/Sources/Antlr3.Runtime/Antlr.Runtime.Tree/TreeWizard.cs

https://bitbucket.org/cyanogenmod/android_external_antlr
C# | 659 lines | 363 code | 53 blank | 243 comment | 80 complexity | 433c1154da1214897f916241c5186ecd MD5 | raw file
  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. // TODO: build indexes for wizard
  33. //#define BUILD_INDEXES
  34. namespace Antlr.Runtime.Tree {
  35. using System.Collections.Generic;
  36. using IList = System.Collections.IList;
  37. #if BUILD_INDEXES
  38. using IDictionary = System.Collections.IDictionary;
  39. #endif
  40. /** <summary>
  41. * Build and navigate trees with this object. Must know about the names
  42. * of tokens so you have to pass in a map or array of token names (from which
  43. * this class can build the map). I.e., Token DECL means nothing unless the
  44. * class can translate it to a token type.
  45. * </summary>
  46. *
  47. * <remarks>
  48. * In order to create nodes and navigate, this class needs a TreeAdaptor.
  49. *
  50. * This class can build a token type -> node index for repeated use or for
  51. * iterating over the various nodes with a particular type.
  52. *
  53. * This class works in conjunction with the TreeAdaptor rather than moving
  54. * all this functionality into the adaptor. An adaptor helps build and
  55. * navigate trees using methods. This class helps you do it with string
  56. * patterns like "(A B C)". You can create a tree from that pattern or
  57. * match subtrees against it.
  58. * </remarks>
  59. */
  60. public class TreeWizard {
  61. protected ITreeAdaptor adaptor;
  62. protected IDictionary<string, int> tokenNameToTypeMap;
  63. public interface IContextVisitor {
  64. // TODO: should this be called visit or something else?
  65. void Visit(object t, object parent, int childIndex, IDictionary<string, object> labels);
  66. }
  67. public abstract class Visitor : IContextVisitor {
  68. public virtual void Visit(object t, object parent, int childIndex, IDictionary<string, object> labels) {
  69. Visit(t);
  70. }
  71. public abstract void Visit(object t);
  72. }
  73. class ActionVisitor : Visitor {
  74. System.Action<object> _action;
  75. public ActionVisitor(System.Action<object> action) {
  76. _action = action;
  77. }
  78. public override void Visit(object t) {
  79. _action(t);
  80. }
  81. }
  82. /** <summary>
  83. * When using %label:TOKENNAME in a tree for parse(), we must
  84. * track the label.
  85. * </summary>
  86. */
  87. public class TreePattern : CommonTree {
  88. public string label;
  89. public bool hasTextArg;
  90. public TreePattern(IToken payload) :
  91. base(payload) {
  92. }
  93. public override string ToString() {
  94. if (label != null) {
  95. return "%" + label + ":"; //+ base.ToString();
  96. } else {
  97. return base.ToString();
  98. }
  99. }
  100. }
  101. public class WildcardTreePattern : TreePattern {
  102. public WildcardTreePattern(IToken payload) :
  103. base(payload) {
  104. }
  105. }
  106. /** <summary>This adaptor creates TreePattern objects for use during scan()</summary> */
  107. public class TreePatternTreeAdaptor : CommonTreeAdaptor {
  108. public override object Create(IToken payload) {
  109. return new TreePattern(payload);
  110. }
  111. }
  112. #if BUILD_INDEXES
  113. // TODO: build indexes for the wizard
  114. /** <summary>
  115. * During fillBuffer(), we can make a reverse index from a set
  116. * of token types of interest to the list of indexes into the
  117. * node stream. This lets us convert a node pointer to a
  118. * stream index semi-efficiently for a list of interesting
  119. * nodes such as function definition nodes (you'll want to seek
  120. * to their bodies for an interpreter). Also useful for doing
  121. * dynamic searches; i.e., go find me all PLUS nodes.
  122. * </summary>
  123. */
  124. protected IDictionary<int, IList<int>> tokenTypeToStreamIndexesMap;
  125. /** <summary>
  126. * If tokenTypesToReverseIndex set to INDEX_ALL then indexing
  127. * occurs for all token types.
  128. * </summary>
  129. */
  130. public static readonly HashSet<int> INDEX_ALL = new HashSet<int>();
  131. /** <summary>
  132. * A set of token types user would like to index for faster lookup.
  133. * If this is INDEX_ALL, then all token types are tracked. If null,
  134. * then none are indexed.
  135. * </summary>
  136. */
  137. protected HashSet<int> tokenTypesToReverseIndex = null;
  138. #endif
  139. public TreeWizard(ITreeAdaptor adaptor) {
  140. this.adaptor = adaptor;
  141. }
  142. public TreeWizard(ITreeAdaptor adaptor, IDictionary<string, int> tokenNameToTypeMap) {
  143. this.adaptor = adaptor;
  144. this.tokenNameToTypeMap = tokenNameToTypeMap;
  145. }
  146. public TreeWizard(ITreeAdaptor adaptor, string[] tokenNames) {
  147. this.adaptor = adaptor;
  148. this.tokenNameToTypeMap = ComputeTokenTypes(tokenNames);
  149. }
  150. public TreeWizard(string[] tokenNames) :
  151. this(null, tokenNames) {
  152. }
  153. /** <summary>
  154. * Compute a Map&lt;String, Integer&gt; that is an inverted index of
  155. * tokenNames (which maps int token types to names).
  156. * </summary>
  157. */
  158. public virtual IDictionary<string, int> ComputeTokenTypes(string[] tokenNames) {
  159. IDictionary<string, int> m = new Dictionary<string, int>();
  160. if (tokenNames == null) {
  161. return m;
  162. }
  163. for (int ttype = TokenTypes.Min; ttype < tokenNames.Length; ttype++) {
  164. string name = tokenNames[ttype];
  165. m[name] = ttype;
  166. }
  167. return m;
  168. }
  169. /** <summary>Using the map of token names to token types, return the type.</summary> */
  170. public virtual int GetTokenType(string tokenName) {
  171. if (tokenNameToTypeMap == null) {
  172. return TokenTypes.Invalid;
  173. }
  174. int value;
  175. if (tokenNameToTypeMap.TryGetValue(tokenName, out value))
  176. return value;
  177. return TokenTypes.Invalid;
  178. }
  179. /** <summary>
  180. * Walk the entire tree and make a node name to nodes mapping.
  181. * For now, use recursion but later nonrecursive version may be
  182. * more efficient. Returns Map&lt;Integer, List&gt; where the List is
  183. * of your AST node type. The Integer is the token type of the node.
  184. * </summary>
  185. *
  186. * <remarks>
  187. * TODO: save this index so that find and visit are faster
  188. * </remarks>
  189. */
  190. public IDictionary<int, IList> Index(object t) {
  191. IDictionary<int, IList> m = new Dictionary<int, IList>();
  192. IndexCore(t, m);
  193. return m;
  194. }
  195. /** <summary>Do the work for index</summary> */
  196. protected virtual void IndexCore(object t, IDictionary<int, IList> m) {
  197. if (t == null) {
  198. return;
  199. }
  200. int ttype = adaptor.GetType(t);
  201. IList elements;
  202. if (!m.TryGetValue(ttype, out elements) || elements == null) {
  203. elements = new List<object>();
  204. m[ttype] = elements;
  205. }
  206. elements.Add(t);
  207. int n = adaptor.GetChildCount(t);
  208. for (int i = 0; i < n; i++) {
  209. object child = adaptor.GetChild(t, i);
  210. IndexCore(child, m);
  211. }
  212. }
  213. class FindTreeWizardVisitor : TreeWizard.Visitor {
  214. IList _nodes;
  215. public FindTreeWizardVisitor(IList nodes) {
  216. _nodes = nodes;
  217. }
  218. public override void Visit(object t) {
  219. _nodes.Add(t);
  220. }
  221. }
  222. class FindTreeWizardContextVisitor : TreeWizard.IContextVisitor {
  223. TreeWizard _outer;
  224. TreePattern _tpattern;
  225. IList _subtrees;
  226. public FindTreeWizardContextVisitor(TreeWizard outer, TreePattern tpattern, IList subtrees) {
  227. _outer = outer;
  228. _tpattern = tpattern;
  229. _subtrees = subtrees;
  230. }
  231. public void Visit(object t, object parent, int childIndex, IDictionary<string, object> labels) {
  232. if (_outer.ParseCore(t, _tpattern, null)) {
  233. _subtrees.Add(t);
  234. }
  235. }
  236. }
  237. /** <summary>Return a List of tree nodes with token type ttype</summary> */
  238. public virtual IList Find(object t, int ttype) {
  239. IList nodes = new List<object>();
  240. Visit(t, ttype, new FindTreeWizardVisitor(nodes));
  241. return nodes;
  242. }
  243. /** <summary>Return a List of subtrees matching pattern.</summary> */
  244. public virtual IList Find(object t, string pattern) {
  245. IList subtrees = new List<object>();
  246. // Create a TreePattern from the pattern
  247. TreePatternLexer tokenizer = new TreePatternLexer(pattern);
  248. TreePatternParser parser =
  249. new TreePatternParser(tokenizer, this, new TreePatternTreeAdaptor());
  250. TreePattern tpattern = (TreePattern)parser.Pattern();
  251. // don't allow invalid patterns
  252. if (tpattern == null ||
  253. tpattern.IsNil ||
  254. tpattern.GetType() == typeof(WildcardTreePattern)) {
  255. return null;
  256. }
  257. int rootTokenType = tpattern.Type;
  258. Visit(t, rootTokenType, new FindTreeWizardContextVisitor(this, tpattern, subtrees));
  259. return subtrees;
  260. }
  261. public virtual object FindFirst(object t, int ttype) {
  262. return null;
  263. }
  264. public virtual object FindFirst(object t, string pattern) {
  265. return null;
  266. }
  267. /** <summary>
  268. * Visit every ttype node in t, invoking the visitor. This is a quicker
  269. * version of the general visit(t, pattern) method. The labels arg
  270. * of the visitor action method is never set (it's null) since using
  271. * a token type rather than a pattern doesn't let us set a label.
  272. * </summary>
  273. */
  274. public void Visit(object t, int ttype, IContextVisitor visitor) {
  275. VisitCore(t, null, 0, ttype, visitor);
  276. }
  277. public void Visit(object t, int ttype, System.Action<object> action) {
  278. Visit(t, ttype, new ActionVisitor(action));
  279. }
  280. /** <summary>Do the recursive work for visit</summary> */
  281. protected virtual void VisitCore(object t, object parent, int childIndex, int ttype, IContextVisitor visitor) {
  282. if (t == null) {
  283. return;
  284. }
  285. if (adaptor.GetType(t) == ttype) {
  286. visitor.Visit(t, parent, childIndex, null);
  287. }
  288. int n = adaptor.GetChildCount(t);
  289. for (int i = 0; i < n; i++) {
  290. object child = adaptor.GetChild(t, i);
  291. VisitCore(child, t, i, ttype, visitor);
  292. }
  293. }
  294. class VisitTreeWizardContextVisitor : TreeWizard.IContextVisitor {
  295. TreeWizard _outer;
  296. IContextVisitor _visitor;
  297. IDictionary<string, object> _labels;
  298. TreePattern _tpattern;
  299. public VisitTreeWizardContextVisitor(TreeWizard outer, IContextVisitor visitor, IDictionary<string, object> labels, TreePattern tpattern) {
  300. _outer = outer;
  301. _visitor = visitor;
  302. _labels = labels;
  303. _tpattern = tpattern;
  304. }
  305. public void Visit(object t, object parent, int childIndex, IDictionary<string, object> unusedlabels) {
  306. // the unusedlabels arg is null as visit on token type doesn't set.
  307. _labels.Clear();
  308. if (_outer.ParseCore(t, _tpattern, _labels)) {
  309. _visitor.Visit(t, parent, childIndex, _labels);
  310. }
  311. }
  312. }
  313. /** <summary>
  314. * For all subtrees that match the pattern, execute the visit action.
  315. * The implementation uses the root node of the pattern in combination
  316. * with visit(t, ttype, visitor) so nil-rooted patterns are not allowed.
  317. * Patterns with wildcard roots are also not allowed.
  318. * </summary>
  319. */
  320. public void Visit(object t, string pattern, IContextVisitor visitor) {
  321. // Create a TreePattern from the pattern
  322. TreePatternLexer tokenizer = new TreePatternLexer(pattern);
  323. TreePatternParser parser =
  324. new TreePatternParser(tokenizer, this, new TreePatternTreeAdaptor());
  325. TreePattern tpattern = (TreePattern)parser.Pattern();
  326. // don't allow invalid patterns
  327. if (tpattern == null ||
  328. tpattern.IsNil ||
  329. tpattern.GetType() == typeof(WildcardTreePattern)) {
  330. return;
  331. }
  332. IDictionary<string, object> labels = new Dictionary<string, object>(); // reused for each _parse
  333. int rootTokenType = tpattern.Type;
  334. Visit(t, rootTokenType, new VisitTreeWizardContextVisitor(this, visitor, labels, tpattern));
  335. }
  336. /** <summary>
  337. * Given a pattern like (ASSIGN %lhs:ID %rhs:.) with optional labels
  338. * on the various nodes and '.' (dot) as the node/subtree wildcard,
  339. * return true if the pattern matches and fill the labels Map with
  340. * the labels pointing at the appropriate nodes. Return false if
  341. * the pattern is malformed or the tree does not match.
  342. * </summary>
  343. *
  344. * <remarks>
  345. * If a node specifies a text arg in pattern, then that must match
  346. * for that node in t.
  347. *
  348. * TODO: what's a better way to indicate bad pattern? Exceptions are a hassle
  349. * </remarks>
  350. */
  351. public bool Parse(object t, string pattern, IDictionary<string, object> labels) {
  352. TreePatternLexer tokenizer = new TreePatternLexer(pattern);
  353. TreePatternParser parser =
  354. new TreePatternParser(tokenizer, this, new TreePatternTreeAdaptor());
  355. TreePattern tpattern = (TreePattern)parser.Pattern();
  356. /*
  357. System.out.println("t="+((Tree)t).toStringTree());
  358. System.out.println("scant="+tpattern.toStringTree());
  359. */
  360. bool matched = ParseCore(t, tpattern, labels);
  361. return matched;
  362. }
  363. public bool Parse(object t, string pattern) {
  364. return Parse(t, pattern, null);
  365. }
  366. /** <summary>
  367. * Do the work for parse. Check to see if the t2 pattern fits the
  368. * structure and token types in t1. Check text if the pattern has
  369. * text arguments on nodes. Fill labels map with pointers to nodes
  370. * in tree matched against nodes in pattern with labels.
  371. * </summary>
  372. */
  373. protected virtual bool ParseCore(object t1, TreePattern tpattern, IDictionary<string, object> labels) {
  374. // make sure both are non-null
  375. if (t1 == null || tpattern == null) {
  376. return false;
  377. }
  378. // check roots (wildcard matches anything)
  379. if (tpattern.GetType() != typeof(WildcardTreePattern)) {
  380. if (adaptor.GetType(t1) != tpattern.Type) {
  381. return false;
  382. }
  383. // if pattern has text, check node text
  384. if (tpattern.hasTextArg && !adaptor.GetText(t1).Equals(tpattern.Text)) {
  385. return false;
  386. }
  387. }
  388. if (tpattern.label != null && labels != null) {
  389. // map label in pattern to node in t1
  390. labels[tpattern.label] = t1;
  391. }
  392. // check children
  393. int n1 = adaptor.GetChildCount(t1);
  394. int n2 = tpattern.ChildCount;
  395. if (n1 != n2) {
  396. return false;
  397. }
  398. for (int i = 0; i < n1; i++) {
  399. object child1 = adaptor.GetChild(t1, i);
  400. TreePattern child2 = (TreePattern)tpattern.GetChild(i);
  401. if (!ParseCore(child1, child2, labels)) {
  402. return false;
  403. }
  404. }
  405. return true;
  406. }
  407. /** <summary>
  408. * Create a tree or node from the indicated tree pattern that closely
  409. * follows ANTLR tree grammar tree element syntax:
  410. *
  411. * (root child1 ... child2).
  412. * </summary>
  413. *
  414. * <remarks>
  415. * You can also just pass in a node: ID
  416. *
  417. * Any node can have a text argument: ID[foo]
  418. * (notice there are no quotes around foo--it's clear it's a string).
  419. *
  420. * nil is a special name meaning "give me a nil node". Useful for
  421. * making lists: (nil A B C) is a list of A B C.
  422. * </remarks>
  423. */
  424. public virtual object Create(string pattern) {
  425. TreePatternLexer tokenizer = new TreePatternLexer(pattern);
  426. TreePatternParser parser = new TreePatternParser(tokenizer, this, adaptor);
  427. object t = parser.Pattern();
  428. return t;
  429. }
  430. /** <summary>
  431. * Compare t1 and t2; return true if token types/text, structure match exactly.
  432. * The trees are examined in their entirety so that (A B) does not match
  433. * (A B C) nor (A (B C)).
  434. * </summary>
  435. *
  436. * <remarks>
  437. * TODO: allow them to pass in a comparator
  438. * TODO: have a version that is nonstatic so it can use instance adaptor
  439. *
  440. * I cannot rely on the tree node's equals() implementation as I make
  441. * no constraints at all on the node types nor interface etc...
  442. * </remarks>
  443. */
  444. public static bool Equals(object t1, object t2, ITreeAdaptor adaptor) {
  445. return EqualsCore(t1, t2, adaptor);
  446. }
  447. /** <summary>
  448. * Compare type, structure, and text of two trees, assuming adaptor in
  449. * this instance of a TreeWizard.
  450. * </summary>
  451. */
  452. public new bool Equals(object t1, object t2) {
  453. return EqualsCore(t1, t2, adaptor);
  454. }
  455. protected static bool EqualsCore(object t1, object t2, ITreeAdaptor adaptor) {
  456. // make sure both are non-null
  457. if (t1 == null || t2 == null) {
  458. return false;
  459. }
  460. // check roots
  461. if (adaptor.GetType(t1) != adaptor.GetType(t2)) {
  462. return false;
  463. }
  464. if (!adaptor.GetText(t1).Equals(adaptor.GetText(t2))) {
  465. return false;
  466. }
  467. // check children
  468. int n1 = adaptor.GetChildCount(t1);
  469. int n2 = adaptor.GetChildCount(t2);
  470. if (n1 != n2) {
  471. return false;
  472. }
  473. for (int i = 0; i < n1; i++) {
  474. object child1 = adaptor.GetChild(t1, i);
  475. object child2 = adaptor.GetChild(t2, i);
  476. if (!EqualsCore(child1, child2, adaptor)) {
  477. return false;
  478. }
  479. }
  480. return true;
  481. }
  482. #if BUILD_INDEXES
  483. // TODO: next stuff taken from CommonTreeNodeStream
  484. /** <summary>
  485. * Given a node, add this to the reverse index tokenTypeToStreamIndexesMap.
  486. * You can override this method to alter how indexing occurs. The
  487. * default is to create a
  488. *
  489. * Map&lt;Integer token type,ArrayList&lt;Integer stream index&gt;&gt;
  490. * </summary>
  491. *
  492. * <remarks>
  493. * This data structure allows you to find all nodes with type INT in order.
  494. *
  495. * If you really need to find a node of type, say, FUNC quickly then perhaps
  496. *
  497. * Map&lt;Integertoken type,Map&lt;Object tree node,Integer stream index&gt;&gt;
  498. *
  499. * would be better for you. The interior maps map a tree node to
  500. * the index so you don't have to search linearly for a specific node.
  501. *
  502. * If you change this method, you will likely need to change
  503. * getNodeIndex(), which extracts information.
  504. * </remarks>
  505. */
  506. protected void fillReverseIndex( object node, int streamIndex )
  507. {
  508. //System.out.println("revIndex "+node+"@"+streamIndex);
  509. if ( tokenTypesToReverseIndex == null )
  510. {
  511. return; // no indexing if this is empty (nothing of interest)
  512. }
  513. if ( tokenTypeToStreamIndexesMap == null )
  514. {
  515. tokenTypeToStreamIndexesMap = new Dictionary<int, IList<int>>(); // first indexing op
  516. }
  517. int tokenType = adaptor.getType( node );
  518. if ( !( tokenTypesToReverseIndex == INDEX_ALL ||
  519. tokenTypesToReverseIndex.Contains( tokenType ) ) )
  520. {
  521. return; // tokenType not of interest
  522. }
  523. IList<int> indexes;
  524. if ( !tokenTypeToStreamIndexesMap.TryGetValue( tokenType, out indexes ) || indexes == null )
  525. {
  526. indexes = new List<int>(); // no list yet for this token type
  527. indexes.Add( streamIndex ); // not there yet, add
  528. tokenTypeToStreamIndexesMap[tokenType] = indexes;
  529. }
  530. else
  531. {
  532. if ( !indexes.Contains( streamIndex ) )
  533. {
  534. indexes.Add( streamIndex ); // not there yet, add
  535. }
  536. }
  537. }
  538. /** <summary>
  539. * Track the indicated token type in the reverse index. Call this
  540. * repeatedly for each type or use variant with Set argument to
  541. * set all at once.
  542. * </summary>
  543. *
  544. * <param name="tokenType" />
  545. */
  546. public void reverseIndex( int tokenType )
  547. {
  548. if ( tokenTypesToReverseIndex == null )
  549. {
  550. tokenTypesToReverseIndex = new HashSet<int>();
  551. }
  552. else if ( tokenTypesToReverseIndex == INDEX_ALL )
  553. {
  554. return;
  555. }
  556. tokenTypesToReverseIndex.add( tokenType );
  557. }
  558. /** <summary>
  559. * Track the indicated token types in the reverse index. Set
  560. * to INDEX_ALL to track all token types.
  561. * </summary>
  562. */
  563. public void reverseIndex( HashSet<int> tokenTypes )
  564. {
  565. tokenTypesToReverseIndex = tokenTypes;
  566. }
  567. /** <summary>
  568. * Given a node pointer, return its index into the node stream.
  569. * This is not its Token stream index. If there is no reverse map
  570. * from node to stream index or the map does not contain entries
  571. * for node's token type, a linear search of entire stream is used.
  572. * </summary>
  573. *
  574. * <remarks>
  575. * Return -1 if exact node pointer not in stream.
  576. * </remarks>
  577. */
  578. public int getNodeIndex( object node )
  579. {
  580. //System.out.println("get "+node);
  581. if ( tokenTypeToStreamIndexesMap == null )
  582. {
  583. return getNodeIndexLinearly( node );
  584. }
  585. int tokenType = adaptor.getType( node );
  586. IList<int> indexes;
  587. if ( !tokenTypeToStreamIndexesMap.TryGetValue( tokenType, out indexes ) || indexes == null )
  588. {
  589. //System.out.println("found linearly; stream index = "+getNodeIndexLinearly(node));
  590. return getNodeIndexLinearly( node );
  591. }
  592. for ( int i = 0; i < indexes.size(); i++ )
  593. {
  594. int streamIndex = indexes[i];
  595. object n = get( streamIndex );
  596. if ( n == node )
  597. {
  598. //System.out.println("found in index; stream index = "+streamIndexI);
  599. return streamIndex; // found it!
  600. }
  601. }
  602. return -1;
  603. }
  604. #endif
  605. }
  606. }