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 if (qright) {
00471 gbContext *gbctx = oqmlGarbManager::peek();
00472 s = qright->eval(db, ctx, &al);
00473 oqmlGarbManager::garbage(gbctx);
00474 if (s) break;
00475 }
00476
00477 s = qleft->eval(db, ctx, &al);
00478 if (s) break;
00479
00480 #ifdef EXT_LOGIC
00481 s = oqml_check_logical(this, al, b);
00482 if (s)
00483 break;
00484
00485 OQML_CHECK_INTR();
00486 #else
00487 if (al->cnt != 1 || !OQML_IS_BOOL(al->first))
00488 return new oqmlStatus(this, "boolean expected for condition");
00489
00490 OQML_CHECK_INTR();
00491
00492 b = OQML_ATOM_BOOLVAL(al->first);
00493 #endif
00494
00495 } while(b);
00496
00497 --oqmlLoopLevel;
00498
00499 *alist = new oqmlAtomList();
00500
00501 if (s && !oqml_is_break(s))
00502 return s;
00503
00504 if (oqml_is_break(s) && oqmlBreakLevel == level)
00505 {
00506 delete s;
00507 return oqmlSuccess;
00508 }
00509
00510 return s;
00511 }
00512
00513 void oqmlDoWhile::evalType(Database *db, oqmlContext *ctx, oqmlAtomType *at)
00514 {
00515 *at = eval_type;
00516 }
00517
00518 oqmlBool oqmlDoWhile::isConstant() const
00519 {
00520 return OQMLBOOL(qleft->isConstant() && qright->isConstant());
00521 }
00522
00523 std::string
00524 oqmlDoWhile::toString(void) const
00525 {
00526 return std::string("do ") +
00527 (qright ? qright->toString() : std::string(""))
00528 + " while " + qleft->toString();
00529 }
00530
00531
00532
00533
00534
00535
00536
00537 oqmlForDo::oqmlForDo(oqmlNode *_start,
00538 oqmlNode *_cond,
00539 oqmlNode *_next,
00540 oqmlNode *_body) : oqmlNode(oqmlFORDO)
00541 {
00542 ident = 0;
00543 start = _start;
00544 cond = _cond;
00545 next = _next;
00546 body = _body;
00547 }
00548
00549 oqmlForDo::oqmlForDo(const char *_ident,
00550 oqmlNode *_start,
00551 oqmlNode *_cond,
00552 oqmlNode *_next,
00553 oqmlNode *_body) : oqmlNode(oqmlFORDO)
00554 {
00555 ident = strdup(_ident);
00556 start = _start;
00557 cond = _cond;
00558 next = _next;
00559 body = _body;
00560 }
00561
00562 oqmlForDo::~oqmlForDo()
00563 {
00564 free(ident);
00565 }
00566
00567 oqmlStatus *oqmlForDo::compile(Database *db, oqmlContext *ctx)
00568 {
00569 oqmlStatus *s;
00570
00571 if (ident)
00572 {
00573 oqmlAtomType at;
00574 ctx->pushSymbol(ident, &at, 0, oqml_False);
00575 }
00576
00577 if (start)
00578 {
00579 s = start->compile(db, ctx);
00580 if (s) return s;
00581 }
00582
00583 if (cond)
00584 {
00585 s = cond->compile(db, ctx);
00586 if (s) return s;
00587 }
00588
00589 if (next)
00590 {
00591 s = next->compile(db, ctx);
00592 if (s) return s;
00593 }
00594
00595 if (body)
00596 {
00597 s = body->compile(db, ctx);
00598 if (s) return s;
00599 }
00600
00601 if (ident)
00602 ctx->popSymbol(ident, oqml_False);
00603
00604 return oqmlSuccess;
00605 }
00606
00607 oqmlStatus *oqmlForDo::eval(Database *db, oqmlContext *ctx, oqmlAtomList **alist, oqmlComp *, oqmlAtom *)
00608 {
00609 oqmlStatus *s = oqmlSuccess;
00610 oqmlBool b;
00611
00612 oqmlAtomList *al;
00613
00614 if (ident)
00615 {
00616 oqmlAtomType at;
00617 ctx->pushSymbol(ident, &at, 0, oqml_False);
00618 }
00619
00620 if (start)
00621 {
00622 s = start->eval(db, ctx, &al);
00623 if (s) return s;
00624 }
00625
00626 int level = ++oqmlLoopLevel;
00627
00628 for (;;) {
00629 if (cond) {
00630 s = cond->eval(db, ctx, &al);
00631 if (s)
00632 return s;
00633
00634 #ifdef EXT_LOGIC
00635 oqmlBool b;
00636 s = oqml_check_logical(this, al, b);
00637 if (s)
00638 break;
00639
00640 if (!b)
00641 break;
00642 #else
00643 if (al->cnt != 1 || !OQML_IS_BOOL(al->first)) {
00644 s = new oqmlStatus(this, "boolean expected for condition");
00645 break;
00646 }
00647
00648 if (!OQML_ATOM_BOOLVAL(al->first))
00649 break;
00650 #endif
00651 }
00652
00653 OQML_CHECK_INTR();
00654
00655 if (body) {
00656 gbContext *gbctx = oqmlGarbManager::peek();
00657 s = body->eval(db, ctx, &al);
00658 oqmlGarbManager::garbage(gbctx);
00659 if (s) break;
00660 }
00661
00662 if (next) {
00663 s = next->eval(db, ctx, &al);
00664 if (s) break;
00665 }
00666 }
00667
00668 --oqmlLoopLevel;
00669
00670 if (ident)
00671 ctx->popSymbol(ident, oqml_False);
00672
00673 *alist = new oqmlAtomList();
00674 if (s && !oqml_is_break(s))
00675 return s;
00676
00677 if (oqml_is_break(s) && oqmlBreakLevel == level)
00678 {
00679 delete s;
00680 return oqmlSuccess;
00681 }
00682
00683 return oqmlSuccess;
00684 }
00685
00686 void oqmlForDo::evalType(Database *db, oqmlContext *ctx, oqmlAtomType *at)
00687 {
00688 *at = eval_type;
00689 }
00690
00691 oqmlBool oqmlForDo::isConstant() const
00692 {
00693 return oqml_False;
00694 }
00695
00696 oqmlBool
00697 oqmlForDo::hasIdent(const char *_ident)
00698 {
00699 return OQMLBOOL((start ? start->hasIdent(_ident) : oqml_False)||
00700 (cond ? cond->hasIdent(_ident) : oqml_False) ||
00701 (next ? next->hasIdent(_ident) : oqml_False) ||
00702 (body ? body->hasIdent(_ident) : oqml_False));
00703 }
00704
00705 void oqmlForDo::lock()
00706 {
00707 oqmlNode::lock();
00708 if (start)
00709 start->lock();
00710 if (cond)
00711 cond->lock();
00712 if (next)
00713 next->lock();
00714 if (body)
00715 body->lock();
00716 }
00717
00718 void oqmlForDo::unlock()
00719 {
00720 oqmlNode::unlock();
00721 if (start)
00722 start->unlock();
00723 if (cond)
00724 cond->unlock();
00725 if (next)
00726 next->unlock();
00727 if (body)
00728 body->unlock();
00729 }
00730
00731 std::string
00732 oqmlForDo::toString(void) const
00733 {
00734 return std::string("for(") +
00735 (start ? start->toString() : std::string("")) + ";" +
00736 (cond ? cond->toString() : std::string("")) + ";" +
00737 (next ? next->toString() : std::string("")) + ") " +
00738 (body ? body->toString() : std::string(""));
00739
00740 }
00741
00742
00743
00744
00745
00746
00747
00748 oqmlThrow::oqmlThrow(oqmlNode * _ql) : oqmlNode(oqmlTHROW)
00749 {
00750 ql = _ql;
00751 }
00752
00753 oqmlThrow::~oqmlThrow()
00754 {
00755 }
00756
00757 oqmlStatus *oqmlThrow::compile(Database *db, oqmlContext *ctx)
00758 {
00759 return ql->compile(db, ctx);
00760 }
00761
00762 oqmlStatus *oqmlThrow::eval(Database *db, oqmlContext *ctx, oqmlAtomList **alist, oqmlComp *, oqmlAtom *)
00763 {
00764 oqmlStatus *s;
00765 oqmlAtomList *al;
00766
00767 s = ql->eval(db, ctx, &al);
00768
00769 if (s) return s;
00770
00771 if (al->cnt == 1 && al->first->as_string())
00772 return new oqmlStatus(OQML_ATOM_STRVAL(al->first));
00773
00774 if (al->cnt == 1)
00775 return oqmlStatus::expected(this, "string", al->first->type.getString());
00776
00777 return new oqmlStatus(this, "string argument expected");
00778 }
00779
00780 void oqmlThrow::evalType(Database *db, oqmlContext *ctx, oqmlAtomType *at)
00781 {
00782 *at = eval_type;
00783 }
00784
00785 oqmlBool oqmlThrow::isConstant() const
00786 {
00787 return oqml_False;
00788 }
00789
00790 std::string
00791 oqmlThrow::toString(void) const
00792 {
00793 return std::string("throw ") + ql->toString() + oqml_isstat();
00794 }
00795
00796
00797
00798
00799
00800
00801
00802 oqmlBreak::oqmlBreak(oqmlNode * _ql) : oqmlNode(oqmlBREAK)
00803 {
00804 ql = _ql;
00805 }
00806
00807 oqmlBreak::~oqmlBreak()
00808 {
00809 }
00810
00811 oqmlStatus *oqmlBreak::compile(Database *db, oqmlContext *ctx)
00812 {
00813 if (ql)
00814 return ql->compile(db, ctx);
00815
00816 return oqmlSuccess;
00817 }
00818
00819 oqmlStatus *oqmlBreak::eval(Database *db, oqmlContext *ctx, oqmlAtomList **alist, oqmlComp *, oqmlAtom *)
00820 {
00821 int level;
00822
00823 if (ql)
00824 {
00825 oqmlStatus *s;
00826 oqmlAtomList *al;
00827
00828 s = ql->eval(db, ctx, &al);
00829
00830 if (s) return s;
00831
00832 if (al->cnt != 1 || !al->first->as_int())
00833 return new oqmlStatus(this, "integer expected");
00834
00835 level = OQML_ATOM_INTVAL(al->first);
00836 }
00837 else
00838 level = 1;
00839
00840 if (level > oqmlLoopLevel)
00841 return new oqmlStatus(this, "level %d is too deep", level);
00842
00843 oqmlBreakLevel = oqmlLoopLevel - level + 1;
00844
00845 return new oqmlStatus(OQML_BREAK_MAGIC);
00846 }
00847
00848 void oqmlBreak::evalType(Database *db, oqmlContext *ctx, oqmlAtomType *at)
00849 {
00850 *at = eval_type;
00851 }
00852
00853 oqmlBool oqmlBreak::isConstant() const
00854 {
00855 return oqml_False;
00856 }
00857
00858 std::string
00859 oqmlBreak::toString(void) const
00860 {
00861 return std::string("break") +
00862 (ql ? std::string(" ") + ql->toString() : std::string("")) + oqml_isstat();
00863 }
00864 }