/vesta/vestasys.org/vesta/eval/98/src/Debug.C

Go to the documentation of this file.
00001 // Copyright (C) 2001, Compaq Computer Corporation
00002 // 
00003 // This file is part of Vesta.
00004 // 
00005 // Vesta is free software; you can redistribute it and/or
00006 // modify it under the terms of the GNU Lesser General Public
00007 // License as published by the Free Software Foundation; either
00008 // version 2.1 of the License, or (at your option) any later version.
00009 // 
00010 // Vesta is distributed in the hope that it will be useful,
00011 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00012 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013 // Lesser General Public License for more details.
00014 // 
00015 // You should have received a copy of the GNU Lesser General Public
00016 // License along with Vesta; if not, write to the Free Software
00017 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00018 
00019 // File: Debug.C
00020 
00021 #include "Debug.H"
00022 #include "Expr.H"
00023 
00024 #include <ThreadIO.H>
00025 
00026 using std::ostream;
00027 using std::cout;
00028 using std::endl;
00029 using std::flush;
00030 using OS::cio;
00031 
00032 bool CacheIt(Val v) {
00033   if (!v->cacheit) {
00034     cio().start_err() << "Cannot be cached." << endl;
00035     cio().end_err();
00036     return false;
00037   }
00038   switch (v->vKind) {
00039   case BindingVK:
00040     {
00041       Binding b = (BindingVC*)v;
00042       Context elems = b->elems;
00043       while (!elems.Null()) {
00044         if (!CacheIt(elems.Pop()->val))
00045           return false;
00046       }
00047       break;
00048     }
00049   case ListVK:
00050     {
00051       Vals elems = ((ListVC*)v)->elems;
00052       while (!elems.Null()) {
00053         if (!CacheIt(elems.Pop()))
00054           return false;
00055       }
00056       break;
00057     }
00058   default:
00059     break;
00060   }
00061   return true;
00062 }
00063 
00064 void PrintVars(ostream& os, const Vars& fv) 
00065 {
00066   Vars vars = fv;
00067   os << "< ";
00068   if (!vars.Null())
00069     os << vars.Pop();
00070   while (!vars.Null())
00071     os << ", " << vars.Pop();
00072   os << " >";
00073   os.flush();
00074 }
00075 
00076 void PrintTags(ostream& os, const FP::List& tags) 
00077 {
00078   os << "{" << endl;
00079   for (int i = 0; i < tags.len; i++) {
00080     os << "  " << i << ". " << tags.fp[i] << endl;
00081   }
00082   os << "}" << endl;
00083   return;
00084 }
00085 
00086 void PrintNames(ostream& os, const FV2::List& names) 
00087 {
00088   os << "{" << endl;
00089   for (int i = 0; i < names.len; i++) {
00090     os << "  " << i << ". " << *names.name[i] << endl;
00091   }
00092   os << "}" << endl;
00093   return;
00094 } 
00095 
00096 Val ContextNames(const Context& c) {
00097   Context work = c;
00098 
00099   Vals names;
00100   while (!work.Null()) {
00101     names.Append1D(NEW_CONSTR(TextVC, (work.Pop()->name)));
00102   }
00103   return NEW_CONSTR(ListVC, (names));
00104 }
00105 
00106 void PrintDpnd(ostream& os, Val v) 
00107 {
00108   int index = 0;
00109   os << "{ ";
00110   if (v->path) {
00111     os << index++ << ". <";
00112     v->path->Print(os);
00113     os << " : ";
00114     v->PrintD(os);
00115     os << ">";
00116     os << ";";
00117   }
00118   if (v->SizeOfDPS() != 0) {
00119     DepPathTbl::TIter iter(v->dps);
00120     DepPathTbl::KVPairPtr ptr;    
00121     if (iter.Next(ptr)) {
00122       os << endl << "  " << index++ << ". <";
00123       ptr->key.Print(os);
00124       os << " : ";
00125       ptr->val->PrintD(os);
00126       os << ">";
00127       while (iter.Next(ptr)) {
00128         os << "," << endl << "  " << index++ << ". <";
00129         ptr->key.Print(os);
00130         os << " : ";
00131         ptr->val->PrintD(os);
00132         os << ">";
00133       }
00134     }
00135   }
00136   os << " }" << endl;
00137 }
00138 
00139 void CollectAllDpnd(Val v, bool isModel, /*OUT*/ DPaths& ps) {
00140   /* Collect all the dependency of v into ps. */
00141 
00142   // collect v->dps:
00143   if (v->SizeOfDPS() == 0)
00144     v->dps = NULL;
00145   else {
00146     DepPathTbl::TIter iter(v->dps);
00147     DepPathTbl::KVPairPtr ptr;
00148     if (isModel) {
00149       while (iter.Next(ptr)) {
00150         if (ptr->key.content->path->getlo() == nameDot)
00151           (void)ps.Put(ptr);
00152       }
00153     }
00154     else {
00155       while (iter.Next(ptr))
00156         (void)ps.Put(ptr);
00157     }
00158   }
00159   DepPath *dp = v->path;
00160   if (dp != NULL) {
00161     // collect v->path:
00162     if (!isModel || (dp->content->path->getlo() == nameDot)) {
00163       DepPathTbl::KVPairPtr pr;
00164       (void)ps.Put(*dp, v, pr);
00165       // assert(v->FingerPrint() == pr->val->FingerPrint());
00166     }
00167     else
00168       v->path = NULL;
00169   }
00170   else {
00171     // collect components of the value (only when no path):
00172     switch (v->vKind) {
00173     case BindingVK:
00174       {
00175         BindingVC *bv = (BindingVC*)v;
00176         if (bv->lenDps != NULL && bv->lenDps->Size() != 0) {
00177           DepPathTbl::TIter iter(bv->lenDps);
00178           DepPathTbl::KVPairPtr ptr;
00179           if (isModel) {
00180             while (iter.Next(ptr)) {
00181               if (ptr->key.content->path->getlo() == nameDot) {
00182                 DepPath lenPath(ptr->key.content->path, BLenPK, ptr->key.content->pathFP);
00183                 Val vNames = ((BindingVC*)ptr->val)->Names();
00184                 (void)ps.Put(lenPath, vNames, ptr);
00185                 // assert(vNames->FingerPrint() == ptr->val->FingerPrint());
00186               }
00187             }
00188           }
00189           else {
00190             while (iter.Next(ptr)) {
00191               DepPath lenPath(ptr->key.content->path, BLenPK, ptr->key.content->pathFP);
00192               Val vNames = ((BindingVC*)ptr->val)->Names();
00193               (void)ps.Put(lenPath, vNames, ptr);
00194               // assert(vNames->FingerPrint() == ptr->val->FingerPrint());
00195             }
00196           }
00197         }
00198         Context work = bv->elems;
00199         while (!work.Null())
00200           CollectAllDpnd(work.Pop()->val, isModel, ps);
00201         break;
00202       }
00203     case ListVK:
00204       {
00205         ListVC *lstv = (ListVC*)v;
00206         if (lstv->lenDps != NULL && lstv->lenDps->Size() != 0) {
00207           DepPathTbl::TIter iter(lstv->lenDps);
00208           DepPathTbl::KVPairPtr ptr;
00209           if (isModel) {
00210             while (iter.Next(ptr)) {
00211               if (ptr->key.content->path->getlo() == nameDot) {
00212                 DepPath lenPath(ptr->key.content->path, LLenPK, 
00213                                 ptr->key.content->pathFP);
00214                 Val vLen = NEW_CONSTR(IntegerVC, 
00215                                       (((ListVC*)ptr->val)->elems.Length()));
00216                 (void)ps.Put(lenPath, vLen, ptr);
00217                 // assert(vLen->FingerPrint() == ptr->val->FingernPrint());
00218               }
00219             }
00220           }
00221           else {
00222             while (iter.Next(ptr)) {
00223               DepPath lenPath(ptr->key.content->path, LLenPK, 
00224                               ptr->key.content->pathFP);
00225               Val vLen = NEW_CONSTR(IntegerVC, 
00226                                     (((ListVC*)ptr->val)->elems.Length()));
00227               (void)ps.Put(lenPath, vLen, ptr);
00228               // assert(vLen->FingerPrint() == ptr->val->FingerPrint());
00229             }
00230           }
00231         }
00232         Vals vv = lstv->elems;
00233         while (!vv.Null())
00234           CollectAllDpnd(vv.Pop(), isModel, ps);
00235         break;
00236       }
00237     case ClosureVK:
00238       {
00239         ClosureVC *cl = (ClosureVC*)v;
00240         Context work = cl->con;
00241         while (!work.Null()) {
00242           Assoc a = work.Pop();
00243           if (cl->func->name != a->name)
00244             CollectAllDpnd(a->val, isModel, ps);
00245         }
00246         break;
00247       }
00248     default:
00249       break;
00250     }
00251   }
00252   return;
00253 }
00254 
00255 void PrintAllDpnd(ostream& os, Val v) 
00256 {
00257   // Collect dependency:
00258   DPaths *ps = NEW_CONSTR(DPaths, (v->SizeOfDPS()));
00259   CollectAllDpnd(v, false, *ps);
00260   ps->Print(os);
00261 }
00262   
00263 void PrintDpndSize(ostream& os, Val v) 
00264 {
00265   switch (v->vKind) {
00266   case BindingVK:
00267     {
00268       Binding b = (BindingVC*)v;
00269       Context elems = b->elems;
00270       os << "[";
00271       os << v->SizeOfDPS();
00272       os << ", ";
00273       if (v->path != NULL) os << "*";
00274       os << "[";
00275       if (!elems.Null())
00276         PrintDpndSize(os, elems.Pop()->val);
00277       while (!elems.Null()) {
00278         os << ", ";
00279         PrintDpndSize(os, elems.Pop()->val);
00280       }
00281       os << "]]";
00282       break;
00283     }
00284   case ListVK:
00285     {
00286       Vals elems = ((ListVC*)v)->elems;
00287       os << "[";
00288       os << v->SizeOfDPS();
00289       os << ", ";
00290       if (v->path != NULL) os << "*";
00291       os << "[";
00292       if (!elems.Null())
00293         PrintDpndSize(os, elems.Pop());
00294       while (!elems.Null()) {
00295         os << ", ";
00296         PrintDpndSize(os, elems.Pop());
00297       }
00298       os << "]]";
00299       break;
00300     }
00301   default:
00302     os << v->SizeOfDPS();
00303     break;
00304   }
00305   return;
00306 }
00307 
00308 #ifndef NO_DUMP_VAL
00309 // Unless you #define NO_DUMP_VAL when compiling this file, an
00310 // additional function will be available:
00311 
00312 void DumpVal(Val v);
00313 
00314 // The DumpVal function isn't called by any part of the evaluator, but
00315 // can be very useful for developers working on the implementation of
00316 // the evaluator.  It dumps out the complete structure of a value,
00317 // including all dependency information to standard output.  Because
00318 // it is not overloaded and you don't have to pass cout to it, it's
00319 // easy to call it from a debugger.
00320 
00321 static Text DumpValIndent(unsigned int nesting)
00322 {
00323   Text result = "";
00324   for(unsigned int i = 0; i < nesting; i++)
00325     result += "    ";
00326   return result;
00327 }
00328 
00329 static const char *DumpValKind(ValueKind k)
00330 {
00331   switch(k)
00332     {
00333     case BooleanVK:
00334       return "bool";
00335     case IntegerVK:
00336       return "int";
00337     case ListVK:
00338       return "list";
00339     case BindingVK:
00340       return "binding";
00341     case PrimitiveVK:
00342       return "prim";
00343     case  TextVK:
00344       return "text";
00345     case ClosureVK:
00346       return "closure";
00347     case ModelVK:
00348       return "model";
00349     case ErrorVK:
00350       return "error";
00351     case FpVK:
00352       return "fp";
00353     case UnbndVK:
00354       return "unbound";
00355     }
00356 }
00357 
00358 static void DumpValInner(Val v, unsigned int nesting = 0)
00359 {
00360   Text indent = DumpValIndent(nesting);
00361   cout << indent << "Val @ " << ((void *) v) << endl
00362        << indent << " type : " << DumpValKind(v->vKind) << endl;
00363   if(v->path)
00364     {
00365       cout << indent << " path @ " << ((void *) v->path) << " : ";
00366       v->path->Print(cout);
00367       cout << endl;
00368     }
00369 
00370   if (v->SizeOfDPS() != 0)
00371     {
00372       cout << indent << " dps @ " << ((void *) v->dps) << " :" << endl;
00373       DepPathTbl::TIter iter(v->dps);
00374       DepPathTbl::KVPairPtr ptr;
00375       while(iter.Next(ptr))
00376         {
00377           int index = 0;
00378           cout << indent << "  " << index++ << ". <" << flush;
00379           ptr->key.Print(cout);
00380           cout << flush;
00381           cout << " : " << flush;
00382           ptr->val->PrintD(cout, false, (nesting*4)+3);
00383           cout << flush;
00384           cout << ">" << endl;
00385         }
00386     }
00387 
00388   switch (v->vKind)
00389     {
00390     case BindingVK:
00391       {
00392         BindingVC *bv = (BindingVC*)v;
00393         if(bv->lenDps && bv->lenDps->Size())
00394           {
00395             cout << indent << " lenDps @ " << ((void *) bv->lenDps) << " :"
00396                  << endl;
00397             DepPathTbl::TIter iter(bv->lenDps);
00398             DepPathTbl::KVPairPtr ptr;
00399             while(iter.Next(ptr))
00400               {
00401                 int index = 0;
00402                 cout << indent << "  " << index++ << ". <";
00403                 ptr->key.Print(cout);
00404                 cout << " : ";
00405                 ptr->val->PrintD(cout, false, (nesting*4)+3);
00406                 cout << ">";
00407               }
00408           }
00409 
00410         Context work = bv->elems;
00411         cout << indent << " value : " << endl
00412              << indent << "  [" << endl;
00413         while (!work.Null())
00414           {
00415             Assoc a = work.Pop();
00416             cout << indent << "   " << a->name << " = " << endl;
00417             DumpValInner(a->val, nesting + 1);
00418           }
00419         cout << indent << "  ]" << endl;
00420       }
00421       break;
00422     case ListVK:
00423       {
00424         ListVC *lv = (ListVC*)v;
00425 
00426         if(lv->lenDps && lv->lenDps->Size())
00427           {
00428             cout << indent << " lenDps @ " << ((void *) lv->lenDps) << " :"
00429                  << endl;
00430             DepPathTbl::TIter iter(lv->lenDps);
00431             DepPathTbl::KVPairPtr ptr;
00432             while(iter.Next(ptr))
00433               {
00434                 int index = 0;
00435                 cout << indent << "  " << index++ << ". <";
00436                 ptr->key.Print(cout);
00437                 cout << " : ";
00438                 ptr->val->PrintD(cout, false, (nesting*4)+3);
00439                 cout << ">";
00440               }
00441           }
00442 
00443         Vals elems = lv->elems;
00444         cout << indent << " value : " << endl
00445              << indent << "  <" << endl;
00446         while (!elems.Null())
00447           {
00448             DumpValInner(elems.Pop(), nesting + 1);
00449           }
00450       }
00451       break;
00452     case ClosureVK:
00453       {
00454         ClosureVC *cl = (ClosureVC*)v;
00455 
00456         cout << indent << " definition : "
00457              << cl->func->loc->file
00458              << ", line " << cl->func->loc->line
00459              << ", char " << cl->func->loc->character << endl;
00460 
00461         Context work = cl->con;
00462         cout << indent << " context : " << endl
00463              << indent << "  [" << endl;
00464         while (!work.Null())
00465           {
00466             Assoc a = work.Pop();
00467             if (a->name != cl->func->name)
00468               {
00469                 cout << indent << "   " << a->name << " = " << endl;
00470                 DumpValInner(a->val, nesting + 1);
00471               }
00472           }
00473         cout << indent << "  ]" << endl;
00474       }
00475       break;
00476     default:
00477       {
00478         cout << indent << " value : " << endl
00479              << indent << "  ";
00480         v->PrintD(cout, false, (nesting*4)+2);
00481         cout << endl;
00482       }
00483       break;
00484     }
00485 }
00486 
00487 void DumpVal(Val v)
00488 {
00489   DumpValInner(v);
00490   cout << endl;
00491 }
00492 #endif
00493 
00494 class DepCompareInfo
00495 {
00496 private:
00497   ostream &out;
00498   const Text &source;
00499   const FP::Tag &pk;
00500   CacheEntry::Index cIndex;
00501   bool printed;
00502 public:
00503   DepCompareInfo(ostream &o, const Text &s,
00504                  const FP::Tag &pk, CacheEntry::Index ci)
00505     : out(o), source(s), pk(pk), cIndex(ci), printed(false)
00506   {
00507   }
00508 
00509   void print()
00510   {
00511     if(!printed)
00512       {
00513         out << endl << "----- Dependency Differences In -----: " << endl 
00514             << source << endl
00515             << "Cache Hit PK: " << pk << endl
00516             << "Cache Index: " << cIndex << endl << endl;
00517         printed = true;
00518       }
00519   }
00520 };
00521 
00522 static void printDPSDiffInner(ostream &out,
00523                               DepCompareInfo &where, Text subpath,
00524                               DPaths* old_dps, DPaths* new_dps)
00525 {
00526   DPaths* deleted = 0;
00527   if(!new_dps)
00528     deleted = old_dps;
00529   else if(old_dps)
00530     deleted = old_dps->Difference(new_dps);
00531   if(deleted && deleted->Empty())
00532     deleted = 0;
00533 
00534   DPaths* added = 0;
00535   if(!old_dps)
00536     added = new_dps;
00537   else if(new_dps)
00538     added = new_dps->Difference(old_dps); 
00539   if(added && added->Empty())
00540     added = 0;
00541 
00542   if(deleted || added) {
00543     where.print();
00544     out << subpath << " :" << endl;
00545     if(deleted)
00546       deleted->Print(out, "-");
00547     if(added)
00548       added->Print(out, "+");
00549     out << endl;
00550   }
00551 }
00552 
00553 static void printDepsDiffInner(ostream &out,
00554                                DepCompareInfo &where, Text subpath,
00555                                Val old_v, Val new_v)
00556 {
00557   // Compare paths
00558   if(old_v->path || new_v->path)
00559     {
00560       // Path missing in old value
00561       if(!old_v->path)
00562         {
00563           where.print();
00564           out << subpath << "->path :" << endl
00565                << "  ! No old path" << endl
00566                << "  + ";
00567           new_v->path->Print(out);
00568           out << endl << endl;
00569         }
00570       // Path missing in new value
00571       else if(!new_v->path)
00572         {
00573           where.print();
00574           out << subpath << "->path :" << endl
00575                << "  - ";
00576           old_v->path->Print(out);
00577           out << endl
00578                << "  ! No new path" << endl << endl;
00579         }
00580       // Different paths
00581       else if(!(*(old_v->path) == *(new_v->path)))
00582         {
00583           where.print();
00584           out << subpath << "->path :" << endl
00585                << "  - ";
00586           old_v->path->Print(out);
00587           out << endl
00588                << "  + ";
00589           new_v->path->Print(out);
00590           out << endl << endl;
00591         }
00592     }
00593 
00594   // Compare dps
00595   printDPSDiffInner(out, where, subpath+"->dps",
00596                     old_v->dps, new_v->dps);
00597 
00598   // Check that they have the same type
00599   if(old_v->vKind != new_v->vKind)
00600     {
00601       where.print();
00602       out << subpath << "->vKind :" << endl
00603            << "  - " << DumpValKind(old_v->vKind) << endl
00604            << "  + " << DumpValKind(new_v->vKind) << endl << endl;
00605 
00606       // Can't possibly recurse on subvalues
00607       return;
00608     }
00609 
00610   // Recurse as appropriate for composite types
00611   switch (old_v->vKind)
00612     {
00613     case BindingVK:
00614       {
00615         BindingVC *old_bv = (BindingVC*)old_v;
00616         BindingVC *new_bv = (BindingVC*)new_v;
00617 
00618         // Compare lenDps
00619         printDPSDiffInner(out, where, subpath+"->lenDps",
00620                           old_bv->lenDps, new_bv->lenDps);
00621 
00622         // Remember binding names added/removed in case the values
00623         // have different names
00624         TextSeq name_del, name_add;
00625 
00626         // Loop over the contents of the old value
00627         Context work = old_bv->elems;
00628         while (!work.Null())
00629           {
00630             Assoc a = work.Pop();
00631             Val new_sv = new_bv->LookupNoDpnd(a->name);
00632             if(new_sv != valUnbnd)
00633               {
00634                 printDepsDiffInner(out, where, subpath+"/"+a->name,
00635                                    a->val, new_sv);
00636               }
00637             else
00638               {
00639                 // Name not bound in new value
00640                 name_del.addhi(a->name);
00641               }
00642           }
00643         // Check for names bound in new but not in old
00644         work = new_bv->elems;
00645         while(!work.Null())
00646           {
00647             Assoc a = work.Pop();
00648             if(old_bv->LookupNoDpnd(a->name) == valUnbnd)
00649               {
00650                 // Name not bound in old value
00651                 name_add.addhi(a->name);
00652               }
00653           }
00654         // If there are names present in one binding but not the
00655         // other, print a message about that.
00656         if((name_add.size() > 0) || (name_del.size() > 0))
00657           {
00658             where.print();
00659             out << subpath << "->{binding names} :" << endl;
00660             while(name_del.size() > 0)
00661               out << "  - " << name_del.remlo() << endl;
00662             while(name_add.size() > 0)
00663               out << "  + " << name_add.remlo() << endl;
00664           }
00665       }
00666       break;
00667     case ListVK:
00668       {
00669         ListVC *old_lv = (ListVC*)old_v;
00670         ListVC *new_lv = (ListVC*)new_v;
00671 
00672         // Compare lenDps
00673         printDPSDiffInner(out, where, subpath+"->lenDps",
00674                           old_lv->lenDps, new_lv->lenDps);
00675 
00676         // Loop over the list elements
00677         Vals old_elems = old_lv->elems;
00678         Vals new_elems = new_lv->elems;
00679         unsigned int i = 0;
00680         while(!old_elems.Null() && !new_elems.Null())
00681           {
00682             Val old_sv = old_elems.Pop();
00683             Val new_sv = new_elems.Pop();
00684             char i_str[11];
00685             sprintf(i_str, "%u", i);
00686             printDepsDiffInner(out, where, subpath+"["+Text(i_str)+"]",
00687                                old_sv, new_sv);
00688             i++;
00689           }
00690         // Check for extra elements in one of the lists
00691         if(!old_elems.Null() || !new_elems.Null())
00692           {
00693             where.print();
00694             out << subpath << "->{list length} :" << endl
00695                  << "  - " << old_lv->elems.Length() << endl
00696                  << "  + " << new_lv->elems.Length()  << endl;
00697           }
00698       }
00699       break;
00700     case ClosureVK:
00701       {
00702         ClosureVC *old_cl = (ClosureVC*)old_v;
00703         ClosureVC *new_cl = (ClosureVC*)new_v;
00704 
00705         // Remember context names added/removed in case the values
00706         // have different names
00707         TextSeq name_del, name_add;
00708 
00709         // Loop over the context of the first function
00710         Context work = old_cl->con;
00711         while(!work.Null())
00712           {
00713             Assoc a = work.Pop();
00714             if(a->name == old_cl->func->name)
00715               // Avoid infinite recursion.  (A functions own name
00716               // referes to itself in its definition context.)
00717               continue;
00718 
00719             Val new_sv = LookupInContext(a->name, new_cl->con);
00720             if(new_sv != valUnbnd)
00721               {
00722                 printDepsDiffInner(out, where, subpath+"/"+a->name,
00723                                    a->val, new_sv);
00724               }
00725             else
00726               {
00727                 // Name not bound in new context
00728                 name_del.addhi(a->name);
00729               }
00730           }
00731         // Check for names bound in new context but not in old
00732         work = new_cl->con;
00733         while(!work.Null())
00734           {
00735             Assoc a = work.Pop();
00736             if(LookupInContext(a->name, old_cl->con) == valUnbnd)
00737               {
00738                 // Name not bound in old value
00739                 name_add.addhi(a->name);
00740               }
00741           }
00742         // If there are names present in one context but not the
00743         // other, print a message about that.
00744         if((name_add.size() > 0) || (name_del.size() > 0))
00745           {
00746             where.print();
00747             out << subpath << "->{context names} :" << endl;
00748             while(name_del.size() > 0)
00749               out << "  - " << name_del.remlo() << endl;
00750             while(name_add.size() > 0)
00751               out << "  + " << name_add.remlo() << endl;
00752           }
00753       }
00754       break;
00755     }
00756 }
00757 
00758 void PrintDepsDiffs(const Text &source, const FP::Tag &pk, CacheEntry::Index cIndex, 
00759                     Val old_v, Val new_v, const Text &name)
00760 {
00761   ostream &out = cio().start_out();
00762 
00763   DepCompareInfo where(out, source, pk, cIndex);
00764   printDepsDiffInner(out, where, name, old_v, new_v);
00765 
00766   cio().end_out();
00767 }

Generated on Thu May 24 23:01:40 2007 for Vesta by  doxygen 1.5.1