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 "oql_p.h"
00026
00027 #define EXT_LOGIC
00028
00029 namespace eyedb {
00030
00031 int oqmlLoopLevel, oqmlBreakLevel;
00032 static const char OQML_BREAK_MAGIC[] = "$oqml$break$magic$";
00033
00034 #define oqml_is_break(S) ((S) && !strcmp((S)->msg, OQML_BREAK_MAGIC))
00035
00036
00037
00038
00039
00040
00041
00042 oqmlIf::oqmlIf(oqmlNode * _qcond, oqmlNode * _qthen, oqmlNode *_qelse,
00043 oqmlBool _is_cond_expr) :
00044 oqmlNode(oqmlIF)
00045 {
00046 qcond = _qcond;
00047 qthen = _qthen;
00048 qelse = _qelse;
00049 qthen_compiled = oqml_False;
00050 qelse_compiled = oqml_False;
00051 is_cond_expr = _is_cond_expr;
00052 }
00053
00054 oqmlIf::~oqmlIf()
00055 {
00056 }
00057
00058 oqmlStatus *oqmlIf::compile(Database *db, oqmlContext *ctx)
00059 {
00060 return qcond->compile(db, ctx);
00061 }
00062
00063 oqmlStatus *oqmlIf::eval(Database *db, oqmlContext *ctx, oqmlAtomList **alist, oqmlComp *, oqmlAtom *)
00064 {
00065 oqmlStatus *s;
00066 oqmlAtomList *al = 0;
00067 oqmlNode *toeval;
00068 oqmlBool *compiled = 0;
00069
00070 s = qcond->eval(db, ctx, &al);
00071 if (s)
00072 return s;
00073
00074 if (!al->cnt) {
00075 toeval = qelse;
00076 compiled = &qelse_compiled;
00077 }
00078 else if (al->cnt == 1) {
00079 oqmlAtom *a = al->first;
00080 #ifdef EXT_LOGIC
00081 oqmlBool b;
00082 s = oqml_check_logical(this, al, b);
00083 if (s)
00084 return s;
00085
00086 if (b) {
00087 toeval = qthen;
00088 compiled = &qthen_compiled;
00089 }
00090 else {
00091 toeval = qelse;
00092 compiled = &qelse_compiled;
00093 }
00094 #else
00095 if (!OQML_IS_BOOL(a))
00096 return new oqmlStatus(this, "boolean expected for condition");
00097
00098 if (OQML_ATOM_BOOLVAL(a)) {
00099 toeval = qthen;
00100 compiled = &qthen_compiled;
00101 }
00102 else {
00103 toeval = qelse;
00104 compiled = &qelse_compiled;
00105 }
00106 #endif
00107 }
00108 else
00109 toeval = qthen;
00110
00111 #ifdef SYNC_GARB
00112 OQL_DELETE(al);
00113 #endif
00114
00115 *alist = 0;
00116
00117 if (toeval) {
00118 if (!*compiled) {
00119 s = toeval->compile(db, ctx);
00120 if (s) return s;
00121 *compiled = oqml_True;
00122 }
00123
00124 s = toeval->eval(db, ctx, alist);
00125 if (s) return s;
00126 }
00127 else
00128 *alist = new oqmlAtomList();
00129
00130 if (!is_cond_expr && toeval) {
00131 #ifdef SYNC_GARB
00132 OQL_DELETE(*alist);
00133 #endif
00134 *alist = new oqmlAtomList();
00135 }
00136
00137 return oqmlSuccess;
00138 }
00139
00140 oqmlBool
00141 oqmlIf::hasIdent(const char *_ident)
00142 {
00143 return OQMLBOOL(qcond->hasIdent(_ident) ||
00144 qthen->hasIdent(_ident) ||
00145 (qelse && qelse->hasIdent(_ident)));
00146 }
00147
00148 void oqmlIf::evalType(Database *db, oqmlContext *ctx, oqmlAtomType *at)
00149 {
00150 *at = eval_type;
00151 }
00152
00153 oqmlBool oqmlIf::isConstant() const
00154 {
00155 return oqml_False;
00156 }
00157
00158 std::string
00159 oqmlIf::toString(void) const
00160 {
00161 if (is_statement)
00162 return std::string("if (") + qcond->toString() + ") " + qthen->toString() +
00163 (qelse ? std::string(" else " ) + qelse->toString() : std::string(""));
00164
00165
00166 return std::string("(") + qcond->toString() + "?" + qthen->toString() +
00167 ":" + qelse->toString() + ")";
00168 }
00169
00170
00171
00172
00173
00174
00175
00176 oqmlForEach::oqmlForEach(const char * _ident, oqmlNode * _in,
00177 oqmlNode * _action) : oqmlNode(oqmlFOREACH)
00178 {
00179 ident = strdup(_ident);
00180 in = _in;
00181 action = _action;
00182 }
00183
00184 oqmlForEach::~oqmlForEach()
00185 {
00186 free(ident);
00187 }
00188
00189 void oqmlForEach::setAction(oqmlNode *_action)
00190 {
00191 action = _action;
00192 }
00193
00194 oqmlStatus *oqmlForEach::compile(Database *db, oqmlContext *ctx)
00195 {
00196 oqmlStatus *s;
00197
00198 s = in->compile(db, ctx);
00199 if (s) return s;
00200
00201 if (action)
00202 {
00203 oqmlAtomType at;
00204 ctx->pushSymbol(ident, &at);
00205 s = action->compile(db, ctx);
00206 ctx->popSymbol(ident);
00207 }
00208
00209 if (s) return s;
00210
00211 return oqmlSuccess;
00212 }
00213
00214 oqmlStatus *oqmlForEach::eval(Database *db, oqmlContext *ctx,
00215 oqmlAtomList **alist, oqmlComp *, oqmlAtom *)
00216 {
00217 oqmlStatus *s;
00218 oqmlAtomList *al;
00219
00220 s = in->eval(db, ctx, &al);
00221 if (s) return s;
00222
00223 oqmlAtom *a = al->first;
00224 int iter = 0;
00225 int level = ++oqmlLoopLevel;
00226
00227 oqmlAtomList *tal;
00228 if (a && OQML_IS_COLL(a)) {
00229 oqmlAtomList *list = OQML_ATOM_COLLVAL(a);
00230 oqmlAtom *x = list->first;
00231 while(x) {
00232 #ifdef SYNC_GARB
00233 if (level == 1) {
00234
00235 iter++;
00236 }
00237 #endif
00238 oqmlAtom * next = x->next;
00239
00240 if (action) {
00241 gbContext *gbctx = oqmlGarbManager::peek();
00242 ctx->pushSymbol(ident, &x->type, x);
00243 tal = 0;
00244 s = action->eval(db, ctx, &tal);
00245 #ifdef SYNC_GARB
00246 OQL_DELETE(tal);
00247 #endif
00248 ctx->popSymbol(ident);
00249 oqmlGarbManager::garbage(gbctx);
00250 if (s)
00251 break;
00252 }
00253
00254 OQML_CHECK_INTR();
00255
00256 x = next;
00257 }
00258 }
00259 else if (action && a) {
00260 ctx->pushSymbol(ident, &a->type, a);
00261 #ifdef SYNC_GARB
00262 tal = 0;
00263 s = action->eval(db, ctx, &tal);
00264 OQL_DELETE(tal);
00265 #else
00266 s = action->eval(db, ctx, alist);
00267 #endif
00268 ctx->popSymbol(ident);
00269 }
00270
00271 #ifdef SYNC_GARB
00272
00273
00274 #endif
00275 --oqmlLoopLevel;
00276
00277 *alist = new oqmlAtomList();
00278 if (s && !oqml_is_break(s))
00279 return s;
00280
00281 if (oqml_is_break(s) && oqmlBreakLevel == level) {
00282 delete s;
00283 return oqmlSuccess;
00284 }
00285
00286 return s;
00287 }
00288
00289 void oqmlForEach::evalType(Database *db, oqmlContext *ctx, oqmlAtomType *at)
00290 {
00291 *at = eval_type;
00292 }
00293
00294 oqmlBool oqmlForEach::isConstant() const
00295 {
00296 return oqml_False;
00297 }
00298
00299 oqmlBool
00300 oqmlForEach::hasIdent(const char *_ident)
00301 {
00302 return OQMLBOOL(in->hasIdent(_ident) ||
00303 (action ? action->hasIdent(_ident) : oqml_False));
00304 }
00305
00306 std::string
00307 oqmlForEach::toString(void) const
00308 {
00309 return std::string("for (") + ident + " in " + in->toString() + ") " +
00310 (action ? action->toString() : std::string(""));
00311 }
00312
00313 void
00314 oqmlForEach::lock()
00315 {
00316 oqmlNode::lock();
00317 in->lock();
00318 if (action)
00319 action->lock();
00320 }
00321
00322 void
00323 oqmlForEach::unlock()
00324 {
00325 oqmlNode::unlock();
00326 in->unlock();
00327 if (action)
00328 action->unlock();
00329 }
00330
00331
00332
00333
00334
00335
00336
00337 oqmlWhile::oqmlWhile(oqmlNode * _qleft, oqmlNode *_qright) : oqmlNode(oqmlWHILE)
00338 {
00339 qleft = _qleft;
00340 qright = _qright;
00341 }
00342
00343 oqmlWhile::~oqmlWhile()
00344 {
00345 }
00346
00347 oqmlStatus *oqmlWhile::compile(Database *db, oqmlContext *ctx)
00348 {
00349 oqmlStatus *s;
00350
00351 s = qleft->compile(db, ctx);
00352 if (s) return s;
00353
00354 s = qright->compile(db, ctx);
00355 if (s) return s;
00356
00357 return oqmlSuccess;
00358 }
00359
00360 oqmlStatus *oqmlWhile::eval(Database *db, oqmlContext *ctx, oqmlAtomList **alist, oqmlComp *, oqmlAtom *)
00361 {
00362 oqmlStatus *s = oqmlSuccess;
00363
00364 int level = ++oqmlLoopLevel;
00365 for (;;)
00366 {
00367 oqmlAtomList *al;
00368
00369 s = qleft->eval(db, ctx, &al);
00370 if (s)
00371 break;
00372
00373 #ifdef EXT_LOGIC
00374 oqmlBool b;
00375 s = oqml_check_logical(this, al, b);
00376 if (s)
00377 break;
00378
00379 if (!b)
00380 break;
00381 #else
00382 if (al->cnt != 1 || !OQML_IS_BOOL(al->first))
00383 return new oqmlStatus(this, "boolean expected for condition");
00384
00385 if (!OQML_ATOM_BOOLVAL(al->first))
00386 break;
00387 #endif
00388
00389 OQML_CHECK_INTR();
00390
00391 if (qright) {
00392 gbContext *gbctx = oqmlGarbManager::peek();
00393 s = qright->eval(db, ctx, &al);
00394 oqmlGarbManager::garbage(gbctx);
00395 if (s) break;
00396 }
00397 }
00398
00399 --oqmlLoopLevel;
00400
00401 *alist = new oqmlAtomList();
00402 if (s && !oqml_is_break(s))
00403 return s;
00404
00405 if (oqml_is_break(s) && oqmlBreakLevel == level)
00406 {
00407 delete s;
00408 return oqmlSuccess;
00409 }
00410
00411 return s;
00412 }
00413
00414 void oqmlWhile::evalType(Database *db, oqmlContext *ctx, oqmlAtomType *at)
00415 {
00416 *at = eval_type;
00417 }
00418
00419 oqmlBool oqmlWhile::isConstant() const
00420 {
00421 return OQMLBOOL(qleft->isConstant() && qright->isConstant());
00422 }
00423
00424 std::string
00425 oqmlWhile::toString(void) const
00426 {
00427 return std::string("while (") + qleft->toString() + ") " +
00428 (qright ? qright->toString() : std::string(""));
00429
00430 }
00431
00432
00433
00434
00435
00436
00437
00438 oqmlDoWhile::oqmlDoWhile(oqmlNode * _qleft, oqmlNode *_qright) : oqmlNode(oqmlDOWHILE)
00439 {
00440 qleft = _qleft;
00441 qright = _qright;
00442 }
00443
00444 oqmlDoWhile::~oqmlDoWhile()
00445 {
00446 }
00447
00448 oqmlStatus *oqmlDoWhile::compile(Database *db, oqmlContext *ctx)
00449 {
00450 oqmlStatus *s;
00451
00452 s = qleft->compile(db, ctx);
00453 if (s) return s;
00454
00455 s = qright->compile(db, ctx);
00456 if (s) return s;
00457
00458 return oqmlSuccess;
00459 }
00460
00461 oqmlStatus *oqmlDoWhile::eval(Database *db, oqmlContext *ctx, oqmlAtomList **alist, oqmlComp *, oqmlAtom *)
00462 {
00463 oqmlStatus *s = oqmlSuccess;
00464 oqmlBool b;
00465
00466 int level = ++oqmlLoopLevel;
00467 do {
00468 oqmlAtomList *al;
00469
00470 s = qleft->eval(db, ctx, &al);
00471 if (s) break;
00472
00473 #ifdef EXT_LOGIC
00474 s = oqml_check_logical(this, al, b);
00475 if (s)
00476 break;
00477
00478 OQML_CHECK_INTR();
00479 #else
00480 if (al->cnt != 1 || !OQML_IS_BOOL(al->first))
00481 return new oqmlStatus(this, "boolean expected for condition");
00482
00483 OQML_CHECK_INTR();
00484
00485 b = OQML_ATOM_BOOLVAL(al->first);
00486 #endif
00487
00488 if (qright)
00489 {
00490 gbContext *gbctx = oqmlGarbManager::peek();
00491 s = qright->eval(db, ctx, &al);
00492 oqmlGarbManager::garbage(gbctx);
00493 if (s) break;
00494 }
00495
00496 } while(b);
00497
00498 --oqmlLoopLevel;
00499
00500 *alist = new oqmlAtomList();
00501
00502 if (s && !oqml_is_break(s))
00503 return s;
00504
00505 if (oqml_is_break(s) && oqmlBreakLevel == level)
00506 {
00507 delete s;
00508 return oqmlSuccess;
00509 }
00510
00511 return s;
00512 }
00513
00514 void oqmlDoWhile::evalType(Database *db, oqmlContext *ctx, oqmlAtomType *at)
00515 {
00516 *at = eval_type;
00517 }
00518
00519 oqmlBool oqmlDoWhile::isConstant() const
00520 {
00521 return OQMLBOOL(qleft->isConstant() && qright->isConstant());
00522 }
00523
00524 std::string
00525 oqmlDoWhile::toString(void) const
00526 {
00527 return std::string("do ") +
00528 (qright ? qright->toString() : std::string(""))
00529 + " while " + qleft->toString();
00530 }
00531
00532
00533
00534
00535
00536
00537
00538 oqmlForDo::oqmlForDo(oqmlNode *_start,
00539 oqmlNode *_cond,
00540 oqmlNode *_next,
00541 oqmlNode *_body) : oqmlNode(oqmlFORDO)
00542 {
00543 ident = 0;
00544 start = _start;
00545 cond = _cond;
00546 next = _next;
00547 body = _body;
00548 }
00549
00550 oqmlForDo::oqmlForDo(const char *_ident,
00551 oqmlNode *_start,
00552 oqmlNode *_cond,
00553 oqmlNode *_next,
00554 oqmlNode *_body) : oqmlNode(oqmlFORDO)
00555 {
00556 ident = strdup(_ident);
00557 start = _start;
00558 cond = _cond;
00559 next = _next;
00560 body = _body;
00561 }
00562
00563 oqmlForDo::~oqmlForDo()
00564 {
00565 free(ident);
00566 }
00567
00568 oqmlStatus *oqmlForDo::compile(Database *db, oqmlContext *ctx)
00569 {
00570 oqmlStatus *s;
00571
00572 if (ident)
00573 {
00574 oqmlAtomType at;
00575 ctx->pushSymbol(ident, &at, 0, oqml_False);
00576 }
00577
00578 if (start)
00579 {
00580 s = start->compile(db, ctx);
00581 if (s) return s;
00582 }
00583
00584 if (cond)
00585 {
00586 s = cond->compile(db, ctx);
00587 if (s) return s;
00588 }
00589
00590 if (next)
00591 {
00592 s = next->compile(db, ctx);
00593 if (s) return s;
00594 }
00595
00596 if (body)
00597 {
00598 s = body->compile(db, ctx);
00599 if (s) return s;
00600 }
00601
00602 if (ident)
00603 ctx->popSymbol(ident, oqml_False);
00604
00605 return oqmlSuccess;
00606 }
00607
00608 oqmlStatus *oqmlForDo::eval(Database *db, oqmlContext *ctx, oqmlAtomList **alist, oqmlComp *, oqmlAtom *)
00609 {
00610 oqmlStatus *s = oqmlSuccess;
00611 oqmlBool b;
00612
00613 oqmlAtomList *al;
00614
00615 if (ident)
00616 {
00617 oqmlAtomType at;
00618 ctx->pushSymbol(ident, &at, 0, oqml_False);
00619 }
00620
00621 if (start)
00622 {
00623 s = start->eval(db, ctx, &al);
00624 if (s) return s;
00625 }
00626
00627 int level = ++oqmlLoopLevel;
00628
00629 for (;;) {
00630 if (cond) {
00631 s = cond->eval(db, ctx, &al);
00632 if (s)
00633 return s;
00634
00635 #ifdef EXT_LOGIC
00636 oqmlBool b;
00637 s = oqml_check_logical(this, al, b);
00638 if (s)
00639 break;
00640
00641 if (!b)
00642 break;
00643 #else
00644 if (al->cnt != 1 || !OQML_IS_BOOL(al->first)) {
00645 s = new oqmlStatus(this, "boolean expected for condition");
00646 break;
00647 }
00648
00649 if (!OQML_ATOM_BOOLVAL(al->first))
00650 break;
00651 #endif
00652 }
00653
00654 OQML_CHECK_INTR();
00655
00656 if (body) {
00657 gbContext *gbctx = oqmlGarbManager::peek();
00658 s = body->eval(db, ctx, &al);
00659 oqmlGarbManager::garbage(gbctx);
00660 if (s) break;
00661 }
00662
00663 if (next) {
00664 s = next->eval(db, ctx, &al);
00665 if (s) break;
00666 }
00667 }
00668
00669 --oqmlLoopLevel;
00670
00671 if (ident)
00672 ctx->popSymbol(ident, oqml_False);
00673
00674 *alist = new oqmlAtomList();
00675 if (s && !oqml_is_break(s))
00676 return s;
00677
00678 if (oqml_is_break(s) && oqmlBreakLevel == level)
00679 {
00680 delete s;
00681 return oqmlSuccess;
00682 }
00683
00684 return oqmlSuccess;
00685 }
00686
00687 void oqmlForDo::evalType(Database *db, oqmlContext *ctx, oqmlAtomType *at)
00688 {
00689 *at = eval_type;
00690 }
00691
00692 oqmlBool oqmlForDo::isConstant() const
00693 {
00694 return oqml_False;
00695 }
00696
00697 oqmlBool
00698 oqmlForDo::hasIdent(const char *_ident)
00699 {
00700 return OQMLBOOL((start ? start->hasIdent(_ident) : oqml_False)||
00701 (cond ? cond->hasIdent(_ident) : oqml_False) ||
00702 (next ? next->hasIdent(_ident) : oqml_False) ||
00703 (body ? body->hasIdent(_ident) : oqml_False));
00704 }
00705
00706 void oqmlForDo::lock()
00707 {
00708 oqmlNode::lock();
00709 if (start)
00710 start->lock();
00711 if (cond)
00712 cond->lock();
00713 if (next)
00714 next->lock();
00715 if (body)
00716 body->lock();
00717 }
00718
00719 void oqmlForDo::unlock()
00720 {
00721 oqmlNode::unlock();
00722 if (start)
00723 start->unlock();
00724 if (cond)
00725 cond->unlock();
00726 if (next)
00727 next->unlock();
00728 if (body)
00729 body->unlock();
00730 }
00731
00732 std::string
00733 oqmlForDo::toString(void) const
00734 {
00735 return std::string("for(") +
00736 (start ? start->toString() : std::string("")) + ";" +
00737 (cond ? cond->toString() : std::string("")) + ";" +
00738 (next ? next->toString() : std::string("")) + ") " +
00739 (body ? body->toString() : std::string(""));
00740
00741 }
00742
00743
00744
00745
00746
00747
00748
00749 oqmlThrow::oqmlThrow(oqmlNode * _ql) : oqmlNode(oqmlTHROW)
00750 {
00751 ql = _ql;
00752 }
00753
00754 oqmlThrow::~oqmlThrow()
00755 {
00756 }
00757
00758 oqmlStatus *oqmlThrow::compile(Database *db, oqmlContext *ctx)
00759 {
00760 return ql->compile(db, ctx);
00761 }
00762
00763 oqmlStatus *oqmlThrow::eval(Database *db, oqmlContext *ctx, oqmlAtomList **alist, oqmlComp *, oqmlAtom *)
00764 {
00765 oqmlStatus *s;
00766 oqmlAtomList *al;
00767
00768 s = ql->eval(db, ctx, &al);
00769
00770 if (s) return s;
00771
00772 if (al->cnt == 1 && al->first->as_string())
00773 return new oqmlStatus(OQML_ATOM_STRVAL(al->first));
00774
00775 if (al->cnt == 1)
00776 return oqmlStatus::expected(this, "string", al->first->type.getString());
00777
00778 return new oqmlStatus(this, "string argument expected");
00779 }
00780
00781 void oqmlThrow::evalType(Database *db, oqmlContext *ctx, oqmlAtomType *at)
00782 {
00783 *at = eval_type;
00784 }
00785
00786 oqmlBool oqmlThrow::isConstant() const
00787 {
00788 return oqml_False;
00789 }
00790
00791 std::string
00792 oqmlThrow::toString(void) const
00793 {
00794 return std::string("throw ") + ql->toString() + oqml_isstat();
00795 }
00796
00797
00798
00799
00800
00801
00802
00803 oqmlBreak::oqmlBreak(oqmlNode * _ql) : oqmlNode(oqmlBREAK)
00804 {
00805 ql = _ql;
00806 }
00807
00808 oqmlBreak::~oqmlBreak()
00809 {
00810 }
00811
00812 oqmlStatus *oqmlBreak::compile(Database *db, oqmlContext *ctx)
00813 {
00814 if (ql)
00815 return ql->compile(db, ctx);
00816
00817 return oqmlSuccess;
00818 }
00819
00820 oqmlStatus *oqmlBreak::eval(Database *db, oqmlContext *ctx, oqmlAtomList **alist, oqmlComp *, oqmlAtom *)
00821 {
00822 int level;
00823
00824 if (ql)
00825 {
00826 oqmlStatus *s;
00827 oqmlAtomList *al;
00828
00829 s = ql->eval(db, ctx, &al);
00830
00831 if (s) return s;
00832
00833 if (al->cnt != 1 || !al->first->as_int())
00834 return new oqmlStatus(this, "integer expected");
00835
00836 level = OQML_ATOM_INTVAL(al->first);
00837 }
00838 else
00839 level = 1;
00840
00841 if (level > oqmlLoopLevel)
00842 return new oqmlStatus(this, "level %d is too deep", level);
00843
00844 oqmlBreakLevel = oqmlLoopLevel - level + 1;
00845
00846 return new oqmlStatus(OQML_BREAK_MAGIC);
00847 }
00848
00849 void oqmlBreak::evalType(Database *db, oqmlContext *ctx, oqmlAtomType *at)
00850 {
00851 *at = eval_type;
00852 }
00853
00854 oqmlBool oqmlBreak::isConstant() const
00855 {
00856 return oqml_False;
00857 }
00858
00859 std::string
00860 oqmlBreak::toString(void) const
00861 {
00862 return std::string("break") +
00863 (ql ? std::string(" ") + ql->toString() : std::string("")) + oqml_isstat();
00864 }
00865 }