00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
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
00035 const char *nameDot = ".";
00036
00038
00039
00040 void ExprC::PrintExprVars(ostream *os) {
00041 *os << "\nfreeVars =";
00042 PrintVars(os, freeVars);
00043 }
00044
00046
00047 Val ConstantEC::Eval(const Context& c) {
00048
00049
00050 return this->val->Copy();
00051 }
00052
00053
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
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
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
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
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
00177 }
00178
00179
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
00583 void FileEC::PrintD(ostream *os) {
00584 *os << ((this->import) ? "<Model `" : "<File `");
00585 *os << name->id << "' (`" << localPath << "')>";
00586 }
00587
00588
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
00654 ApplyEC::ApplyEC(Expr tfunc, ArgList targs, SrcLoc *tloc)
00655 : ExprC(ApplyEK, tloc), func(tfunc), args(targs) {
00656
00657
00658
00659
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
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
00742 Expr item = ((BindEC*)elems.get(i))->rhs;
00743 if (item->kind == FileEK)
00744 found = !IsAbsolutePath(((FileEC*)item)->localPath);
00745 else {
00746
00747 Exprs elems1 = ((BindingEC*)item)->assocs;
00748 if (elems1.size() != 0) {
00749
00750
00751 Expr item1 = ((BindEC*)elems1.getlo())->rhs;
00752
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
00770 void TypedEC::PrintD(ostream *os) {
00771 val->PrintD(os);
00772 *os << ": ";
00773 typ->PrintD(os);
00774 }
00775
00776
00777 void ListTEC::PrintD(ostream *os) {
00778 *os << "list";
00779 if (type) {
00780 *os << "[ ";
00781 type->PrintD(os);
00782 *os << " ]";
00783 }
00784 }
00785
00786
00787 void BindingTEC::PrintD(ostream *os) {
00788 *os << "binding";
00789 if (fields) fields->PrintD(os);
00790 }
00791
00792
00793 void FuncTEC::PrintD(ostream *os) {
00794 *os << "function";
00795 if (fields) fields->PrintD(os);
00796 }
00797
00798
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
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
00879 bool IsId(const Text& id) {
00880
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 }