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 <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
00035 const char *nameDot = ".";
00036
00038
00039
00040 void ExprC::PrintExprVars(ostream& os)
00041 {
00042 os << endl << "freeVars =";
00043 PrintVars(os, freeVars);
00044 }
00045
00047
00048 Val ConstantEC::Eval(const Context& c) {
00049
00050
00051 return this->val->Copy();
00052 }
00053
00054
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
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
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
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
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
00181 }
00182
00183
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
00600 void FileEC::PrintD(ostream& os)
00601 {
00602 os << ((this->import) ? "<Model `" : "<File `");
00603 os << name->id << "' (`" << localPath << "')>";
00604 }
00605
00606
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
00671 ApplyEC::ApplyEC(Expr tfunc, ArgList targs, SrcLoc *tloc)
00672 : ExprC(ApplyEK, tloc), func(tfunc), args(targs) {
00673
00674
00675
00676
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
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
00762 Expr item = ((BindEC*)elems.get(i))->rhs;
00763 if (item->kind == FileEK)
00764 found = !IsAbsolutePath(((FileEC*)item)->localPath);
00765 else {
00766
00767 Exprs elems1 = ((BindingEC*)item)->assocs;
00768 if (elems1.size() != 0) {
00769
00770
00771 Expr item1 = ((BindEC*)elems1.getlo())->rhs;
00772
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
00790 void TypedEC::PrintD(ostream& os)
00791 {
00792 val->PrintD(os);
00793 os << ": ";
00794 typ->PrintD(os);
00795 }
00796
00797
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
00809 void BindingTEC::PrintD(ostream& os)
00810 {
00811 os << "binding";
00812 if (fields) fields->PrintD(os);
00813 }
00814
00815
00816 void FuncTEC::PrintD(ostream& os)
00817 {
00818 os << "function";
00819 if (fields) fields->PrintD(os);
00820 }
00821
00822
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
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
00903 bool IsId(const Text& id) {
00904
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
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
00990 abort();
00991 }
00992 }
00993 return cc;
00994 }