Inferno
0.2
|
00001 #include "search_replace.hpp" 00002 #include "conjecture.hpp" 00003 #include "common/hit_count.hpp" 00004 #include "helpers/simple_compare.hpp" 00005 00006 //#define STRACE 00007 00008 int CompareReplace::repetitions; 00009 bool CompareReplace::rep_error; 00010 00011 00012 /** Walks the tree, avoiding the "search"/"compare" and "replace" members of slaves 00013 but still recurses through the "through" member. Therefore, it visits all the 00014 nodes at the same slave level as the root. Based on UniqueWalk, so each node only 00015 visited once. */ 00016 class UniqueWalkNoSlavePattern_iterator : public UniqueWalk::iterator 00017 { 00018 public: 00019 UniqueWalkNoSlavePattern_iterator( TreePtr<Node> &root ) : UniqueWalk::iterator(root) {} 00020 UniqueWalkNoSlavePattern_iterator() : UniqueWalk::iterator() {} 00021 virtual shared_ptr<ContainerInterface::iterator_interface> Clone() const 00022 { 00023 return shared_ptr<UniqueWalkNoSlavePattern_iterator>( new UniqueWalkNoSlavePattern_iterator(*this) ); 00024 } 00025 private: 00026 virtual shared_ptr<ContainerInterface> GetChildContainer( TreePtr<Node> n ) const 00027 { 00028 // We need to create a container of elements of the child. 00029 if( shared_ptr<SlaveBase> sb = dynamic_pointer_cast<SlaveBase>( n ) ) 00030 { 00031 // it's a slave, so set up a container containing only "through", not "compare" or "replace" 00032 shared_ptr< Sequence<Node> > seq( new Sequence<Node> ); 00033 seq->push_back( sb->GetThrough() ); 00034 return seq; 00035 } 00036 else 00037 { 00038 // it's not a slave, so proceed as for UniqueWalk 00039 return UniqueWalk::iterator::GetChildContainer(n); 00040 } 00041 } 00042 }; 00043 00044 typedef ContainerFromIterator< UniqueWalkNoSlavePattern_iterator, TreePtr<Node> > UniqueWalkNoSlavePattern; 00045 00046 00047 CompareReplace::CompareReplace( TreePtr<Node> cp, 00048 TreePtr<Node> rp, 00049 bool im ) : 00050 is_master( im ), 00051 compare_pattern( NULL ), 00052 replace_pattern( NULL ), 00053 master_ptr( NULL ) 00054 { 00055 if( cp ) 00056 Configure( cp, rp ); 00057 } 00058 00059 00060 void CompareReplace::Configure( TreePtr<Node> cp, 00061 TreePtr<Node> rp ) 00062 { 00063 // TODO now that this operates per-slave instead of recursing through everything from the 00064 // master, we need to obey the rule that slave patterns are complete before Configure, as 00065 // with master. Maybe an optional check on first invocation? And change all existing 00066 // steps to comply. 00067 ASSERT( cp ); 00068 00069 // If only a search pattern is supplied, make the replace pattern the same 00070 // so they couple and then an overlay node can split them apart again. 00071 if( !rp ) 00072 rp = cp; 00073 00074 TRACE("Elaborating ")(string( *this ))(" at %p\n", this); 00075 // Fill in fields on the stuff nodes, but not in slaves 00076 UniqueWalkNoSlavePattern tsp(cp); 00077 FOREACH( TreePtr<Node> n, tsp ) 00078 { 00079 if( shared_ptr<StuffBase> sb = dynamic_pointer_cast<StuffBase>(n) ) 00080 { 00081 TRACE("Found stuff@%p, rr@%p\n", sb.get(), sb->recurse_restriction.get()); 00082 sb->recurse_comparer.coupling_keys.SetMaster( &coupling_keys ); 00083 sb->recurse_comparer.compare_pattern = sb->recurse_restriction; // TODO could move into a Stuff node constructor if there was one 00084 } 00085 if( shared_ptr<CouplingSlave> cs = dynamic_pointer_cast<CouplingSlave>(n) ) 00086 { 00087 TRACE("Found coupling slave in search pattern at %p\n", cs.get() ); 00088 cs->SetCouplingsMaster( &coupling_keys ); 00089 } 00090 } 00091 00092 // look for first-level slaves. Set their couplings master pointer to point 00093 // to our couplings. 00094 UniqueWalkNoSlavePattern ss(rp); 00095 FOREACH( TreePtr<Node> n, ss ) 00096 { 00097 if( shared_ptr<CouplingSlave> cs = dynamic_pointer_cast<CouplingSlave>(n) ) 00098 { 00099 TRACE("Found coupling slave in replace pattern at %p\n", cs.get() ); 00100 cs->SetCouplingsMaster( &coupling_keys ); 00101 } 00102 if( shared_ptr<CompareReplace> cr = dynamic_pointer_cast<CompareReplace>(n) ) 00103 { 00104 cr->master_ptr = this; 00105 } 00106 } 00107 00108 // Finally store the patterns in the object (we are now ready to transform) 00109 compare_pattern = cp; 00110 replace_pattern = rp; 00111 } 00112 00113 00114 void CompareReplace::GetGraphInfo( vector<string> *labels, 00115 vector< TreePtr<Node> > *links ) const 00116 { 00117 labels->push_back("compare"); 00118 links->push_back(compare_pattern); 00119 labels->push_back("replace"); 00120 links->push_back(replace_pattern); 00121 } 00122 00123 00124 // Helper for DecidedCompare that does the actual match testing work for the children and recurses. 00125 // Also checks for soft matches. 00126 bool CompareReplace::DecidedCompare( const TreePtrInterface &x, 00127 TreePtr<Node> pattern, 00128 bool can_key, 00129 Conjecture &conj ) const 00130 { 00131 NormalAgent agent; 00132 agent.Configure( this, &coupling_keys ); 00133 return agent.DecidedCompare( x, pattern, can_key, conj ); 00134 } 00135 00136 00137 bool CompareReplace::MatchingDecidedCompare( const TreePtrInterface &x, 00138 TreePtr<Node> pattern, 00139 bool can_key, 00140 Conjecture &conj ) const 00141 { 00142 INDENT; 00143 bool r; 00144 00145 if( can_key ) 00146 coupling_keys.Clear(); 00147 00148 // Only key if the keys are already set to KEYING (which is 00149 // the initial value). Keys could be RESTRICTING if we're under 00150 // a SoftNot node, in which case we only want to restrict. 00151 if( can_key ) 00152 { 00153 // Do a two-pass matching process: first get the keys... 00154 TRACE("doing KEYING pass....\n"); 00155 conj.PrepareForDecidedCompare(); 00156 r = DecidedCompare( x, pattern, true, conj ); 00157 TRACE("KEYING pass result %d\n", r ); 00158 if( !r ) 00159 return false; // Save time by giving up if no match found 00160 } 00161 00162 // Now restrict the search according to the couplings 00163 TRACE("doing RESTRICTING pass....\n"); 00164 conj.PrepareForDecidedCompare(); 00165 r = DecidedCompare( x, pattern, false, conj ); 00166 TRACE("RESTRICTING pass result %d\n", r ); 00167 if( !r ) 00168 return false; // Save time by giving up if no match found 00169 00170 // Do not revert match keys if we were successful - keep them for replace 00171 // and any slave search and replace operations we might do. 00172 return true; 00173 } 00174 00175 00176 void CompareReplace::FlushSoftPatternCaches( TreePtr<Node> pattern ) const 00177 { 00178 UniqueWalk t(pattern); 00179 FOREACH( TreePtr<Node> n, t ) 00180 if( shared_ptr<Flushable> ssp = dynamic_pointer_cast<Flushable>(n) ) 00181 ssp->FlushCache(); 00182 } 00183 00184 00185 bool CompareReplace::Compare( const TreePtrInterface &x, 00186 TreePtr<Node> pattern, 00187 bool can_key ) const 00188 { 00189 INDENT("C"); 00190 ASSERT( x ); 00191 ASSERT( pattern ); 00192 TRACE("Compare @%p x=", this)(*x); 00193 TRACE(" pattern=")(*pattern); 00194 TRACE(" can_key=%d \n", (int)can_key); 00195 //TRACE(**pcontext)(" @%p\n", pcontext); 00196 00197 // easy optimisation - also important because couplings do this a lot 00198 if( x == pattern ) 00199 return true; 00200 00201 // Reset caches for this search run - the input tree will not change until 00202 // the search is complete so stuff may be cached. 00203 FlushSoftPatternCaches( pattern ); 00204 00205 // Create the conjecture object we will use for this compare, and keep iterating 00206 // though different conjectures trying to find one that allows a match. 00207 Conjecture conj; 00208 bool r; 00209 while(1) 00210 { 00211 // Try out the current conjecture. This will call HandlDecision() once for each decision; 00212 // HandleDecision() will return the current choice for that decision, if absent it will 00213 // add the decision and choose the first choice, if the decision reaches the end it 00214 // will remove the decision. 00215 r = MatchingDecidedCompare( x, pattern, can_key, conj ); 00216 00217 // If we got a match, we're done. If we didn't, and we've run out of choices, we're done. 00218 if( r ) 00219 break; // Success 00220 00221 if( !conj.Increment() ) 00222 break; // Failure 00223 } 00224 return r; 00225 } 00226 00227 00228 bool CompareReplace::IsMatch( TreePtr<Node> context, 00229 TreePtr<Node> root ) 00230 { 00231 pcontext = &context; 00232 ASSERT( compare_pattern ); 00233 bool r = Compare( root, compare_pattern, false ); 00234 pcontext = NULL; 00235 return r == true; 00236 } 00237 00238 00239 TreePtr<Node> CompareReplace::DuplicateNode( TreePtr<Node> source, 00240 bool force_dirty ) const 00241 { 00242 INDENT; 00243 00244 // Make the new node (destination node) 00245 shared_ptr<Cloner> dup_dest = source->Duplicate(source); 00246 TreePtr<Node> dest = dynamic_pointer_cast<Node>( dup_dest ); 00247 ASSERT(dest); 00248 00249 bool source_dirty = GetOverallMaster()->dirty_grass.find( source ) != GetOverallMaster()->dirty_grass.end(); 00250 if( force_dirty || // requested by caller 00251 source_dirty ) // source was dirty 00252 { 00253 TRACE("dirtying ")(*dest)(" force=%d source=%d (")(*source)(")\n", force_dirty, source_dirty); 00254 GetOverallMaster()->dirty_grass.insert( dest ); 00255 } 00256 00257 return dest; 00258 } 00259 00260 00261 TreePtr<Node> CompareReplace::DuplicateSubtree( TreePtr<Node> source, 00262 TreePtr<Node> source_terminus, 00263 TreePtr<Node> dest_terminus ) const 00264 { 00265 INDENT; 00266 ASSERT( source ); 00267 if( source_terminus ) 00268 ASSERT( dest_terminus ); 00269 // Under substitution, we should be duplicating a subtree of the input 00270 // program, which should not contain any special nodes 00271 ASSERT( !(dynamic_pointer_cast<SpecialBase>(source)) ) 00272 ("Cannot duplicate special node ")(*source); 00273 00274 // If source_terminus and dest_terminus are supplied, substitute dest_terminus node 00275 // in place of all copes of source terminus (directly, without duplicating). 00276 if( source_terminus && source == source_terminus ) 00277 return dest_terminus; 00278 00279 // Make a new node, since we're substituting, preserve dirtyness 00280 TreePtr<Node> dest = DuplicateNode( source, false ); 00281 00282 // Itemise the members. Note that the itemiser internally does a 00283 // dynamic_cast onto the type of source, and itemises over that type. dest must 00284 // be dynamic_castable to source's type. 00285 vector< Itemiser::Element * > keynode_memb = source->Itemise(); 00286 vector< Itemiser::Element * > dest_memb = dest->Itemise(); 00287 00288 TRACE("Duplicating %d members source=", dest_memb.size())(*source)(" dest=")(*dest)("\n"); 00289 // Loop over all the members of source (which can be a subset of dest) 00290 // and for non-NULL members, duplicate them by recursing and write the 00291 // duplicates to the destination. 00292 for( int i=0; i<dest_memb.size(); i++ ) 00293 { 00294 TRACE("Duplicating member %d\n", i ); 00295 ASSERT( keynode_memb[i] )( "itemise returned null element" ); 00296 ASSERT( dest_memb[i] )( "itemise returned null element" ); 00297 00298 if( ContainerInterface *keynode_con = dynamic_cast<ContainerInterface *>(keynode_memb[i]) ) 00299 { 00300 ContainerInterface *dest_con = dynamic_cast<ContainerInterface *>(dest_memb[i]); 00301 00302 dest_con->clear(); 00303 00304 TRACE("Duplicating container size %d\n", keynode_con->size() ); 00305 FOREACH( const TreePtrInterface &p, *keynode_con ) 00306 { 00307 ASSERT( p ); // present simplified scheme disallows NULL 00308 TRACE("Duplicating ")(*p)("\n"); 00309 TreePtr<Node> n = DuplicateSubtree( p, source_terminus, dest_terminus ); 00310 TRACE("Normal element, inserting ")(*n)(" directly\n"); 00311 dest_con->insert( n ); 00312 } 00313 } 00314 else if( TreePtrInterface *keynode_ptr = dynamic_cast<TreePtrInterface *>(keynode_memb[i]) ) 00315 { 00316 TRACE("Duplicating node ")(*keynode_ptr)("\n"); 00317 TreePtrInterface *dest_ptr = dynamic_cast<TreePtrInterface *>(dest_memb[i]); 00318 ASSERT( *keynode_ptr )("source should be non-NULL"); 00319 *dest_ptr = DuplicateSubtree( *keynode_ptr, source_terminus, dest_terminus ); 00320 ASSERT( *dest_ptr ); 00321 ASSERT( TreePtr<Node>(*dest_ptr)->IsFinal() ); 00322 } 00323 else 00324 { 00325 ASSERTFAIL("got something from itemise that isn't a sequence or a shared pointer"); 00326 } 00327 } 00328 00329 return dest; 00330 } 00331 00332 00333 // Key for replace by just walking the tree (uniquised walk, not recursing into 00334 // the compare, search or replace fields of slaves) activating soft nodes and keying 00335 // them. 00336 void CompareReplace::KeyReplaceNodes( TreePtr<Node> pattern ) const 00337 { 00338 INDENT; 00339 TRACE("Walking replace pattern to key the soft nodes\n"); 00340 00341 UniqueWalkNoSlavePattern e(pattern); 00342 FOREACH( TreePtr<Node> pattern, e ) 00343 { 00344 TRACE(*pattern)("\n"); 00345 TreePtr<Node> key = pattern; 00346 if( shared_ptr<SoftReplacePattern> srp = dynamic_pointer_cast<SoftReplacePattern>( pattern ) ) 00347 { 00348 TRACE("Soft replace pattern not keyed, ")(*pattern)("\n"); 00349 00350 // Call the soft pattern impl 00351 key = srp->DuplicateSubtree( this ); 00352 if( key ) 00353 { 00354 // Allow this to key a coupling. 00355 coupling_keys.DoKey( key, pattern ); 00356 } 00357 } 00358 } 00359 } 00360 00361 00362 TreePtr<Node> CompareReplace::BuildReplace( TreePtr<Node> pattern ) const 00363 { 00364 NormalAgent agent; 00365 agent.Configure( this, &coupling_keys ); 00366 return agent.BuildReplace( pattern ); 00367 } 00368 00369 TreePtr<Node> CompareReplace::ReplacePhase( TreePtr<Node> pattern ) const 00370 { 00371 INDENT("R"); 00372 00373 // Do a two-pass process: first get the keys... 00374 TRACE("doing replace KEYING pass....\n"); 00375 //(void)DuplicateSubtree( pattern, true ); 00376 KeyReplaceNodes( pattern ); 00377 TRACE("replace KEYING pass\n" ); 00378 00379 // Now replace according to the couplings 00380 TRACE("doing replace SUBSTITUTING pass....\n"); 00381 TreePtr<Node> r = BuildReplace( pattern ); 00382 00383 // TODO do an overlay, means *proot needs passing in here and this fn should be renamed. 00384 TRACE("replace SUBSTITUTING pass\n" ); 00385 return r; 00386 } 00387 00388 00389 bool CompareReplace::SingleCompareReplace( TreePtr<Node> *proot ) 00390 { 00391 INDENT; 00392 00393 // Explicitly preserve the coupling keys structure - we do this instead 00394 // of clearing the keys in case the keys were set up in advance, as will 00395 // be the case if this is a slave. 00396 00397 TRACE("%p Begin search\n", this); 00398 bool r = Compare( *proot, compare_pattern, true ); 00399 if( !r ) 00400 return false; 00401 00402 if( r == true && replace_pattern ) 00403 { 00404 TRACE("%p Search successful, now replacing\n", this); 00405 *proot = ReplacePhase( replace_pattern ); 00406 } 00407 00408 // Clean up, to allow dead nodes to be deleted 00409 coupling_keys.Clear(); 00410 00411 return r; 00412 } 00413 00414 00415 // Perform search and replace on supplied program based 00416 // on supplied patterns and couplings. Does search and replace 00417 // operations repeatedly until there are no more matches. Returns how 00418 // many hits we got. 00419 int CompareReplace::RepeatingCompareReplace( TreePtr<Node> *proot ) 00420 { 00421 INDENT; 00422 if( !master_ptr ) 00423 dirty_grass.clear(); 00424 00425 TRACE("begin RCR %p\n", this); 00426 00427 bool r=false; 00428 int i=0; 00429 for(i=0; i<repetitions; i++) 00430 { 00431 r = SingleCompareReplace( proot ); 00432 TRACE("%p SCR result %d\n", this, r); 00433 if( !r ) 00434 break; // when the compare fails, we're done 00435 TRACE("Dirty grass:"); 00436 FOREACH( TreePtr<Node> n, dirty_grass ) 00437 TRACE(" ")(*n); 00438 TRACE("\n"); 00439 // Validate()( *pcontext, proot ); 00440 } 00441 00442 if( r==true ) 00443 { 00444 TRACE("Over %d reps\n",i); 00445 if(rep_error) 00446 ASSERT(i<repetitions) 00447 ("Still getting matches after %d repetitions, may be repeating forever.\n" 00448 "Try using -rn%d to suppress this error\n", i, i); 00449 } 00450 00451 if( !master_ptr ) 00452 dirty_grass.clear(); 00453 00454 TRACE("%p exiting\n", this); 00455 return i; 00456 } 00457 00458 00459 // Do a search and replace based on patterns stored in our members 00460 void CompareReplace::operator()( TreePtr<Node> c, TreePtr<Node> *proot ) 00461 { 00462 INDENT(""); 00463 TRACE("Enter S&R instance at %p\n", this); 00464 ASSERT( compare_pattern )("CompareReplace (or SearchReplace) object was not configured before invocation.\n" 00465 "Either call Configure() or supply pattern arguments to constructor.\n" 00466 "Thank you for taking the time to read this message.\n"); 00467 00468 // If the initial root and context are the same node, then arrange for the context 00469 // to follow the root node as we modify it (in SingleSearchReplace()). This ensures 00470 // new declarations can be found in slave searches. 00471 // 00472 // TODO but does not work for sub-slaves, because the first level slave's proot 00473 // is not the same as pcontext. When slave finishes a singe CR, only the locally-created 00474 // *proot is updated, not the top level *proot or *pcontext, so the updates do not appear 00475 // in the context until the first level slave completes, the local *proot is copied over 00476 // the TL *proot (and hence *pcontext) and the mechanism described here kicks in 00477 // 00478 // We could get the 00479 // same effect by taking the context as a reference, but leave it like this for now. 00480 // If *proot is under context, then we're OK as long as proot points to the actual 00481 // tree node - then the walk at context will follow the new *proot pointer and get 00482 // into the new subtree. 00483 if( c == *proot ) 00484 pcontext = proot; 00485 else 00486 pcontext = &c; 00487 00488 (void)RepeatingCompareReplace( proot ); 00489 00490 pcontext = NULL; // just to avoid us relying on the context outside of a search+replace pass 00491 } 00492 00493 00494 SearchReplace::SearchReplace( TreePtr<Node> sp, 00495 TreePtr<Node> rp, 00496 bool im ) : 00497 CompareReplace( NULL, NULL, im ) 00498 { 00499 if( sp ) 00500 Configure( sp, rp ); 00501 } 00502 00503 00504 void SearchReplace::Configure( TreePtr<Node> sp, 00505 TreePtr<Node> rp ) 00506 { 00507 ASSERT( sp ); // a search pattern is required to configure the engine 00508 00509 // Make a non-rooted search and replace (ie where the base of the search pattern 00510 // does not have to be the root of the whole program tree). 00511 // Insert a Stuff node as root of the search pattern 00512 // Needs to be Node, because we don't want pre-restriction action here (if we're a slave 00513 // we got pre-restricted already. 00514 TreePtr< Stuff<Node> > stuff( new Stuff<Node> ); 00515 00516 if( !rp ) 00517 { 00518 // Search and replace immediately coupled, insert Stuff, but don't bother 00519 // with the redundant Overlay. 00520 stuff->terminus = sp; 00521 CompareReplace::Configure( stuff ); 00522 } 00523 else 00524 { 00525 // Classic search and replace with seperate replace pattern, we can use 00526 // an Overlay node to overwrite the replace pattern at replace time. 00527 00528 // Insert a Stuff node as root of the replace pattern 00529 TreePtr< Overlay<Node> > overlay( new Overlay<Node> ); 00530 stuff->terminus = overlay; 00531 overlay->through = sp; 00532 overlay->overlay = rp; 00533 00534 // Configure the rooted implementation (CompareReplace) with new patterns and couplings 00535 CompareReplace::Configure( stuff, stuff ); 00536 } 00537 } 00538 00539 00540 void SearchReplace::GetGraphInfo( vector<string> *labels, 00541 vector< TreePtr<Node> > *links ) const 00542 { 00543 // Find the original patterns 00544 TreePtr< Stuff<Node> > stuff = dynamic_pointer_cast< Stuff<Node> >(compare_pattern); 00545 ASSERT( stuff ); 00546 TreePtr< Overlay<Node> > overlay = dynamic_pointer_cast< Overlay<Node> >(stuff->terminus); 00547 if( overlay ) 00548 { 00549 labels->push_back("search"); 00550 links->push_back(overlay->through); 00551 labels->push_back("replace"); 00552 links->push_back(overlay->overlay); 00553 } 00554 else 00555 { 00556 labels->push_back("search_replace"); 00557 links->push_back(stuff->terminus); 00558 } 00559 } 00560 00561 00562 shared_ptr<ContainerInterface> StuffBase::GetContainerInterface( TreePtr<Node> x ) 00563 00564 { 00565 Filter *rf = NULL; 00566 if( recurse_restriction ) 00567 { 00568 ASSERT( recurse_comparer.compare_pattern )("Stuff node in slave must be initialised before slave (at %p)\n", this); 00569 rf = &recurse_comparer; 00570 } 00571 00572 if( one_level ) 00573 return shared_ptr<ContainerInterface>( new FlattenNode( x ) ); 00574 else 00575 return shared_ptr<ContainerInterface>( new Walk( x, NULL, rf ) ); 00576 } 00577 00578 00579 bool StarBase::MatchRange( const CompareReplace *sr, 00580 ContainerInterface &range, 00581 bool can_key ) 00582 { 00583 INDENT; 00584 // this is an abnormal context (which of the program nodes 00585 // in the range should key the pattern?) so just wave keying 00586 // pass right on through. 00587 if( can_key ) 00588 return true; 00589 00590 TreePtr<Node> p = GetPattern(); 00591 if( p ) 00592 { 00593 TRACE("MatchRange pattern\n"); 00594 // Apply pattern restriction - will be at least as strict as pre-restriction 00595 FOREACH( TreePtr<Node> x, range ) 00596 { 00597 bool r = sr->Compare( x, p, false ); 00598 if( !r ) 00599 return false; 00600 } 00601 } 00602 else 00603 { 00604 TRACE("MatchRange pre-res\n"); 00605 // No pattern, so just use pre-restrictions 00606 FOREACH( TreePtr<Node> x, range ) 00607 { 00608 if( !IsLocalMatch( x.get()) ) 00609 return false; 00610 } 00611 } 00612 TRACE("done\n"); 00613 return true; 00614 } 00615 00616 00617 00618 shared_ptr<ContainerInterface> AnyNodeBase::GetContainerInterface( TreePtr<Node> x ) 00619 { 00620 TRACE("FlattenNodeing an AnyNode at ")(*x)(": { "); 00621 FlattenNode f( x ); 00622 FOREACH( TreePtr<Node> pn, f ) 00623 {TRACE(*pn)(" ");} 00624 TRACE("}\n"); 00625 00626 return shared_ptr<ContainerInterface>( new FlattenNode( x ) ); 00627 } 00628 00629 00630 void CompareReplace::Test() 00631 { 00632 #if 0 00633 CompareReplace sr = CompareReplace( MakeTreePtr<Nop>(), MakeTreePtr<Nop>() ); // TODO we're only using compare side 00634 00635 { 00636 // single node with topological wildcarding 00637 TreePtr<Void> v(new Void); 00638 ASSERT( sr.Compare( v, v ) == true ); 00639 TreePtr<Boolean> b(new Boolean); 00640 ASSERT( sr.Compare( v, b ) == false ); 00641 ASSERT( sr.Compare( b, v ) == false ); 00642 TreePtr<Type> t(new Type); 00643 ASSERT( sr.Compare( v, t ) == true ); 00644 ASSERT( sr.Compare( t, v ) == false ); 00645 ASSERT( sr.Compare( b, t ) == true ); 00646 ASSERT( sr.Compare( t, b ) == false ); 00647 00648 // node points directly to another with TC 00649 TreePtr<Pointer> p1(new Pointer); 00650 p1->destination = v; 00651 ASSERT( sr.Compare( p1, b ) == false ); 00652 ASSERT( sr.Compare( p1, p1 ) == true ); 00653 TreePtr<Pointer> p2(new Pointer); 00654 p2->destination = b; 00655 ASSERT( sr.Compare( p1, p2 ) == false ); 00656 p2->destination = t; 00657 ASSERT( sr.Compare( p1, p2 ) == true ); 00658 ASSERT( sr.Compare( p2, p1 ) == false ); 00659 } 00660 00661 { 00662 // string property 00663 TreePtr<SpecificString> s1( new SpecificString("here") ); 00664 TreePtr<SpecificString> s2( new SpecificString("there") ); 00665 ASSERT( sr.Compare( s1, s1 ) == true ); 00666 // ASSERT( sr.Compare( s1, s2 ) == false ); 00667 //TODO seems to get a crash freeing s1 or s2 if uncommented, latent problem in SpecificString? 00668 } 00669 00670 { 00671 // int property 00672 TreePtr<SpecificInteger> i1( new SpecificInteger(3) ); 00673 TreePtr<SpecificInteger> i2( new SpecificInteger(5) ); 00674 TRACE(" %s %s\n", ((llvm::APSInt)*i1).toString(10).c_str(), ((llvm::APSInt)*i2).toString(10).c_str() ); 00675 ASSERT( sr.Compare( i1, i1 ) == true ); 00676 ASSERT( sr.Compare( i1, i2 ) == false ); 00677 } 00678 00679 00680 { 00681 // node with sequence, check lengths 00682 TreePtr<Compound> c1( new Compound ); 00683 ASSERT( sr.Compare( c1, c1 ) == true ); 00684 TreePtr<Nop> n1( new Nop ); 00685 c1->statements.push_back( n1 ); 00686 ASSERT( sr.Compare( c1, c1 ) == true ); 00687 TreePtr<Nop> n2( new Nop ); 00688 c1->statements.push_back( n2 ); 00689 ASSERT( sr.Compare( c1, c1 ) == true ); 00690 TreePtr<Compound> c2( new Compound ); 00691 ASSERT( sr.Compare( c1, c2 ) == false ); 00692 TreePtr<Nop> n3( new Nop ); 00693 c2->statements.push_back( n3 ); 00694 ASSERT( sr.Compare( c1, c2 ) == false ); 00695 TreePtr<Nop> n4( new Nop ); 00696 c2->statements.push_back( n4 ); 00697 ASSERT( sr.Compare( c1, c2 ) == true ); 00698 TreePtr<Nop> n5( new Nop ); 00699 c2->statements.push_back( n5 ); 00700 ASSERT( sr.Compare( c1, c2 ) == false ); 00701 } 00702 00703 { 00704 // node with sequence, TW 00705 TreePtr<Compound> c1( new Compound ); 00706 TreePtr<Nop> n1( new Nop ); 00707 c1->statements.push_back( n1 ); 00708 TreePtr<Compound> c2( new Compound ); 00709 TreePtr<Statement> s( new Statement ); 00710 c2->statements.push_back( s ); 00711 ASSERT( sr.Compare( c1, c2 ) == true ); 00712 ASSERT( sr.Compare( c2, c1 ) == false ); 00713 } 00714 00715 { 00716 // topological with extra member in target node 00717 /* gone obsolete with tree changes TODO un-obsolete 00718 TreePtr<Label> l( new Label ); 00719 TreePtr<Public> p1( new Public ); 00720 l->access = p1; 00721 00722 TreePtr<LabelIdentifier> li( new LabelIdentifier ); 00723 li->name = "mylabel"; 00724 l->identifier = li; 00725 TreePtr<Declaration> d( new Declaration ); 00726 TreePtr<Public> p2( new Public ); 00727 d->access = p2; 00728 ASSERT( sr.Compare( l, d ) == true ); 00729 ASSERT( sr.Compare( d, l ) == false ); 00730 TreePtr<Private> p3( new Private ); 00731 d->access = p3; 00732 ASSERT( sr.Compare( l, d ) == false ); 00733 ASSERT( sr.Compare( d, l ) == false ); 00734 TreePtr<AccessSpec> p4( new AccessSpec ); 00735 d->access = p4; 00736 ASSERT( sr.Compare( l, d ) == true ); 00737 ASSERT( sr.Compare( d, l ) == false ); 00738 */ 00739 } 00740 #endif 00741 } 00742 /* 00743 #ifdef STRACE 00744 TRACE("DuplicateSubtree pattern={"); 00745 Walk w(pattern); 00746 bool first=true; 00747 FOREACH( TreePtr<Node> n, w ) 00748 { 00749 if( !first ) 00750 TRACE(", "); 00751 if( n ) 00752 TRACE( *n )(":%p", n.get()); 00753 else 00754 TRACE("NULL"); 00755 first=false; 00756 } 00757 TRACE("}\n"); // TODO put this in as a common utility somewhere 00758 #endif 00759 */