00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #include <assert.h>
00026 #include "oql_p.h"
00027
00028 namespace eyedb {
00029
00030 int oqmlCallLevel;
00031 static const char OQML_RETURN_MAGIC[] = "$oqml$return$magic$";
00032
00033 #define oqml_is_return(S) ((S) && !strcmp((S)->msg, OQML_RETURN_MAGIC))
00034
00035 int OQML_EVAL_ARGS;
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049 struct oqmlOQMLFunctionDesc {
00050 oqml_ParamList *param_list;
00051 oqmlNode *body;
00052
00053 oqmlOQMLFunctionDesc(oqml_ParamList *_param_list,
00054 oqmlNode *_body) {
00055 param_list = _param_list;
00056 body = _body;
00057 lock();
00058 }
00059
00060 std::string toString(const char *ident) const {
00061 std::string s = std::string(ident) + "(";
00062 if (param_list)
00063 s += param_list->toString();
00064 s += ") ";
00065
00066 return s + (body ? body->toString() : std::string(""));
00067 }
00068
00069 void lock() {
00070 if (body)
00071 body->lock();
00072
00073 if (param_list)
00074 param_list->lock();
00075 }
00076
00077 void unlock() {
00078 if (body)
00079 body->unlock();
00080
00081 if (param_list)
00082 param_list->unlock();
00083 }
00084
00085 ~oqmlOQMLFunctionDesc() {
00086 unlock();
00087 delete param_list;
00088 }
00089 };
00090
00091 struct oqmlFunctionEntry {
00092 char *ident;
00093
00094 oqmlOQMLFunctionDesc *OQMLdesc;
00095
00096 oqmlFunctionEntry *prev, *next;
00097
00098 oqmlFunctionEntry(const char *_ident, oqml_ParamList *_param_list,
00099 oqmlNode *_body) {
00100 ident = strdup(_ident);
00101 OQMLdesc = new oqmlOQMLFunctionDesc(_param_list, _body);
00102 prev = next = 0;
00103 oqml_append(OQML_ATOM_COLLVAL(oqml_functions), ident);
00104 }
00105
00106 std::string toString() const {
00107 return OQMLdesc->toString(ident);
00108 }
00109
00110 ~oqmlFunctionEntry() {
00111
00112 oqml_suppress(OQML_ATOM_COLLVAL(oqml_functions), ident);
00113 free(ident);
00114 delete OQMLdesc;
00115 }
00116 };
00117
00118 oqml_ParamLink::oqml_ParamLink(const char *_ident, oqmlNode *_node)
00119 {
00120 next = 0;
00121 node = _node;
00122 if (_ident && *_ident == '@')
00123 {
00124 ident = strdup(&_ident[1]);
00125 unval = oqml_True;
00126 return;
00127 }
00128
00129 ident = strdup(_ident);
00130 unval = oqml_False;
00131 }
00132
00133 oqml_ParamLink::~oqml_ParamLink()
00134 {
00135 free(ident);
00136 }
00137
00138 oqml_ParamList::oqml_ParamList(const char *ident, oqmlNode *node)
00139 {
00140 first = new oqml_ParamLink(ident, node);
00141 last = first;
00142 cnt = 1;
00143 min_cnt = 0;
00144 }
00145
00146 void oqml_ParamList::add(const char *ident, oqmlNode *node)
00147 {
00148 oqml_ParamLink *l = new oqml_ParamLink(ident, node);
00149
00150 last->next = l;
00151 last = l;
00152 cnt++;
00153 }
00154
00155 void
00156 oqml_ParamList::lock()
00157 {
00158 oqml_ParamLink *pl = first;
00159
00160 while (pl)
00161 {
00162 if (pl->node)
00163 pl->node->lock();
00164 pl = pl->next;
00165 }
00166 }
00167
00168 void
00169 oqml_ParamList::unlock()
00170 {
00171 oqml_ParamLink *pl = first;
00172
00173 while (pl)
00174 {
00175 if (pl->node)
00176 pl->node->unlock();
00177 pl = pl->next;
00178 }
00179 }
00180
00181 std::string
00182 oqml_ParamList::toString() const
00183 {
00184 std::string s;
00185 oqml_ParamLink *pl = first;
00186
00187 for (int n = 0; pl; n++)
00188 {
00189 if (n) s += ",";
00190 if (pl->unval)
00191 s += std::string("|");
00192 s += pl->ident;
00193 if (pl->node)
00194 s += std::string("?") + pl->node->toString();
00195 pl = pl->next;
00196 }
00197
00198 return s;
00199 }
00200
00201 oqml_ParamList::~oqml_ParamList()
00202 {
00203 oqml_ParamLink *l = first;
00204
00205 while (l)
00206 {
00207 oqml_ParamLink *next = l->next;
00208 delete l;
00209 l = next;
00210 }
00211 }
00212
00213 void oqmlContext::popFunction(const char *ident)
00214 {
00215 oqmlFunctionEntry *entry;
00216
00217 if (getFunction(ident, &entry))
00218 {
00219 if (entry->prev)
00220 entry->prev->next = entry->next;
00221 if (entry->next)
00222 entry->next->prev = entry->prev;
00223
00224 if (entry == symtab->flast)
00225 symtab->flast = entry->prev;
00226 if (entry == symtab->ffirst)
00227 symtab->ffirst = entry->next;
00228
00229 delete entry;
00230 }
00231 }
00232
00233 oqmlStatus *
00234 oqmlContext::setFunction(const char *ident, oqml_ParamList *param_list,
00235 oqmlNode *body)
00236 {
00237 oqmlFunctionEntry *entry;
00238 if (getFunction(ident, &entry) &&
00239 entry->OQMLdesc->body == body &&
00240 entry->OQMLdesc->param_list == param_list)
00241 return oqmlSuccess;
00242
00243 popFunction(ident);
00244
00245 entry = new oqmlFunctionEntry(ident, param_list, body);
00246
00247 if (symtab->flast)
00248 {
00249 symtab->flast->next = entry;
00250 entry->prev = symtab->flast;
00251 }
00252 else
00253 symtab->ffirst = entry;
00254
00255 symtab->flast = entry;
00256
00257 return oqmlSuccess;
00258 }
00259
00260 int oqmlContext::getFunction(const char *ident, oqmlFunctionEntry **pentry)
00261 {
00262 if (!strncmp(ident, oqml_global_scope, oqml_global_scope_len))
00263 ident = &ident[oqml_global_scope_len];
00264
00265 oqmlFunctionEntry *entry = symtab->ffirst;
00266
00267 while (entry)
00268 {
00269 if (!strcmp(entry->ident, ident))
00270 {
00271 *pentry = entry;
00272 return 1;
00273 }
00274
00275 entry = entry->next;
00276 }
00277
00278 return 0;
00279 }
00280
00281
00282
00283
00284
00285
00286
00287 oqmlFunction::oqmlFunction(const char *_name, oqml_ParamList *_param_list,
00288 oqmlNode *_ql) : oqmlNode(oqmlFUNCTION)
00289 {
00290 name = strdup(_name);
00291 ql = _ql;
00292 param_list = _param_list;
00293
00294 eval_type.type = oqmlATOM_IDENT;
00295 }
00296
00297 oqmlFunction::~oqmlFunction()
00298 {
00299 free(name);
00300 }
00301
00302 oqmlBool
00303 checkInList(oqml_ParamLink *pl, int nx)
00304 {
00305 const char *ident = pl->ident;
00306 for (int n = 0; pl; pl = pl->next, n++)
00307 if (n > nx && !strcmp(pl->ident, ident))
00308 return oqml_True;
00309
00310 return oqml_False;
00311 }
00312
00313 oqmlStatus *oqmlFunction::compile(Database *db, oqmlContext *ctx)
00314 {
00315 oqml_ParamLink *pl = param_list ? param_list->first : 0;
00316
00317 int min_cnt, n;
00318 for (min_cnt = 0, n = 0; pl; pl = pl->next, n++)
00319 {
00320 if (checkInList(pl, n))
00321 return new oqmlStatus(this, "duplicate identifier '%s' in parameter "
00322 "list", pl->ident);
00323
00324 if (!pl->node)
00325 {
00326 if (min_cnt != n)
00327 return new oqmlStatus(this, "default arguments must be at the end "
00328 "of the parameter list");
00329 min_cnt++;
00330 }
00331 }
00332
00333 if (param_list)
00334 param_list->min_cnt = min_cnt;
00335 return ctx->setFunction(name, param_list, ql);
00336 }
00337
00338 oqmlStatus *oqmlFunction::eval(Database *db, oqmlContext *ctx, oqmlAtomList **alist, oqmlComp *, oqmlAtom *)
00339 {
00340 oqmlStatus *s;
00341
00342 *alist = new oqmlAtomList(new oqmlAtom_ident(name));
00343 return oqmlSuccess;
00344 }
00345
00346 void oqmlFunction::evalType(Database *db, oqmlContext *ctx, oqmlAtomType *at)
00347 {
00348 *at = eval_type;
00349 }
00350
00351 oqmlBool oqmlFunction::isConstant() const
00352 {
00353 return oqml_False;
00354 }
00355
00356 void
00357 oqmlFunction::lock()
00358 {
00359 oqmlNode::lock();
00360 if (ql) ql->lock();
00361 if (param_list) param_list->lock();
00362 }
00363
00364 void
00365 oqmlFunction::unlock()
00366 {
00367 oqmlNode::unlock();
00368 if (ql) ql->unlock();
00369 if (param_list) param_list->unlock();
00370 }
00371
00372 std::string
00373 oqmlFunction::toString(void) const
00374 {
00375 std::string s = is_statement ? std::string("function ") + name + "(" :
00376 std::string("define ") + name + "(";
00377
00378 if (param_list)
00379 s += param_list->toString();
00380
00381 if (is_statement)
00382 return s + ") " + ql->toString() + "; ";
00383
00384 return s + ") as " + ql->toString();
00385 }
00386
00387
00388
00389
00390
00391
00392
00393 #define NEWBODYOF
00394
00395 oqmlBodyOf::oqmlBodyOf(oqmlNode * _ql) : oqmlNode(oqmlBODYOF)
00396 {
00397 ql = _ql;
00398 ident = 0;
00399 eval_type.type = oqmlATOM_STRING;
00400 }
00401
00402 oqmlBodyOf::~oqmlBodyOf()
00403 {
00404 free(ident);
00405 }
00406
00407 oqmlStatus *oqmlBodyOf::compile(Database *db, oqmlContext *ctx)
00408 {
00409 #ifdef NEWBODYOF
00410 return oqml_opident_compile(this, db, ctx, ql, ident);
00411 #else
00412 oqmlStatus *s = ql->compile(db, ctx);
00413 if (s) return s;
00414
00415 oqmlAtomType at;
00416 ql->evalType(db, ctx, &at);
00417
00418 if (at.type == oqmlATOM_UNKNOWN_TYPE)
00419 return oqmlSuccess;
00420
00421 if (at.type != oqmlATOM_IDENT)
00422 return oqmlStatus::expected(this, "ident", at.getString());
00423
00424 return oqmlSuccess;
00425 #endif
00426 }
00427
00428 oqmlStatus *oqmlBodyOf::eval(Database *db, oqmlContext *ctx, oqmlAtomList **alist, oqmlComp *, oqmlAtom *)
00429 {
00430 #ifdef NEWBODYOF
00431 oqmlStatus *s = oqml_opident_preeval(this, db, ctx, ql, ident);
00432 if (s) return s;
00433 #else
00434
00435 oqmlAtomList *al;
00436 oqmlStatus *s = ql->eval(db, ctx, &al);
00437 if (s) return s;
00438
00439 if (!al->cnt)
00440 return oqmlStatus::expected(this, "ident", "nil");
00441
00442 oqmlAtom *r = al->first;
00443
00444 if (r->type.type != oqmlATOM_IDENT)
00445 return oqmlStatus::expected(this, "ident", r->type.getString());
00446
00447 const char *ident = OQML_ATOM_IDENTVAL(r);
00448 #endif
00449 oqmlFunctionEntry *entry;
00450 if (!ctx->getFunction(ident, &entry))
00451 return new oqmlStatus(this, "unknown function '%s'", ident);
00452
00453 (*alist) = new oqmlAtomList(new oqmlAtom_string(entry->toString().c_str()));
00454 return oqmlSuccess;
00455 }
00456
00457 void oqmlBodyOf::evalType(Database *db, oqmlContext *ctx, oqmlAtomType *at)
00458 {
00459 *at = eval_type;
00460 }
00461
00462 oqmlBool oqmlBodyOf::isConstant() const
00463 {
00464 return oqml_False;
00465 }
00466
00467 std::string
00468 oqmlBodyOf::toString(void) const
00469 {
00470 if (is_statement)
00471 return std::string("bodyof ") + ql->toString() + "; ";
00472 return std::string("(bodyof ") + ql->toString() + ")";
00473 }
00474
00475
00476
00477
00478
00479
00480
00481
00482
00483
00484
00485
00486
00487
00488
00489
00490
00491
00492
00493
00494
00495
00496
00497
00498
00499
00500
00501 oqmlCall::oqmlCall(oqmlNode *_ql, oqml_List *_list) : oqmlNode(oqmlCALL)
00502 {
00503 name = 0;
00504 ql = _ql;
00505 list = _list;
00506 qlbuiltin = 0;
00507 compiling = oqml_False;
00508 }
00509
00510 oqmlCall::~oqmlCall()
00511 {
00512 free(name);
00513 if (!qlbuiltin)
00514 delete list;
00515 }
00516
00517 oqmlStatus *oqmlCall::preCompile(Database *db, oqmlContext *ctx)
00518 {
00519 deferredEval = oqml_False;
00520 last_entry = 0;
00521 last_builtin = 0;
00522
00523 if (!ql)
00524 return oqmlSuccess;
00525
00526 free(name);
00527
00528 if (ql->getType() == oqmlIDENT)
00529 {
00530 name = strdup(((oqmlIdent *)ql)->getName());
00531
00532 if (ctx->getSymbol(name))
00533 deferredEval = oqml_True;
00534
00535 return oqmlSuccess;
00536 }
00537
00538 oqmlStatus *s;
00539
00540 s = ql->compile(db, ctx);
00541
00542 if (s) return s;
00543
00544 oqmlAtomList *al;
00545 s = ql->eval(db, ctx, &al);
00546 if (s) return s;
00547
00548 if (al->cnt != 1 || al->first->type.type != oqmlATOM_IDENT)
00549 return new oqmlStatus(this, "invalid function '%s'",
00550 ql->toString().c_str());
00551
00552 name = strdup(OQML_ATOM_IDENTVAL(al->first));
00553
00554 return oqmlSuccess;
00555 }
00556
00557 oqmlStatus *oqmlCall::compile(Database *db, oqmlContext *ctx)
00558 {
00559 if (compiling)
00560 return oqmlSuccess;
00561
00562 compiling = oqml_True;
00563
00564 oqmlStatus *s;
00565 int n;
00566 qlbuiltin = 0;
00567
00568
00569
00570
00571
00572
00573 s = preCompile(db, ctx);
00574
00575 if (s || deferredEval)
00576 {
00577 compiling = oqml_False;
00578 return s;
00579 }
00580
00581 s = postCompile(db, ctx, oqml_False);
00582 compiling = oqml_False;
00583 return s;
00584 }
00585
00586 oqmlStatus *oqmlCall::postCompile(Database *db, oqmlContext *ctx,
00587 oqmlBool checkSymbol)
00588 {
00589 oqmlStatus *s;
00590
00591 const char *fname = 0;
00592 if (checkSymbol)
00593 {
00594 oqmlAtom *x;
00595 if (ctx->getSymbol(name, 0, &x))
00596 {
00597 if (!x || !OQML_IS_IDENT(x))
00598 return new oqmlStatus(this,
00599 "identifier '%s': function expected, "
00600 "got '%s'",
00601 name, x ? x->type.getString() : "nil");
00602 fname = OQML_ATOM_IDENTVAL(x);
00603 }
00604 }
00605
00606 if (!fname)
00607 fname = name;
00608
00609 int found = ctx->getFunction(fname, &entry);
00610
00611 if (checkBuiltIn(db, this, fname, found))
00612 {
00613 if (qlbuiltin == last_builtin)
00614 return oqmlSuccess;
00615
00616 if (isLocked())
00617 qlbuiltin->lock();
00618
00619 s = qlbuiltin->compile(db, ctx);
00620 if (s) return s;
00621 last_builtin = qlbuiltin;
00622 return oqmlSuccess;
00623 }
00624
00625 if (!found)
00626 return new oqmlStatus(this, "unknown function '%s'", fname);
00627
00628 if (entry == last_entry)
00629 return oqmlSuccess;
00630
00631 int param_list_max_cnt = entry->OQMLdesc->param_list ?
00632 entry->OQMLdesc->param_list->cnt : 0;
00633
00634 int param_list_min_cnt = entry->OQMLdesc->param_list ?
00635 entry->OQMLdesc->param_list->min_cnt : 0;
00636
00637 int list_cnt = list ? list->cnt : 0;
00638
00639 if (list_cnt > param_list_max_cnt)
00640 return new oqmlStatus(this, "function %s expects at most %d arguments, "
00641 "got %d", fname, param_list_max_cnt, list_cnt);
00642
00643 if (list_cnt < param_list_min_cnt)
00644 return new oqmlStatus(this, "function %s expects at least %d arguments, "
00645 "got %d", fname, param_list_min_cnt, list_cnt);
00646
00647 #ifdef CALL_TRACE
00648 printf("\n%s: compiling function %s %p ctx=%p level=%d\n",
00649 (const char *)toString(), fname, this, ctx, ctx->getLocalDepth());
00650 #endif
00651 s = ctx->pushLocalTable();
00652 if (s) return s;
00653
00654 oqml_ParamLink *pl;
00655 oqml_Link *l = (list ? list->first : 0);
00656
00657 pl = entry->OQMLdesc->param_list ? entry->OQMLdesc->param_list->first : 0;
00658
00659
00660 for (int n = 0; pl; n++)
00661 {
00662 if (pl->unval)
00663 {
00664 oqmlAtomType at(oqmlATOM_STRING);
00665 ctx->pushSymbol(pl->ident, &at);
00666 }
00667 else
00668 {
00669 ctx->pushArgLevel();
00670 if (l)
00671 s = l->ql->compile(db, ctx);
00672 else if (pl->node)
00673 s = pl->node->compile(db, ctx);
00674 else
00675 s = new oqmlStatus(this, "mandatory parameter '%s' is missing",
00676 pl->ident);
00677
00678 ctx->popArgLevel();
00679
00680 if (s)
00681 {
00682 ctx->popLocalTable();
00683 return s;
00684 }
00685
00686 oqmlAtomType at;
00687 if (l)
00688 l->ql->evalType(db, ctx, &at);
00689 else
00690 pl->node->evalType(db, ctx, &at);
00691 ctx->pushSymbol(pl->ident, &at);
00692 }
00693
00694 if (l)
00695 l = l->next;
00696 pl = pl->next;
00697 }
00698
00699 if (entry->OQMLdesc->body)
00700 s = entry->OQMLdesc->body->compile(db, ctx);
00701 else
00702 s = oqmlSuccess;
00703
00704 ctx->popLocalTable();
00705
00706 if (!s)
00707 last_entry = entry;
00708 return s;
00709 }
00710
00711 oqmlStatus *oqmlCall::eval(Database *db, oqmlContext *ctx, oqmlAtomList **alist, oqmlComp *, oqmlAtom *)
00712 {
00713 oqmlStatus *s;
00714
00715
00716 int select_ctx_cnt = ctx->setSelectContextCount(0);
00717
00718 if (deferredEval)
00719 {
00720 s = postCompile(db, ctx, oqml_True);
00721 if (s) return s;
00722 }
00723
00724 int level = ++oqmlCallLevel;
00725
00726 if (qlbuiltin)
00727 s = qlbuiltin->eval(db, ctx, alist);
00728 else
00729 s = realize(db, ctx, alist);
00730
00731 --oqmlCallLevel;
00732
00733 if (s && !oqml_is_return(s))
00734 return s;
00735
00736 if (oqml_is_return(s)) {
00737 #ifdef SYNC_GARB
00738 OQL_DELETE(*alist);
00739 #endif
00740 (*alist) = new oqmlAtomList(s->returnAtom);
00741 delete s;
00742
00743
00744 ctx->setSelectContextCount(select_ctx_cnt);
00745 return oqmlSuccess;
00746 }
00747
00748
00749 ctx->setSelectContextCount(select_ctx_cnt);
00750
00751 return s;
00752 }
00753
00754 oqmlStatus *oqmlCall::realize(Database *db, oqmlContext *ctx,
00755 oqmlAtomList **alist)
00756 {
00757 oqmlStatus *s;
00758 int n;
00759 oqmlAtom *a;
00760
00761 oqml_Link *l;
00762 oqml_ParamLink *pl;
00763
00764 #ifdef CALL_TRACE
00765 printf("\n%s: calling function %s %p ctx=%p level=%d\n",
00766 (const char *)toString(), entry->ident, this, ctx, ctx->getLocalDepth());
00767 #endif
00768 s = ctx->pushLocalTable();
00769 if (s) return s;
00770
00771 l = list ? list->first : 0;
00772 pl = entry->OQMLdesc->param_list ? entry->OQMLdesc->param_list->first : 0;
00773
00774
00775 for (n = 0; pl; n++)
00776 {
00777 oqmlAtomList *al;
00778
00779 if (pl->unval)
00780 {
00781 oqmlAtomType at(oqmlATOM_STRING);
00782 if (l)
00783 ctx->pushSymbol(pl->ident, &at,
00784 new oqmlAtom_string(l->ql->toString().c_str()));
00785 else if (pl->node)
00786 ctx->pushSymbol(pl->ident, &at,
00787 new oqmlAtom_string(pl->node->toString().c_str()));
00788 }
00789 else
00790 {
00791 ctx->pushArgLevel();
00792 if (l)
00793 s = l->ql->eval(db, ctx, &al);
00794 else if (pl->node)
00795 s = pl->node->eval(db, ctx, &al);
00796 else
00797 s = new oqmlStatus(this, "mandatory parameter '%s' is missing",
00798 pl->ident);
00799 ctx->popArgLevel();
00800
00801 if (s)
00802 {
00803 ctx->popLocalTable();
00804 return s;
00805 }
00806
00807 a = (al ? al->first : 0);
00808
00809 ctx->pushSymbol(pl->ident, (a ? &a->type : 0), a);
00810 #ifdef SYNC_GARB
00811 if (al && !al->refcnt) {
00812 al->first = 0;
00813 OQL_DELETE(al);
00814 }
00815 #endif
00816 }
00817
00818 if (l)
00819 l = l->next;
00820 pl = pl->next;
00821 }
00822
00823 if (entry->OQMLdesc->body)
00824 s = entry->OQMLdesc->body->eval(db, ctx, alist);
00825 else
00826 s = oqmlSuccess;
00827
00828 ctx->popLocalTable();
00829
00830 return s;
00831 }
00832
00833 oqmlStatus *oqmlCall::realizePostAction(Database *db, oqmlContext *ctx,
00834 const char *name,
00835 oqmlFunctionEntry *entry,
00836 oqmlAtom_string *rs,
00837 oqmlAtom *ra,
00838 oqmlAtomList **alist)
00839 {
00840 int cnt = !entry->OQMLdesc->param_list ? cnt :
00841 entry->OQMLdesc->param_list->cnt;
00842
00843 if (cnt != 2)
00844 return new oqmlStatus("postaction function %s: "
00845 "expected 2 arguments, got %d",
00846 name, cnt);
00847 oqmlStatus *s;
00848 oqml_ParamLink *pl;
00849
00850 pl = entry->OQMLdesc->param_list->first;
00851
00852 ctx->pushSymbol(pl->ident, &rs->type, rs, oqml_False);
00853 ctx->pushSymbol(pl->next->ident, (ra ? &ra->type : 0), ra, oqml_False);
00854
00855 if (entry->OQMLdesc->body) {
00856 s = entry->OQMLdesc->body->compile(db, ctx);
00857 if (!s)
00858 s = entry->OQMLdesc->body->eval(db, ctx, alist);
00859 }
00860 else
00861 s = oqmlSuccess;
00862
00863 pl = entry->OQMLdesc->param_list->first;
00864 ctx->popSymbol(pl->ident, oqml_False);
00865 ctx->popSymbol(pl->next->ident, oqml_False);
00866
00867 return s;
00868 }
00869
00870 oqmlStatus *oqmlCall::realizeCall(Database *db, oqmlContext *ctx,
00871 oqmlFunctionEntry *entry,
00872 oqmlAtomList **alist)
00873 {
00874 oqmlStatus *s;
00875 if (entry->OQMLdesc->body) {
00876 s = entry->OQMLdesc->body->compile(db, ctx);
00877 if (s) return s;
00878 }
00879
00880 int level = ++oqmlCallLevel;
00881
00882 if (entry->OQMLdesc->body)
00883 s = entry->OQMLdesc->body->eval(db, ctx, alist);
00884 else
00885 s = oqmlSuccess;
00886
00887 --oqmlCallLevel;
00888
00889 if (s && !oqml_is_return(s))
00890 return s;
00891
00892 if (oqml_is_return(s))
00893 {
00894 (*alist) = new oqmlAtomList(s->returnAtom);
00895 delete s;
00896 return oqmlSuccess;
00897 }
00898
00899 return s;
00900 }
00901
00902 void oqmlCall::evalType(Database *db, oqmlContext *ctx, oqmlAtomType *at)
00903 {
00904 *at = eval_type;
00905 }
00906
00907 oqmlBool oqmlCall::isConstant() const
00908 {
00909 return oqml_False;
00910 }
00911
00912 oqmlBool
00913 oqmlCall::checkBuiltIn(Database *db, oqmlNode *node, const char *fname,
00914 int found)
00915 {
00916 return getBuiltIn(db, node, fname, found, &qlbuiltin, list);
00917 }
00918
00919 oqmlBool
00920 oqmlCall::getBuiltIn(Database *db, oqmlNode *node, const char *name,
00921 int found, oqmlNode **pqlbuiltin, oqml_List *list)
00922 {
00923 if (!strcmp(name, "list"))
00924 {
00925 if (pqlbuiltin)
00926 *pqlbuiltin = new oqmlListColl(list);
00927 return oqml_True;
00928 }
00929
00930 if (!strcmp(name, "set"))
00931 {
00932 if (pqlbuiltin)
00933 *pqlbuiltin = new oqmlSetColl(list);
00934 return oqml_True;
00935 }
00936
00937 if (!strcmp(name, "array"))
00938 {
00939 if (pqlbuiltin)
00940 *pqlbuiltin = new oqmlArrayColl(list);
00941 return oqml_True;
00942 }
00943
00944 if (!strcmp(name, "bag"))
00945 {
00946 if (pqlbuiltin)
00947 *pqlbuiltin = new oqmlBagColl(list);
00948 return oqml_True;
00949 }
00950
00951 if (!strcmp(name, "timeformat"))
00952 {
00953 if (pqlbuiltin)
00954 *pqlbuiltin = new oqmlTimeFormat(list);
00955 return oqml_True;
00956 }
00957
00958 if (!strcmp(name, "sort"))
00959 {
00960 if (pqlbuiltin)
00961 *pqlbuiltin = new oqmlSort(list, oqml_False);
00962 return oqml_True;
00963 }
00964
00965 if (!strcmp(name, "rsort"))
00966 {
00967 if (pqlbuiltin)
00968 *pqlbuiltin = new oqmlSort(list, oqml_True);
00969 return oqml_True;
00970 }
00971
00972 if (!strcmp(name, "isort"))
00973 {
00974 if (pqlbuiltin)
00975 *pqlbuiltin = new oqmlISort(list, oqml_False);
00976 return oqml_True;
00977 }
00978
00979 if (!strcmp(name, "risort"))
00980 {
00981 if (pqlbuiltin)
00982 *pqlbuiltin = new oqmlISort(list, oqml_True);
00983 return oqml_True;
00984 }
00985
00986 if (!found && db->getSchema()->getClass(name) && (!list || !list->cnt))
00987 {
00988 if (pqlbuiltin)
00989 *pqlbuiltin = new oqmlNew(OQML_NEW_HINT(), name, (oqmlNode *)0);
00990 return oqml_True;
00991 }
00992
00993
00994
00995
00996
00997
00998
00999
01000
01001
01002
01003
01004
01005
01006
01007
01008
01009
01010
01011
01012
01013
01014
01015
01016
01017
01018
01019 return oqml_False;
01020 }
01021
01022 std::string
01023 oqmlCall::toString(void) const
01024 {
01025 std::string s = (ql ? ql->toString() : std::string(name)) + "(";
01026 if (list)
01027 {
01028 oqml_Link *l = list->first;
01029
01030 for (int n = 0; l; n++)
01031 {
01032 if (n) s += ",";
01033 s += l->ql->toString();
01034 l = l->next;
01035 }
01036 }
01037
01038 return s + ")" + oqml_isstat();
01039 }
01040
01041 oqmlBool
01042 oqmlCall::hasIdent(const char *_ident)
01043 {
01044 return OQMLBOOL(((ql && ql->hasIdent(_ident)) ||
01045 (qlbuiltin && qlbuiltin->hasIdent(_ident)) ||
01046 list->hasIdent(_ident)));
01047 }
01048
01049 oqmlStatus *
01050 oqmlCall::requalify(Database *db, oqmlContext *ctx,
01051 const char *ident, oqmlNode *node, oqmlBool &done)
01052 {
01053 if (!list)
01054 return oqmlSuccess;
01055
01056 oqml_Link *l = list->first;
01057
01058 while (l)
01059 {
01060 oqmlStatus *s = l->ql->requalify(db, ctx, ident, node, done);
01061 if (s) return s;
01062 l = l->next;
01063 }
01064
01065 return oqmlSuccess;
01066 }
01067
01068 oqmlStatus *
01069 oqmlCall::requalify(Database *db, oqmlContext *ctx,
01070 const Attribute **attrs, int attr_cnt,
01071 const char *ident)
01072 {
01073 if (!list)
01074 return oqmlSuccess;
01075
01076 oqml_Link *l = list->first;
01077
01078 while (l)
01079 {
01080 oqmlStatus *s = l->ql->requalify(db, ctx, attrs, attr_cnt, ident);
01081 if (s) return s;
01082 l = l->next;
01083 }
01084
01085 return oqmlSuccess;
01086 }
01087
01088 oqmlStatus *
01089 oqmlCall::requalify_back(Database *db, oqmlContext *ctx)
01090 {
01091 if (!list)
01092 return oqmlSuccess;
01093
01094 oqml_Link *l = list->first;
01095
01096 while (l)
01097 {
01098 oqmlStatus *s = l->ql->requalify_back(db, ctx);
01099 if (s) return s;
01100 l = l->next;
01101 }
01102
01103 return oqmlSuccess;
01104 }
01105
01106 void
01107 oqmlCall::lock()
01108 {
01109 oqmlNode::lock();
01110 if (ql) ql->lock();
01111 if (qlbuiltin) qlbuiltin->lock();
01112 if (list) list->lock();
01113 }
01114
01115 void
01116 oqmlCall::unlock()
01117 {
01118 oqmlNode::unlock();
01119 if (ql) ql->unlock();
01120 if (qlbuiltin) qlbuiltin->unlock();
01121 if (list) list->unlock();
01122 }
01123
01124
01125
01126
01127
01128
01129
01130 oqmlReturn::oqmlReturn(oqmlNode * _ql) : oqmlNode(oqmlRETURN)
01131 {
01132 ql = _ql;
01133 }
01134
01135 oqmlReturn::~oqmlReturn()
01136 {
01137 }
01138
01139 oqmlStatus *oqmlReturn::compile(Database *db, oqmlContext *ctx)
01140 {
01141 if (ql)
01142 return ql->compile(db, ctx);
01143
01144 return oqmlSuccess;
01145 }
01146
01147 oqmlStatus *oqmlReturn::eval(Database *db, oqmlContext *ctx, oqmlAtomList **alist, oqmlComp *, oqmlAtom *)
01148 {
01149 if (oqmlCallLevel == 0)
01150 return new oqmlStatus(this, "return must be performed in a function");
01151
01152 oqmlStatus *s;
01153 oqmlAtom *r;
01154
01155 if (ql)
01156 {
01157 oqmlAtomList *al;
01158
01159 s = ql->eval(db, ctx, &al);
01160
01161 if (s)
01162 return s;
01163
01164 r = al->first;
01165 }
01166 else
01167 r = 0;
01168
01169 s = new oqmlStatus(OQML_RETURN_MAGIC);
01170 s->returnAtom = r;
01171 oqmlLock(s->returnAtom, oqml_True, oqml_False);
01172 return s;
01173 }
01174
01175 void oqmlReturn::evalType(Database *db, oqmlContext *ctx, oqmlAtomType *at)
01176 {
01177 *at = eval_type;
01178 }
01179
01180 oqmlBool oqmlReturn::isConstant() const
01181 {
01182 return oqml_False;
01183 }
01184
01185 std::string
01186 oqmlReturn::toString(void) const
01187 {
01188 return std::string("return") +
01189 (ql ? std::string(" ") + ql->toString() : std::string("")) + oqml_isstat();
01190 }
01191
01192 oqmlStatus *
01193 oqml_realize_postaction(Database *db, oqmlContext *ctx, const char *ident,
01194 oqmlAtom_string *rs, oqmlAtom *ra,
01195 oqmlAtomList **alist)
01196 {
01197 oqmlFunctionEntry *entry;
01198
01199 if (!ctx->getFunction(ident, &entry))
01200 return new oqmlStatus("postactions: unknown function '%s'.", ident);
01201
01202
01203
01204
01205
01206
01207 return oqmlCall::realizePostAction(db, ctx, ident, entry, rs, ra, alist);
01208 }
01209
01210 }
01211