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

Expr.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: Expr.C
00020 
00021 #include "Expr.H"
00022 #include "ApplyCache.H"
00023 #include "Files.H"
00024 #include "Debug.H"
00025 #include "ThreadData.H"
00026 #include <sstream>
00027 #include <FPStream.H>
00028 
00029 using std::ostream;
00030 using std::cerr;
00031 using Basics::OBufStream;
00032 using FP::FPStream;
00033 
00034 // Constants:
00035 const char *nameDot = ".";
00036 
00038 // Eval returns the value and dependency of evaluating an expression.
00039 // Each subclass of ExprC should override Eval. 
00040 void ExprC::PrintExprVars(ostream *os) {
00041   *os << "\nfreeVars =";
00042   PrintVars(os, freeVars);
00043 }
00044 
00046 // ConstantEC
00047 Val ConstantEC::Eval(const Context& c) {
00048   // assert(!val->path && (val->dps->Size() == 0))
00049   // Must copy here!
00050   return this->val->Copy();
00051 }
00052 
00053 // IfEC
00054 IfEC::IfEC(Expr tcond, Expr tthen, Expr tels, SrcLoc *tloc) 
00055 : ExprC(IfEK, tloc), test(tcond), then(tthen), els(tels) {
00056   freeVars  = AddVars(test->freeVars, 
00057                       AddVars(els->freeVars, then->freeVars));
00058 }
00059 
00060 void IfEC::PrintD(ostream *os) {
00061   *os << "(";
00062   *os << "if ";      test->PrintD(os);
00063   *os << "\n then "; then->PrintD(os);
00064   *os << "\n else "; els->PrintD(os);
00065   *os << ")";
00066 }
00067 
00068 Val IfEC::Eval(const Context& c) {
00069   Val result, b = this->test->Eval(c);
00070 
00071   if (IsValTrue(b)) {
00072     result = this->then->Eval(c)->Merge(b);
00073     result->cacheit = result->cacheit && b->cacheit;
00074   }
00075   else if (IsValFalse(b)) {
00076     result = this->els->Eval(c)->Merge(b);
00077     result->cacheit = result->cacheit && b->cacheit;
00078   }
00079   else {
00080     outputMu.lock();
00081     this->EError("The test of an if-expression must be boolean.\n");
00082     outputMu.unlock();    
00083     result = RecordErrorOnStack(this);
00084     result->MergeDPS(b->dps);
00085     result->AddToDPS(b->path, ValType(b), TypePK);
00086   }
00087   return result;
00088 }
00089 
00090 // ComputedEC
00091 void ComputedEC::PrintD(ostream *os) {
00092   *os << '%';
00093   name->PrintD(os);
00094   *os << '%';
00095 }
00096 
00097 Val ComputedEC::Eval(const Context& c) {
00098   Val v = this->name->Eval(c);
00099 
00100   if (v->vKind == TextVK) return v;
00101   outputMu.lock();  
00102   this->EError("Expected a text value. \n");
00103   outputMu.unlock();  
00104   Val err = RecordErrorOnStack(this);
00105   err->MergeDPS(v->dps);
00106   return err->AddToDPS(v->path, ValType(v), TypePK);
00107 }
00108 
00109 // ExprListEC
00110 void ExprListEC::PrintD(ostream *os) {
00111   int n = elems.size() - 1;
00112 
00113   for (int i = 0; i < n; i++) {
00114     elems.get(i)->PrintD(os);
00115     *os << "; ";
00116   }
00117   if (n >= 0)
00118     elems.get(n)->PrintD(os);
00119 }
00120 
00121 void ExprListEC::AddExpr(Expr telem) {
00122   this->elems.addhi(telem);
00123   freeVars = AddVars(freeVars, telem->freeVars);
00124 }
00125 
00126 Val ExprListEC::Eval(const Context& c) {
00127   Vals vals;
00128 
00129   for (int i = 0; i < elems.size(); i++) {
00130     Val elem = elems.get(i)->Eval(c);
00131     vals.Append1D(elem);
00132   }
00133   Val result = NEW_CONSTR(ListVC, (vals));
00134   return result;
00135 }
00136 
00137 // ArgListEC
00138 void ArgListEC::PrintD(ostream *os) {
00139   int n = elems.size() - 1;
00140 
00141   for (int i = 0; i < n; i++) {
00142     elems.get(i)->PrintD(os);
00143     *os << ", ";
00144   }
00145   if (n >= 0)
00146     elems.get(n)->PrintD(os);
00147 }
00148 
00149 void ArgListEC::AddExpr(Expr telem, bool inPK) {
00150   if (inPK) {
00151     inPKs |= ((Bit64)1 << elems.size());
00152   }
00153   this->elems.addhi(telem);
00154   freeVars = AddVars(freeVars, telem->freeVars);
00155 }
00156 
00157 // StmtListEC
00158 void StmtListEC::PrintD(ostream *os) {
00159   int n = elems.size() - 1;
00160 
00161   for (int i = 0; i < n; i++) {
00162     this->elems.get(i)->PrintD(os);
00163     *os << ";\n";
00164   }
00165   if (n >= 0)
00166     this->elems.get(n)->PrintD(os);
00167 }
00168 
00169 void StmtListEC::AddExpr(Expr telem) {
00170   this->elems.addhi(telem);
00171   freeVars = AddVars(freeVars, Remove(telem->freeVars, boundVars));
00172   if (telem->kind == AssignEK)
00173     boundVars = Vars(((AssignEC*)telem)->lhs->id, boundVars);
00174   else if (telem->kind == IterateEK)
00175     boundVars = AddVars(boundVars, ((IterateEC*)telem)->body->boundVars);
00176   // assert(telem->kind == EvalEK)
00177 }
00178 
00179 // ListEC
00180 void ListEC::PrintD(ostream *os) {
00181   *os << "< ";
00182 
00183   int n = this->elems.size() - 1;
00184   for (int i = 0; i < n; i++) {
00185     this->elems.get(i)->PrintD(os);
00186     *os << ", ";
00187   }
00188   if (n >= 0)
00189     this->elems.get(n)->PrintD(os);
00190 
00191   *os << " >";
00192 }
00193 
00194 Val ListEC::Eval(const Context& c) {
00195   Vals vals;
00196   
00197   for (int i = 0; i < elems.size(); i++) {
00198     Val elem = elems.get(i)->Eval(c);
00199     vals.Append1D(elem);
00200   }
00201   Val result = NEW_CONSTR(ListVC, (vals));
00202   return result;
00203 }
00204 
00205 void ListEC::AddExpr(Expr telem) {
00206   this->elems.addhi(telem);
00207   freeVars = AddVars(freeVars, telem->freeVars);
00208 }
00209 
00210 // AssignEC
00211 AssignEC::AssignEC(Name tlhs, Expr trhs, bool tfunc, SrcLoc *tloc)
00212 : ExprC(AssignEK, tloc), lhs(tlhs), rhs(trhs), isFunc(tfunc) {
00213   freeVars = (tfunc) ? Remove(rhs->freeVars, lhs->id) : rhs->freeVars;
00214 }
00215 
00216 void AssignEC::PrintD(ostream *os) {
00217   lhs->PrintD(os);
00218   if (!this->isFunc) *os << " = ";
00219   rhs->PrintD(os);
00220 }
00221 
00222 // BindEC
00223 BindEC::BindEC(Expr tlhs, Expr trhs, SrcLoc *tloc)
00224 : ExprC(BindEK, tloc), lhs(tlhs), rhs(trhs) {
00225   freeVars = AddVars(lhs->freeVars, rhs->freeVars);
00226 }
00227 
00228 void BindEC::PrintD(ostream *os) {
00229   lhs->PrintD(os);
00230   *os << "=";
00231   rhs->PrintD(os);
00232 }
00233 
00234 // NameEC
00235 Val NameEC::Eval(const Context& c) {
00236   Val v = LookupInContext(id, c);
00237 
00238   if (v->vKind == UnbndVK) {
00239     outputMu.lock();
00240     this->EError(Text("\nUnbound variable `") + id +
00241                  "' encountered during evaluation in context:\n");
00242     PrintContext(&cerr, c);
00243     ErrorDetail(".\n");
00244     outputMu.unlock();    
00245     Val err = RecordErrorOnStack(this);
00246     return err->AddToDPS(NEW_CONSTR(DepPath, (id)), valFalse, BangPK);
00247   }
00248   Val result = v->Copy(true);
00249   result->path = NEW_CONSTR(DepPath, (id));
00250   return result;
00251 }
00252 
00253 // BindingEC
00254 void BindingEC::PrintD(ostream *os) {
00255   *os << "[ ";
00256 
00257   int n = this->assocs.size() - 1;
00258   for (int i = 0; i < n; i++) {
00259     this->assocs.get(i)->PrintD(os);
00260     *os << ", ";
00261   }
00262   if (n >= 0)
00263     this->assocs.get(n)->PrintD(os);
00264 
00265   *os << " ]";
00266 }
00267 
00268 Val BindingEC::Eval(const Context& c) {
00269   Text name;
00270   Val computed, result;
00271   Context bb;
00272   Vals vv;
00273   bool cacheit = true;
00274 
00275   for (int i = 0; i < assocs.size(); i++) {
00276     BindEC *a = (BindEC*)(assocs.get(i));
00277     // Get the field name:
00278     switch (a->lhs->kind) {
00279     case NameEK:
00280       name = ((Name)a->lhs)->id;
00281       computed = NULL;
00282       break;
00283     case ComputedEK:
00284       computed = a->lhs->Eval(c);
00285       if (computed->vKind != TextVK) {
00286         outputMu.lock();        
00287         this->EError("Field name in binding must evaluate to text: `");
00288         ErrorExpr(a->lhs);
00289         ErrorDetail("'.\n");
00290         outputMu.unlock();      
00291         result = RecordErrorOnStack(a->lhs);
00292         result->MergeDPS(computed->dps);
00293         return result->AddToDPS(computed->path, ValType(computed), TypePK);
00294       }
00295       name = ((TextVC*)computed)->NDS();
00296       cacheit = cacheit && computed->cacheit;
00297       vv.Push(computed);
00298       break;
00299     default:
00300       outputMu.lock();      
00301       this->EError("Field name in binding has wrong type: `");
00302       ErrorExpr(a->lhs);
00303       ErrorDetail("'.\n");
00304       outputMu.unlock();      
00305       result = RecordErrorOnStack(a->lhs);
00306       return result;
00307     }
00308     if (name.Empty()) {
00309       outputMu.lock();      
00310       a->EError("Empty field name in binding.");
00311       outputMu.unlock();      
00312       result = RecordErrorOnStack(a);
00313       return (computed ? result->Merge(computed) : result);
00314     }
00315     if (FindInContext(name, bb) != nullAssoc) {
00316       outputMu.lock();      
00317       this->EError("Field name conflicts in binding.");
00318       outputMu.unlock();      
00319       result = RecordErrorOnStack(this);
00320       while (!vv.Null()) result->Merge(vv.Pop());
00321       return result;
00322     }
00323     AppendDToContext(name, a->rhs, c, bb);
00324   }
00325   result = NEW_CONSTR(BindingVC, (bb));
00326   while (!vv.Null()) {
00327     result->Merge(vv.Pop());
00328   }
00329   result->cacheit = cacheit;
00330   return result;
00331 }
00332 
00333 void BindingEC::AddExpr(Expr telem) {
00334   this->assocs.addhi(telem);
00335   freeVars = AddVars(freeVars, telem->freeVars);
00336 }
00337 
00338 // ApplyOpEC
00339 ApplyOpEC::ApplyOpEC(Expr te1, const Text& top, Expr te2, SrcLoc *tloc)
00340 : ExprC(ApplyOpEK, tloc), e1(te1), op(top), e2(te2) {
00341   freeVars = AddVars(e1->freeVars, e2->freeVars);
00342 }
00343 
00344 Val ApplyOpEC::Eval(const Context& c) {
00345   if (recordCallStack) {
00346     callStackMu.lock();      
00347     ThreadDataGet()->callStack->addlo(this);
00348     callStackMu.unlock();          
00349   }
00350   Val result = LookupOp(this->op)(this->e1, this->e2, c);
00351   if (recordCallStack) {
00352     callStackMu.lock();          
00353     ThreadDataGet()->callStack->remlo();
00354     callStackMu.unlock();          
00355   }
00356   return result;
00357 }
00358 
00359 void ApplyOpEC::PrintD(ostream *os) {
00360   *os << "(";
00361   e1->PrintD(os);
00362   *os << ' ' << op << ' ';
00363   e2->PrintD(os);
00364   *os << ")";
00365 }
00366 
00367 // ApplyUnOpEC
00368 Val ApplyUnOpEC::Eval(const Context& c) {
00369   if (recordCallStack) {
00370     callStackMu.lock();          
00371     ThreadDataGet()->callStack->addlo(this);
00372     callStackMu.unlock();          
00373   }
00374   Val result = LookupUnOp(this->op)(this->e, c);
00375   if (recordCallStack) {
00376     callStackMu.lock();          
00377     ThreadDataGet()->callStack->remlo();
00378     callStackMu.unlock();          
00379   }
00380   return result;
00381 }
00382 
00383 void ApplyUnOpEC::PrintD(ostream *os) {
00384   *os << ' ' << op;
00385   e->PrintD(os);
00386   *os << ' ';
00387 }
00388 
00389 // PairEC
00390 PairEC::PairEC(Expr tfirst, Expr tsecond, SrcLoc *tloc) 
00391 : ExprC(PairEK, tloc), first(tfirst), second(tsecond) {
00392   freeVars = AddVars(first->freeVars, second->freeVars);
00393 }
00394 
00395 void PairEC::PrintD(ostream *os) {
00396   *os << "[ ";
00397   first->PrintD(os);
00398   *os << " = ";
00399   second->PrintD(os);
00400   *os << " ]";
00401 }
00402 
00403 // SelectEC
00404 SelectEC::SelectEC(Expr tbinding, Expr tfield, bool tbang,
00405                    SrcLoc *tloc)
00406 : ExprC(SelectEK, tloc), binding(tbinding), field(tfield),
00407   bang(tbang) {
00408   if (field->kind == NameEK)
00409     freeVars = binding->freeVars;
00410   else
00411     freeVars = AddVars(binding->freeVars, field->freeVars);
00412 }
00413 
00414 void SelectEC::PrintD(ostream *os) {
00415   binding->PrintD(os);
00416   *os << (bang ? '!' : '/');
00417   field->PrintD(os);
00418 }
00419 
00420 Val SelectEC::Eval(const Context& c) {
00421   Val lhs, rhs, result, err;
00422   Text id;
00423 
00424   // Compute the field name:
00425   switch (field->kind) {
00426   case NameEK:
00427     rhs = NULL;
00428     id = ((Name)field)->id;
00429     break;
00430   case ComputedEK:
00431     rhs = field->Eval(c);
00432     if (rhs->vKind != TextVK) {
00433       outputMu.lock();
00434       this->EError("Field selector must be evaluated to text: `");
00435       ErrorExpr(field);
00436       ErrorDetail("'.\n");
00437       outputMu.unlock();      
00438       err = RecordErrorOnStack(field);
00439       err->MergeDPS(rhs->dps);
00440       return err->AddToDPS(rhs->path, ValType(rhs), TypePK);
00441     }
00442     id = ((TextVC*)rhs)->NDS();
00443     break;
00444   default:
00445     outputMu.lock();    
00446     this->EError("Field selector has wrong type: `");
00447     ErrorExpr(field);
00448     ErrorDetail("'.\n");
00449     outputMu.unlock();    
00450     return RecordErrorOnStack(field);
00451   }
00452   // Compute the binding:
00453   lhs = binding->Eval(c);
00454   if (lhs->vKind != BindingVK) {
00455     outputMu.lock();              
00456     if (bang) {
00457       this->EError(Text("Applying `!") + id + "' to a non-binding value: `");
00458     }    
00459     else {
00460       this->EError(Text("Selecting `") + id + "' from a non-binding value: `");
00461     }
00462     ErrorVal(lhs);
00463     ErrorDetail("'.\n");
00464     outputMu.unlock();    
00465     err = RecordErrorOnStack(binding);
00466     err = err->MergeDPS(lhs->dps);
00467     return err->AddToDPS(lhs->path, ValType(lhs), TypePK);
00468   }
00469   // Select the field:
00470   if (rhs) lhs->Merge(rhs);
00471   if (bang) {
00472     result = ((BindingVC*)lhs)->Defined(id);
00473     if (rhs)
00474       result->cacheit = result->cacheit && rhs->cacheit;
00475     return result;
00476   }
00477   result = ((BindingVC*)lhs)->Lookup(id);
00478   if (result->vKind == UnbndVK) {
00479     outputMu.lock();
00480     this->EError(Text("The field `") + id + "' is undefined in:\n");
00481     ErrorVal(lhs);
00482     ErrorDetail(".\n");
00483     outputMu.unlock();
00484     err = RecordErrorOnStack(this);
00485     err->MergeDPS(result->dps);
00486     return err->AddToDPS(result->path, valFalse, BangPK);
00487   }
00488   if (rhs)
00489     result->cacheit = result->cacheit && rhs->cacheit;
00490   return result;
00491 }
00492 
00493 // FuncEC
00494 FuncEC::FuncEC(bool tnoCache, const Text& tname, ArgList targs,
00495                Expr tbody, SrcLoc *tloc)
00496 : ExprC(FuncEK, tloc), noCache(tnoCache), name(tname), args(targs),
00497   body(tbody), tagged(false) {
00498   Exprs work = args->elems;
00499   Vars boundVars(nameDot);
00500   for (int i = 0; i < work.size(); i++) {
00501     Expr fe = work.get(i);
00502     if (fe->kind == NameEK)
00503       boundVars.Push(((NameEC*)fe)->id);
00504     else
00505       boundVars.Push(((AssignEC*)fe)->lhs->id);
00506   }
00507   freeVars = AddVars(args->freeVars,
00508                      Remove(body->freeVars, boundVars));
00509 }
00510 
00511 void FuncEC::PrintD(ostream *os) {
00512   *os << "(";
00513   args->PrintD(os);
00514   *os << ")";
00515   body->PrintD(os);
00516   *os << "\n";
00517 }
00518 
00519 Val FuncEC::Eval(const Context& c) {
00520   return NEW_CONSTR(ClosureVC, (this, RestrictContext(c, freeVars), true));
00521 }
00522 
00523 FP::Tag FuncEC::FingerPrint() {
00524   if (!this->tagged) {
00525     FPStream stream;
00526     this->PrintD(&stream);
00527     this->tag = stream.tag();
00528     this->tagged = true;
00529   }
00530   return this->tag;
00531 }
00532 
00533 // BlockEC
00534 BlockEC::BlockEC(StmtListEC *tassocs, Expr tbody, bool treturn,
00535                  SrcLoc *tloc)
00536 : ExprC(BlockEK, tloc), assocs(tassocs), body(tbody), 
00537   isReturn(treturn) {
00538   freeVars = AddVars(assocs->freeVars,
00539                      Remove(body->freeVars, assocs->boundVars));
00540 } 
00541 
00542 void BlockEC::PrintD(ostream *os) {
00543   *os << "{";
00544   assocs->PrintD(os);
00545   if (!assocs->Empty()) *os << ";";
00546   *os << (isReturn ? "\nreturn " : "\nvalue ");
00547   body->PrintD(os);
00548   *os << ";\n}\n";
00549 }
00550 
00551 Val BlockEC::Eval(const Context& c) {
00552   Context cc = AddStmtAssocs(assocs, c);
00553   Context work = cc, ac;
00554 
00555   while (!work.EqualQ(c))
00556     ac.Append1D(work.Pop());
00557   Val result = body->Eval(cc);
00558   if (cacheOption < 2) return result;
00559   return LetDpnd(result, ac);
00560 }
00561 
00562 // IterateEC
00563 IterateEC::IterateEC(Expr tcontrol, Expr te, StmtListEC *tbody, SrcLoc *tloc)
00564 : ExprC(IterateEK, tloc), control(tcontrol), e(te), body(tbody) {
00565   freeVars  = AddVars(e->freeVars, 
00566                       Remove(body->freeVars, control->freeVars));
00567 }
00568 
00569 void IterateEC::PrintD(ostream *os) {
00570   *os << "\nforeach ";
00571   if (control->kind == NameEK)
00572     control->PrintD(os);
00573   else if (control->kind == PairEK)
00574     control->PrintD(os);
00575   *os << " in ";
00576   e->PrintD(os);
00577   *os << " do\n{";
00578   body->PrintD(os);
00579   *os << "}\n";
00580 }  
00581 
00582 // FileEC
00583 void FileEC::PrintD(ostream *os) {
00584   *os << ((this->import) ? "<Model `" : "<File `");
00585   *os << name->id  << "' (`" << localPath << "')>";
00586 }
00587 
00588 // Internal callback for FileEC Eval.
00589 struct FileECClosure {
00590   BindingEC *dir;
00591   VestaSource *newRoot;
00592   SrcLoc *loc;
00593 };
00594 
00595 static bool FileECCallback(void* closure, VestaSource::typeTag type, 
00596                            Arc arc, unsigned int index, Bit32 pseudoInode,
00597                            ShortId filesid, bool master) {
00598   FileECClosure *cl = (FileECClosure*)closure;
00599 
00600   Name name = NEW_CONSTR(NameEC, (arc, cl->loc));
00601   Expr e = NEW_CONSTR(FileEC, (name, arc, cl->newRoot, false, cl->loc));
00602   cl->dir->AddExpr(NEW_CONSTR(BindEC, (name, e, cl->loc)));
00603   return true;
00604 }
00605 
00606 Val FileEC::Eval(const Context& c) {
00607   Text path(this->localPath);
00608   VestaSource *newRoot;
00609   VestaSource::errorCode newRootErr;
00610 
00611   if (IsDirectory(modelRoot, path, newRoot, newRootErr)) {
00612     if (this->import) {
00613       char c = path[path.Length()-1];
00614       if (IsDelimiter(c))
00615         path = path + "build.ves";
00616       else
00617         path = path + PathnameSep + "build.ves";
00618       return NEW_CONSTR(ModelVC, (path, modelRoot, loc));
00619     }
00620     else if (newRoot->type == VestaSource::immutableDirectory) {
00621       FileECClosure cl;
00622       cl.dir = NEW_CONSTR(BindingEC, (5, loc));
00623       cl.newRoot = newRoot;
00624       cl.loc = loc;
00625       if (newRoot->list(0, FileECCallback, &cl) != VestaSource::ok) {
00626         outputMu.lock();        
00627         this->EError("Failed to list all objects in a directory.\n");
00628         outputMu.unlock();      
00629         return RecordErrorOnStack(this);
00630       };
00631       return cl.dir->Eval(c);
00632     }
00633     else {
00634       outputMu.lock();
00635       this->EError("Cannot import appendable directory.\n");
00636       outputMu.unlock();
00637       return RecordErrorOnStack(this);
00638     }
00639   }
00640   if (this->import) {
00641     Text modelPath(setSuffix(path, ".ves"));
00642     return NEW_CONSTR(ModelVC, (modelPath, modelRoot, loc));
00643   }
00644   if (newRootErr == VestaSource::ok) {
00645     return NEW_CONSTR(TextVC, (name->id, NULL, newRoot));
00646   }
00647   outputMu.lock();  
00648   Error(Text(VestaSourceErrorMsg(newRootErr)) + " opening `" + path + "'.\n");
00649   outputMu.unlock();  
00650   return RecordErrorOnStack(this);
00651 }
00652   
00653 // ApplyEC
00654 ApplyEC::ApplyEC(Expr tfunc, ArgList targs, SrcLoc *tloc) 
00655 : ExprC(ApplyEK, tloc), func(tfunc), args(targs) {
00656   /* In Vesta, the . parameter may be passed implicitly. Since 
00657      we have not evaluated tfunc, we have no way to know if . is 
00658      actually needed.  So, we always add (conservatively) it into 
00659      freeVars.  */
00660   freeVars = AddVars(func->freeVars, args->freeVars);
00661   if (!freeVars.Member(nameDot))
00662     freeVars.Push(nameDot);
00663 }
00664 
00665 void ApplyEC::PrintD(ostream *os) {
00666   func->PrintD(os);
00667   *os << "(";
00668   args->PrintD(os);
00669   *os << ")";
00670 }
00671 
00672 Val ApplyEC::Eval(const Context& c) {
00673   Val result;
00674 
00675   if (recordCallStack) {
00676     callStackMu.lock();          
00677     ThreadDataGet()->callStack->addlo(this);
00678     callStackMu.unlock();          
00679   }
00680 
00681   Val fun = func->Eval(c);
00682   switch (fun->vKind) {
00683   case ClosureVK:
00684     result = ApplyFunction((ClosureVC*)fun, this, c);
00685     break;
00686   case ModelVK:
00687     result = ApplyModel((ModelVC*)fun, this, c);
00688     break;
00689   case PrimitiveVK:
00690     {
00691       PrimitiveVC *prim = (PrimitiveVC*)fun;
00692       if (prim->exec != NULL) {
00693         result = prim->exec(args, c);
00694         result->Merge(fun);
00695       }
00696       else {
00697         outputMu.lock();        
00698         this->EError("Trying to apply non-existing primitive: `");
00699         ErrorVal(prim);
00700         ErrorDetail("'.\n");
00701         outputMu.unlock();      
00702         result = NEW(ErrorVC);
00703         result->Merge(fun);
00704       }
00705       break;
00706     }
00707   default:
00708     outputMu.lock();
00709     this->EError("Trying to apply non-primitive, non-function, non-model: `");
00710     ErrorVal(fun);
00711     ErrorDetail("'.\n");
00712     outputMu.unlock();
00713     result = NEW(ErrorVC);
00714     result->MergeDPS(fun->dps);
00715     result->AddToDPS(fun->path, ValType(fun), TypePK);
00716   }
00717 
00718   if (recordCallStack) {
00719     callStackMu.lock();          
00720     ThreadDataGet()->callStack->remlo();
00721     callStackMu.unlock();          
00722   }
00723   return result;
00724 }
00725 
00726 // ModelEC
00727 void ModelEC::PrintD(ostream *os) {
00728   *os << "files\n";
00729   files->PrintD(os);
00730   *os << "\nimport\n";
00731   imports->PrintD(os);
00732   *os << "\n";
00733   block->PrintD(os);
00734 }
00735 
00736 bool ModelEC::ImportLocalModel() {
00737   Exprs elems = this->imports->elems;
00738   bool found = false;
00739 
00740   for (int i = 0; i < elems.size(); i++) {
00741     // assert(elems.get(i)->kind == BindEK);
00742     Expr item = ((BindEC*)elems.get(i))->rhs;
00743     if (item->kind == FileEK)
00744       found = !IsAbsolutePath(((FileEC*)item)->localPath);
00745     else {
00746       // assert(item->kind == BindingEK);
00747       Exprs elems1 = ((BindingEC*)item)->assocs;
00748       if (elems1.size() != 0) {
00749         // We only need to check one of them:
00750         // assert(elems1.getlo()->kind == BindEK);
00751         Expr item1 = ((BindEC*)elems1.getlo())->rhs;
00752         // assert(item1->kind == FileEK);
00753         found = !IsAbsolutePath(((FileEC*)item1)->localPath);
00754       }
00755     }
00756     if (found) break;
00757   }
00758   return found;
00759 }
00760 
00761 Val ModelEC::Eval(const Context& c) {
00762   Context cc = ProcessModelHead(this);
00763   Name eDot = NEW_CONSTR(NameEC, (nameDot, loc));
00764 
00765   PushToContext(nameDot, eDot, c, cc);
00766   return block->Eval(cc);
00767 }
00768 
00769 // TypedEC
00770 void TypedEC::PrintD(ostream *os) {
00771   val->PrintD(os);
00772   *os << ": ";
00773   typ->PrintD(os);
00774 }
00775 
00776 // ListTEC
00777 void ListTEC::PrintD(ostream *os) {
00778   *os << "list";
00779   if (type) {
00780     *os << "[ ";
00781     type->PrintD(os);
00782     *os << " ]";
00783   }
00784 }
00785 
00786 // BindingTEC
00787 void BindingTEC::PrintD(ostream *os) {
00788   *os << "binding";
00789   if (fields) fields->PrintD(os);
00790 }
00791 
00792 // FuncTEC
00793 void FuncTEC::PrintD(ostream *os) {
00794   *os << "function";
00795   if (fields) fields->PrintD(os);
00796 }
00797 
00798 // ErrorEC
00799 ErrorEC::ErrorEC(SrcLoc *tloc, bool runTime)
00800 : ExprC(ErrorEK, tloc) {
00801   if (runTime)
00802     throw(Evaluator::failure(Text("exiting"), false));
00803 }
00804 
00806 FP::Tag FingerPrint(Expr expr) {
00807   FPStream stream;
00808   expr->PrintD(&stream);
00809   return stream.tag();
00810 }
00811 
00812 Vals EvalArgs(ArgList args, const Context& c) {
00813   Exprs elems = args->elems;
00814   Vals result;
00815 
00816   for (int i = 0; i < elems.size(); i++) {
00817     result.Append1D(elems.get(i)->Eval(c));
00818   }
00819   return result;
00820 }
00821 
00822 Vars AddVars(const Vars& fv1, const Vars& fv2) {
00823   Vars work = fv1;
00824   Vars result = fv2;
00825 
00826   while (!work.Null()) {
00827     Text fv(work.Pop());
00828     if (!fv2.Member(fv))
00829       result.Push(fv);
00830   }
00831   return result;
00832 }
00833 
00834 Vars Remove(const Vars& body, const Text& id) {
00835   Vars work = body, result;
00836   Text fv;
00837   while (!work.Null()) {
00838     fv = work.Pop();
00839     if (fv != id)
00840       result.Push(fv);
00841   }
00842   return result;
00843 }
00844 
00845 Vars Remove(const Vars& body, const Vars& bound) {
00846   if (bound.Null())
00847     return body;
00848 
00849   Vars work = body, result;
00850   Text fv;
00851   while (!work.Null()) {
00852     fv = work.Pop();
00853     if (!bound.Member(fv))
00854       result.Push(fv);
00855   }
00856   return result;
00857 }
00858 
00859 bool AllFreeVarsBoundInContext(const Expr e, const Context& c) {
00860   // Unused anywhere.
00861   Vars fv = e->freeVars;
00862 
00863   while(!fv.Null()) {
00864     Text id(fv.Pop());
00865     if (FindInContext(id, c) == nullAssoc) {
00866       outputMu.lock();      
00867       e->EError(Text("\n  Variable `") + id
00868                 + "' is free in next expression, but not bound in context.");
00869       ErrorDetail("\nCurrent context:\n");
00870       PrintContext(&cerr, c);
00871       outputMu.unlock();      
00872       return false;
00873     }
00874   }
00875   return true;
00876 }
00877 
00878 // Process the file and import clauses.
00879 bool IsId(const Text& id) {
00880   /* True iff id is an identifier. */
00881   int idx = 0, base = 10;
00882   if (id[0] == '0') {
00883     if (id[1] == 'x' || id[1] == 'X') {
00884       idx = 2;
00885       base = 16;
00886     } else {
00887       idx = 1;
00888       base = 8;
00889     }
00890   }
00891   bool isNumber = true, isIdOrNumber = true;
00892   for (int i = idx; i < id.Length(); i++) {
00893     char ch = id[i];
00894     switch (ch) {
00895     case '0': case '1': case '2': case '3': case '4': case '5':
00896     case '6': case '7':
00897       break;
00898     case '8': case '9':
00899       isNumber = isNumber && (base != 8);
00900       break;
00901     case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
00902     case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
00903       isNumber = isNumber && (base == 16);
00904       break;
00905     default:
00906       isNumber = false;
00907       isIdOrNumber = (isIdOrNumber &&
00908                       ((ch >= 'a') && (ch <= 'z') ||
00909                        (ch >= 'A') && (ch <= 'Z') ||
00910                        (ch == '_') ||
00911                        (ch == '.')));
00912       break;
00913     }
00914   }
00915   return isIdOrNumber && !isNumber && (id[0] != '\0');
00916 }
00917 
00918 Context ProcessModelHead(ModelEC *model) {
00919   Exprs felems = model->files->elems;
00920   Exprs ielems = model->imports->elems;
00921   Context cc;
00922   Expr elem;
00923   BindEC *bind;
00924   int i;
00925 
00926   for (i = 0; i < felems.size(); i++) {
00927     elem = felems.get(i);
00928     if (elem->kind == BindEK) {
00929       bind = (BindEC*)elem;
00930       Name name = (Name)bind->lhs;
00931       if (IsId(name->id))
00932         PushToContext(name->id, bind->rhs, conEmpty, cc);
00933       else {
00934         outputMu.lock();        
00935         name->EError(Text("The name `") + name->id
00936                      + "' for this file clause must be an identifier.");
00937         outputMu.unlock();
00938         throw(Evaluator::failure(Text("exiting"), false));
00939       }
00940     }
00941     else {
00942       outputMu.lock();
00943       InternalError("ProcessModelHead (processing files).");
00944       outputMu.unlock();
00945     }
00946   }
00947 
00948   for (i = 0; i < ielems.size(); i++) {
00949     elem = ielems.get(i);
00950     if (elem->kind == BindEK) {
00951       bind = (BindEC*)elem;
00952       Name name = (Name)bind->lhs;
00953       if (IsId(name->id))
00954         PushToContext(name->id, bind->rhs, conEmpty, cc);
00955       else {
00956         outputMu.lock();
00957         name->EError(Text("The name `") + name->id
00958                      + "' for this import clause must be an identifier.");
00959         outputMu.unlock();      
00960         throw(Evaluator::failure(Text("exiting"), false));
00961       }
00962     }
00963     else {
00964       outputMu.lock();      
00965       InternalError("ProcessModelHead (processing imports).");
00966       outputMu.unlock();
00967     }
00968   }
00969   return cc;
00970 }

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