Main Page | Namespace List | Class Hierarchy | Class List | Directories | File List | Namespace Members | Class Members | File Members

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

Generated on Mon May 8 00:48:41 2006 for Vesta by  doxygen 1.4.2