/vesta/vestasys.org/vesta/eval/98/src/Val.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: Val.C
00020 
00021 #include "Val.H"
00022 #include "Expr.H"
00023 #include "Parser.H"
00024 #include "Location.H"
00025 #include "ModelState.H"
00026 #include "PrimRunTool.H"
00027 #include "Files.H"
00028 #include "Debug.H"
00029 #include <CacheC.H>
00030 #include <VestaSource.H>
00031 #include <UniqueId.H>
00032 #include <sys/types.h>
00033 #include <sys/stat.h>
00034 #include <BufStream.H>
00035 
00036 using std::ios;
00037 using std::ostream;
00038 using std::istream;
00039 using std::fstream;
00040 using std::endl;
00041 using std::oct;
00042 using std::hex;
00043 using std::dec;
00044 using Basics::OBufStream;
00045 using Basics::IBufStream;
00046 using OS::cio;
00047 
00048 static Basics::mutex valMu;
00049 
00050 // Useful constants:
00051 Val valTrue       = NEW_CONSTR(BooleanVC, (true));
00052 Val valFalse      = NEW_CONSTR(BooleanVC, (false));
00053 Val valZero       = NEW_CONSTR(IntegerVC, (0));
00054 Val valErr        = NEW_CONSTR(ErrorVC, (true));
00055 Val valUnbnd      = NEW(UnbndVC);
00056 Assoc nullAssoc   = NEW_CONSTR(AssocVC, (nameDot, valUnbnd));
00057 
00058 // Text strings for types:
00059 Val valTBinding = NEW_CONSTR(TextVC, ("t_binding"));
00060 Val valTBool    = NEW_CONSTR(TextVC, ("t_bool"));
00061 Val valTClosure = NEW_CONSTR(TextVC, ("t_closure"));
00062 Val valTErr     = NEW_CONSTR(TextVC, ("t_err"));
00063 Val valTInt     = NEW_CONSTR(TextVC, ("t_int"));
00064 Val valTList    = NEW_CONSTR(TextVC, ("t_list"));
00065 Val valTText    = NEW_CONSTR(TextVC, ("t_text"));
00066 
00067 // Typecode fingerprints:
00068 FP::Tag booleanTag("Bool"),
00069         integerTag("Int"),
00070         listTag("List"),
00071         bindingTag("Binding"),
00072         primitiveTag("Prim"),
00073         textTag("Text"),
00074         closureTag("Closure"),
00075         modelTag("Model"),
00076         errorTag("Error"),
00077         unbndTag("Unbnd");
00078 
00079 Context conEmpty, conInitial;
00080 
00081 Val CollectLet(const Text& name, Val v1, Val v2);
00082 void CollectLet(const Text& name, Val v1, DPaths *ps, Val res,
00083                 /*OUT*/ DPaths*& nps);
00084 Val CollectFunc(Val bodyv, Val fv, const Context& c);
00085 void CollectFunc(DPaths *ps, Val fv, const Context& c, Val res,
00086                  /*OUT*/ DPaths*& nps);
00087 Val CollectModel(Val bodyv, Val fv, const Context& c);
00088 void CollectModel(DPaths *ps, const Context& c, Val res,
00089                   /*OUT*/ DPaths*& nps);
00090 
00091 // Used to memorize that a dependency set has been collected.
00092 static int currentDpsVersion = 0;
00093 static int currentDpathVersion = 0;
00094 
00095 static void Indent(ostream& os, int amount) {
00096   while (amount--) os << " ";
00097 }
00098 
00099 static int counter = 0;
00100 
00101 static Text GetUniqueName() {
00102   int num = IncCounter(&counter);
00103   char buff[16];
00104   sprintf(buff, "%d", num);
00105   Text res(buff);
00106   return res;
00107 }
00108 
00109 // Fingerprinting a context.
00110 FP::Tag FingerPrintContext(const Context& c) {
00111   Context work = c;
00112 
00113   RawFP fp = POLY_ONE;
00114   while (!work.Null())
00115     FP::Tag::ExtendRaw(/*INOUT*/ fp, work.Pop()->FingerPrint());
00116   FP::Tag tag;
00117   tag.Permute(fp);
00118   return tag;
00119 }
00120 
00121 FP::Tag FingerPrintContext(const Context& c, const Text& id) {
00122   Context work = c;
00123 
00124   RawFP fp = POLY_ONE;
00125   while (!work.Null()) {
00126     Assoc a = work.Pop();
00127     if (a->name != id)
00128       FP::Tag::ExtendRaw(/*INOUT*/ fp, a->FingerPrint());
00129   }
00130   FP::Tag tag;
00131   tag.Permute(fp);
00132   return tag;
00133 }
00134 
00135 // Print context.
00136 void PrintContext(ostream& os, const Context& c, bool verbose, int indent) 
00137 {
00138   Context cc = c;
00139   os << "[ ";
00140   if (!cc.Null())
00141     cc.Pop()->PrintD(os, verbose, indent + 2);
00142   while (!cc.Null()) {
00143     os << ",\n";
00144     Indent(os, indent + 2);
00145     cc.Pop()->PrintD(os, verbose, indent + 2);
00146   }
00147   os << " ]";
00148 }
00149 
00150 void PrintContext(ostream& os, const Context& c, const Text& id, bool verbose,
00151                   int indent) 
00152 {
00153   Context cc = c;
00154   os << "[ ";
00155   while (!cc.Null()) {
00156     Assoc a = cc.Pop();
00157     if (a->name != id) {
00158       a->PrintD(os, verbose, indent + 2);
00159       break;
00160     }
00161   }
00162   while (!cc.Null()) {
00163     Assoc a = cc.Pop();
00164     if (a->name != id) {
00165       os << "," << endl;
00166       Indent(os, indent + 2);
00167       a->PrintD(os, verbose, indent + 2);
00168     }
00169   }
00170   os << " ]";
00171 }
00172 
00174 Val ValC::MergeDPS(DPaths* ps) {
00175   if (ps != NULL) {
00176     if (this->dps == NULL)
00177       this->dps = NEW_CONSTR(DPaths, (ps->Size()));
00178     this->dps = this->dps->Union(ps);
00179   }
00180   return this;
00181 }
00182 
00183 Val ValC::Merge(Val v) {
00184   this->MergeDPS(v->dps);
00185   if (v->path != NULL) {
00186     if (this->dps == NULL)
00187       this->dps = NEW(DPaths);
00188     // No need to deep copy v->path.
00189     DepPathTbl::KVPairPtr pr;
00190     (void)this->dps->Put(*(v->path), v, pr);
00191     // assert(v->FingerPrint() == pr->val->FingerPrint());
00192   }
00193   return this;
00194 }
00195 
00196 Val ValC::MergeAndTypeDPS(Val v) {
00197   this->MergeDPS(v->dps);
00198   if (v->path != NULL)
00199     this->AddToDPS(v->path, ValType(v), TypePK);
00200   return this;
00201 }
00202 
00203 Val ValC::MergeLenDPS(Val v) {
00204   if (v->vKind == BindingVK) {
00205     DPaths *ps = ((BindingVC*)v)->lenDps;
00206     if (ps != NULL) {
00207       if (this->dps == NULL)
00208         this->dps = NEW_CONSTR(DPaths, (ps->Size()));
00209       DepPathTbl::TIter iter(ps);
00210       DepPathTbl::KVPairPtr ptr;
00211       while (iter.Next(ptr)) {
00212         DepPath lenPath(ptr->key.content->path, BLenPK, ptr->key.content->pathFP);
00213         Val vNames = ((BindingVC*)ptr->val)->Names();
00214         (void)this->dps->Put(lenPath, vNames, ptr);
00215         // assert(vNames->FingerPrint() == ptr->val->FingerPrint());
00216       }
00217     }
00218   }
00219   else {
00220     assert(v->vKind == ListVK);
00221     DPaths *ps = ((ListVC*)v)->lenDps;
00222     if (ps != NULL) {
00223       if (this->dps == NULL)
00224         this->dps = NEW_CONSTR(DPaths, (ps->Size()));
00225       DepPathTbl::TIter iter(ps);
00226       DepPathTbl::KVPairPtr ptr;
00227       while (iter.Next(ptr)) {
00228         DepPath lenPath(ptr->key.content->path, LLenPK, ptr->key.content->pathFP);
00229         Val vLen = NEW_CONSTR(IntegerVC, (((ListVC*)ptr->val)->elems.Length()));
00230         (void)this->dps->Put(lenPath, vLen, ptr);
00231         // assert(vLen->FingerPrint() == ptr->val->FingerPrint());
00232       }
00233     }
00234   }
00235   return this;
00236 }
00237 
00238 Val ValC::MergeAndLenDPS(Val v) {
00239   this->MergeDPS(v->dps);
00240   if (v->vKind == BindingVK) {
00241     BindingVC *bv = (BindingVC*)v;
00242     if (bv->path != NULL)
00243       this->AddToDPS(bv->path, bv->Names(), BLenPK);
00244     else
00245       this->MergeLenDPS(bv);
00246   }
00247   else {
00248     assert(v->vKind == ListVK);
00249     ListVC *lstv = (ListVC*)v;
00250     if (lstv->path != NULL) {
00251       int len = lstv->elems.Length();
00252       IntegerVC *vLen = NEW_CONSTR(IntegerVC, (len));
00253       this->AddToDPS(lstv->path, vLen, LLenPK);
00254     }
00255     else
00256       this->MergeLenDPS(lstv);
00257   }
00258   return this;
00259 }
00260 
00261 Val ValC::AddToDPS(DepPath *dp, Val v, PathKind pk) {
00262   if (dp != NULL) {
00263     if (this->dps == NULL)
00264       this->dps = NEW(DPaths);
00265     DepPathTbl::KVPairPtr ptr;
00266     if (pk == DummyPK)
00267       ptr = NEW_CONSTR(DepPathTbl::KVPair, (*dp, v));
00268     else {
00269       DepPath newPath(dp->content->path, pk, dp->content->pathFP);
00270       ptr = NEW_CONSTR(DepPathTbl::KVPair, (newPath, v));
00271     }
00272     (void)this->dps->Put(ptr);
00273   }
00274   return this;
00275 }
00276 
00277 Val ValC::AddExtendToDPS(DepPath *dp, Val v, PathKind pk, const Text& id) {
00278   if (dp != NULL) {
00279     if (this->dps == NULL)
00280       this->dps = NEW(DPaths);
00281     DepPath newPath(dp->content);
00282     newPath.Extend(id);
00283     newPath.content->pKind = pk;
00284     DepPathTbl::KVPairPtr pr;
00285     (void)this->dps->Put(newPath, v, pr);
00286     // assert(v->FingerPrint() == pr->val->FingerPrint());
00287   }
00288   return this;
00289 }
00290 
00291 Val ValC::Extend(Val v, const Text& id, PathKind pk, bool add) {
00292   Val result;
00293 
00294   if (this->path != NULL) {
00295     result = v->Copy();
00296     result->path = this->path->DeepCopy();
00297     result->path->Extend(id, pk);
00298     if (add) result->dps = this->dps;
00299   }
00300   else if (add) {
00301     result = v->Copy();
00302     result->path = v->path;
00303     result->MergeDPS(v->dps)->MergeDPS(this->dps);
00304   }
00305   else
00306     // No need to copy.
00307     return v;
00308   return result;
00309 }
00310 
00312 // BooleanVC
00313 FP::Tag BooleanVC::FingerPrint() {
00314   if (!this->tagged) {
00315     FP::Tag theTag = booleanTag;
00316     bool8 fp_b = b ? 1 : 0;
00317     theTag.Extend(&fp_b, sizeof_assert(fp_b, 1));
00318     this->tag = theTag;
00319     this->tagged = true;
00320   }
00321   return this->tag;
00322 }
00323 
00324 // IntegerVC
00325 FP::Tag IntegerVC::FingerPrint() {
00326   if (!this->tagged) {
00327     FP::Tag theTag = integerTag;
00328     Basics::int32 num_net = Basics::hton32(num);
00329     theTag.Extend((char*)(&num_net), sizeof_assert(num_net, 4));
00330     this->tag = theTag;
00331     this->tagged = true;
00332   }
00333   return this->tag;
00334 }
00335 
00336 // ListVC
00337 void ListVC::PrintD(ostream& os, bool verbose, int indent) 
00338 {
00339   Vals vv = this->elems;
00340   os << "< ";
00341   if (!vv.Null())
00342     vv.Pop()->PrintD(os, verbose, indent + 2);
00343   while (!vv.Null()) {
00344     os << "," << endl;
00345     Indent(os, indent + 2);
00346     vv.Pop()->PrintD(os, verbose, indent + 2);
00347   }
00348   os << " >";
00349 }
00350 
00351 FP::Tag ListVC::FingerPrint() {
00352   Vals vv = elems;
00353 
00354   if (!this->tagged) {
00355     FP::Tag theTag = listTag;
00356     RawFP fp;
00357     theTag.Unpermute(/*OUT*/ fp);
00358     while (!vv.Null())
00359       FP::Tag::ExtendRaw(/*INPUT*/ fp, vv.Pop()->FingerPrint());
00360     theTag.Permute(fp);
00361     this->tag = theTag;
00362     this->tagged = true;
00363   }
00364   return this->tag;
00365 }
00366 
00367 IntegerVC* ListVC::Length() {
00368   int len = this->elems.Length();
00369   IntegerVC *result = NEW_CONSTR(IntegerVC, (len));
00370 
00371   result->MergeDPS(this->dps);
00372   if (this->path != NULL) {
00373     FpVC *fpv = NEW_CONSTR(FpVC, (result->FingerPrint()));
00374     result->AddToDPS(this->path, fpv, LLenPK);
00375   }
00376   else
00377     result->MergeLenDPS(this);
00378   result->cacheit = this->cacheit;
00379   return result;
00380 }
00381 
00382 Val ListVC::GetElem(int index) {
00383   Vals vv = this->elems;
00384   Val result;
00385 
00386   if (index < 0 || index >= vv.Length()) {
00387     // Out of bounds:
00388     result = NEW(ErrorVC);
00389     return result->MergeAndLenDPS(this);
00390   }
00391   result = vv.Nth(index);
00392   if (path != NULL) {
00393     result = result->Copy();
00394     result->path = path->DeepCopy();
00395     result->path->Extend(IntArc(index));
00396     result->dps = this->dps;
00397   }
00398   else
00399     result->MergeDPS(this->dps);
00400   result->cacheit = result->cacheit && this->cacheit;
00401   return result;
00402 }
00403 
00404 Val ListVC::GetElemNoDpnd(int index) {
00405   Vals vv = elems;
00406 
00407   if (index < 0 || index >= vv.Length())
00408     return valErr;
00409   return vv.Nth(index);
00410 }
00411 
00412 Val ListVC::AddToLenDPS(const DepPath& dp, Val val) {
00413   if (this->lenDps == NULL) {
00414     this->lenDps = NEW_CONSTR(DPaths, (1));  // sizeHint = 1.
00415   }
00416   DepPathTbl::KVPairPtr pr;
00417   (void)this->lenDps->Put(dp, val, pr);
00418   // assert(val->FingerPrint() == pr->val->FingerPrint());
00419   return this;
00420 }
00421 
00422 Val ListVC::MergeToLenDPS(DPaths *ps) {
00423   /* Precondition: ps must be the lenDps of a binding or a list. */
00424   if (ps != NULL) {
00425     if (this->lenDps == NULL) {
00426       this->lenDps = NEW_CONSTR(DPaths, (ps->Size()));
00427     }
00428     this->lenDps = this->lenDps->Union(ps);
00429   }
00430   return this;
00431 }
00432 
00433 Val ListVC::Copy(bool more) {
00434   ListVC *result = NEW_CONSTR(ListVC, (*this));
00435   if (more) {
00436     if (this->lenDps != NULL && this->lenDps->Size() != 0) {
00437       result->lenDps = NEW_CONSTR(DPaths, (this->lenDps));
00438     }
00439   }
00440   return result;
00441 }
00442 
00443 // BindingVC
00444 BindingVC::BindingVC(BindingVC *b1, BindingVC *b2, bool rec)
00445 : ValC(BindingVK), lenDps(NULL) {
00446   /* We leave this->dps to be empty. The caller must set this field
00447      accordingly after creating a new binding value. */
00448   // Merge the two bindings:
00449   if (rec)
00450     this->elems = b1->RecursiveOverlay(b2);
00451   else
00452     this->elems = b1->SimpleOverlay(b2);
00453 
00454   // Handle length dependency:
00455   if (b1->path != NULL)
00456     this->AddToLenDPS(*b1->path, b1);
00457   else
00458     this->MergeToLenDPS(b1->lenDps);
00459 
00460   if (b2->path != NULL)
00461     this->AddToLenDPS(*b2->path, b2);
00462   else
00463     this->MergeToLenDPS(b2->lenDps);
00464 
00465   // Finally, set the cacheit flag: 
00466   this->cacheit = b1->cacheit && b2->cacheit;
00467 }
00468 
00469 void BindingVC::PrintD(ostream& os, bool verbose, int indent) {
00470   Context work = this->elems;
00471   os << "[ ";
00472   if (!work.Null()) 
00473     work.Pop()->PrintD(os, verbose, indent + 2);
00474   while (!work.Null()) {
00475     os << "," << endl;
00476     Indent(os, indent + 2);
00477     work.Pop()->PrintD(os, verbose, indent + 2);
00478   }
00479   os << " ]";
00480 }
00481 
00482 FP::Tag BindingVC::FingerPrint() {
00483   if (!this->tagged) {
00484     FP::Tag theTag = bindingTag;
00485     Context work = this->elems;
00486     RawFP fp;
00487     theTag.Unpermute(/*OUT*/ fp);
00488     while (!work.Null()) {
00489       FP::Tag::ExtendRaw(/*INPUT*/ fp, work.Pop()->FingerPrint());
00490     }
00491     theTag.Permute(fp);
00492     this->tag = theTag;
00493     this->tagged = true;
00494   }
00495   return this->tag;
00496 }
00497 
00498 Val BindingVC::Names() {
00499   Context work = this->elems;
00500 
00501   Vals vs;
00502   while (!work.Null())
00503     vs.Append1D(NEW_CONSTR(TextVC, (work.Pop()->name)));
00504   return NEW_CONSTR(ListVC, (vs));
00505 }
00506 
00507 IntegerVC* BindingVC::Length() {
00508   int len = this->elems.Length();
00509   IntegerVC *result = NEW_CONSTR(IntegerVC, (len));
00510 
00511   result->MergeDPS(this->dps);
00512   if (this->path != NULL)
00513     result->AddToDPS(this->path, this->Names(), BLenPK);
00514   else
00515     result->MergeLenDPS(this);
00516   result->cacheit = this->cacheit;
00517   return result;
00518 }
00519 
00520 Val BindingVC::Defined(const Text& id) {
00521   Assoc elem = FindInContext(id, this->elems);
00522   bool b = (elem != nullAssoc);
00523   Val result = NEW_CONSTR(BooleanVC, (b));
00524 
00525   // Figure out the dependency:
00526   result->MergeDPS(this->dps);
00527   if (this->path != NULL) {
00528     Val val = (b ? valTrue : valFalse);
00529     result->AddExtendToDPS(this->path, val, BangPK, id);
00530   }
00531   else if (this->lenDps != NULL) {
00532     DepPathTbl::TIter iter(this->lenDps);
00533     DepPathTbl::KVPairPtr ptr;
00534     while (iter.Next(ptr)) {
00535       Context work = ((BindingVC*)ptr->val)->elems;
00536       bool b1 = false;
00537       while (!work.Null()) {
00538         if (work.Pop()->name == id) {
00539           b1 = true;
00540           break;
00541         }
00542       }
00543       Val val = (b1 ? valTrue : valFalse);
00544       result->AddExtendToDPS(&(ptr->key), val, BangPK, id);
00545     }
00546   }
00547   result->cacheit = this->cacheit;
00548   return result;
00549 }
00550 
00551 Val BindingVC::Lookup(const Text& id) {
00552   Val v = LookupInContext(id, this->elems);
00553   Val result = this->Extend(v, id);
00554   result->cacheit = result->cacheit && this->cacheit;
00555   return result;
00556 }
00557 
00558 Context BindingVC::SimpleOverlay(BindingVC *bv) {
00559   Context c1 = this->elems, c2 = bv->elems;
00560   Context result;
00561   Assoc a, a1, a2;
00562   Val v, v1, v2;
00563   Text name;
00564 
00565   while (!c1.Null()) {
00566     a1 = c1.Pop();
00567     name = a1->name;
00568     a2 = FindInContext(name, c2);
00569     if (a2 == nullAssoc) {
00570       v1 = a1->val;
00571       v = this->Extend(v1, name, NormPK, false);
00572       v->AddExtendToDPS(bv->path, valFalse, BangPK, name);
00573     }
00574     else {
00575       v2 = a2->val;
00576       v = bv->Extend(v2, name, NormPK, false);
00577     }
00578     a = NEW_CONSTR(AssocVC, (name, v));
00579     result.Append1D(a);
00580   }
00581   c1 = this->elems;
00582   while (!c2.Null()) {
00583     a2 = c2.Pop();
00584     name = a2->name;
00585     if (FindInContext(name, c1) == nullAssoc) {
00586       v2 = a2->val;
00587       v = bv->Extend(v2, name, NormPK, false);
00588       a = NEW_CONSTR(AssocVC, (name, v));
00589       result.Append1D(a);
00590     }
00591   }
00592   return result;
00593 }
00594 
00595 Context BindingVC::RecursiveOverlay(BindingVC *bv) {
00596   Context c1 = this->elems;
00597   Context c2 = bv->elems;
00598   Context result;
00599   Assoc a, a1, a2;
00600   Val v, v1, v2;
00601   Text name;
00602 
00603   while (!c1.Null()) {
00604     a1 = c1.Pop();
00605     name = a1->name;
00606     a2 = FindInContext(name, c2);
00607     if (a2 == nullAssoc) {
00608       v1 = a1->val;
00609       v = this->Extend(v1, name, NormPK, false);
00610       v->AddExtendToDPS(bv->path, valFalse, BangPK, name);
00611     }
00612     else {
00613       v2 = a2->val;
00614       if (v2->vKind == BindingVK) {
00615         v1 = a1->val;
00616         if (v1->vKind == BindingVK) {
00617           v1 = this->Extend(v1, name, NormPK, false);
00618           v2 = bv->Extend(v2, name, NormPK, false);
00619           v = NEW_CONSTR(BindingVC, ((BindingVC*)v1, (BindingVC*)v2, true));
00620           v->MergeDPS(v1->dps)->MergeDPS(v2->dps);
00621         }
00622         else {
00623           v = bv->Extend(v2, name, NormPK, false);
00624           v->AddExtendToDPS(this->path, ValType(v1), TypePK, name);
00625         }
00626       }
00627       else
00628         v = bv->Extend(v2, name, NormPK, false);
00629     }
00630     a = NEW_CONSTR(AssocVC, (name, v));
00631     result.Append1D(a);
00632   }
00633   c1 = this->elems;
00634   while (!c2.Null()) {
00635     a2 = c2.Pop();
00636     name = a2->name;
00637     if (FindInContext(name, c1) == nullAssoc) {
00638       v2 = a2->val;
00639       v = bv->Extend(v2, name, NormPK, false);
00640       if (v2->vKind == BindingVK)
00641         v->AddExtendToDPS(path, valFalse, BangPK, name);
00642       a = NEW_CONSTR(AssocVC, (name, v));
00643       result.Append1D(a);
00644     }
00645   }
00646   return result;
00647 }
00648 
00649 Val BindingVC::GetElem(const Text& name, int& index) {
00650   Context work = this->elems;
00651   Val result;
00652   
00653   index = 0;
00654   while (!work.Null()) {
00655     Assoc a = work.Pop();
00656     if (a->name == name) {
00657       result = a->val;
00658       return Extend(result, name);
00659     }
00660     index++;
00661   }
00662   result = NEW(ErrorVC);
00663   result->MergeDPS(dps);
00664   result->AddExtendToDPS(path, valFalse, BangPK, name);
00665   result->cacheit = result->cacheit && this->cacheit;
00666   return result;
00667 }
00668 
00669 Val BindingVC::GetElem(int index, Text& name) {
00670   Context work = this->elems;
00671   Val result;
00672 
00673   if (index < 0 || index >= work.Length()) {
00674     result = NEW(ErrorVC);
00675     return result->MergeAndLenDPS(this);
00676   }
00677   Assoc a = work.Nth(index);
00678   name = a->name;
00679   result = this->Extend(a->val, IntArc(index));
00680   result->cacheit = result->cacheit && this->cacheit;
00681   return result;
00682 }
00683 
00684 bool BindingVC::DefinedNoDpnd(const Text& id) {
00685   return (FindInContext(id, this->elems) != nullAssoc);
00686 }
00687 
00688 Val BindingVC::LookupNoDpnd(const Text& id) {
00689   return LookupInContext(id, this->elems);
00690 }
00691 
00692 Val BindingVC::GetElemNoDpnd(const Text& name, int& index) {
00693   Context work = this->elems;
00694   index = 0;
00695   
00696   while (!work.Null()) {
00697     Assoc a = work.Pop();
00698     if (a->name == name)
00699       return a->val;
00700     index++;
00701   }
00702   return valErr;
00703 }
00704 
00705 Val BindingVC::GetElemNoDpnd(int index, Text& name) {
00706   Context work = this->elems;
00707 
00708   if (index < 0 || index >= work.Length())
00709     return valErr;
00710   Assoc a = work.Nth(index);
00711   name = a->name;
00712   return a->val;
00713 }
00714 
00715 Binding BindingVC::AddBindingAssoc(const Text& name, Val v) {
00716   return NEW_CONSTR(BindingVC, 
00717                     (Context(NEW_CONSTR(AssocVC, (name, v)), this->elems)));
00718 }
00719 
00720 Binding BindingVC::RemoveBindingAssoc(const Text& id) {
00721   Context work = this->elems;
00722   bool found;
00723   return NEW_CONSTR(BindingVC, (Snip(work, id, found)));
00724 }
00725 
00726 Val BindingVC::AddToLenDPS(const DepPath& dp, Val val) {
00727   if (this->lenDps == NULL)
00728     this->lenDps = NEW_CONSTR(DPaths, (1));   // sizeHint = 1.
00729   DepPathTbl::KVPairPtr pr;
00730   (void)this->lenDps->Put(dp, val, pr);
00731   // assert(val->FingerPrint() == pr->val->FingerPrint());
00732   return this;
00733 }
00734 
00735 Val BindingVC::MergeToLenDPS(DPaths *ps) {
00736   if (ps != NULL) {
00737     if (this->lenDps == NULL)
00738       this->lenDps = NEW_CONSTR(DPaths, (ps->Size()));
00739     this->lenDps = this->lenDps->Union(ps);
00740   }
00741   return this;
00742 }
00743 
00744 Val BindingVC::Copy(bool more) {
00745   BindingVC *result = NEW_CONSTR(BindingVC, (*this));
00746   if (more) {
00747     if (this->lenDps != NULL && this->lenDps->Size() != 0) {
00748       result->lenDps = NEW_CONSTR(DPaths, (this->lenDps));
00749     }
00750   }
00751   return result;
00752 }
00753 
00754 // PrimitiveVC
00755 FP::Tag PrimitiveVC::FingerPrint() {
00756   if (!this->tagged) {
00757     FP::Tag theTag = primitiveTag;
00758     theTag.Extend(name);
00759     this->tag = theTag;
00760     this->tagged = true;
00761   }
00762   return this->tag;
00763 }
00764 
00765 // TextVC
00766 TextVC::TextC::TextC(const Text& tname, const Text& ttext)
00767 : hasTxt(false), hasName(true), name(tname) {
00768   try {
00769     VestaSource* vs = CreateDerived();
00770     this->shortId = vs->shortId();
00771     this->name = SourceOrDerived::shortIdToName(this->shortId);
00772     this->hasName = true;
00773     int len = ttext.Length();
00774     VestaSource::errorCode err = vs->write(ttext.chars(), &len, 0);
00775     delete vs; 
00776     vs = NULL;
00777     if(err != VestaSource::ok) {
00778       Error(cio().start_err(), 
00779             Text("Failed to convert text to file: ") + this->name 
00780             + ": " + VestaSource::errorCodeString(err) + ".\n");
00781       cio().end_err();
00782       throw(Evaluator::failure(Text("exiting"), false));      
00783     }
00784   } catch (SRPC::failure f) {
00785     // Failed to create because an SRPC::failure is thrown:
00786     Error(cio().start_err(), 
00787           Text("Failed to convert text to file:  SRPC::failure (")
00788           + IntToText(f.r) + "), " + f.msg + ".\n");
00789     cio().end_err();
00790     throw(Evaluator::failure(Text("exiting"), false));
00791   }
00792 }
00793 
00794 TextVC::TextC::TextC(const Text& tname, fstream *iFile, VestaSource *vSource)
00795 : name(tname), hasTxt(false), hasName(true), shortId(NullShortId) {
00796   this->shortId = vSource->shortId();
00797 }
00798 
00799 TextVC::TextVC(const Text& tname, const Text& ttext, char c, const FP::Tag& fp)
00800 : ValC(TextVK) {
00801   content = NEW_CONSTR(TextC, (tname, ttext));
00802   this->tag = textTag;
00803   this->tag.Extend(c);
00804   this->tag.Extend(fp);
00805   this->tagged = true;
00806 }
00807 
00808 TextVC::TextVC(const Text& tname, fstream *iFile, VestaSource *vSource)
00809 : ValC(TextVK) {
00810   this->content = NEW_CONSTR(TextC, (tname, iFile, vSource));
00811   this->tag = vSource->fptag;
00812   this->tagged = true;
00813 }
00814 
00815 TextVC::TextVC(const Text& tname, const ShortId sid, int fp_content)
00816 : ValC(TextVK) {
00817   this->content = NEW_CONSTR(TextC, (tname, sid));
00818   this->tag = textTag;
00819   if (fp_content != 0) {
00820     SourceOrDerived f;
00821     f.open(sid);
00822     if (fp_content == -1) {
00823       this->tag.Extend('D');
00824       FP::FileContents(f, /*INOUT*/ this->tag);
00825       FS::Close(f);
00826     }
00827     else {
00828       f.seekg(0, ios::end);
00829       int length = f.tellg();
00830       f.seekg(0, ios::beg);
00831       if (length < fp_content) {
00832         this->tag.Extend('D');
00833         FP::FileContents(f, /*INOUT*/ this->tag);
00834         FS::Close(f);
00835       }
00836       else {
00837         this->tag.Extend('d');
00838         this->tag.Extend(UniqueId());
00839       }
00840     }
00841   }
00842   else {
00843     this->tag.Extend('d');
00844     this->tag.Extend(UniqueId());
00845   }
00846   this->tagged = true;
00847 }
00848 
00849 void TextVC::PrintD(ostream& os, bool verbose, int indent) 
00850 {
00851   if (verbose || this->HasTxt()) {
00852     bool close;
00853     istream *txt = this->Content(close);
00854     if (txt == NULL) return;
00855     os << '"' << oct;
00856     int ch;
00857     while ((ch = txt->get()) != EOF) {
00858       unsigned char c = ch;
00859       switch (c) {
00860       case '\n': os << "\\n";  break;
00861       case '\t': os << "\\t";  break;
00862       case '\r': os << "\\r";  break;
00863       case '\f': os << "\\f";  break;
00864       case '\b': os << "\\b";  break;
00865       case '\\': os << "\\\\"; break;
00866       case '"':  os << "\\\""; break;
00867       default:
00868         if (c < ' ' || c > '~') {
00869           char oc = os.fill('0');
00870           int ow = os.width(3);
00871           os << '\\' << (int)c;
00872           (void)os.fill(oc);
00873         }
00874         else os << c;
00875       }
00876     }
00877     os << '"' << dec;
00878     if (close) ((SourceOrDerived*)txt)->close();
00879   }
00880   else {
00881     if (this->HasSid()) {
00882       os << "<file";
00883       if(printSidNum) {
00884         char sidbuf[9];
00885         sprintf(sidbuf, "0x%08x", this->content->shortId);
00886         os << " " << sidbuf;
00887       }
00888       os << ": " 
00889          << SourceOrDerived::shortIdToName(this->content->shortId, false)
00890          << ">"; 
00891     }
00892     else {
00893       // No text and shortid means bad file.
00894       os << "<badfile " << this->content->name << ">";
00895     }
00896   }
00897 }
00898 
00899 FP::Tag TextVC::FingerPrint() {
00900   if (!this->tagged) {
00901     // It must have text.
00902     FP::Tag theTag = textTag;
00903     bool8 fp_hasTxt = content->hasTxt ? 1 : 0;
00904     theTag.Extend(&fp_hasTxt, sizeof_assert(fp_hasTxt, 1));
00905     theTag.Extend(content->txt);
00906     this->tag = theTag;
00907     this->tagged = true;
00908   }
00909   return this->tag;
00910 }
00911 
00912 static SourceOrDerived *open_shortid(ShortId sid,
00913                                      const char *err_what,
00914                                      const Text &err_name)
00915 {
00916   SourceOrDerived *result = NEW(SourceOrDerived);
00917   errno = 0;
00918   result->open(sid);
00919   int l_errno_save = errno;
00920   if (result->fail())
00921     {
00922       OBufStream l_err_msg;
00923       char *l_sid_path = SourceOrDerived::shortIdToName(sid, false);
00924       l_err_msg << "Failed to open " << err_what
00925                 << ": " << err_name << endl
00926                 << "  shortid = 0x" << hex << sid << dec << " ("
00927                 << l_sid_path << ")" << endl;
00928       if(l_errno_save != 0)
00929         {
00930           l_err_msg << "  " << Basics::errno_Text(l_errno_save)
00931                     << " (errno = " << l_errno_save << ")" << endl;
00932         }
00933       else if(!FS::Exists(l_sid_path))
00934         {
00935           l_err_msg << "  shortid doesn't exist!" << endl;
00936         }
00937       delete [] l_sid_path;
00938       Error(cio().start_err(), l_err_msg.str());
00939       cio().end_err();
00940       return 0;
00941     }
00942   return result;
00943 }
00944 
00945 istream* TextVC::Content(bool& closeIt) {
00946   if (this->content->hasTxt) {
00947     closeIt = false;
00948     return NEW_CONSTR(IBufStream, (this->content->txt.chars()));
00949   }
00950   assert(this->HasSid());
00951   SourceOrDerived *iFile =
00952     open_shortid(this->content->shortId,
00953                  "file",
00954                  (this->content->hasName
00955                   ? this->content->name
00956                   : SourceOrDerived::shortIdToName(this->content->shortId)));
00957   if (!iFile) {
00958     if (!this->content->hasName) {
00959       this->content->name = iFile->shortIdToName(this->content->shortId);
00960       this->content->hasName = true;
00961     }
00962     throw(Evaluator::failure(Text("exiting"), false));      
00963   }
00964   closeIt = true;
00965   return iFile;
00966 }
00967 
00968 Text TextVC::NDS() {
00969   if (this->content->hasTxt) {
00970     return this->content->txt;
00971   }
00972   // assert(this->HasSid());
00973   SourceOrDerived *file =
00974     open_shortid(this->content->shortId,
00975                  "file",
00976                  (this->content->hasName
00977                   ? this->content->name
00978                   : SourceOrDerived::shortIdToName(this->content->shortId)));
00979   if (!file) {
00980     throw(Evaluator::failure(Text("exiting"), false));      
00981   }
00982   file->seekg(0, ios::end);
00983   unsigned long length = file->tellg();
00984   // Make sure this file is a reasonable size to read into a text
00985   // value.
00986   if(length > Text::MaxInt)
00987     {
00988       VError(cio().start_err(), Text("file ") + 
00989              file->shortIdToName(content->shortId) +
00990              " too big to manipulate as a text value");
00991       cio().end_err();
00992       throw(Evaluator::failure(Text("exiting"), false));
00993     }
00994   file->seekg(0, ios::beg);
00995   char *bytes = NEW_PTRFREE_ARRAY(char, length+1);
00996   if (!file->read(bytes, length)) {
00997     VError(cio().start_err(), 
00998            Text("reading file ") + file->shortIdToName(content->shortId));
00999     cio().end_err();
01000     throw(Evaluator::failure(Text("exiting"), false));
01001   }
01002   file->close();
01003   // Add the terminating null byte.
01004   bytes[length] = 0;
01005   return Text(bytes, (void*)1);
01006 }
01007 
01008 ShortId TextVC::Sid() {
01009   valMu.lock();    
01010   if (this->HasSid()) {
01011     ShortId sid = this->content->shortId;
01012     valMu.unlock();
01013     return sid;
01014   }
01015   // assert(content->hasTxt);
01016   try {
01017     VestaSource* vs = CreateDerived();
01018     this->content->shortId = vs->shortId();
01019     if (!this->content->hasName) {
01020       this->content->name = SourceOrDerived::shortIdToName(content->shortId);
01021       this->content->hasName = true;
01022     }
01023     int len = this->content->txt.Length();
01024     VestaSource::errorCode err = 
01025       vs->write(this->content->txt.chars(), &len, 0);
01026     delete vs;
01027     vs = NULL;
01028     if(err != VestaSource::ok) {
01029       valMu.unlock();
01030       VError(cio().start_err(), Text("Failed to convert text to file: ") + 
01031              VestaSource::errorCodeString(err) + ".\n");
01032       cio().end_err();
01033       throw(Evaluator::failure(Text("exiting"), false));
01034     }
01035   } catch (SRPC::failure f) {
01036     // Failed to create because an SRPC::failure is thrown:
01037     valMu.unlock();      
01038     VError(cio().start_err(), 
01039            Text("Failed to convert text to file:  SRPC::failure (")
01040            + IntToText(f.r) + "), " + f.msg + ".\n");
01041     cio().end_err();
01042     throw(Evaluator::failure(Text("exiting"), false));
01043   } catch (SourceOrDerived::Fatal f) {
01044     // Failed to create because an SourceOrDerived::Fatal is thrown:
01045     valMu.unlock();      
01046     VError(cio().start_err(), 
01047            Text("Failed to convert text to file: ") + f.msg + ".\n");
01048     cio().end_err();
01049     throw(Evaluator::failure(Text("exiting"), false));
01050   }
01051   ShortId sid = this->content->shortId;
01052   valMu.unlock();  
01053   return sid; 
01054 }
01055 
01056 Text TextVC::TName() {
01057   valMu.lock();    
01058   if (this->content->hasName) {
01059     valMu.unlock();    
01060     return this->content->name;
01061   }
01062   // Force the name.
01063   valMu.unlock();
01064   this->Sid();
01065   return this->content->name;
01066 }
01067 
01068 int TextVC::Length() {
01069   if (this->content->hasTxt) {
01070     return this->content->txt.Length();
01071   }
01072   assert(this->HasSid());
01073   SourceOrDerived *file = 
01074     open_shortid(this->content->shortId,
01075                  "file",
01076                  (this->content->hasName
01077                   ? this->content->name
01078                   : SourceOrDerived::shortIdToName(this->content->shortId)));
01079   if (!file) {
01080     throw(Evaluator::failure(Text("exiting"), false));
01081   }
01082   file->seekg(0, ios::end);
01083   int length = file->tellg();
01084   file->close();
01085   return length;
01086 }
01087 
01088 // ClosureVC
01089 ClosureVC::ClosureVC(FuncEC *tfunc, const Context& c, bool fresh)
01090 : ValC(ClosureVK), func(tfunc), exprTagged(false) {
01091   if (fresh) {
01092     Context work = c;
01093     while (!work.Null()) {
01094       Assoc a = work.Pop();
01095       Val val = a->val->Copy(true);
01096       val->path = NEW_CONSTR(DepPath, (a->name));
01097       this->con.Append1D(NEW_CONSTR(AssocVC, (a->name, val)));
01098     }
01099   }
01100   else
01101     this->con = c;
01102 }
01103 
01104 void ClosureVC::PrintD(ostream& os, bool verbose, int indent) 
01105 {
01106   if (verbose) {
01107     os << "((Closure: formals = ";
01108     this->func->args->PrintD(os);
01109     os << endl;
01110     Indent(os, indent);
01111     os << "--Closure: body = ";
01112     this->func->body->PrintD(os);
01113     os << endl;
01114     Indent(os, indent);
01115     os << "--Closure: context =" << endl;
01116     Indent(os, indent + 2);
01117     PrintContext(os, this->con, this->func->name, true, indent + 2);
01118     os << endl;
01119     Indent(os, indent);
01120     os << "--End Closure))";
01121   }
01122   else {
01123     os << "<Closure>";
01124   }
01125 }
01126 
01127 FP::Tag ClosureVC::FingerPrint() {
01128   if (!this->tagged) {
01129     FP::Tag theTag = this->FingerPrintExpr();
01130     theTag.Extend(FingerPrintContext(con, this->func->name));
01131     this->tag = theTag;
01132     this->tagged = true;
01133   }
01134   return this->tag;
01135 }
01136 
01137 FP::Tag ClosureVC::FingerPrintExpr() {
01138   if (!this->exprTagged) {
01139     FP::Tag theTag = closureTag;
01140     theTag.Extend(this->func->FingerPrint());
01141     this->exprTag = theTag;
01142     this->exprTagged = true;
01143   }
01144   return this->exprTag;
01145 }
01146 
01147 // ModelVC
01148 ModelVC::ModelVC(const Text& tname, ShortId tsid, VestaSource *root, 
01149                  Expr mod, const Context& cc, VestaSource *vSource)
01150 : ValC(ModelVK) {
01151   this->content = NEW_CONSTR(ModelC, (tname, tsid, root, mod, cc));
01152   // tag is the fp of vSource:
01153   this->tag = modelTag;
01154   this->tag.Extend(vSource->fptag);
01155   this->tagged = true;
01156   // lidTag is fp combination of the model root fp and model name:
01157   this->lidTag = modelTag;
01158   this->lidTag.Extend(root->fptag);
01159   Text prefix, tail;
01160   SplitPath(tname, prefix, tail);
01161   this->lidTag.Extend(tail);
01162 }
01163 
01164 ModelVC::ModelVC(const Text& tlPath, VestaSource *root, SrcLoc *loc)
01165 : ValC(ModelVK) {
01166   this->content = NEW_CONSTR(ModelC, (tlPath));
01167   if (!IsAbsolutePath(tlPath)) {
01168     Text prefix, tail;
01169     SplitPath(loc->file, prefix, tail);
01170     this->content->name = prefix + tlPath;
01171   }
01172   fstream *iFile;
01173   VestaSource *vSource;
01174   this->cacheit = OpenSource(root, tlPath, loc, /*OUT*/ iFile, 
01175                              /*OUT*/ content->mRoot, /*OUT*/ content->sid,
01176                              /*OUT*/ vSource);
01177   if (this->cacheit) {
01178     // tag is the fp of vSource:
01179     this->tag = modelTag;
01180     this->tag.Extend(vSource->fptag);
01181     this->tagged = true;
01182     // lidTag is fp combination of the model root fp and model name:
01183     this->lidTag = modelTag;
01184     this->lidTag.Extend(content->mRoot->fptag);
01185     Text prefix, tail;
01186     SplitPath(tlPath, prefix, tail);
01187     this->lidTag.Extend(tail);
01188   }
01189   else {
01190     throw(Evaluator::failure(Text("exiting"), false));
01191   }
01192 }
01193 
01194 void ModelVC::PrintD(ostream& os, bool verbose, int indent) 
01195 {
01196   //  os << "<Model " << form("0x%08x", this->content->sid) << ">";
01197   os << "<Model " << this->content->name << ">";
01198 }
01199 
01200 Val ModelVC::Force() {
01201   valMu.lock();
01202   if (!this->content->parsed) {
01203     // Need to parse the model:
01204     SourceOrDerived *iFile = open_shortid(content->sid,
01205                                           "the model", content->name);
01206     if (!iFile) {
01207       valMu.unlock();
01208       return NEW(ErrorVC);
01209     }
01210     try {
01211       content->model = Parse(iFile, this->content->name, this->content->sid, 
01212                              this->content->mRoot);
01213     } catch (const char* report) {
01214       valMu.unlock();
01215       throw report;
01216     }
01217     iFile->close();
01218     this->content->c = ProcessModelHead((ModelEC*)content->model);
01219     this->content->parsed = true;
01220   }
01221   valMu.unlock();
01222   return this;
01223 }
01224 
01225 // ErrorVC
01226 ErrorVC::ErrorVC()
01227 : ValC(ErrorVK) {
01228   // Fatal error: always terminate.
01229   throw(Evaluator::failure(Text("exiting"), false));
01230 }
01231 
01232 FP::Tag ErrorVC::FingerPrint() { return errorTag; }
01233 
01234 // UnbndVC
01235 FP::Tag UnbndVC::FingerPrint() { return unbndTag; }
01236 
01237 // AssocVC
01238 void AssocVC::PrintD(ostream& os, bool verbose, int indent) 
01239 {
01240   bool quote = false;
01241 
01242   for (int i = 0; i < name.Length(); i++) {
01243     char c = name[i];
01244     if (((c < 'a') || (c > 'z')) &&
01245         ((c < 'A') || (c > 'Z')) &&
01246         ((c < '0') || (c > '9')) &&
01247         (c != '_') &&
01248         (c != '.')) {
01249       quote = true;
01250       break;
01251     }
01252   }
01253   if (quote)
01254     os << '"' << name << "\"=";
01255   else
01256     os << name << "=";
01257   switch (this->val->vKind) {
01258   case BindingVK:
01259   case ListVK:
01260     os << endl;
01261     Indent(os, indent);
01262     break;
01263   case ClosureVK:
01264     if (verbose) {
01265       os << endl;
01266       Indent(os, indent);
01267     }
01268     break;
01269   default:
01270     break;
01271   }
01272   this->val->PrintD(os, verbose, indent);
01273 }
01274 
01275 FP::Tag AssocVC::FingerPrint() {
01276   FP::Tag tag(this->name);
01277   tag.Extend(this->val->FingerPrint());
01278   return tag;
01279 }
01280 
01282 // Type predicates.
01283 bool IsValTrue(Val v) {
01284   return ((v->vKind == BooleanVK) && ((BooleanVC*)v)->b);
01285 }
01286 
01287 bool IsValFalse(Val v) {
01288   return ((v->vKind == BooleanVK) && !(((BooleanVC*)v)->b));
01289 }
01290      
01291 bool IsEmptyBinding(Val v) {
01292   return ((v->vKind == BindingVK) && ((BindingVC*)v)->Null());
01293 }
01294 
01295 bool IsEmptyList(Val v) {
01296   return ((v->vKind == ListVK) && ((ListVC*)v)->elems.Null());
01297 }
01298 
01299 // The type of a vesta value.
01300 Val ValType(Val v) {
01301   switch(v->vKind) {
01302   case BooleanVK:
01303     return valTBool;
01304   case IntegerVK:
01305     return valTInt;
01306   case TextVK:
01307     return valTText;
01308   case BindingVK:
01309     return valTBinding;
01310   case ListVK:
01311     return valTList;
01312   case ClosureVK: case ModelVK: case PrimitiveVK:
01313     return valTClosure;
01314   case ErrorVK: case UnbndVK:
01315     return valTErr;
01316   default:
01317     assert(v != 0);
01318     ostream& err_str = cio().start_err();
01319     v->VError(err_str, "Unexpected type");
01320     err_str << "v = ";
01321     v->PrintD(err_str);
01322     err_str << endl;
01323     InternalError(err_str, cio().helper(true), "ValType");
01324     // Unreached: InternalError never returns
01325     abort();
01326   }
01327   return NULL;
01328 }
01329 
01330 // Functions related to dependency analysis.
01331 void DeleteDuplicatePathsInner(Val v, DPaths *ps) {
01332   // Filter v->dps:
01333   if (v->SizeOfDPS() == 0)
01334     v->dps = NULL;
01335   else {
01336     DepPathTbl::TIter iter(v->dps);
01337     DepPathTbl::KVPairPtr ptr;
01338     DPaths *newDps = NEW_CONSTR(DPaths, (v->SizeOfDPS()));
01339     while (iter.Next(ptr)) {
01340       if (!ps->Member(ptr->key))
01341         (void)newDps->Put(ptr);
01342     }
01343     v->dps = (newDps->Size() == 0) ? NULL : newDps;
01344   }
01345 
01346   // Filter subvalues:
01347   if (v->path == NULL) {
01348     switch (v->vKind) {
01349     case BindingVK:
01350       {
01351         Context work = ((BindingVC*)v)->elems;
01352         while (!work.Null())
01353           DeleteDuplicatePathsInner(work.Pop()->val, ps);
01354         break;
01355       }
01356     case ListVK:
01357       {
01358         Vals elems = ((ListVC*)v)->elems;
01359         while (!elems.Null())
01360           DeleteDuplicatePathsInner(elems.Pop(), ps);
01361         break;
01362       }
01363     default:
01364       break;
01365     }
01366   }
01367   return;
01368 }
01369 
01370 void DeleteDuplicatePaths(Val v) {
01371   DPaths *ps = v->dps;
01372 
01373   // If v->path or v->dps is not empty, just return:
01374   if (v->path != NULL || ps == NULL || ps->Size() == 0)
01375     return;
01376   
01377   switch (v->vKind) {
01378   case BindingVK:
01379     {
01380       Context work = ((BindingVC*)v)->elems;
01381       while (!work.Null())
01382         DeleteDuplicatePathsInner(work.Pop()->val, ps);
01383       break;
01384     }
01385   case ListVK:
01386     {
01387       Vals elems = ((ListVC*)v)->elems;
01388       while (!elems.Null())
01389         DeleteDuplicatePathsInner(elems.Pop(), ps);
01390       break;
01391     }
01392   default:
01393     break;
01394   }
01395   return;
01396 }
01397 
01398 Val CanonicalDpnd(Val v) {
01399   /* Canonicalize dependency of the value. */
01400   DPaths *ps = v->dps;
01401   
01402   // Trivial cases:
01403   if (v->path != NULL || ps == NULL || ps->Size() == 0)
01404     return v;
01405   
01406   // We only need to canonicalize dependency for composite value.
01407   switch (v->vKind) {
01408   case BindingVK:
01409     {
01410       Context work = ((BindingVC*)v)->elems;
01411       int len = work.Length();
01412       
01413       if (len == 0) return v;
01414       DPaths **psList = NEW_ARRAY(DPaths*, len);
01415       DPaths *psi = CanonicalDpnd(work.Pop()->val)->dps;
01416       int minSize = (psi ? psi->Size() : 0);
01417       psList[0] = psi;
01418       for (int i = 1; i < len; i++) {
01419         psi = CanonicalDpnd(work.Pop()->val)->dps;
01420         psList[i] = psi;
01421         minSize = min(minSize, (psi ? psi->Size() : 0));
01422       }
01423       if (minSize > 0)
01424         // Add the shared paths in the sub-values to ps, and delete
01425         // them from the dependency sets in the subvalues.
01426         {
01427           // Find the interesection of the sub-value dependency sets
01428           DPaths *intersection = DPaths::Intersection(psList, len);
01429 
01430           if(intersection && !intersection->Empty())
01431             {
01432               // Merge the interesection into ps
01433               ps = ps->Union(intersection);
01434 
01435               // And remove the intersection from the sub-value
01436               // dependency sets
01437               work = ((BindingVC*)v)->elems;
01438               while(!work.Null())
01439                 {
01440                   Val sv = work.Pop()->val;
01441                   sv->dps = sv->dps->Difference(intersection);
01442                 }
01443             }
01444         }
01445       break;
01446     }
01447   case ListVK:
01448     {
01449       Vals elems = ((ListVC*)v)->elems;
01450       int len = elems.Length();
01451       
01452       if (len == 0) return v;
01453       DPaths **psList = NEW_ARRAY(DPaths*, len);
01454       DPaths *psi = CanonicalDpnd(elems.Pop())->dps;
01455       int minSize = (psi ? psi->Size() : 0);
01456       psList[0] = psi;
01457       for (int i = 1; i < len; i++) {
01458         psi = CanonicalDpnd(elems.Pop())->dps;
01459         psList[i] = psi;
01460         minSize = min(minSize, (psi ? psi->Size() : 0));
01461       }
01462       if (minSize > 0)
01463         // Add the shared paths in the sub-values to ps, and delete
01464         // them from the dependency sets in the subvalues.
01465         {
01466           // Find the interesection of the sub-value dependency sets
01467           DPaths *intersection = DPaths::Intersection(psList, len);
01468 
01469           if(intersection && !intersection->Empty())
01470             {
01471               // Merge the interesection into ps
01472               ps = ps->Union(intersection);
01473 
01474               // And remove the intersection from the sub-value
01475               // dependency sets
01476               elems = ((ListVC*)v)->elems;
01477               while(!elems.Null())
01478                 {
01479                   Val sv = elems.Pop();
01480                   sv->dps = sv->dps->Difference(intersection);
01481                 }
01482             }
01483         }
01484       break;
01485     }
01486   default:
01487     break;
01488   }
01489   return v;
01490 }
01491 
01492 void ModelCutOff(Val v) {
01493   /* Cut off local dependency of a model. This prevents local
01494      dependency from propagating up in the call graph. */
01495 
01496   // v->dps:
01497   if (v->SizeOfDPS() == 0)
01498     v->dps = NULL;
01499   else
01500     v->dps = v->dps->Restrict(nameDot);
01501 
01502   DepPath *dp = v->path;
01503   if (dp != NULL) {
01504     if (dp->content->path->getlo() != nameDot)
01505       v->path = NULL;
01506   }
01507   else {
01508     // collect components of the value (only when no path):
01509     switch (v->vKind) {
01510     case BindingVK:
01511       {
01512         BindingVC *bv = (BindingVC*)v;
01513         if (bv->lenDps != NULL && bv->lenDps->Size() != 0) {
01514           bv->lenDps = bv->lenDps->Restrict(nameDot);
01515         }
01516         Context work = bv->elems;
01517         while (!work.Null()) ModelCutOff(work.Pop()->val);
01518         break;
01519       }
01520     case ListVK:
01521       {
01522         ListVC *lstv = (ListVC*)v;
01523         if (lstv->lenDps != NULL && lstv->lenDps->Size() != 0) {
01524           lstv->lenDps = lstv->lenDps->Restrict(nameDot);
01525         }
01526         Vals vv = lstv->elems;
01527         while (!vv.Null()) ModelCutOff(vv.Pop());
01528         break;
01529       }
01530     case ClosureVK:
01531       {
01532         ClosureVC *cl = (ClosureVC*)v;
01533         Context work = cl->con;
01534         while (!work.Null()) {
01535           Assoc a = work.Pop();
01536           if (cl->func->name != a->name) ModelCutOff(a->val);
01537         }
01538         break;
01539       }
01540     default:
01541       break;
01542     }
01543   }
01544   return;
01545 }
01546 
01547 void CollectDefined(BindingVC *bv, const Text& id, DPaths *ps) {
01548   /* Collect dependency for the path !/id into ps.
01549      Precondition: ps # NULL.  */
01550   if (bv->path != NULL) {
01551     bool b = bv->DefinedNoDpnd(id);
01552     Val val = (b ? valTrue : valFalse);
01553     ps = ps->AddExtend(bv->path, val, BangPK, id);
01554   }
01555   else if (bv->lenDps != NULL) {
01556     DepPathTbl::TIter iter(bv->lenDps);
01557     DepPathTbl::KVPairPtr ptr;
01558     while (iter.Next(ptr)) {
01559       Context work = ((BindingVC*)ptr->val)->elems;
01560       bool b1 = false;
01561       while (!work.Null()) {
01562         if (work.Pop()->name == id) {
01563           b1 = true;
01564           break;
01565         }
01566       }
01567       Val val = (b1 ? valTrue : valFalse);
01568       ps = ps->AddExtend(&(ptr->key), val, BangPK, id);
01569     }
01570   }
01571   return;
01572 }
01573 
01574 Val CollectLookup(BindingVC *bv, const Text& id, DepPath*& path, 
01575                   DPaths *ps) {
01576   /* Collect dependency for the id component of bv into ps.
01577      Precondition: ps # NULL.  */
01578   if (bv->path != NULL) {
01579     path = bv->path->DeepCopy();
01580     path->Extend(id);
01581     return bv->LookupNoDpnd(id);
01582   }
01583   path = NULL;
01584   Val result = LookupInContext(id, bv->elems);
01585   if (result->dpsVersion != currentDpsVersion) {
01586     ps = ps->Union(result->dps);
01587     result->dpsVersion = currentDpsVersion;
01588   }
01589   return result;
01590 }
01591 
01592 void ValueDpnd(Val v, DPaths *ps) {
01593   /* Collect all the dependency of v into ps.
01594      Assume: v->dps has been collected by the caller. */
01595 
01596   DepPath *dp = v->path;
01597   if (dp != NULL) {
01598     // collect v->path:
01599     DepPathTbl::KVPairPtr pr;
01600     (void)ps->Put(*dp, v, pr);
01601     // assert(v->FingerPrint() == pr->val->FingerPrint());
01602   }
01603   else {
01604     // collect components of the value (only when there is no path):
01605     switch (v->vKind) {
01606     case BindingVK:
01607       {
01608         BindingVC *bv = (BindingVC*)v;
01609         if (bv->lenDps != NULL && bv->lenDps->Size() != 0) {
01610           ps = ps->Union(bv->lenDps);
01611         }
01612         Context work = bv->elems;
01613         while (!work.Null()) {
01614           Val v1 = work.Pop()->val;
01615           ps = ps->Union(v1->dps);
01616           ValueDpnd(v1, ps);
01617         }
01618         break;
01619       }
01620     case ListVK:
01621       {
01622         ListVC *lstv = (ListVC*)v;
01623         if (lstv->lenDps != NULL && lstv->lenDps->Size() != 0) {
01624           ps = ps->Union(lstv->lenDps);
01625         }
01626         Vals vv = lstv->elems;
01627         while (!vv.Null()) {
01628           Val v1 = vv.Pop();
01629           ps = ps->Union(v1->dps);
01630           ValueDpnd(v1, ps);
01631         }
01632         break;
01633       }
01634     case ClosureVK:
01635       {
01636         ClosureVC *cl = (ClosureVC*)v;
01637         Context work = cl->con;
01638         while (!work.Null()) {
01639           Assoc a = work.Pop();
01640           if (cl->func->name != a->name) {
01641             ps = ps->Union(a->val->dps);
01642             ValueDpnd(a->val, ps);
01643           }
01644         }
01645         break;
01646       }
01647     default:
01648       break;
01649     }
01650   }
01651   return;
01652 }
01653 
01654 DepPath* CollectDpnd(Val v, DepPath *dp, DPaths *ps, bool all = true) {
01655   /* Collect dependency of value v on path p into ps.
01656      Precondition: ps # NULL.  
01657      NOTE: When called, the fingerprint of the argument dp may not be
01658      correct. For example, we remlo, but are not bothered to recompute
01659      the fingerprint.  */
01660   DepPath *newPath = NULL;
01661 
01662   if (v->path != NULL) {
01663     dp->ExtendLow(v->path);
01664     return dp;
01665   }
01666   if (dp->Size() == 0) {
01667     if (all) {
01668       switch (dp->content->pKind) {
01669       case NormPK:
01670         {
01671           ValueDpnd(v, ps);
01672           break;
01673         }
01674       case BLenPK:
01675         {
01676           DPaths *lenDps = ((BindingVC*)v)->lenDps;
01677           if (lenDps != NULL && lenDps->Size() != 0) {
01678             DepPathTbl::TIter iter(lenDps);
01679             DepPathTbl::KVPairPtr ptr;
01680             while (iter.Next(ptr)) {
01681               DepPath lenPath(ptr->key.content->path, BLenPK, ptr->key.content->pathFP);
01682               Val vNames = ((BindingVC*)ptr->val)->Names();
01683               (void)ps->Put(lenPath, vNames, ptr);
01684               // assert(vNames->FingerPrint() == ptr->val->FingerPrint());
01685             }
01686           }
01687           break;
01688         }
01689       case LLenPK:
01690         {
01691           DPaths *lenDps = ((ListVC*)v)->lenDps;
01692           if (lenDps != NULL && lenDps->Size() != 0) {
01693             ps = ps->Union(lenDps);
01694           }
01695           break;
01696         }
01697       case TypePK:
01698         {
01699           DPaths *lenDps = NULL;
01700           if (v->vKind == BindingVK) {
01701             lenDps = ((BindingVC*)v)->lenDps;
01702             if (lenDps != NULL && lenDps->Size() != 0) {
01703               DepPathTbl::TIter iter(lenDps);
01704               DepPathTbl::KVPairPtr ptr;
01705               while (iter.Next(ptr)) {
01706                 DepPath typePath(ptr->key.content->path, TypePK, ptr->key.content->pathFP);
01707                 (void)ps->Put(typePath, valTBinding, ptr);
01708                 // assert(valTBinding->FingerPrint() == ptr->val->FingerPrint());
01709               }
01710             }
01711           }
01712           else if (v->vKind == ListVK) {
01713             lenDps = ((ListVC*)v)->lenDps;
01714             if (lenDps != NULL && lenDps->Size() != 0) {
01715               ps = ps->Union(lenDps);
01716             }
01717           }
01718           break;
01719         }
01720       default:
01721         break;
01722       }
01723     }
01724     return NULL;
01725   }
01726   switch (v->vKind) {
01727   case BindingVK:
01728     {
01729       BindingVC *bv = (BindingVC*)v;
01730       if (dp->Size() == 1 && dp->content->pKind == BangPK)
01731         CollectDefined(bv, dp->content->path->getlo(), ps);
01732       else {
01733         int n = ArcInt(dp->content->path->getlo());
01734         if (n == -1) {
01735           Val v1 = CollectLookup(bv, dp->content->path->getlo(), newPath, ps);
01736           dp->content->path->remlo();
01737           if (newPath != NULL) {
01738             newPath->Extend(*dp->content->path, dp->content->pKind);
01739             return newPath;
01740           }
01741           newPath = CollectDpnd(v1, dp, ps);
01742         }
01743         else {
01744           Context elems = bv->elems;
01745           dp->content->path->remlo();
01746           newPath = CollectDpnd(elems.Nth(n)->val, dp, ps);
01747         }
01748       }
01749       break;
01750     }
01751   case ListVK:
01752     {
01753       int n = ArcInt(dp->content->path->getlo());
01754       dp->content->path->remlo();
01755       Val v1 = ((ListVC*)v)->elems.Nth(n);
01756       if (v1->dpsVersion != currentDpsVersion) {
01757         ps = ps->Union(v1->dps);
01758         v1->dpsVersion = currentDpsVersion;
01759       }
01760       newPath = CollectDpnd(v1, dp, ps);
01761       break;
01762     }
01763   case ClosureVK:
01764     {
01765       ClosureVC *cl = (ClosureVC*)v;
01766       Context work = cl->con;
01767       Text name(dp->content->path->getlo());
01768       while (!work.Null()) {
01769         Assoc a = work.Pop();
01770         if (a->name == name) {
01771           Val v1 = a->val;
01772           if (v1->dpsVersion != currentDpsVersion) {
01773             ps = ps->Union(v1->dps);
01774             v1->dpsVersion = currentDpsVersion;
01775           }
01776           dp->content->path->remlo();
01777           newPath = CollectDpnd(v1, dp, ps);
01778           return newPath;
01779         }
01780       }
01781       break;
01782     }
01783   default:
01784     assert(v != 0);
01785     assert(dp != 0);
01786     ostream& err_str = cio().start_err();
01787     Error(err_str, "(Impl) CollectDpnd: wrong type of value.\n");
01788     // Before bailing out completely, print out some more information,
01789     // in hopes of helping to debug this when it happens.
01790     err_str << "v = ";
01791     v->PrintD(err_str);
01792     err_str << endl;
01793     err_str << "dp = ";
01794     dp->Print(err_str);
01795     err_str << endl;
01796     InternalError(err_str, cio().helper(true), "CollectDpnd");
01797     // Unreached: InternalError never returns
01798     abort();
01799     break;
01800   }
01801   return newPath;
01802 }
01803 
01804 Val CollectLetS(const Text& name, Val v1, Val v2) {
01805   /* We only need to do something for composite values. */
01806   switch (v2->vKind) {
01807   case BindingVK:
01808     {
01809       // Collect dependency for each element of the binding:
01810       BindingVC *bv = (BindingVC*)v2;
01811       Context rc, work = bv->elems;
01812       while (!work.Null()) {
01813         Assoc a = work.Pop();
01814         a = NEW_CONSTR(AssocVC, (a->name, CollectLet(name, v1, a->val)));
01815         rc.Append1D(a);
01816       }
01817       bv->elems = rc;
01818       // Collect dependency for lenDps of the binding:
01819       DPaths *newLenDps;
01820       CollectLet(name, v1, bv->lenDps, bv, newLenDps);
01821       bv->lenDps = newLenDps;
01822       return bv;
01823     }
01824   case ListVK:
01825     {
01826       // Collect dependency for each element of the list:
01827       ListVC *lstv = (ListVC*)v2;
01828       Vals res, elems = lstv->elems;
01829       while (!elems.Null())
01830         res.Append1D(CollectLet(name, v1, elems.Pop()));
01831       lstv->elems = res;
01832       // Collect dependency for lenDps of the list:
01833       DPaths *newLenDps;
01834       CollectLet(name, v1, lstv->lenDps, lstv, newLenDps);
01835       lstv->lenDps = newLenDps;
01836       return lstv;
01837     }
01838   case ClosureVK:
01839     {
01840       ClosureVC *cl = (ClosureVC*)v2;
01841       Context rc, work = cl->con;
01842       while (!work.Null()) {
01843         Assoc a = work.Pop();
01844         if (a->name != cl->func->name)
01845           a = NEW_CONSTR(AssocVC, (a->name, CollectLet(name, v1, a->val)));
01846         rc.Append1D(a);
01847       }
01848       cl->con = rc;
01849       return v2;
01850     }
01851   default:
01852     break;
01853   }
01854   return v2;
01855 }
01856 
01857 Val CollectLet(const Text& name, Val v1, Val v2) {
01858   // Special case (control expr of foreach):
01859   if (name == emptyText) {
01860     // See IterateAssoc for the meaning of v1.
01861     v2->Merge(v1);
01862     return v2;
01863   }
01864 
01865   // Normal case:
01866   bool found = false;
01867   DepPath *newPath = NULL;
01868   DPaths *rps;
01869   // Collect dependency of v2->dps:
01870   if (v2->SizeOfDPS() != 0) {
01871     found = v2->dps->ContainsPrefix(name);
01872     if (found) {
01873       rps = NEW(DPaths);
01874       DepPathTbl::TIter iter(v2->dps);
01875       DepPathTbl::KVPairPtr ptr;
01876       while (iter.Next(ptr)) {
01877         if (ptr->key.content->path->getlo() == name) {
01878           if (v1->dpsVersion != currentDpsVersion) {
01879             rps = rps->Union(v1->dps);
01880             v1->dpsVersion = currentDpsVersion;
01881           }
01882           DepPath key1;
01883           key1.DeepCopy(ptr->key, currentDpathVersion);
01884           key1.content->path->remlo();
01885           newPath = CollectDpnd(v1, &key1, rps);
01886           if (newPath != NULL) {
01887             DepPathTbl::KVPairPtr pr;
01888             (void)rps->Put(*newPath, ptr->val, pr);
01889             // assert(ptr->val->FingerPrint() == pr->val->FingerPrint());
01890           }
01891         }
01892         else
01893           (void)rps->Put(ptr);
01894       }
01895     }
01896   }
01897   // Collect dependency of v2->path:
01898   DepPath *dp = v2->path;
01899   Val v3 = v2->Copy(true);
01900   v3->dps = (found) ? rps : v2->dps;
01901   rps = NULL;   // No longer needed.
01902   if (dp != NULL) {
01903     v3->path = dp;
01904     if (dp->content->path->getlo() == name) {
01905       if (v1->dpsVersion != currentDpsVersion) {
01906         v3->MergeDPS(v1->dps);
01907         v1->dpsVersion = currentDpsVersion;
01908       }
01909       newPath = dp->DeepCopy();
01910       newPath->content->path->remlo();
01911       if (v3->dps == NULL)
01912         v3->dps = NEW(DPaths);
01913       v3->path = CollectDpnd(v1, newPath, v3->dps, false); 
01914     }
01915     return v3;
01916   }
01917   /* We get here only when v2->path is NULL. So we recursively
01918      collect dependency for subvalues of v2.  */
01919   return CollectLetS(name, v1, v3);
01920 }
01921 
01922 Val LetDpnd(Val v, const Context& c) {
01923   Context work = c;
01924   Assoc a;
01925 
01926   /* The counter currentDpathVersion is incremented for every LetDpnd
01927      call, while the counter currentDpsVersion is incremented for every
01928      iteration in a LetDpnd call.  */
01929   currentDpathVersion++;
01930   while (!work.Null()) {
01931     a = work.Pop();
01932     currentDpsVersion++;
01933     v = CollectLet(a->name, a->val, v);
01934     /* After each round of collecting dependency, we try to make
01935        the dependency compact by:
01936         1. Delete any duplicate copies of any dependency path.
01937         2. Promote shared dependency paths.  */
01938     DeleteDuplicatePaths(v);
01939     CanonicalDpnd(v);
01940   }
01941   return v;
01942 }
01943 
01944 Val CollectFuncS(Val bodyv, Val fv, const Context& c) {
01945   /* We only need to do something for composite values. */
01946   switch (bodyv->vKind) {
01947   case BindingVK:
01948     {
01949       BindingVC *bv = (BindingVC*)bodyv;
01950       Context rc, work = bv->elems;
01951       while (!work.Null()) {
01952         Assoc a = work.Pop();
01953         a = NEW_CONSTR(AssocVC, (a->name, CollectFunc(a->val, fv, c)));
01954         rc.Append1D(a);
01955       }
01956       bv->elems = rc;
01957       DPaths *newLenDps;
01958       CollectFunc(bv->lenDps, fv, c, bv, newLenDps);
01959       bv->lenDps = newLenDps;
01960       return bv;
01961     }
01962   case ListVK:
01963     {
01964       ListVC *lstv = (ListVC*)bodyv;
01965       Vals res, elems = lstv->elems;
01966       while (!elems.Null())
01967         res.Append1D(CollectFunc(elems.Pop(), fv, c));
01968       lstv->elems = res;
01969       DPaths *newLenDps;
01970       CollectFunc(lstv->lenDps, fv, c, lstv, newLenDps);
01971       lstv->lenDps = newLenDps;
01972       return lstv;
01973     }
01974   case ClosureVK:
01975     {
01976       ClosureVC *cl = (ClosureVC*)bodyv;
01977       Context rc, work = cl->con;
01978       while (!work.Null()) {
01979         Assoc a = work.Pop();
01980         if (a->name != cl->func->name)
01981           a = NEW_CONSTR(AssocVC, (a->name, CollectFunc(a->val, fv, c)));
01982         rc.Append1D(a);
01983       }
01984       cl->con = rc;
01985       return cl;
01986     }
01987   default:
01988     break;
01989   }
01990   return bodyv;
01991 }
01992 
01993 Val CollectFunc(Val bodyv, Val fv, const Context& c) {
01994   Text name;
01995   DepPath *newPath = NULL;
01996   bool fromArgsCon;
01997 
01998   // argsCon1 are arguments which have an identical path in the
01999   // calling scope.  This allows us to avoid rewriting some dependency
02000   // paths.
02001 
02002   // argsCon2 is all other arguments.
02003   Context argsCon1, argsCon2;
02004   Context work = c;
02005   while (!work.Null()) {
02006     Assoc a = work.Pop();
02007     if (a->val->path != NULL &&
02008         a->val->path->Size() == 1 &&
02009         a->name == a->val->path->content->path->getlo())
02010       argsCon1.Push(a);
02011     else
02012       argsCon2.Push(a);
02013   }
02014 
02015   DPaths *rps = NEW(DPaths);
02016   // Path dependency for bodyv:
02017   if (bodyv->dps != NULL) {
02018     DepPathTbl::TIter iter(bodyv->dps);
02019     DepPathTbl::KVPairPtr ptr;
02020     DepPath key1;
02021     while (iter.Next(ptr)) {
02022       name = ptr->key.content->path->getlo();
02023       fromArgsCon = false;
02024       work = argsCon1;
02025       while (!fromArgsCon && !work.Null()) {
02026         Assoc a = work.Pop();
02027         if (a->name == name) {
02028           if (a->val->dpsVersion != currentDpsVersion) {
02029             rps = rps->Union(a->val->dps);
02030             a->val->dpsVersion = currentDpsVersion;
02031           }
02032           // This argument's value has the same name in the calling
02033           // scope, so we can just copy the dependency path as-is.
02034           newPath = NULL;
02035           (void)rps->Put(ptr);
02036           fromArgsCon = true;
02037         }
02038       }
02039       work = argsCon2;
02040       while (!fromArgsCon && !work.Null()) {
02041         Assoc a = work.Pop();
02042         if (a->name == name) {
02043           if (a->val->dpsVersion != currentDpsVersion) {
02044             rps = rps->Union(a->val->dps);
02045             a->val->dpsVersion = currentDpsVersion;
02046           }
02047           key1.DeepCopy(ptr->key);
02048           key1.content->path->remlo();
02049           newPath = CollectDpnd(a->val, &key1, rps);
02050           fromArgsCon = true;
02051         }
02052       }
02053       if (!fromArgsCon) {
02054         key1.DeepCopy(ptr->key);
02055         if (((ClosureVC*)fv)->func->name == name) {
02056           // The function fv is calling itself recursively!
02057           key1.content->path->remlo();
02058         }
02059         newPath = CollectDpnd(fv, &key1, rps);
02060       }
02061       if (newPath != NULL) {
02062         DepPathTbl::KVPairPtr pr;
02063         (void)rps->Put(*newPath, ptr->val, pr);
02064         // assert(ptr->val->FingerPrint() == pr->val->FingerPrint());
02065       }
02066     }
02067   }
02068   
02069   // Dependency for function body:
02070   if (fv->dpsVersion != currentDpsVersion) {
02071     rps = rps->Union(fv->dps);
02072     fv->dpsVersion = currentDpsVersion;
02073   }
02074   rps = rps->Add(fv->path, fv, ExprPK);
02075   
02076   // Dependency for path of bodyv:
02077   DepPath *dp = bodyv->path;
02078   Val bodyv1 = bodyv->Copy(true);
02079   bodyv1->dps = rps;
02080   bodyv1->path = dp;
02081   if (dp != NULL) {
02082     name = dp->content->path->getlo();
02083     fromArgsCon = false;
02084     work = argsCon1;
02085     while (!fromArgsCon && !work.Null()) {
02086       Assoc a = work.Pop();
02087       if (a->name == name) {
02088         if (a->val->dpsVersion != currentDpsVersion) {
02089           bodyv1->MergeDPS(a->val->dps);
02090           a->val->dpsVersion = currentDpsVersion;
02091         }
02092         fromArgsCon = true;
02093       }
02094     }
02095     work = argsCon2;
02096     while (!fromArgsCon && !work.Null()) {
02097       Assoc a = work.Pop();
02098       if (a->name == name) {
02099         if (a->val->dpsVersion != currentDpsVersion) {
02100           bodyv1->MergeDPS(a->val->dps);
02101           a->val->dpsVersion = currentDpsVersion;
02102         }
02103         newPath = dp->DeepCopy();
02104         newPath->content->path->remlo();
02105         bodyv1->path = CollectDpnd(a->val, newPath, bodyv1->dps, false);
02106         fromArgsCon = true;
02107       }
02108     }
02109     if (!fromArgsCon) {
02110       newPath = dp->DeepCopy();
02111       if (((ClosureVC*)fv)->func->name == name) {
02112         // This function is recursive!
02113         newPath->content->path->remlo();
02114       }
02115       bodyv1->path = CollectDpnd(fv, newPath, bodyv1->dps, false);
02116     }
02117     return bodyv1;
02118   }
02119 
02120   /* Structural dependency for bodyv.
02121      We get here only when bodyv->path is NULL.  So we recursively
02122      collect dependency for subvalues of v2.  */
02123   return CollectFuncS(bodyv1, fv, c);
02124 }
02125 
02126 Val FuncDpnd(Val bodyv, Val fv, const Context& c) {
02127   currentDpsVersion++;
02128   return CollectFunc(bodyv, fv, c);
02129 }
02130 
02131 Val CollectModelS(Val bodyv, Val fv, const Context& c) {
02132   /* Only for composite values. */
02133   switch (bodyv->vKind) {
02134   case BindingVK:
02135     {
02136       BindingVC *bv = (BindingVC*)bodyv;
02137       Context rc, work = bv->elems;
02138       while (!work.Null()) {
02139         Assoc a = work.Pop();
02140         a = NEW_CONSTR(AssocVC, (a->name, CollectModel(a->val, fv, c)));
02141         rc.Append1D(a);
02142       }
02143       bv->elems = rc;
02144       DPaths *newLenDps;
02145       CollectModel(bv->lenDps, c, bv, newLenDps);
02146       bv->lenDps = newLenDps;
02147       return bv;
02148     }
02149   case ListVK:
02150     {
02151       ListVC *lstv = (ListVC*)bodyv;
02152       Vals res, elems = lstv->elems;
02153       while (!elems.Null())
02154         res.Append1D(CollectModel(elems.Pop(), fv, c));
02155       lstv->elems = res;
02156       DPaths *newLenDps;
02157       CollectModel(lstv->lenDps, c, lstv, newLenDps);
02158       lstv->lenDps = newLenDps;
02159       return lstv;
02160     }
02161   case ClosureVK:
02162     {
02163       ClosureVC *cl = (ClosureVC*)bodyv;
02164       Context rc, work = cl->con;
02165       while (!work.Null()) {
02166         Assoc a = work.Pop();
02167         if (a->name != cl->func->name)
02168           a = NEW_CONSTR(AssocVC, (a->name, CollectModel(a->val, fv, c)));
02169         rc.Append1D(a);
02170       }
02171       cl->con = rc;
02172       return cl;
02173     }
02174   default:
02175     break;
02176   }
02177   return bodyv;
02178 }
02179 
02180 Val CollectModel(Val bodyv, Val fv, const Context& c) {
02181   DepPath *newPath = NULL;
02182   bool merged = false;
02183   // assert((c.Length() == 1) && (c.Nth(0)->name == nameDot))
02184   Val dotVal = c.Nth(0)->val;
02185   DPaths *rps = NEW(DPaths);
02186 
02187   // Path dependency for v:
02188   if (bodyv->SizeOfDPS() != 0) {
02189     DepPathTbl::TIter iter(bodyv->dps);
02190     DepPathTbl::KVPairPtr ptr;
02191     DepPath key1;
02192     while (iter.Next(ptr)) {
02193       assert(ptr->key.content->path->getlo() == nameDot);
02194       if (dotVal->dpsVersion != currentDpsVersion) {
02195         rps = rps->Union(dotVal->dps);
02196         dotVal->dpsVersion = currentDpsVersion;
02197       }
02198       key1.DeepCopy(ptr->key);
02199       key1.content->path->remlo();
02200       newPath = CollectDpnd(dotVal, &key1, rps);
02201       if (newPath != NULL) {
02202         DepPathTbl::KVPairPtr pr;
02203         (void)rps->Put(*newPath, ptr->val, pr);
02204         // assert(ptr->val->FingerPrint() == pr->val->FingerPrint());
02205       }
02206     }
02207   }
02208   // Dependency for function body:
02209   rps = rps->Union(fv->dps);
02210   rps = rps->Add(fv->path, fv, ExprPK);  // redundant, but added for caching
02211   rps = rps->Add(fv->path, fv, NormPK);
02212 
02213   // Dependency for path of bodyv:
02214   DepPath *dp = bodyv->path;
02215   Val bodyv1 = bodyv->Copy(true);
02216   bodyv1->dps = rps;
02217   if (dp != NULL) {
02218     newPath = NULL;
02219     assert(dp->content->path->getlo() == nameDot);
02220     if (dotVal->dpsVersion != currentDpsVersion)
02221       bodyv1->MergeDPS(dotVal->dps);
02222     newPath = dp->DeepCopy();
02223     newPath->content->path->remlo();
02224     newPath = CollectDpnd(dotVal, newPath, bodyv1->dps, false);
02225     bodyv1->path = newPath;
02226     return bodyv1;
02227   }
02228   /* We get here only when bodyv->path is NULL.  So we now collect
02229      dependency for subvalues of v2.  */
02230   return CollectModelS(bodyv1, fv, c);
02231 }
02232 
02233 Val ModelDpnd(Val bodyv, Val fv, const Context& c) {
02234   currentDpsVersion++;
02235   return CollectModel(bodyv, fv, c);
02236 }
02237 
02238 void CollectLet(const Text& name, Val v1, DPaths *ps, Val res,
02239                 /*OUT*/ DPaths*& nps) {
02240   // Control expr of foreach:
02241   if (name == emptyText) {
02242     // See the function IterateAssoc for the meaning of v1.
02243     res->MergeDPS(v1->dps)->MergeDPS(ps);
02244     return;
02245   }
02246   // Trivial cases:
02247   if (ps == NULL || ps->Size() == 0) {
02248     nps = NULL;
02249     return;
02250   }
02251   // Normal case:
02252   bool found = false;
02253   DepPath *newPath = NULL;
02254   found = ps->ContainsPrefix(name);
02255   if (!found) {
02256     nps = ps;
02257   }
02258   else {
02259     nps = NEW(DPaths);
02260     if (res->dps == NULL)
02261       res->dps = NEW(DPaths);
02262     DPaths *rps = res->dps;
02263     DepPathTbl::TIter iter(ps);
02264     DepPathTbl::KVPairPtr ptr;
02265     while (iter.Next(ptr)) {
02266       if (ptr->key.content->path->getlo() != name)
02267         (void)nps->Put(ptr);
02268       else {
02269         if (v1->dpsVersion != currentDpsVersion) {
02270           rps = rps->Union(v1->dps);
02271           v1->dpsVersion = currentDpsVersion;
02272         }
02273         DepPath key1;
02274         key1.DeepCopy(ptr->key, currentDpathVersion);
02275         key1.content->path->remlo();
02276         newPath = CollectDpnd(v1, &key1, rps);
02277         if (newPath != NULL) {
02278           DepPathTbl::KVPairPtr pr;
02279           nps->Put(*newPath, ptr->val, pr);
02280           // assert(ptr->val->FingerPrint() == pr->val->FingerPrint());
02281         }
02282       }
02283     }
02284   }
02285   if (nps->Size() == 0) nps = NULL;
02286   return;
02287 }
02288 
02289 void CollectFunc(DPaths *ps, Val fv, const Context& c, Val res,
02290                  /*OUT*/ DPaths*& nps) {
02291   // Trivial cases:
02292   if (ps == NULL || ps->Size() == 0) {
02293     nps = NULL;
02294     return;
02295   }
02296   // Normal case:
02297   DepPath *newPath = NULL;
02298   Text name;
02299   bool fromArgsCon;
02300   nps = NEW(DPaths);
02301   if (res->dps == NULL)
02302     res->dps = NEW(DPaths);
02303   DPaths *rps = res->dps;
02304   DepPathTbl::TIter iter(ps);
02305   DepPathTbl::KVPairPtr ptr;
02306   DepPath key1;
02307   while (iter.Next(ptr)) {
02308     name = ptr->key.content->path->getlo();
02309     Context work = c;
02310     fromArgsCon = false;
02311     while (!fromArgsCon && !work.Null()) {
02312       Assoc a = work.Pop();
02313       if (a->name == name) {
02314         if (a->val->dpsVersion != currentDpsVersion) {
02315           rps = rps->Union(a->val->dps);
02316           a->val->dpsVersion = currentDpsVersion;
02317         }
02318         key1.DeepCopy(ptr->key);
02319         key1.content->path->remlo();
02320         newPath = CollectDpnd(a->val, &key1, rps);
02321         fromArgsCon = true;
02322       }
02323     }
02324     if (!fromArgsCon) {
02325       key1.DeepCopy(ptr->key);
02326       if (((ClosureVC*)fv)->func->name == name) {
02327         key1.content->path->remlo();
02328       }
02329       if (fv->dpsVersion != currentDpsVersion) {
02330         rps = rps->Union(fv->dps);
02331         fv->dpsVersion = currentDpsVersion;
02332       }
02333       newPath = CollectDpnd(fv, &key1, rps);
02334     }
02335     if (newPath != NULL) {
02336       DepPathTbl::KVPairPtr pr;
02337       nps->Put(*newPath, ptr->val, pr);
02338       // assert(ptr->val->FingerPrint() == pr->val->FingerPrint());
02339     }
02340   }
02341   if (nps->Size() == 0) nps = NULL;
02342   return;
02343 }
02344 
02345 void CollectModel(DPaths *ps, const Context& c, Val res,
02346                   /*OUT*/ DPaths*& nps) {
02347   DepPath *newPath = NULL;
02348   // assert((c.Length() == 1) && (c.Nth(0)->name == nameDot))
02349 
02350   if (ps == NULL)
02351     nps = NULL;
02352   else {
02353     Val dotVal = c.Nth(0)->val;
02354     nps = NEW(DPaths);
02355     if (res->dps == NULL)
02356       res->dps = NEW(DPaths);
02357     DPaths *rps = res->dps;
02358     DepPathTbl::TIter iter(ps);
02359     DepPathTbl::KVPairPtr ptr;
02360     DepPath key1;
02361     while (iter.Next(ptr)) {
02362       assert(ptr->key.content->path->getlo() == nameDot);
02363       if (dotVal->dpsVersion != currentDpsVersion) {
02364         rps = rps->Union(dotVal->dps);
02365         dotVal->dpsVersion = currentDpsVersion;
02366       }
02367       key1.DeepCopy(ptr->key);
02368       key1.content->path->remlo();
02369       newPath = CollectDpnd(dotVal, &key1, rps);
02370       if (newPath != NULL) {
02371         DepPathTbl::KVPairPtr pr;
02372         nps->Put(*newPath, ptr->val, pr);
02373         // assert(ptr->val->FingerPrint() == pr->val->FingerPrint());
02374       }
02375     }
02376   }
02377   return;
02378 }
02379 
02380 // Pretty-printing a value.
02381 Text PrintForm(Val v) {
02382   OBufStream stream;
02383   v->PrintD(stream);
02384   return Text(stream.str());
02385 }
02386 
02387 // Lookup in context.
02388 Assoc FindInContext(const Text& id, const Context& c) {
02389   Context work = c;
02390 
02391   while (!work.Null()) {
02392     Assoc a = work.Pop();
02393     if (a->name == id) return a;
02394   }
02395   return nullAssoc;
02396 }
02397 
02398 Val LookupInContext(const Text& id, const Context& c) {
02399   return FindInContext(id, c)->val;
02400 }
02401 
02402 // For performance, we use the LookupNoDpnd methods for LookupPath. 
02403 // They return the same value as Lookup methods, but do not record
02404 // dependency.
02405 Val LookupArc(const Text& arc, Val v) {
02406   switch (v->vKind) {
02407   case BindingVK:
02408     {
02409       int n = ArcInt(arc);
02410       if (n == -1)
02411         v = ((BindingVC*)v)->LookupNoDpnd(arc);
02412       else {
02413         Text arc1;
02414         v = ((BindingVC*)v)->GetElemNoDpnd(n, arc1);
02415       }
02416       break;
02417     }
02418   case ListVK:
02419     {
02420       int n = ArcInt(arc);
02421       if (n == -1) return valUnbnd;
02422       v = ((ListVC*)v)->GetElemNoDpnd(n);      
02423       break;
02424     }
02425   case ClosureVK:
02426     v = LookupInContext(arc, ((ClosureVC*)v)->con);
02427     break;
02428   default:
02429     // cannot do a lookup with simple value.
02430     return valUnbnd;
02431   }
02432   return v;
02433 }
02434 
02435 Val LookupPath(const FV2::T& path, const Context& c) {
02436   /* The function is used to compute the values of the free variables
02437      in the current context.  The 0-th element of path is the kind of
02438      the path. See cache lookup.  */
02439   int len = path.size();
02440   Val result;
02441 
02442   // figure out the path kind:
02443   PathKind pkind = (PathKind)path.get(0).chars()[0];
02444 
02445   // lookup for the first arc:
02446   result = LookupInContext(path.get(1), c);
02447   if (result->vKind == UnbndVK) return result;
02448 
02449   // lookup for the remaining arcs:
02450   if (pkind == BangPK) {
02451     for (int i = 2; i < (len - 1); i++) {
02452       result = LookupArc(path.get(i), result);
02453       if (result->vKind == UnbndVK) return result;
02454     }
02455     if (result->vKind != BindingVK)
02456       return valUnbnd;
02457     return ((BindingVC*)result)->DefinedNoDpnd(path.get(len-1)) ? valTrue : valFalse;
02458   }
02459   for (int i = 2; i < len; i++) {
02460     result = LookupArc(path.get(i), result);
02461     if (result->vKind == UnbndVK) return result;
02462   }
02463 
02464   // Special treatment for the following kinds of path:
02465   switch (pkind) {
02466   case BLenPK:
02467     if (result->vKind != BindingVK) return valUnbnd;
02468     return ((BindingVC*)result)->Names();
02469   case LLenPK:
02470     if (result->vKind != ListVK) return valUnbnd;
02471     return ((ListVC*)result)->Length();
02472   case TypePK:
02473     return ValType(result);
02474   case ExprPK:
02475     if (result->vKind == ClosureVK)
02476       result = NEW_CONSTR(FpVC, (((ClosureVC*)result)->FingerPrintExpr()));
02477     else if (result->vKind == ModelVK)
02478       result = NEW_CONSTR(FpVC, (((ModelVC*)result)->FingerPrintFile()));
02479     else
02480       result = valUnbnd;
02481     return result;
02482   default:
02483     return result;
02484   }
02485   // return result; // not reached
02486 }
02487 
02488 Val LookupPath(DepPath *dp, const Context& c) {
02489   /* The function is used in Unpickle to restore the fingerprint for
02490      DPS's and the value for path and LenDPS's. See Unpickle. */
02491   PathKind pkind = dp->content->pKind;
02492   ArcSeq *path = dp->content->path;
02493   int len = path->size();
02494 
02495   // Lookup for the first arc. It must be bound in the context.
02496   Val result = LookupInContext(path->get(0), c);
02497 
02498   // lookup for the remaining arcs:
02499   if (pkind == BangPK) {
02500     for (int i = 1; i < len-1; i++) {
02501       assert(result->vKind != UnbndVK);
02502       result = LookupArc(path->get(i), result);
02503     }
02504     assert(result->vKind == BindingVK);
02505     return ((BindingVC*)result)->DefinedNoDpnd(path->get(len-1)) ? valTrue : valFalse;
02506   }
02507   for (int i = 1; i < len; i++) {
02508     assert(result->vKind != UnbndVK);
02509     result = LookupArc(path->get(i), result);
02510   }
02511   
02512   // Special treatment for the following kinds of path:
02513   switch (pkind) {
02514   case BLenPK:
02515     assert(result->vKind == BindingVK);
02516     return ((BindingVC*)result)->Names();
02517   case LLenPK:
02518     assert(result->vKind == ListVK);
02519     return ((ListVC*)result)->Length();
02520   case TypePK:
02521     return ValType(result);
02522   case ExprPK:
02523     if (result->vKind == ClosureVK)
02524       result = NEW_CONSTR(FpVC, (((ClosureVC*)result)->FingerPrintExpr()));
02525     else {
02526       assert(result->vKind == ModelVK);
02527       result = NEW_CONSTR(FpVC, (((ModelVC*)result)->FingerPrintFile()));
02528     }
02529     return result;
02530   default:
02531     return result;
02532   }
02533   // return result; // not reached
02534 }
02535 
02536 Val Lookup(Basics::uint16 idx, const PrefixTbl& tbl,
02537            const Context& c, Val* vals) {
02538   Val res;
02539   if (vals[idx] == NULL) {
02540     if (tbl.PrefixIndex(idx) == PrefixTbl::endMarker) {
02541       res = LookupInContext(tbl.Arc(idx), c);
02542       vals[idx] = res;
02543     }
02544     else {
02545       res = Lookup(tbl.PrefixIndex(idx), tbl, c, vals);
02546       if (res->vKind == UnbndVK) {
02547         vals[idx] = valUnbnd;
02548       }
02549       else {
02550         res = LookupArc(tbl.Arc(idx), res);
02551         vals[idx] = res;
02552       }
02553     }
02554   }
02555   else {
02556     res = vals[idx];
02557   }
02558   return res;
02559 }
02560 
02561 Val LookupPath(Basics::uint16 idx, PathKind pkind, const PrefixTbl& tbl,
02562                const Context& c, Val *vals) {
02563   Val result;
02564   if (pkind == BangPK) {
02565     short int idx1 = tbl.PrefixIndex(idx);
02566     result = Lookup(idx1, tbl, c, vals);
02567     if (result->vKind == BindingVK)
02568       result = ((BindingVC*)result)->DefinedNoDpnd(tbl.Arc(idx)) ? valTrue : valFalse;
02569     else
02570       result = valUnbnd;
02571   }
02572   else {
02573     result = Lookup(idx, tbl, c, vals);
02574     switch (pkind) {
02575     case BLenPK:
02576       if (result->vKind == BindingVK)
02577         result = ((BindingVC*)result)->Names();
02578       else
02579         result = valUnbnd;
02580       break;
02581     case LLenPK:
02582       if (result->vKind == ListVK)
02583         result = ((ListVC*)result)->Length();
02584       else
02585         result = valUnbnd;
02586       break;
02587     case TypePK:
02588       result = ValType(result);
02589       break;
02590     case ExprPK:
02591       if (result->vKind == ClosureVK)
02592         result = NEW_CONSTR(FpVC, (((ClosureVC*)result)->FingerPrintExpr()));
02593       else if (result->vKind == ModelVK)
02594         result = NEW_CONSTR(FpVC, (((ModelVC*)result)->FingerPrintFile()));
02595       else
02596         result = valUnbnd;
02597       break;
02598     default:
02599       break;
02600     }
02601   }
02602   return result;
02603 }
02604 
02605 void AppendDToContext(const Text& name, Expr elem, const Context& cElem, 
02606                      Context& cc) {
02607   // Val v = elem->Eval(cElem);
02608   Val v = elem->Eval(RestrictContext(cElem, elem->freeVars));
02609   cc.Append1D(NEW_CONSTR(AssocVC, (name, v)));
02610 }
02611 
02612 void PushToContext(const Text& name, Expr elem, const Context& cElem,
02613                    Context& in) {
02614   // Val v = elem->Eval(cElem);
02615   Val v = elem->Eval(RestrictContext(cElem, elem->freeVars));
02616   in.Push(NEW_CONSTR(AssocVC, (name, v)));
02617 }
02618 
02619 Context RestrictContext(const Context& con, Vars fv) {
02620   Context result;
02621 
02622   while (!fv.Null()) {
02623     Text id(fv.Pop());
02624     Assoc a = FindInContext(id, con);
02625     if (a != nullAssoc) result.Append1D(a);
02626   }
02627   return result;
02628 }
02629 
02630 Context Snip(const Context& orig, const Text& name, bool& found) {
02631   Context result;
02632   Context work = orig;
02633   Assoc a;
02634 
02635   found = false;
02636   while (!work.Null()) {
02637     a = work.Pop();
02638     if (a->name == name) {
02639       found = true;
02640       break;
02641     }
02642     result.Append1D(a);
02643   }
02644   if (!found) return orig;
02645   while (!work.Null()) {
02646     a = work.Pop();
02647     if (a->name != name)
02648       result.Append1D(a);
02649   }
02650   return result;
02651 }
02652 
02653 Context Prune(const Context& orig, const Context& remove) {
02654   if (remove.Null()) return orig;
02655 
02656   Context work = orig;
02657   Context result;
02658   while (!work.Null()) {
02659     Assoc a = work.Pop();
02660     if (FindInContext(a->name, remove) == nullAssoc)
02661       result.Append1D(a);
02662   }
02663   return result;
02664 }
02665 
02666 void AssignAssoc(AssignEC *ae, Context& con) {
02667   Text name(ae->lhs->id);
02668 
02669   if (ae->isFunc) {
02670     FuncEC *e = (FuncEC*)ae->rhs;
02671     ClosureVC *cl = NEW_CONSTR(ClosureVC, (e, con, true));
02672     AssocVC* av = NEW_CONSTR(AssocVC, (name, cl));
02673     con.Push(av);
02674     cl->con = RestrictContext(Context(av, cl->con), e->freeVars);
02675   }
02676   else {
02677     Expr e = ae->rhs;
02678     ExprKind ek = e->kind;
02679     if (ek != BaseTEK && ek != ListTEK &&
02680         ek != BindingTEK && ek != FuncTEK) {
02681       Val v = e->Eval(RestrictContext(con, e->freeVars));
02682       con.Push(NEW_CONSTR(AssocVC, (name, v)));
02683     }
02684   }
02685 }
02686 
02687 void IterateAssoc(IterateEC *it, Context& c) {
02688   Expr control = it->control, e = it->e;
02689   StmtListEC *body = it->body;
02690   Val v = e->Eval(c), v1;
02691   Text newName = GetUniqueName();
02692   c.Push(NEW_CONSTR(AssocVC, (newName, v)));
02693 
02694   if (control->kind == NameEK) {
02695     Text id(((Name)control)->id);
02696     if (v->vKind == ListVK) {
02697       int len = ((ListVC*)v)->elems.Length();
02698       v1 = NEW_CONSTR(IntegerVC, (len));
02699       FpVC *fpv = NEW_CONSTR(FpVC, (v1->FingerPrint()));
02700       v1->AddToDPS(NEW_CONSTR(DepPath, (newName)), fpv, LLenPK);
02701       c.Push(NEW_CONSTR(AssocVC, (emptyText, v1)));
02702       Vals vlist = ((ListVC*)v)->elems;
02703       int i = 0;
02704       while (!vlist.Null()) {
02705         v1 = vlist.Pop()->Copy();
02706         v1->path = NEW_CONSTR(DepPath, (newName));
02707         v1->path->Extend(IntArc(i++), NormPK);
02708         c.Push(NEW_CONSTR(AssocVC, (id, v1)));
02709         c = AddStmtAssocs(body, c);
02710       }
02711     }
02712     else {
02713       c.Push(NEW_CONSTR(AssocVC, (emptyText, v)));
02714       ostream& err_stream = cio().start_err();
02715       Error(err_stream, "Control expression doesn't evaluate to list.\n", e->loc);
02716       ErrorVal(err_stream, v);
02717       cio().end_err();
02718       throw(Evaluator::failure(Text("exiting"), false));
02719     }
02720   }
02721   else {
02722     // control is PairEK:
02723     PairEC *pair = (PairEC*)control;
02724     Text id1(((Name)(pair->first))->id);
02725     Text id2(((Name)(pair->second))->id);
02726     if (v->vKind == BindingVK) {
02727       BindingVC *bv = (BindingVC*)v;
02728       int len = bv->elems.Length();
02729       v1 = NEW_CONSTR(IntegerVC, (len));
02730       v1->AddToDPS(NEW_CONSTR(DepPath, (newName)), bv->Names(), BLenPK);
02731       c.Push(NEW_CONSTR(AssocVC, (emptyText, v1)));
02732       Context es = ((BindingVC*)v)->elems;
02733       while (!es.Null()) {
02734         Assoc a = es.Pop();
02735         c.Push(NEW_CONSTR(AssocVC, (id1, NEW_CONSTR(TextVC, (a->name)))));
02736         v1 = a->val->Copy();
02737         v1->path = NEW_CONSTR(DepPath, (newName));
02738         v1->path->Extend(a->name, NormPK);
02739         c.Push(NEW_CONSTR(AssocVC, (id2, v1)));
02740         c = AddStmtAssocs(body, c);
02741       }
02742     }
02743     else {
02744       c.Push(NEW_CONSTR(AssocVC, (emptyText, v)));
02745       ostream& err_stream = cio().start_err();
02746       Error(err_stream, "Control expression doesn't evaluate to binding.\n", e->loc);
02747       ErrorVal(err_stream, v);
02748       cio().end_err();
02749       throw(Evaluator::failure(Text("exiting"), false));
02750     }
02751   }
02752   return;
02753 }
02754 
02755 Context AddStmtAssocs(StmtListEC *assocs, const Context& c) {
02756   Context cc = c;
02757   Exprs els = assocs->elems;
02758   
02759   for (int i = 0; i < els.size(); i++) {
02760     Expr e = els.get(i);
02761     switch (e->kind) {
02762     case TypedEK:
02763       // Type-checking: to be added.
02764       break;
02765     case AssignEK:
02766       AssignAssoc((AssignEC*)e, cc);
02767       break;
02768     case IterateEK:
02769       IterateAssoc((IterateEC*)e, cc);
02770       break;
02771     case TryEK:
02772       e->Eval(cc);
02773       break;
02774     default:
02775       ostream& err_stream = cio().start_err();
02776       Error(err_stream, "Invalid statement:\n`", e->loc);
02777       ErrorExpr(err_stream, e);
02778       ErrorDetail(err_stream, "'.");
02779       cio().end_err();
02780     }
02781   }
02782   return cc;
02783 }
02784 
02785 extern "C" void ValInit_inner() {
02786   conInitial.Push(NEW_CONSTR(AssocVC, (nameDot, NEW(BindingVC))));
02787 }
02788 
02789 void ValInit()
02790 {
02791   static pthread_once_t init_once = PTHREAD_ONCE_INIT;
02792   pthread_once(&init_once, ValInit_inner);
02793 }

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