Inferno  0.2
search_replace.cpp
Go to the documentation of this file.
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 */