PageRenderTime 48ms CodeModel.GetById 14ms RepoModel.GetById 1ms app.codeStats 0ms

/projects/antlr-3.4/runtime/ObjC/Framework/ANTLRTreeWizard.m

https://gitlab.com/essere.lab.public/qualitas.class-corpus
Objective C | 735 lines | 433 code | 58 blank | 244 comment | 87 complexity | e61b335242fb125b822c250bccabb6c4 MD5 | raw file
  1. //
  2. // ANTLRTreeWizard.m
  3. // ANTLR
  4. //
  5. // Created by Alan Condit on 6/18/10.
  6. // [The "BSD licence"]
  7. // Copyright (c) 2010 Alan Condit
  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. #import "ANTLRTreeWizard.h"
  32. #import "ANTLRTreePatternLexer.h"
  33. #import "ANTLRTreePatternParser.h"
  34. #import "ANTLRIntArray.h"
  35. @implementation ANTLRVisitor
  36. + (ANTLRVisitor *)newANTLRVisitor:(NSInteger)anAction Actor:(id)anActor Object:(id)anObject1 Object:(id)anObject2
  37. {
  38. return [[ANTLRVisitor alloc] initWithAction:anAction Actor:(id)anActor Object:(id)anObject1 Object:(id)anObject2];
  39. }
  40. - (id) initWithAction:(NSInteger)anAction Actor:(id)anActor Object:(id)anObject1 Object:(id)anObject2
  41. {
  42. if ((self = [super init]) != nil) {
  43. action = anAction;
  44. actor = anActor;
  45. if ( actor ) [actor retain];
  46. object1 = anObject1;
  47. if ( object1 ) [object1 retain];
  48. object2 = anObject2;
  49. if ( object2 ) [object2 retain];
  50. }
  51. return self;
  52. }
  53. - (void) dealloc
  54. {
  55. #ifdef DEBUG_DEALLOC
  56. NSLog( @"called dealloc in ANTLRVisitor" );
  57. #endif
  58. if ( actor ) [actor release];
  59. if ( object1 ) [object1 release];
  60. if ( object2 ) [object2 release];
  61. [super dealloc];
  62. }
  63. - (void) visit:(ANTLRCommonTree *)t Parent:(ANTLRCommonTree *)parent ChildIndex:(NSInteger)childIndex Map:(ANTLRMap *)labels
  64. {
  65. switch (action) {
  66. case 0:
  67. [(ANTLRMap *)object2 /* labels */ clear];
  68. if ( [(ANTLRTreeWizard *)actor _parse:t Pattern:object1/* tpattern */ Map:object2 /* labels */] ) {
  69. [self visit:t Parent:parent ChildIndex:childIndex Map:object2 /* labels */];
  70. }
  71. break;
  72. case 1:
  73. if ( [(ANTLRTreeWizard *)actor _parse:t Pattern:object1/* tpattern */ Map:nil] ) {
  74. [(AMutableArray *)object2/* subtrees */ addObject:t];
  75. }
  76. break;
  77. }
  78. // [self visit:t];
  79. return;
  80. }
  81. - (void) visit:(ANTLRCommonTree *)t
  82. {
  83. [object1 addObject:t];
  84. return;
  85. }
  86. @synthesize action;
  87. @synthesize actor;
  88. @synthesize object1;
  89. @synthesize object2;
  90. @end
  91. /** When using %label:TOKENNAME in a tree for parse(), we must
  92. * track the label.
  93. */
  94. @implementation ANTLRTreePattern
  95. @synthesize label;
  96. @synthesize hasTextArg;
  97. + (ANTLRCommonTree *)newANTLRTreePattern:(id<ANTLRToken>)payload
  98. {
  99. return (ANTLRCommonTree *)[[ANTLRTreePattern alloc] initWithToken:payload];
  100. }
  101. - (id) initWithToken:(id<ANTLRToken>)payload
  102. {
  103. self = [super initWithToken:payload];
  104. if ( self != nil ) {
  105. }
  106. return (ANTLRCommonTree *)self;
  107. }
  108. - (void) dealloc
  109. {
  110. #ifdef DEBUG_DEALLOC
  111. NSLog( @"called dealloc in ANTLRTreePattern" );
  112. #endif
  113. if ( label ) [label release];
  114. [super dealloc];
  115. }
  116. - (NSString *)toString
  117. {
  118. if ( label != nil ) {
  119. return [NSString stringWithFormat:@"\% %@ : %@", label, [super toString]];
  120. }
  121. else {
  122. return [super toString];
  123. }
  124. }
  125. @end
  126. @implementation ANTLRWildcardTreePattern
  127. + (ANTLRWildcardTreePattern *)newANTLRWildcardTreePattern:(id<ANTLRToken>)payload
  128. {
  129. return(ANTLRWildcardTreePattern *)[[ANTLRWildcardTreePattern alloc] initWithToken:(id<ANTLRToken>)payload];
  130. }
  131. - (id) initWithToken:(id<ANTLRToken>)payload
  132. {
  133. self = [super initWithToken:payload];
  134. if ( self != nil ) {
  135. }
  136. return self;
  137. }
  138. @end
  139. /** This adaptor creates TreePattern objects for use during scan() */
  140. @implementation ANTLRTreePatternTreeAdaptor
  141. + (ANTLRTreePatternTreeAdaptor *)newTreeAdaptor
  142. {
  143. return [[ANTLRTreePatternTreeAdaptor alloc] init];
  144. }
  145. - (id) init
  146. {
  147. self = [super init];
  148. if ( self != nil ) {
  149. }
  150. return self;
  151. }
  152. - (ANTLRCommonTree *)createTreePattern:(id<ANTLRToken>)payload
  153. {
  154. return (ANTLRCommonTree *)[super create:payload];
  155. }
  156. @end
  157. @implementation ANTLRTreeWizard
  158. // TODO: build indexes for the wizard
  159. /** During fillBuffer(), we can make a reverse index from a set
  160. * of token types of interest to the list of indexes into the
  161. * node stream. This lets us convert a node pointer to a
  162. * stream index semi-efficiently for a list of interesting
  163. * nodes such as function definition nodes (you'll want to seek
  164. * to their bodies for an interpreter). Also useful for doing
  165. * dynamic searches; i.e., go find me all PLUS nodes.
  166. protected Map tokenTypeToStreamIndexesMap;
  167. ** If tokenTypesToReverseIndex set to INDEX_ALL then indexing
  168. * occurs for all token types.
  169. public static final Set INDEX_ALL = new HashSet();
  170. ** A set of token types user would like to index for faster lookup.
  171. * If this is INDEX_ALL, then all token types are tracked. If nil,
  172. * then none are indexed.
  173. protected Set tokenTypesToReverseIndex = nil;
  174. */
  175. + (ANTLRTreeWizard *) newANTLRTreeWizard:(id<ANTLRTreeAdaptor>)anAdaptor
  176. {
  177. return [[ANTLRTreeWizard alloc] initWithAdaptor:anAdaptor];
  178. }
  179. + (ANTLRTreeWizard *)newANTLRTreeWizard:(id<ANTLRTreeAdaptor>)anAdaptor Map:(ANTLRMap *)aTokenNameToTypeMap
  180. {
  181. return [[ANTLRTreeWizard alloc] initWithAdaptor:anAdaptor Map:aTokenNameToTypeMap];
  182. }
  183. + (ANTLRTreeWizard *)newANTLRTreeWizard:(id<ANTLRTreeAdaptor>)anAdaptor TokenNames:(NSArray *)theTokNams
  184. {
  185. return [[ANTLRTreeWizard alloc] initWithTokenNames:anAdaptor TokenNames:theTokNams];
  186. }
  187. + (ANTLRTreeWizard *)newANTLRTreeWizardWithTokenNames:(NSArray *)theTokNams
  188. {
  189. return [[ANTLRTreeWizard alloc] initWithTokenNames:theTokNams];
  190. }
  191. - (id) init
  192. {
  193. if ((self = [super init]) != nil) {
  194. }
  195. return self;
  196. }
  197. - (id) initWithAdaptor:(id<ANTLRTreeAdaptor>)anAdaptor
  198. {
  199. if ((self = [super init]) != nil) {
  200. adaptor = anAdaptor;
  201. if ( adaptor ) [adaptor retain];
  202. }
  203. return self;
  204. }
  205. - (id) initWithAdaptor:(id<ANTLRTreeAdaptor>)anAdaptor Map:(ANTLRMap *)aTokenNameToTypeMap
  206. {
  207. if ((self = [super init]) != nil) {
  208. adaptor = anAdaptor;
  209. if ( adaptor ) [adaptor retain];
  210. tokenNameToTypeMap = aTokenNameToTypeMap;
  211. }
  212. return self;
  213. }
  214. - (id) initWithTokenNames:(NSArray *)theTokNams
  215. {
  216. if ((self = [super init]) != nil) {
  217. #pragma warning Fix initWithTokenNames.
  218. // adaptor = anAdaptor;
  219. //tokenNameToTypeMap = aTokenNameToTypeMap;
  220. tokenNameToTypeMap = [[self computeTokenTypes:theTokNams] retain];
  221. }
  222. return self;
  223. }
  224. - (id) initWithTokenNames:(id<ANTLRTreeAdaptor>)anAdaptor TokenNames:(NSArray *)theTokNams
  225. {
  226. if ((self = [super init]) != nil) {
  227. adaptor = anAdaptor;
  228. if ( adaptor ) [adaptor retain];
  229. // tokenNameToTypeMap = aTokenNameToTypeMap;
  230. tokenNameToTypeMap = [[self computeTokenTypes:theTokNams] retain];
  231. }
  232. return self;
  233. }
  234. - (void) dealloc
  235. {
  236. #ifdef DEBUG_DEALLOC
  237. NSLog( @"called dealloc in ANTLRTreePatternTreeAdaptor" );
  238. #endif
  239. if ( adaptor ) [adaptor release];
  240. if ( tokenNameToTypeMap ) [tokenNameToTypeMap release];
  241. [super dealloc];
  242. }
  243. /** Compute a Map<String, Integer> that is an inverted index of
  244. * tokenNames (which maps int token types to names).
  245. */
  246. - (ANTLRMap *)computeTokenTypes:(NSArray *)theTokNams
  247. {
  248. ANTLRMap *m = [ANTLRMap newANTLRMap];
  249. if ( theTokNams == nil ) {
  250. return m;
  251. }
  252. for (int ttype = ANTLRTokenTypeMIN; ttype < [theTokNams count]; ttype++) {
  253. NSString *name = (NSString *) [theTokNams objectAtIndex:ttype];
  254. [m putName:name TType:ttype];
  255. }
  256. return m;
  257. }
  258. /** Using the map of token names to token types, return the type. */
  259. - (NSInteger)getTokenType:(NSString *)tokenName
  260. {
  261. if ( tokenNameToTypeMap == nil ) {
  262. return ANTLRTokenTypeInvalid;
  263. }
  264. NSInteger aTType = (NSInteger)[tokenNameToTypeMap getTType:tokenName];
  265. if ( aTType != -1 ) {
  266. return aTType;
  267. }
  268. return ANTLRTokenTypeInvalid;
  269. }
  270. /** Walk the entire tree and make a node name to nodes mapping.
  271. * For now, use recursion but later nonrecursive version may be
  272. * more efficient. Returns Map<Integer, List> where the List is
  273. * of your AST node type. The Integer is the token type of the node.
  274. *
  275. * TODO: save this index so that find and visit are faster
  276. */
  277. - (ANTLRMap *)index:(ANTLRCommonTree *)t
  278. {
  279. ANTLRMap *m = [ANTLRMap newANTLRMap];
  280. [self _index:t Map:m];
  281. return m;
  282. }
  283. /** Do the work for index */
  284. - (void) _index:(ANTLRCommonTree *)t Map:(ANTLRMap *)m
  285. {
  286. if ( t==nil ) {
  287. return;
  288. }
  289. #pragma warning Fix _index use of ANTLRMap.
  290. NSInteger ttype = [adaptor getType:t];
  291. ANTLRMap *elements = (ANTLRMap *)[m getName:ttype];
  292. if ( elements == nil ) {
  293. elements = [ANTLRMap newANTLRMapWithLen:100];
  294. [m putNode:ttype Node:elements];
  295. }
  296. [elements addObject:t];
  297. int n = [adaptor getChildCount:t];
  298. for (int i=0; i<n; i++) {
  299. ANTLRCommonTree * child = [adaptor getChild:t At:i];
  300. [self _index:child Map:m];
  301. }
  302. }
  303. /** Return a List of tree nodes with token type ttype */
  304. - (AMutableArray *)find:(ANTLRCommonTree *)t Type:(NSInteger)ttype
  305. {
  306. #ifdef DONTUSENOMO
  307. final List nodes = new ArrayList();
  308. visit(t, ttype, new TreeWizard.Visitor() {
  309. public void visit(Object t) {
  310. [nodes addObject t];
  311. }
  312. } );
  313. #endif
  314. AMutableArray *nodes = [AMutableArray arrayWithCapacity:100];
  315. ANTLRVisitor *contextVisitor = [ANTLRVisitor newANTLRVisitor:3 Actor:self Object:(id)nodes Object:nil];
  316. [self visit:t Type:ttype Visitor:contextVisitor];
  317. return nodes;
  318. }
  319. /** Return a List of subtrees matching pattern. */
  320. - (AMutableArray *)find:(ANTLRCommonTree *)t Pattern:(NSString *)pattern
  321. {
  322. AMutableArray *subtrees = [AMutableArray arrayWithCapacity:100];
  323. // Create a TreePattern from the pattern
  324. ANTLRTreePatternLexer *tokenizer = [ANTLRTreePatternLexer newANTLRTreePatternLexer:pattern];
  325. ANTLRTreePatternParser *parser = [ANTLRTreePatternParser newANTLRTreePatternParser:tokenizer
  326. Wizard:self
  327. Adaptor:[ANTLRTreePatternTreeAdaptor newTreeAdaptor]];
  328. ANTLRCommonTree *tpattern = (ANTLRCommonTree *)[parser pattern];
  329. // don't allow invalid patterns
  330. if ( tpattern == nil ||
  331. [tpattern isNil] ||
  332. [tpattern class] == [ANTLRWildcardTreePattern class] )
  333. {
  334. return nil;
  335. }
  336. int rootTokenType = [tpattern type];
  337. #ifdef DONTUSENOMO
  338. visit(t, rootTokenType, new TreeWizard.ContextVisitor() {
  339. public void visit(Object t, Object parent, int childIndex, Map labels) {
  340. if ( _parse(t, tpattern, null) ) {
  341. subtrees.add(t);
  342. }
  343. }
  344. } );
  345. #endif
  346. ANTLRVisitor *contextVisitor = [ANTLRVisitor newANTLRVisitor:1 Actor:self Object:tpattern Object:subtrees];
  347. [self visit:t Type:rootTokenType Visitor:contextVisitor];
  348. return subtrees;
  349. }
  350. - (ANTLRTreeWizard *)findFirst:(ANTLRCommonTree *) t Type:(NSInteger)ttype
  351. {
  352. return nil;
  353. }
  354. - (ANTLRTreeWizard *)findFirst:(ANTLRCommonTree *) t Pattern:(NSString *)pattern
  355. {
  356. return nil;
  357. }
  358. /** Visit every ttype node in t, invoking the visitor. This is a quicker
  359. * version of the general visit(t, pattern) method. The labels arg
  360. * of the visitor action method is never set (it's nil) since using
  361. * a token type rather than a pattern doesn't let us set a label.
  362. */
  363. - (void) visit:(ANTLRCommonTree *)t Type:(NSInteger)ttype Visitor:(ANTLRVisitor *)visitor
  364. {
  365. [self _visit:t Parent:nil ChildIndex:0 Type:ttype Visitor:visitor];
  366. }
  367. /** Do the recursive work for visit */
  368. - (void) _visit:(ANTLRCommonTree *)t
  369. Parent:(ANTLRCommonTree *)parent
  370. ChildIndex:(NSInteger)childIndex
  371. Type:(NSInteger)ttype
  372. Visitor:(ANTLRVisitor *)visitor
  373. {
  374. if ( t == nil ) {
  375. return;
  376. }
  377. if ( [adaptor getType:t] == ttype ) {
  378. [visitor visit:t Parent:parent ChildIndex:childIndex Map:nil];
  379. }
  380. int n = [adaptor getChildCount:t];
  381. for (int i=0; i<n; i++) {
  382. ANTLRCommonTree * child = [adaptor getChild:t At:i];
  383. [self _visit:child Parent:t ChildIndex:i Type:ttype Visitor:visitor];
  384. }
  385. }
  386. /** For all subtrees that match the pattern, execute the visit action.
  387. * The implementation uses the root node of the pattern in combination
  388. * with visit(t, ttype, visitor) so nil-rooted patterns are not allowed.
  389. * Patterns with wildcard roots are also not allowed.
  390. */
  391. - (void)visit:(ANTLRCommonTree *)t Pattern:(NSString *)pattern Visitor:(ANTLRVisitor *)visitor
  392. {
  393. // Create a TreePattern from the pattern
  394. ANTLRTreePatternLexer *tokenizer = [ANTLRTreePatternLexer newANTLRTreePatternLexer:pattern];
  395. ANTLRTreePatternParser *parser =
  396. [ANTLRTreePatternParser newANTLRTreePatternParser:tokenizer Wizard:self Adaptor:[ANTLRTreePatternTreeAdaptor newTreeAdaptor]];
  397. ANTLRCommonTree *tpattern = [parser pattern];
  398. // don't allow invalid patterns
  399. if ( tpattern == nil ||
  400. [tpattern isNil] ||
  401. [tpattern class] == [ANTLRWildcardTreePattern class] )
  402. {
  403. return;
  404. }
  405. ANTLRMapElement *labels = [ANTLRMap newANTLRMap]; // reused for each _parse
  406. int rootTokenType = [tpattern type];
  407. #pragma warning This is another one of those screwy nested constructs that I have to figure out
  408. #ifdef DONTUSENOMO
  409. visit(t, rootTokenType, new TreeWizard.ContextVisitor() {
  410. public void visit(Object t, Object parent, int childIndex, Map unusedlabels) {
  411. // the unusedlabels arg is null as visit on token type doesn't set.
  412. labels.clear();
  413. if ( _parse(t, tpattern, labels) ) {
  414. visitor.visit(t, parent, childIndex, labels);
  415. }
  416. }
  417. });
  418. #endif
  419. ANTLRVisitor *contextVisitor = [ANTLRVisitor newANTLRVisitor:0 Actor:self Object:tpattern Object:labels];
  420. [self visit:t Type:rootTokenType Visitor:contextVisitor];
  421. }
  422. /** Given a pattern like (ASSIGN %lhs:ID %rhs:.) with optional labels
  423. * on the various nodes and '.' (dot) as the node/subtree wildcard,
  424. * return true if the pattern matches and fill the labels Map with
  425. * the labels pointing at the appropriate nodes. Return false if
  426. * the pattern is malformed or the tree does not match.
  427. *
  428. * If a node specifies a text arg in pattern, then that must match
  429. * for that node in t.
  430. *
  431. * TODO: what's a better way to indicate bad pattern? Exceptions are a hassle
  432. */
  433. - (BOOL)parse:(ANTLRCommonTree *)t Pattern:(NSString *)pattern Map:(ANTLRMap *)labels
  434. {
  435. #ifdef DONTUSENOMO
  436. TreePatternLexer tokenizer = new TreePatternLexer(pattern);
  437. TreePatternParser parser =
  438. new TreePatternParser(tokenizer, this, new TreePatternTreeAdaptor());
  439. TreePattern tpattern = (TreePattern)parser.pattern();
  440. /*
  441. System.out.println("t="+((Tree)t).toStringTree());
  442. System.out.println("scant="+tpattern.toStringTree());
  443. */
  444. boolean matched = _parse(t, tpattern, labels);
  445. return matched;
  446. #endif
  447. ANTLRTreePatternLexer *tokenizer = [ANTLRTreePatternLexer newANTLRTreePatternLexer:pattern];
  448. ANTLRTreePatternParser *parser = [ANTLRTreePatternParser newANTLRTreePatternParser:tokenizer
  449. Wizard:self
  450. Adaptor:[ANTLRTreePatternTreeAdaptor newTreeAdaptor]];
  451. ANTLRCommonTree *tpattern = [parser pattern];
  452. /*
  453. System.out.println("t="+((Tree)t).toStringTree());
  454. System.out.println("scant="+tpattern.toStringTree());
  455. */
  456. //BOOL matched = [self _parse:t Pattern:tpattern Map:labels];
  457. //return matched;
  458. return [self _parse:t Pattern:tpattern Map:labels];
  459. }
  460. - (BOOL) parse:(ANTLRCommonTree *)t Pattern:(NSString *)pattern
  461. {
  462. return [self parse:t Pattern:pattern Map:nil];
  463. }
  464. /** Do the work for parse. Check to see if the t2 pattern fits the
  465. * structure and token types in t1. Check text if the pattern has
  466. * text arguments on nodes. Fill labels map with pointers to nodes
  467. * in tree matched against nodes in pattern with labels.
  468. */
  469. - (BOOL) _parse:(ANTLRCommonTree *)t1 Pattern:(ANTLRCommonTree *)aTPattern Map:(ANTLRMap *)labels
  470. {
  471. ANTLRTreePattern *tpattern;
  472. // make sure both are non-nil
  473. if ( t1 == nil || aTPattern == nil ) {
  474. return NO;
  475. }
  476. if ( [aTPattern isKindOfClass:[ANTLRWildcardTreePattern class]] ) {
  477. tpattern = (ANTLRTreePattern *)aTPattern;
  478. }
  479. // check roots (wildcard matches anything)
  480. if ( [tpattern class] != [ANTLRWildcardTreePattern class] ) {
  481. if ( [adaptor getType:t1] != [tpattern type] )
  482. return NO;
  483. // if pattern has text, check node text
  484. if ( tpattern.hasTextArg && ![[adaptor getText:t1] isEqualToString:[tpattern text]] ) {
  485. return NO;
  486. }
  487. }
  488. if ( tpattern.label != nil && labels!=nil ) {
  489. // map label in pattern to node in t1
  490. [labels putName:tpattern.label Node:t1];
  491. }
  492. // check children
  493. int n1 = [adaptor getChildCount:t1];
  494. int n2 = [tpattern getChildCount];
  495. if ( n1 != n2 ) {
  496. return NO;
  497. }
  498. for (int i=0; i<n1; i++) {
  499. ANTLRCommonTree * child1 = [adaptor getChild:t1 At:i];
  500. ANTLRCommonTree *child2 = (ANTLRCommonTree *)[tpattern getChild:i];
  501. if ( ![self _parse:child1 Pattern:child2 Map:labels] ) {
  502. return NO;
  503. }
  504. }
  505. return YES;
  506. }
  507. /** Create a tree or node from the indicated tree pattern that closely
  508. * follows ANTLR tree grammar tree element syntax:
  509. *
  510. * (root child1 ... child2).
  511. *
  512. * You can also just pass in a node: ID
  513. *
  514. * Any node can have a text argument: ID[foo]
  515. * (notice there are no quotes around foo--it's clear it's a string).
  516. *
  517. * nil is a special name meaning "give me a nil node". Useful for
  518. * making lists: (nil A B C) is a list of A B C.
  519. */
  520. - (ANTLRCommonTree *) createTree:(NSString *)pattern
  521. {
  522. ANTLRTreePatternLexer *tokenizer = [ANTLRTreePatternLexer newANTLRTreePatternLexer:pattern];
  523. ANTLRTreePatternParser *parser = [ANTLRTreePatternParser newANTLRTreePatternParser:tokenizer Wizard:self Adaptor:adaptor];
  524. ANTLRCommonTree * t = [parser pattern];
  525. return t;
  526. }
  527. /** Compare t1 and t2; return true if token types/text, structure match exactly.
  528. * The trees are examined in their entirety so that (A B) does not match
  529. * (A B C) nor (A (B C)).
  530. // TODO: allow them to pass in a comparator
  531. * TODO: have a version that is nonstatic so it can use instance adaptor
  532. *
  533. * I cannot rely on the tree node's equals() implementation as I make
  534. * no constraints at all on the node types nor interface etc...
  535. */
  536. - (BOOL)equals:(id)t1 O2:(id)t2 Adaptor:(id<ANTLRTreeAdaptor>)anAdaptor
  537. {
  538. return [self _equals:t1 O2:t2 Adaptor:anAdaptor];
  539. }
  540. /** Compare type, structure, and text of two trees, assuming adaptor in
  541. * this instance of a TreeWizard.
  542. */
  543. - (BOOL)equals:(id)t1 O2:(id)t2
  544. {
  545. return [self _equals:t1 O2:t2 Adaptor:adaptor];
  546. }
  547. - (BOOL) _equals:(id)t1 O2:(id)t2 Adaptor:(id<ANTLRTreeAdaptor>)anAdaptor
  548. {
  549. // make sure both are non-nil
  550. if ( t1==nil || t2==nil ) {
  551. return NO;
  552. }
  553. // check roots
  554. if ( [anAdaptor getType:t1] != [anAdaptor getType:t2] ) {
  555. return NO;
  556. }
  557. if ( ![[anAdaptor getText:t1] isEqualTo:[anAdaptor getText:t2]] ) {
  558. return NO;
  559. }
  560. // check children
  561. NSInteger n1 = [anAdaptor getChildCount:t1];
  562. NSInteger n2 = [anAdaptor getChildCount:t2];
  563. if ( n1 != n2 ) {
  564. return NO;
  565. }
  566. for (int i=0; i<n1; i++) {
  567. ANTLRCommonTree * child1 = [anAdaptor getChild:t1 At:i];
  568. ANTLRCommonTree * child2 = [anAdaptor getChild:t2 At:i];
  569. if ( ![self _equals:child1 O2:child2 Adaptor:anAdaptor] ) {
  570. return NO;
  571. }
  572. }
  573. return YES;
  574. }
  575. // TODO: next stuff taken from CommonTreeNodeStream
  576. /** Given a node, add this to the reverse index tokenTypeToStreamIndexesMap.
  577. * You can override this method to alter how indexing occurs. The
  578. * default is to create a
  579. *
  580. * Map<Integer token type,ArrayList<Integer stream index>>
  581. *
  582. * This data structure allows you to find all nodes with type INT in order.
  583. *
  584. * If you really need to find a node of type, say, FUNC quickly then perhaps
  585. *
  586. * Map<Integertoken type, Map<Object tree node, Integer stream index>>
  587. *
  588. * would be better for you. The interior maps map a tree node to
  589. * the index so you don't have to search linearly for a specific node.
  590. *
  591. * If you change this method, you will likely need to change
  592. * getNodeIndex(), which extracts information.
  593. - (void)fillReverseIndex:(ANTLRCommonTree *)node Index:(NSInteger)streamIndex
  594. {
  595. //System.out.println("revIndex "+node+"@"+streamIndex);
  596. if ( tokenTypesToReverseIndex == nil ) {
  597. return; // no indexing if this is empty (nothing of interest)
  598. }
  599. if ( tokenTypeToStreamIndexesMap == nil ) {
  600. tokenTypeToStreamIndexesMap = [ANTLRMap newANTLRMap]; // first indexing op
  601. }
  602. int tokenType = [adaptor getType:node];
  603. Integer tokenTypeI = new Integer(tokenType);
  604. if ( !(tokenTypesToReverseIndex == INDEX_ALL ||
  605. [tokenTypesToReverseIndex contains:tokenTypeI]) ) {
  606. return; // tokenType not of interest
  607. }
  608. NSInteger streamIndexI = streamIndex;
  609. AMutableArray *indexes = (AMutableArray *)[tokenTypeToStreamIndexesMap objectAtIndex:tokenTypeI];
  610. if ( indexes==nil ) {
  611. indexes = [AMutableArray arrayWithCapacity:100]; // no list yet for this token type
  612. indexes.add(streamIndexI); // not there yet, add
  613. [tokenTypeToStreamIndexesMap put:tokenTypeI Idexes:indexes];
  614. }
  615. else {
  616. if ( ![indexes contains:streamIndexI] ) {
  617. [indexes add:streamIndexI]; // not there yet, add
  618. }
  619. }
  620. }
  621. ** Track the indicated token type in the reverse index. Call this
  622. * repeatedly for each type or use variant with Set argument to
  623. * set all at once.
  624. * @param tokenType
  625. public void reverseIndex:(NSInteger)tokenType
  626. {
  627. if ( tokenTypesToReverseIndex == nil ) {
  628. tokenTypesToReverseIndex = [ANTLRMap newANTLRMap];
  629. }
  630. else if ( tokenTypesToReverseIndex == INDEX_ALL ) {
  631. return;
  632. }
  633. tokenTypesToReverseIndex.add(new Integer(tokenType));
  634. }
  635. ** Track the indicated token types in the reverse index. Set
  636. * to INDEX_ALL to track all token types.
  637. public void reverseIndex(Set tokenTypes) {
  638. tokenTypesToReverseIndex = tokenTypes;
  639. }
  640. ** Given a node pointer, return its index into the node stream.
  641. * This is not its Token stream index. If there is no reverse map
  642. * from node to stream index or the map does not contain entries
  643. * for node's token type, a linear search of entire stream is used.
  644. *
  645. * Return -1 if exact node pointer not in stream.
  646. public int getNodeIndex(Object node) {
  647. //System.out.println("get "+node);
  648. if ( tokenTypeToStreamIndexesMap==nil ) {
  649. return getNodeIndexLinearly(node);
  650. }
  651. int tokenType = adaptor.getType(node);
  652. Integer tokenTypeI = new Integer(tokenType);
  653. ArrayList indexes = (ArrayList)tokenTypeToStreamIndexesMap.get(tokenTypeI);
  654. if ( indexes==nil ) {
  655. //System.out.println("found linearly; stream index = "+getNodeIndexLinearly(node));
  656. return getNodeIndexLinearly(node);
  657. }
  658. for (int i = 0; i < indexes.size(); i++) {
  659. Integer streamIndexI = (Integer)indexes.get(i);
  660. Object n = get(streamIndexI.intValue());
  661. if ( n==node ) {
  662. //System.out.println("found in index; stream index = "+streamIndexI);
  663. return streamIndexI.intValue(); // found it!
  664. }
  665. }
  666. return -1;
  667. }
  668. */
  669. @synthesize adaptor;
  670. @synthesize tokenNameToTypeMap;
  671. @end