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

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