oqlfunc.cc

00001 /* 
00002    EyeDB Object Database Management System
00003    Copyright (C) 1994-2008 SYSRA
00004    
00005    EyeDB is free software; you can redistribute it and/or
00006    modify it under the terms of the GNU Lesser General Public
00007    License as published by the Free Software Foundation; either
00008    version 2.1 of the License, or (at your option) any later version.
00009    
00010    EyeDB is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY; without even the implied warranty of
00012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013    Lesser General Public License for more details.
00014    
00015    You should have received a copy of the GNU Lesser General Public
00016    License along with this library; if not, write to the Free Software
00017    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA 
00018 */
00019 
00020 /*
00021    Author: Eric Viara <viara@sysra.com>
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   // function module
00040   //
00041   // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
00042 
00043   // -----------------------------------------------------------------------
00044   //
00045   // static utility classes and functions
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   // oqmlFunction operator methods
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   // oqmlBodyOf operator methods
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   // oqmlCall operator methods
00478   //
00479   // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
00480 
00481   /*
00482     oqmlCall::oqmlCall(const char *_name, oqml_List *_list) : oqmlNode(oqmlCALL)
00483     {
00484     name = strdup(_name);
00485     list = _list;
00486     ql = 0;
00487     qlbuiltin = 0;
00488     }
00489 
00490     oqmlCall::oqmlCall(const char *_name, oqmlNode *_oqml) : oqmlNode(oqmlCALL)
00491     {
00492     name = strdup(_name);
00493     list = new oqml_List();
00494     if (_oqml)
00495     list->add(_oqml);
00496     ql = 0;
00497     qlbuiltin = 0;
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     // TBD: il faudrait tester que:
00570     // (1) il n'y a aucun argument identique dans une param list
00571     // (2) il n'existe pas d'argument en commun entre la param list et
00572     //     la local param list
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     //  for (int n = 0; l; n++)
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     // added the 3/07/01
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       // added the 3/07/01
00744       ctx->setSelectContextCount(select_ctx_cnt);
00745       return oqmlSuccess;
00746     }
00747 
00748     // added the 3/07/01
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     //for (n = 0; l; n++)
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       if (!found)
00995       {
00996       if (pqlbuiltin)
00997       *pqlbuiltin = new oqmlMethodCall("oql", name, list, node);
00998       return oqml_True;
00999       }
01000     */
01001 
01002     // -------------------------- NOT YET IMPLEMENTED ------------------------
01003     /*
01004       if (!strcmp(name, "psort"))
01005       {
01006       if (pqlbuiltin)
01007       *pqlbuiltin = new oqmlPSort(list, oqml_False);
01008       return oqml_True;
01009       }
01010 
01011       if (!strcmp(name, "rpsort"))
01012       {
01013       if (pqlbuiltin)
01014       *pqlbuiltin = new oqmlPSort(list, oqml_True);
01015       return oqml_True;
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   // oqmlReturn operator methods
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       printf("executing postaction %s(%s, %s)\n", ident,
01204       rs->getString(), ra ? ra->getString() : "");
01205     */
01206 
01207     return oqmlCall::realizePostAction(db, ctx, ident, entry, rs, ra, alist);
01208   }
01209 
01210 }
01211   

Generated on Mon Dec 22 18:16:05 2008 for eyedb by  doxygen 1.5.3