lbp_function.cpp

Go to the documentation of this file.
00001 /** @file lbp_function.cpp luafaudes class to run scripts as rti functions */
00002 
00003 /* 
00004 FAU Discrete Event Systems Library (libfaudes)
00005 
00006 Copyright (C) 2010 Thomas Moor
00007 
00008 This library is free software; you can redistribute it and/or
00009 modify it under the terms of the GNU Lesser General Public
00010 License as published by the Free Software Foundation; either
00011 version 2.1 of the License, or (at your option) any later version.
00012 
00013 This library is distributed in the hope that it will be useful,
00014 but WITHOUT ANY WARRANTY; without even the implied warranty of
00015 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00016 Lesser General Public License for more details.
00017 
00018 You should have received a copy of the GNU Lesser General Public
00019 License along with this library; if not, write to the Free Software
00020 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA 
00021 
00022 
00023 */
00024 
00025 
00026 // my header
00027 #include "lbp_function.h"
00028 
00029 // all lua headers, incl luafaudes
00030 #include "libluafaudes.h"
00031 
00032 
00033 
00034 namespace faudes{
00035 
00036 /*
00037 ********************************************************************
00038 ********************************************************************
00039 ********************************************************************
00040 
00041 Borrow from SWIG type system
00042 
00043 ********************************************************************
00044 ********************************************************************
00045 ********************************************************************
00046 */
00047 
00048 
00049 /*
00050 SWIGS representation of user data (lua runtime version 4, swig 1.3.36)
00051 Note: the below interface has also been verified to meet SWIG 1.3.40 
00052 and 2.0.1. Other versions of SWIG may or may not have compatible interfaces
00053 and, hence, should be carefully verified befor use.
00054 */
00055 typedef void *(*swig_converter_func)(void *, int *);
00056 typedef struct swig_type_info *(*swig_dycast_func)(void **);
00057 typedef struct swig_cast_info {
00058   swig_type_info         *type;     /* pointer to type that is equivalent to this type */
00059   swig_converter_func     converter;    /* function to cast the void pointers */
00060   struct swig_cast_info  *next;     /* pointer to next cast in linked list */
00061   struct swig_cast_info  *prev;     /* pointer to the previous cast */
00062 } swig_cast_info;
00063 typedef struct swig_type_info {
00064   const char             *name;     /* mangled name of this type */
00065   const char             *str;      /* human readable name of this type */
00066   swig_dycast_func        dcast;    /* dynamic cast function down a hierarchy */
00067   struct swig_cast_info  *cast;     /* linked list of types that can cast into this type */
00068   void                   *clientdata;   /* language specific type data */
00069   int                    owndata;   /* flag if the structure owns the clientdata */
00070 } swig_type_info;
00071 typedef struct {
00072   swig_type_info   *type;
00073   int               own;                        /* 1 <> owned by swig (garbadge collector wont destroy) */  
00074   void              *ptr;
00075 } swig_lua_userdata;
00076 
00077 
00078 
00079 /* 
00080 Swig runtime sytem: dynamic cast of swig userdata pointers.
00081 We need this to cast swig's userdata to the faudes base type 
00082 faudes::Type. In contrast to the original SWIG runtime function
00083 SWIG_ConvertPtr, the below variant is are more picky on types 
00084 that do mot cast to faufes::Type. For such types, we return NULL
00085 */
00086 void* SwigCastPtr(void* ptr, swig_type_info *from, swig_type_info *ty) {
00087   void* res=ptr;
00088   if(!ptr) return 0;
00089   if(!from) return 0;
00090   if(!ty) return 0;
00091   swig_cast_info *iter = ty->cast;
00092   while(iter) {
00093     if(iter->type == from) {
00094       if(iter == ty->cast) break;
00095       iter->prev->next = iter->next;
00096       if(iter->next)
00097         iter->next->prev = iter->prev;
00098       iter->next = ty->cast;
00099       iter->prev = 0;
00100       if(ty->cast) ty->cast->prev = iter;
00101       ty->cast = iter;
00102       break;
00103     }
00104     iter = iter->next;
00105   }
00106   if(!iter) return 0;
00107   if(!iter->converter) return 0;
00108   int nm;
00109   res= (*iter->converter)(ptr,&nm);
00110   return res;
00111 }
00112 
00113 /*
00114 Test whether userdata is SWIG generated, i.e., can be examined by 
00115 the SWIG type system
00116 */
00117 swig_lua_userdata* SwigUserData(lua_State* L, int index) {
00118   if(!lua_isuserdata(L,index)) return NULL;
00119   // get the metatable
00120   if(!lua_getmetatable(L,index)) return NULL;
00121   // get the ".type" entry
00122   lua_pushstring(L,".type");
00123   lua_rawget(L,-2);
00124   if(!lua_isstring(L,-1)) { lua_pop(L,2); return NULL;};
00125   const char* ftype = lua_tostring(L,-1);
00126   if(!ftype) {lua_pop(L,2); return NULL;};
00127   // todo: test whether this is a faudes type?
00128   // todo: test whether the metatable is a registered by swig
00129   lua_pop(L,2);
00130   return (swig_lua_userdata*) lua_touserdata(L,index);
00131 }
00132 
00133 
00134 /*
00135 ********************************************************************
00136 ********************************************************************
00137 ********************************************************************
00138 
00139 local helper, may go to cfl_helper.*
00140 
00141 ********************************************************************
00142 ********************************************************************
00143 ********************************************************************
00144 */
00145 
00146 std::string MangleString(const std::string& str) {
00147   std::string res=str;
00148   std::size_t src=0;
00149   std::size_t dst=0;
00150   while(src<res.length()) {
00151     if(isalnum(res.at(src))) {res[dst++]=res[src++]; continue;}
00152     res[dst++]='_';
00153     for(;src<res.length();src++) 
00154       if(isalnum(res.at(src))) break;
00155   }
00156   if(dst>2)
00157   if(res[dst-1]=='_')
00158     dst--;
00159   res.resize(dst);
00160   return res;
00161 }
00162 
00163 
00164 /*
00165 ********************************************************************
00166 ********************************************************************
00167 ********************************************************************
00168 
00169 Implementation of class LuaFunctionDefinition
00170 
00171 ********************************************************************
00172 ********************************************************************
00173 ********************************************************************
00174 */
00175 
00176 // faudes type
00177 FAUDES_TYPE_IMPLEMENTATION(LuaFunctionDefinition,LuaFunctionDefinition,FunctionDefinition)
00178 
00179 // construct
00180 LuaFunctionDefinition::LuaFunctionDefinition(const std::string& name) : 
00181   FunctionDefinition(name),
00182   pDefaultL(0) 
00183 {
00184   Prototype(new LuaFunction(0));
00185   FD_DLB("LuaFunctionDefinition::LuaFunctionDefinition("<<this<<"): name   " << name);
00186   FD_DLB("LuaFunctionDefinition::LuaFunctionDefinition("<<this<<"): proto   " << mpFunction);
00187   FD_DLB("LuaFunctionDefinition::LuaFunctionDefinition("<<this<<"): has def " << mpFunction->Definition());
00188 }
00189 
00190 // copy construct
00191 LuaFunctionDefinition::LuaFunctionDefinition(const LuaFunctionDefinition& rSrc) : 
00192   FunctionDefinition(rSrc.Name()),
00193   pDefaultL(0) 
00194 {
00195   FD_DLB("LuaFunctionDefinition::LuaFunctionDefinition(copy)");
00196   DoAssign(rSrc);
00197 }
00198 
00199 // std faudes type
00200 void LuaFunctionDefinition::DoAssign(const LuaFunctionDefinition& rSrc) {
00201   FD_DLB("LuaFunctionDefinition::DoAssign()");
00202   // assign base members
00203   FunctionDefinition::DoAssign(rSrc);
00204   // assign my members
00205   mLuaCode=rSrc.mLuaCode;
00206   mLuaFile=rSrc.mLuaFile;
00207   // special member
00208   pLuaFunction=dynamic_cast<LuaFunction*>(mpFunction);
00209   // report
00210   FD_DLB("LuaFunctionDefinition::DoAssign("<<this<<"): name   " << mName);
00211   FD_DLB("LuaFunctionDefinition::DoAssign("<<this<<"): proto   " << mpFunction);
00212   FD_DLB("LuaFunctionDefinition::DoAssign("<<this<<"): has def " << mpFunction->Definition())
00213 }
00214 
00215 // std faudes type
00216 bool LuaFunctionDefinition::DoEqual(const LuaFunctionDefinition& rOther) const {
00217   // test base members
00218   if(!FunctionDefinition::DoEqual(rOther)) return false;
00219   // test my members
00220   if(mLuaCode!=rOther.mLuaCode) return false;
00221   if(mLuaFile!=rOther.mLuaFile) return false;
00222   return true;
00223 }
00224 
00225 // clear (all but prototype)
00226 void LuaFunctionDefinition::Clear(){
00227   FD_DLB("LuaFunctionDefinition::Clear(): " << Name());
00228   // call base
00229   FunctionDefinition::Clear();
00230   // clear my data
00231   mLuaCode.clear();
00232 }
00233 
00234 
00235 // set prototype object
00236 void LuaFunctionDefinition::Prototype(Function* pFunc){
00237   FunctionDefinition::Prototype(pFunc);
00238   // set typed version
00239   pLuaFunction=dynamic_cast<LuaFunction*>(pFunc);
00240 }
00241 
00242 
00243 // get lua code
00244 const std::string& LuaFunctionDefinition::LuaCode(void) const {
00245   return mLuaCode;
00246 }
00247 
00248 // set lua code
00249 void LuaFunctionDefinition::LuaCode(const std::string& rCode) {
00250   mLuaCode=rCode;
00251 }
00252 
00253 // get/set default lua state
00254 LuaState* LuaFunctionDefinition::DefaultL(void) const {
00255   if(!pDefaultL)  return const_cast<LuaFunctionDefinition*>(this)->pDefaultL=LuaState::G();
00256   return pDefaultL;
00257 }
00258 
00259 // get/set default lua state
00260 void LuaFunctionDefinition::DefaultL(LuaState* pL) {
00261   pDefaultL=pL;
00262 }
00263 
00264 // test all variants
00265 std::string LuaFunctionDefinition::SyntaxCheck(void) {
00266   // trivial case ... use evaluate
00267   if(VariantsSize()==0) {
00268     FD_DLB("LuaFunctionDefinition::SyntaxCheck(): no variants defined, evaluate");
00269     return Evaluate();
00270   }    
00271   // allocate function
00272   faudes::LuaFunction* lfnct = pLuaFunction->New();
00273   // iterate variants
00274   std::string err = "";
00275   for(int i=0; i<lfnct->VariantsSize(); i++) {
00276     // select
00277     lfnct->Variant(i);
00278     FD_DLB("LuaFunctionDefinition::SyntaxCheck(): variant " << 
00279       lfnct->Variant()->Name());
00280     // allocate args (exception on unknown type, will lead to mem leak)
00281     try {
00282       lfnct->AllocateValues();
00283       // let luafunction have a go
00284       if(err=="") try {
00285         lfnct->SyntaxCheck();
00286       } catch(faudes::Exception ex)  {
00287         err = ex.What();
00288       }
00289       // free args
00290       lfnct->FreeValues();
00291     // alloc err
00292     } catch(faudes::Exception ex)  {
00293       err = "cannot allocate parameters for variant " + lfnct->Variant()->Name();
00294     }
00295   } // iterate variants
00296   delete lfnct;
00297   // done
00298   return err;
00299 }
00300 
00301 
00302 // test all variants
00303 std::string LuaFunctionDefinition::Evaluate(LuaState* pL) {
00304   // allocate function and set state
00305   faudes::LuaFunction* lfnct = pLuaFunction->New();
00306   lfnct->L(pL);
00307   // evaluate
00308   std::string err = "";
00309   try {
00310     lfnct->Evaluate();
00311   } catch(faudes::Exception ex)  {
00312     err = ex.What();
00313   }
00314   // done
00315   delete lfnct;
00316   return err;
00317 }
00318 
00319 // install myself to a lua state
00320 void LuaFunctionDefinition::Install(LuaState* pL) const {
00321   if(!pL) pL=DefaultL();
00322   Install(pL->LL());
00323 }
00324 
00325 // install myself to a lua state
00326 void LuaFunctionDefinition::Install(lua_State* pLL) const {
00327   FD_DLB("LuaFunctionDefinition::Install(): " << Name());
00328 
00329   // bail out if no signature (it's a DESTool plain script)
00330   if(VariantsSize()==0) {
00331     FD_DLB("LuaFunctionDefinition::Install(): no signatures for fnct " << Name());
00332     return;
00333   }
00334 
00335   // function name (ctype overwrites name)
00336   std::string lfname = Name();  
00337   if(CType()!="") {
00338     size_t pos=CType().find("faudes::");
00339     if(pos!=std::string::npos) 
00340     lfname=CType().substr(std::string("faudes::").length());
00341   }
00342 
00343   // parse signatures, test consistence
00344   std::vector< std::string > lffnct;                          //fnct names
00345   std::vector< int > lfparcnt;                                // # actual parameters
00346   std::vector< std::vector<std::string> > lfparams;           // par names
00347   std::vector< std::vector<Parameter::ParamAttr> > lfattrib;  // par access
00348   std::vector< std::vector<bool> > lfretval;                  // actual return value
00349   std::vector< std::vector<bool> > lfparval;                  // actual parameter
00350   lffnct.resize(VariantsSize());
00351   lfparcnt.resize(VariantsSize());
00352   lfparams.resize(VariantsSize());
00353   lfattrib.resize(VariantsSize());
00354   lfretval.resize(VariantsSize());
00355   lfparval.resize(VariantsSize());
00356   for(int i=0; i<VariantsSize(); i++) {
00357     const Signature& sigi=Variant(i);
00358     int parcnt=0;
00359     for(int j=0; j<sigi.Size(); j++) {
00360       // retrieve faudes type and attrib
00361       std::string ftype=sigi.At(j).Type();
00362       Parameter::ParamAttr fattr=sigi.At(j).Attribute();
00363       // autodefault creturn flag
00364       bool fcret=false;
00365       if(fattr==Parameter::Out) fcret=true;
00366       if(fattr==Parameter::InOut) fcret=true;
00367       // get creturn from signature for non-elementary
00368       if(ftype!="Boolean")
00369       if(ftype!="Integer")
00370       if(ftype!="String")
00371          fcret=sigi.At(j).CReturn();  
00372       // bail out on non-out ret value
00373       if(fcret)
00374       if((fattr!=Parameter::Out) && (fattr!=Parameter::InOut)) 
00375         break;
00376       // bail out on unknown faudestype
00377       if(ftype!="Boolean")
00378       if(ftype!="Integer")
00379       if(ftype!="String")
00380       if(!TypeRegistry::G()->Exists(ftype)) 
00381         break;
00382       // figure and count actual parameters
00383       bool fcpar=true;
00384       if(fcret && fattr==Parameter::Out) fcpar=false;
00385       if(fcpar) parcnt++;
00386       // bail out on undef attribute
00387       if(fattr==Parameter::UnDef) break;
00388       // param ok
00389       lfparams.at(i).push_back(ftype);
00390       lfattrib.at(i).push_back(fattr);
00391       lfretval.at(i).push_back(fcret);
00392       lfparval.at(i).push_back(fcpar);
00393     } 
00394     // test for signature error
00395     if((int) lfparams.at(i).size()!=sigi.Size()) {
00396       FD_WARN("LuaFunctionDefinition::Install(): cannot interpret signature \"" << sigi.Name() << "\"");
00397       lffnct.resize(i);
00398       break;
00399     }
00400     // record function name
00401     lffnct.at(i)=MangleString(sigi.Name()); 
00402     lfparcnt.at(i)=parcnt;
00403   }
00404   FD_DLB("LuaFunctionDefinition::Install(): #" << lffnct.size() << " valid signatures");
00405 
00406   // todo: filter out doublets as in rti2code
00407   // prepare lua code for signature dispatch 
00408   std::vector< std::string > lftest1;
00409   std::vector< std::string > lftest2;
00410   std::vector< std::string > lfcall;
00411   std::vector< std::string > lfsig;
00412   for(unsigned int i=0; i<lffnct.size(); i++) {
00413     // create type conditional, part1: lua types
00414     std::string test1="(arg['n']==" + ToStringInteger(lfparcnt.at(i)) + ")" ;    
00415     unsigned int pj=0;    
00416     for(unsigned int j=0; j<lfparams.at(i).size(); j++) {
00417       if(!lfparval.at(i).at(j)) continue;
00418       pj++;
00419       test1=test1+" and ";
00420       std::string ltype="userdata";
00421       if(lfparams.at(i).at(j) == "Integer") ltype="number";
00422       if(lfparams.at(i).at(j) == "Boolean") ltype="bool";
00423       if(lfparams.at(i).at(j) == "String") ltype="string";
00424       test1=test1 + "(type(arg[" + ToStringInteger(pj) + "])=='" + ltype + "')";
00425     }
00426     lftest1.push_back(test1);
00427     // create type conditional, part2: faudes types
00428     std::string test2="";
00429     pj=0;    
00430     for(unsigned int j=0; j<lfparams.at(i).size(); j++) {
00431       if(!lfparval.at(i).at(j)) continue;
00432       pj++;
00433       if(lfparams.at(i).at(j) == "Integer") continue;
00434       if(lfparams.at(i).at(j) == "Boolean") continue;
00435       if(lfparams.at(i).at(j) == "String") continue;
00436       if(test2.size()>0) test2=test2+" and ";
00437       test2=test2 + "faudes.TypeTest(\"" + lfparams.at(i).at(j) + "\", arg[" + ToStringInteger(pj) + "])";
00438     }
00439     lftest2.push_back(test2);
00440     // create function call
00441     std::string call= lffnct.at(i) + "(";
00442     pj=0;
00443     for(unsigned int j=0; j<lfparams.at(i).size(); j++) {
00444       if(!lfparval.at(i).at(j)) continue;
00445       pj++;
00446       if(pj>1) call = call + ", ";
00447       call = call + "arg[" + ToStringInteger(pj) + "]";
00448     }
00449     call = call + ")";
00450     lfcall.push_back(call);
00451     // create nice signature. note: this should match the respective code in rti2code.cpp
00452     std::string nsig = " " + lfname + "(";
00453     bool leftcomma = false;
00454     bool rightcomma = false;
00455     for(unsigned int j=0; j<lfparams.at(i).size(); j++) {
00456       // return value
00457       if(lfretval.at(i).at(j)) {
00458         if(leftcomma) nsig = "," + nsig;
00459   nsig=lfparams.at(i).at(j) + nsig;
00460         leftcomma=true;
00461       }
00462       // parameter value
00463       if(lfparval.at(i).at(j)) {
00464         if(rightcomma) nsig += ", ";
00465         const Signature& sigi=Variant(i);
00466         nsig += sigi.At(j).Str();
00467         rightcomma=true;
00468       }
00469     }  
00470     nsig+=")";
00471     lfsig.push_back(nsig);
00472   }
00473  
00474   // add to help system
00475   if(TextDoc()!="") {
00476     for(unsigned int i=0; i< lfsig.size(); i++) {
00477       std::string topic= PlugIn();
00478       std::string key1=  KeywordAt(1);
00479       if(topic.length()>0) topic.at(0)=toupper(topic.at(0));
00480       if(key1.length()>0) key1.at(0)=toupper(key1.at(0));
00481       luafaudes_dict_insert_entry(topic,key1,lfsig.at(i));
00482     }
00483   }
00484 
00485 
00486   // set up wrapper frunction
00487   std::stringstream lfwrap;
00488   //lfwrap << "-- LuaFunctionDefinition.Install() " << Name() << std::endl;
00489   //lfwrap << std::endl;
00490   lfwrap << LuaCode();
00491   //lfwrap << std::endl;
00492   lfwrap << std::endl;
00493   //lfwrap << "-- LuaFunctionDefinition.Install(): dispatch / typecheck" << std::endl;
00494   lfwrap << "function faudes." << lfname << "(...)" << std::endl;
00495   for(unsigned int i=0; i< lftest1.size(); i++) {
00496     lfwrap << "  if (" << lftest1.at(i) << ") then " << std::endl;
00497     lfwrap << "  if (" << lftest2.at(i) << ") then " << std::endl;
00498     lfwrap << "    return faudes." << lfcall.at(i) << std::endl;
00499     lfwrap << "  end" << std::endl;
00500     lfwrap << "  end" << std::endl;
00501   }
00502   lfwrap << "  faudes.Error([[" << lfname << ": parameter mismatch: expected signature(s): " << std::endl;
00503   for(unsigned int i=0; i< lfsig.size(); i++) {
00504     lfwrap << lfsig.at(i) << std::endl;
00505   }
00506   lfwrap << "]])" << std::endl;
00507   lfwrap << "end" << std::endl;
00508 
00509 
00510   // debugging report
00511   //FD_WARN("LuaFunctionDefinition:Install(): code:" << std::endl << lfwrap.str());
00512   FD_DLB("LuaFunctionDefinition:Install(): code: done");
00513 
00514   // finally install (aka run) the wrapper
00515   int errexec=luaL_dostring(pLL,lfwrap.str().c_str());  
00516   if(errexec!=0) {
00517     std::string lerr= std::string(lua_tostring(pLL, -1));
00518     int c1 = lerr.find_first_of(':');
00519     if(c1<0) c1=0;
00520     int c2 = lerr.find_first_of(':',c1+1);
00521     if(c2<0) c2=1;
00522     std::string line = lerr.substr(c1+1,c2-c1-1);  
00523     if(c2>1) {
00524       lerr="error in Lua script: line " + line + ": " + lerr.substr(c2+2);
00525     }
00526     throw Exception("LuaFunctionDefinition::Install(): " + Name(), lerr, 49);
00527   }
00528 }
00529 
00530 // token io
00531 void LuaFunctionDefinition::DoRead(TokenReader& rTr,  const std::string& rLabel, const Type* pContext) {
00532   FD_DLB("LuaFunctionDefinition::DoRead()");
00533   // ignore
00534   (void) pContext;
00535   // label
00536   std::string label=rLabel;
00537   if(label=="") label="LuaFunctionDefinition";
00538   // base can handle this
00539   FunctionDefinition::DoRead(rTr,label,pContext);
00540   // report
00541   FD_DLB("LuaFunctionDefinition::DoRead(): done " << mPlugIn << "::" << mName);
00542 }
00543 
00544 
00545 // register all definitions froma file with the function registry
00546 void LuaFunctionDefinition::Register(const std::string& rFilename) {
00547   FD_DLB("LuaFunctionDefinition::Register(): file " << rFilename);
00548   TokenReader tr(rFilename);
00549   Token token;
00550   while(tr.Peek(token)) {
00551     if(!token.IsBegin("LuaFunctionDefinition")) {
00552       tr.Get(token);
00553       continue;
00554     }
00555     LuaFunctionDefinition*  plfd = new LuaFunctionDefinition();
00556     plfd->Read(tr);
00557     FD_DLB("LuaFunctionDefinition::Register(): found " << plfd->Name());
00558     if(FunctionRegistry::G()->Exists(plfd->Name())) {
00559       FD_DLB("LuaFunctionDefinition::Register(): skipping doublet " << plfd->Name());
00560       delete plfd;
00561       continue;
00562     }
00563     // Registry takes ownership
00564     FunctionRegistry::G()->Insert(plfd);
00565   }
00566 }
00567 
00568 
00569 // token io
00570 void LuaFunctionDefinition::DoReadCore(TokenReader& rTr) {
00571   FD_DLB("LuaFunctionDefinition::DoReadCore()");
00572   // call base
00573   FunctionDefinition::DoReadCore(rTr);  
00574   // read my members
00575   Token token;
00576   rTr.Peek(token);
00577   // case a: embedded lua code
00578   if(token.IsBegin())
00579   if(token.StringValue()=="LuaCode") {
00580     mLuaFile="";
00581     mLuaCode="";
00582     rTr.ReadBegin("LuaCode");
00583     Token code;
00584     while(rTr.Peek(code)) {
00585       if(!code.IsString()) break;
00586       rTr.Get(code);
00587       mLuaCode.append(code.StringValue());
00588     }
00589     rTr.ReadEnd("LuaCode");
00590   }
00591   // case b: lua file
00592   if(token.IsBegin())
00593   if(token.StringValue()=="LuaFile") {
00594     rTr.ReadBegin("LuaFile");
00595     std::string mLuaFile=rTr.ReadString();
00596     // todo: read that file
00597     rTr.ReadEnd("LuaFile");
00598   }
00599 }
00600 
00601 
00602 // token io
00603 void LuaFunctionDefinition::DoWrite(TokenWriter& rTw,  const std::string& rLabel, const Type* pContext) const {
00604    // label
00605   std::string label=rLabel;
00606   if(label=="") label="LuaFunctionDefinition";
00607   // base can handle
00608   Documentation::DoWrite(rTw,label,pContext); 
00609 }
00610 
00611 // token io
00612 void LuaFunctionDefinition::DoWriteCore(TokenWriter& rTw) const {
00613   FD_DLB("LuaFunctionDefinition::DoWriteCore(): file " << rTw.FileName());
00614   // call base core
00615   FunctionDefinition::DoWriteCore(rTw);  
00616   // case a: embedded code
00617   if(mLuaFile=="") {
00618     rTw.WriteBegin("LuaCode");
00619     rTw.WriteVerbatim(mLuaCode);
00620     rTw.WriteEnd("LuaCode");
00621   }
00622   // case a: embedded code
00623   if(mLuaFile!="") {
00624     rTw.WriteBegin("LuaFile");
00625     rTw.WriteString(mLuaFile);
00626     rTw.WriteEnd("LuaFile");
00627     // todo: write that file
00628   }
00629 }
00630 
00631 /*
00632 ********************************************************************
00633 ********************************************************************
00634 ********************************************************************
00635 
00636 Implementation of class LuaFunction
00637 
00638 ********************************************************************
00639 ********************************************************************
00640 ********************************************************************
00641 */
00642 
00643 // Constructor 
00644 LuaFunction::LuaFunction(const LuaFunctionDefinition* fdef) : 
00645   Function(fdef),
00646   pLuaFuncDef(fdef),
00647   pL(0),
00648   pLL(0)
00649 {
00650   FD_DLB("LuaFunction::LuaFunction(): fdef  " << pFuncDef);
00651 }
00652 
00653 // new on heap
00654 LuaFunction* LuaFunction::New(void) const {
00655   return new LuaFunction(pLuaFuncDef);
00656 }
00657 
00658 // set function definition
00659 void LuaFunction::Definition(const FunctionDefinition* fdef) {
00660   // cast and pass to base
00661   pLuaFuncDef = dynamic_cast<const LuaFunctionDefinition*>(fdef);
00662   Function::Definition(pLuaFuncDef);
00663 }
00664 
00665 // get function definition
00666 const LuaFunctionDefinition* LuaFunction::Definition(void) const {
00667   return pLuaFuncDef;
00668 }
00669 
00670 // set variant signature (accept -1)
00671 void LuaFunction::DoVariant(int n) {
00672   // std case by base 
00673   if(n!=-1) {
00674     Function::DoVariant(n);
00675     return;
00676   }
00677   // special case -1
00678   mVariantIndex=-1;
00679   mParameterValues.clear(); 
00680 }
00681 
00682 
00683 // implement typecheck
00684 bool LuaFunction::DoTypeCheck(int n) {
00685   FD_DLB("LuaFunction::DoTypeCheck("<< n << "): for " << Variant()->At(n).Type());
00686   const Type* proto = TypeRegistry::G()->Prototype(Variant()->At(n).Type()); 
00687   if(!proto) {
00688     FD_DLB("LuaFunction::DoTypeCheck("<< n << "): unknown type");
00689     return false;
00690   }
00691   if(!proto->Cast(ParamValue(n))) {
00692     FD_DLB("LuaFunction::DoTypeCheck("<< n << "): could not cast param value");
00693     return false;
00694   }
00695   return true;
00696 }
00697 
00698 
00699 // get/set lua state
00700 LuaState* LuaFunction::L(void) {
00701   if(!pL) pL=Definition()->DefaultL();
00702   return pL;
00703 }
00704 
00705 // get/set default lua state
00706 void LuaFunction::L(LuaState* l) {
00707  pL=l;
00708 }
00709 
00710 
00711 // implement execute: run stages
00712 void LuaFunction::DoExecute(void) {
00713   FD_DLB("LuaFunction::DoExecute()");
00714   /*
00715   for(int i=0; i< Variant()->Size(); i++) {
00716     FD_DLB("LuaFunction::DoExecute(): value at #" << i);
00717     ParamValue(i)->Write();
00718   }
00719   */
00720   // use the global state
00721   if(!pL) pL=L();
00722   pLL=pL->LL();
00723   mEntryStack=lua_gettop(pLL);
00724   // run stages
00725   DoExecuteA();
00726   DoExecuteB();
00727   DoExecuteC();
00728   DoExecuteD();
00729   DoExecuteE();
00730   // done
00731   lua_settop(pLL,mEntryStack);
00732   FD_DLB("LuaFunction::DoExecute(): done");
00733 }
00734 
00735 // implement execute: syntaxcheck
00736 void LuaFunction::SyntaxCheck(void) {
00737   FD_DLB("LuaFunction::SyntaxCheck()");
00738   if(!Variant()) {
00739     std::stringstream errstr;
00740     errstr << "no valid variant";
00741     throw Exception("LuaFunction::Syntaxcheck()", errstr.str(), 47);
00742   }
00743   // use the global state
00744   if(!pL) pL=L();
00745   pLL=pL->LL();
00746   mEntryStack=lua_gettop(pLL);
00747   // run stages
00748   DoExecuteA();
00749   DoExecuteB();
00750   // done
00751   lua_settop(pLL,mEntryStack);
00752   FD_DLB("LuaFunction::SyntaxCheck(): done");
00753 }
00754 
00755 // implement execute: plain evaluation
00756 void LuaFunction::Evaluate(void) {
00757   FD_DLB("LuaFunction::SyntaxCheck()");
00758   // use the global state
00759   if(!pL) pL=L();
00760   pLL=pL->LL();
00761   mEntryStack=lua_gettop(pLL);
00762   // run stages
00763   DoExecuteA();
00764   // done
00765   lua_settop(pLL,mEntryStack);
00766   FD_DLB("LuaFunction::SyntaxCheck(): done");
00767 }
00768 
00769 // implement execute: run lua code i.e. define lua functions
00770 void LuaFunction::DoExecuteA(void) {
00771   FD_DLB("LuaFunction::DoExecuteA()");
00772   // Lua stack: empty
00773   // load my script 
00774   const char* script = pLuaFuncDef->LuaCode().c_str();
00775   int script_len = pLuaFuncDef->LuaCode().size();
00776   int errload=luaL_loadbuffer(pLL, script, script_len, "luafaudes");
00777   if(errload!=0) {
00778     std::string lerr= std::string(lua_tostring(pLL, -1));
00779     int c1 = lerr.find_first_of(':');
00780     if(c1<0) c1=0;
00781     int c2 = lerr.find_first_of(':',c1+1);
00782     if(c2<0) c2=1;
00783     std::string line = lerr.substr(c1+1,c2-c1-1);  
00784     if(c2>1) {
00785       lerr="error in Lua script: line " + line + ": " + lerr.substr(c2+2);
00786     }
00787     lua_settop(pLL,mEntryStack);
00788     throw Exception("LuaFunction::DoExecuteA()", lerr, 49);
00789   }
00790   // Lua stack: script
00791   // install all functions aka run the script
00792   int errrun=lua_pcall(pLL, 0, 0, 0); 
00793   if(errrun!=0) {
00794     std::stringstream errstr;
00795     errstr << "failed to run script: ";
00796     errstr << std::string(lua_tostring(pLL, -1));
00797     lua_settop(pLL,mEntryStack);
00798     throw Exception("LuaFunction::DoExecuteA()", errstr.str(), 49);
00799   }
00800   // stack: []
00801 }
00802 
00803 // implement execute: find the function of this variant
00804 void LuaFunction::DoExecuteB(void) {
00805   FD_DLB("LuaFunction::DoExecuteB()");
00806   // Lua stack: empty
00807   // get the swig generated table of faudes functions
00808   lua_getglobal(pLL,"faudes");
00809   mFtable=lua_gettop(pLL);
00810   if(!lua_istable(pLL,-1)) {
00811     lua_settop(pLL,mEntryStack);
00812     throw Exception("LuaFunction::DoExecuteB()", "failed to load faudes table", 49);
00813   }
00814   // stack: [faudes]
00815   // find my function: look up in faudes name space ...
00816   std::string fname = MangleString(Variant()->Name());
00817   lua_pushstring(pLL,fname.c_str());
00818   lua_gettable(pLL,mFtable);
00819   if(!lua_isfunction(pLL,-1)) {
00820     lua_pop(pLL, 1); // pop nil.
00821     lua_getglobal(pLL,fname.c_str()); // ... or as global (compatibility with pre 2.19)
00822     if(!lua_isfunction(pLL,-1)) {
00823       std::stringstream errstr;
00824       errstr << "missing function \"" << fname << "\"";
00825       lua_settop(pLL,mEntryStack);
00826       throw Exception("LuaFunction::DoExecuteB()", errstr.str(), 49);
00827     }
00828   }
00829   // stack: [faudes, luafnct]
00830   // construct a plain Type usrdata 
00831   lua_pushstring(pLL,"Type");
00832   lua_gettable(pLL,mFtable);
00833   if(!lua_isfunction(pLL,-1)) {
00834     lua_settop(pLL,mEntryStack);
00835     throw Exception("LuaFunction::DoExecuteB():", "failed to construct plain Type (1)", 49);
00836   }
00837   // stack: [faudes, luafnct, Type constructor]
00838   if(lua_pcall(pLL, 0, 1, 0) != 0) { 
00839     lua_settop(pLL,mEntryStack);
00840     throw Exception("LuaFunction::DoExecuteB():", "failed to construct plain Type (2)", 49);
00841   }
00842   // stack: [faudes, luafnct, Type variable]
00843   swig_lua_userdata* susr = (swig_lua_userdata*) lua_touserdata (pLL, -1);
00844   if(!susr) {
00845     lua_settop(pLL,mEntryStack);
00846     throw Exception("LuaFunction::DoExecuteB():", "failed to construct plain Type (3)", 49);
00847   }
00848   FD_DLB("LuaFunction::DoExecuteB(): plain type is " << susr->type->name);
00849   // record swig type of faudes plain Type
00850   mFType=susr->type;
00851   lua_pop(pLL, 1); 
00852   // stack: [faudes, luafnct]
00853 }
00854 
00855 
00856 
00857 // implement execute: prepare parameters
00858 void LuaFunction::DoExecuteC(void) {
00859   FD_DLB("LuaFunction::DoExecuteC()");
00860   // stack: [faudes, luafnct]
00861   // interpret signature
00862   mLReturn.resize(Variant()->Size());
00863   mLParameter.resize(Variant()->Size());
00864   mLReturnCount=0;
00865   mLParameterCount=0;
00866   for(int i=0; i< Variant()->Size(); i++) {
00867     const std::string& ftype= Variant()->At(i).Type();
00868     // default: parameter except for explicit creturn && out
00869     mLParameter.at(i)= !(Variant()->At(i).CReturn() && (Variant()->At(i).Attribute()==Parameter::Out));
00870     // default: explicitly declared creturn 
00871     mLReturn.at(i)= Variant()->At(i).CReturn();
00872     // autofix elementary parameters 
00873     if((ftype=="Integer") || (ftype=="Boolean") || (ftype=="String")) {
00874       // ... out becomes return value only
00875       if(Variant()->At(i).Attribute()==Parameter::Out) {
00876         mLReturn.at(i)=true;
00877         mLParameter.at(i)=false;
00878       }
00879       // ... inout becomes return value and parameter
00880       if(Variant()->At(i).Attribute()==Parameter::InOut) {
00881         mLReturn.at(i)=true;
00882         mLParameter.at(i)=true;
00883       }
00884       // ... in becomes parameter only
00885       if(Variant()->At(i).Attribute()==Parameter::In) {
00886         mLReturn.at(i)=false;
00887         mLParameter.at(i)=true;
00888       }
00889     }
00890     // keep counts
00891     if(mLReturn.at(i)) mLReturnCount++;
00892     if(mLParameter.at(i)) mLParameterCount++;
00893   }
00894 
00895   FD_DLB("LuaFunction::DoExecuteC(): found " << mLReturnCount << " return values and " 
00896    << mLParameterCount << " parameters");
00897   // stack: [faudes, luafnct]
00898   // construct my parameters in Lua
00899   for(int i=0; i< Variant()->Size(); i++) {
00900     const std::string& ftype= Variant()->At(i).Type();
00901     // skip non-parameter 
00902     if(!mLParameter.at(i)) {
00903       FD_DLB("LuaFunction::DoExecuteC(): skip nonparameter value pos " << i);
00904       continue;
00905     }
00906     // special case: int as lua number
00907     if(ftype=="Integer") {
00908       lua_pushnumber(pLL,((Integer*)ParamValue(i))->CValue());
00909       FD_DLB("LuaFunction::DoExecuteC(): created ftype " << ftype);
00910       continue;
00911     }
00912     // special case: bool as lua bool
00913     if(ftype=="Boolean") {
00914       lua_pushboolean(pLL,((Boolean*)ParamValue(i))->CValue());
00915       FD_DLB("LuaFunction::DoExecuteC(): created ftype " << ftype);
00916       continue;
00917     }
00918     // special case: str as lua string
00919     if(ftype=="String") {
00920       lua_pushstring(pLL,((String*)ParamValue(i))->CValue().c_str());
00921       FD_DLB("LuaFunction::DoExecuteC(): created ftype " << ftype);
00922       continue;
00923     }
00924     // std case: faudes type: construct 1
00925     lua_pushstring(pLL,ftype.c_str());
00926     lua_gettable(pLL,mFtable);
00927     if(!lua_isfunction(pLL,-1)) {
00928       std::stringstream errstr;
00929       errstr << "failed to load constructor for \"" << ftype << "\"";
00930       lua_settop(pLL,mEntryStack);
00931       throw Exception("LuaFunction::DoExecuteC()", errstr.str(), 49);
00932     }
00933     // std case: faudes type: construct 2
00934     if(lua_pcall(pLL, 0, 1, 0) != 0) { 
00935       std::stringstream errstr;
00936       errstr << "failed to construct for \"" << ftype << "\" (1)";
00937       lua_settop(pLL,mEntryStack);
00938       throw Exception("LuaFunction::DoExecuteC()", errstr.str(), 49);
00939     }
00940     // std case: test user data pointer
00941     swig_lua_userdata* susr = (swig_lua_userdata*) lua_touserdata (pLL, -1);
00942     if(!susr) {
00943       std::stringstream errstr;
00944       errstr << "failed to construct for\"" << ftype << "\" (2)";
00945       lua_settop(pLL,mEntryStack);
00946       throw Exception("LuaFunction::DoExecuteB()", errstr.str(), 49);
00947     }
00948     // inspect stack 
00949     FD_DLB("LuaFunction::DoExecuteC(): created stype " << susr->type->name << " for ftype " << ftype);
00950     FD_DLB("LuaFunction::DoExecuteC(): faudes parameter at " << ParamValue(i));
00951     FD_DLB("LuaFunction::DoExecuteC(): swig usrdata ptr  " << susr->ptr);
00952     FD_DLB("LuaFunction::DoExecuteC(): swig usrdata own flag  " << susr->own);
00953     /*
00954     // variant a: copy parameter value
00955     void* fptr=SwigCastPtr(susr->ptr,susr->type,(swig_type_info*)mFType);
00956     FD_DLB("LuaFunction::DoExecuteB(): faudes::Type converted ptr " << fptr);
00957     if(Variant()->At(i).Attribute()!=Parameter::Out) {
00958       FD_DLB("LuaFunction::DoExecuteB(): copy parameter value");
00959       ((Type*)fptr)->Assign(*ParamValue(i));
00960     }
00961     */
00962     // variant b: use references
00963     if(susr->own) free(susr->ptr);
00964     susr->own=0;
00965     susr->ptr = dynamic_cast<void*>(ParamValue(i)); // dynamic-up-cast: needed for multiple inheritance (!!)
00966   }
00967   // stack: [faudes, luafnct, rp_1 ... rp_n]
00968   FD_DLB("LuaFunction::DoExecuteC(): done");
00969 }
00970 
00971 // implement execute: execute the function
00972 void LuaFunction::DoExecuteD(void) {
00973   FD_DLB("LuaFunction::DoExecuteD()");
00974   // stack: [faudes, luafnct, rp_1 ... rp_n]
00975   // duplicate all my parameters (incl. the actual function for convenience)
00976   // note: needed only for variant a to retrieve values of faudes typed parameters 
00977   // note: duplication is cheap since these are references
00978   int t1=lua_gettop(pLL)-mLParameterCount;
00979   int t2=lua_gettop(pLL);
00980   for(int i= t1; i<=t2; i++) {
00981     lua_pushvalue(pLL,i);
00982 #ifdef  FAUDES_DEBUG_LUABINDINGS
00983     // report user data
00984     swig_lua_userdata* susr = (swig_lua_userdata*) lua_touserdata (pLL, -1);
00985     if(!susr) continue;
00986     // inspect user data stack 
00987     FD_DLB("LuaFunction::DoExecuteD(): inspect stype " << susr->type->name);
00988     FD_DLB("LuaFunction::DoExecuteD(): swig usrdata ptr  " << susr->ptr);
00989     FD_DLB("LuaFunction::DoExecuteD(): swig usrdata own flag  " << susr->own);
00990     void* fptr=SwigCastPtr(susr->ptr,susr->type,(swig_type_info*)mFType);
00991     FD_DLB("LuaFunction::DoExecuteD(): faudes::Type converted ptr " << fptr);
00992 #endif
00993   }
00994   // stack: [faudes, luafnct, rp_1 ... rp_n, luafnct, rp_1 ... rp_n]
00995   // run my function
00996   if(lua_pcall(pLL, mLParameterCount, mLReturnCount, 0) != 0) { 
00997     FD_DLB("LuaFunction::DoExecuteD(): detect error");
00998     std::string lerr= std::string(lua_tostring(pLL, -1));
00999     // user request via loopback exception
01000     if(lerr.find("break on application request")!=std::string::npos) {
01001       lerr="break on application request";
01002     }
01003     // user request via explicit exception
01004     else if(lerr.find("luafaudes script:")!=std::string::npos) {
01005       std::size_t c1=lerr.find("luafaudes script:");
01006       lerr=lerr.substr(c1);
01007     }
01008     // have line number ?
01009     else if(lerr.size()>=2) {
01010       std::size_t c1 = lerr.find_first_of(':');
01011       if(c1==std::string::npos) c1=0;
01012       if(c1+1>=lerr.size()) c1=0;
01013       std::size_t c2 = lerr.find_first_of(':',c1+1);
01014       if(c2==std::string::npos) c2=c1+1;
01015       if(c2>c1+1) {
01016         std::string line = lerr.substr(c1+1,c2-c1-1);  
01017         lerr="error in Lua script: line " + line + ": " + lerr.substr(c2+2);
01018       }
01019     }
01020     // anyway: fix stack
01021     lua_settop(pLL,mEntryStack);
01022     throw Exception("LuaFunction::DoExecuteD()", lerr, 49);
01023   }
01024   FD_DLB("LuaFunction::DoExecuteD():done ");
01025   // stack: [faudes, luafnct, rp_1 ... rp_n, lp1 ... lpm]
01026 }
01027 
01028 // implement execute: retrieve results
01029 void LuaFunction::DoExecuteE(void) {
01030   FD_DLB("LuaFunction::DoExecuteE()");
01031   // stack: [faudes, luafnct, rp_1 ... rp_n, lp1 ... lpm]
01032   // retrieve results from stack: return values
01033   for(int i=Variant()->Size()-1; i>=0; i--) {
01034     // skip non-return values
01035     if(!mLReturn.at(i)) continue;
01036     // switch on ftype
01037     const std::string& ftype= Variant()->At(i).Type();
01038     // int as lua number
01039     if(ftype=="Integer" && lua_isnumber(pLL,-1)) {
01040       FD_DLB("LuaFunction::DoExecuteE(): retrieve type " << ftype);
01041       ((Integer*)ParamValue(i))->CValue(lua_tonumber(pLL,-1));
01042       lua_pop(pLL, 1); 
01043       continue;
01044     }
01045     // bool as lua bool
01046     if(ftype=="Boolean" && lua_isboolean(pLL,-1)) {
01047       ((Boolean*)ParamValue(i))->CValue(lua_toboolean(pLL,-1));
01048       FD_DLB("LuaFunction::DoExecuteE(): retrieved type " << ftype);
01049       lua_pop(pLL, 1); 
01050       continue;
01051     }
01052     // str as lua string
01053     if(ftype=="String" && lua_isstring(pLL,-1)) {
01054       ((String*)ParamValue(i))->CValue(lua_tostring(pLL,-1));
01055       FD_DLB("LuaFunction::DoExecuteE(): retrieved type " << ftype);
01056       lua_pop(pLL, 1); 
01057       continue;
01058     }
01059     // report error
01060     std::stringstream errstr;
01061     errstr << "invalid return values in \"" << Variant()->Name() << "\"";
01062     lua_settop(pLL,mEntryStack);
01063     throw Exception("LuaFunction::DoExecuteE()", errstr.str(), 49);
01064   }
01065 
01066   // stack: [faudes, luafnct, rp_1 ... rp_n]
01067 
01068   /*
01069   // variant a: need to copy results
01070 
01071   // retrieve results from stack: duplicate references to parameters
01072   for(int i=Variant()->Size()-1; i>=0; i--) {
01073     // skip return values
01074     if(mLReturn.at(i)) continue;
01075     // switch on type type
01076     const std::string& ftype= Variant()->At(i).Type();
01077     // discrad/ignore duplicate parameters with access In
01078     if(Variant()->At(i).Attribute()==Parameter::In) {
01079       FD_DLB("LuaFunction::DoExecuteD(): ignore in-paremeter of type " << ftype);
01080       lua_pop(pLL, 1); 
01081       continue;
01082     }
01083     // discrad/ignore elementary types (lua call by value)
01084     if((ftype=="Integer") || (ftype=="Boolean") || (ftype=="String")) {
01085       FD_DLB("LuaFunction::DoExecuteD(): ignore elementary type parameter " << ftype);
01086       lua_pop(pLL, 1); 
01087       continue;
01088     }
01089     // std case: get updated value
01090     if(lua_isuserdata(pLL,-1)) {
01091       FD_DLB("LuaFunction::DoExecuteD(): try to retrieve type " << ftype);
01092       swig_lua_userdata* susr = (swig_lua_userdata*) lua_touserdata(pLL, -1);
01093       if(susr) {
01094         FD_DLB("LuaFunction::DoExecuteD(): found swig type " << susr->type->name << " at " << susr->ptr);
01095         FD_DLB("LuaFunction::DoExecuteD(): swig usrdata ptr " << susr->ptr);
01096         FD_DLB("LuaFunction::DoExecuteD(): swig usrdata own flag " << susr->own);
01097         void* fptr=SwigCastPtr(susr->ptr,susr->type,(swig_type_info*)mFType);
01098         FD_DLB("LuaFunction::DoExecuteD(): swig usrdata ptr faudes::Type converted " << fptr);
01099         FD_DLB("LuaFunction::DoExecuteD(): parameter value " << ParamValue(i));
01100         FD_DLB("LuaFunction::DoExecuteD(): copy parameter value");
01101         ParamValue(i)->Assign(*((Type*)fptr));
01102         // pop
01103         lua_pop(pLL, 1); 
01104         continue;
01105       }
01106     }
01107 
01108   */
01109 
01110   // variant b: discard duplicate parameters (did not need them for variant b anyway)
01111   for(int i=Variant()->Size()-1; i>=0; i--) {
01112     if(mLReturn.at(i)) continue;
01113     lua_pop(pLL, 1); 
01114   }
01115 
01116 } 
01117 
01118 
01119 
01120 /*
01121 ********************************************************************
01122 ********************************************************************
01123 ********************************************************************
01124 
01125 LuaState implementation
01126 
01127 ********************************************************************
01128 ********************************************************************
01129 ********************************************************************
01130 */
01131 
01132 // include Mike Pall's completer 
01133 #include "lbp_completion.cpp"
01134 
01135 
01136 // construct/destruct
01137 LuaState::LuaState(void) : mpLL(0) { Open(); }
01138 LuaState::~LuaState(void) { Close(); }   
01139 
01140 //access
01141 lua_State* LuaState::LL(void) { return mpLL; }
01142 
01143 // re-init
01144 void LuaState::Reset(void) { 
01145   // have a new state
01146   Close(); 
01147   Open(); 
01148   // install from function registry
01149   FunctionRegistry::Iterator fit=FunctionRegistry::G()->Begin();
01150   for(;fit!=FunctionRegistry::G()->End(); fit++) {
01151     const LuaFunctionDefinition* lfd=dynamic_cast<const LuaFunctionDefinition*>(fit->second);
01152     if(!lfd) continue;
01153     lfd->Install(mpLL);
01154   }
01155 }
01156 
01157 // install extension
01158 void LuaState::Install(const std::string& rFilename) {
01159   Install(mpLL, rFilename);
01160 }
01161 
01162 // static state (convenience)
01163 LuaState* LuaState::G(void) {
01164   static LuaState* sls=NULL;
01165   if(!sls) sls=new LuaState();
01166   return sls;
01167 }
01168 
01169 // open/close lua state
01170 void LuaState::Open(void) {
01171   Close();
01172   FD_DLB("LuaState::Open()");
01173   mpLL=lua_open();
01174   Initialize(mpLL);
01175   luafaudes_print_register(mpLL);  // todo:  configure this
01176   luafaudes_hook_register(mpLL);   // todo:  configure this
01177   FD_DLB("LuaState::Done()");
01178 }
01179 
01180 // open/close lua state
01181 void LuaState::Close(void) {
01182   if(!mpLL) return;
01183   FD_DLB("LuaState::Close()");
01184   lua_close(mpLL);
01185   mpLL=NULL;
01186 }
01187 
01188 // lua style interface to initialize lua state
01189 void LuaState::Initialize(lua_State* pLL) {
01190   lua_gc(pLL, LUA_GCSTOP, 0);     /* stop collector during initialization */
01191   luaL_openlibs(pLL);             /* open libraries */
01192   luaopen_faudes_allplugins(pLL); /* install my namespace */
01193   lua_gc(pLL, LUA_GCRESTART, 0);  /* restart collector */
01194 }
01195 
01196 
01197 
01198 // convenience function: load all luafunctions defined in a file
01199 void LuaState::Install(lua_State* pLL, const std::string& rFilename) {
01200   FD_DLB("LuaState::Insatll(): file " << rFilename);
01201   TokenReader tr(rFilename);
01202   Token token;
01203   while(tr.Peek(token)) {
01204     // todo: figure title  and ... luafaudes_dict_insert_topic(const std::string& topic, const std::string& text);
01205     if(!token.IsBegin("LuaFunctionDefinition")) {
01206       tr.Get(token);
01207       continue;
01208     }
01209     LuaFunctionDefinition lfd;
01210     lfd.Read(tr);
01211     FD_DLB("LuaState::Install(): found " << lfd.Name());
01212     lfd.Install(pLL);
01213   }
01214 }
01215 
01216 // push a faudes typed object on the stack
01217 void LuaState::Push(const Type* fdata) {
01218   Push(mpLL,fdata);
01219 }
01220 
01221 // push a faudes typed object on the stack
01222 void LuaState::Push(lua_State* pLL, const Type* fdata) {
01223   FD_DLB("LuaFunction::Push()");
01224   int savetop=lua_gettop(pLL);
01225   // stack: []
01226   // get the swig generated table of faudes functions
01227   lua_getglobal(pLL,"faudes");
01228   int ftable=lua_gettop(pLL);
01229   if(!lua_istable(pLL,-1)) {
01230     lua_settop(pLL,savetop);
01231     throw Exception("LuaState::Push()", "failed to load faudes table", 49);
01232   }
01233   // stack: [faudes]
01234   // construct a plain Type usrdata 
01235   lua_pushstring(pLL,"Type");
01236   lua_gettable(pLL,ftable);
01237   if(!lua_isfunction(pLL,-1)) {
01238     lua_settop(pLL,savetop);
01239     throw Exception("LuaState::Push()", "failed to construct plain Type (1)", 49);
01240   }
01241   // stack: [faudes, Type constructor]
01242   if(lua_pcall(pLL, 0, 1, 0) != 0) { 
01243     lua_settop(pLL,savetop);
01244     throw Exception("LuaState::Push()", "failed to construct plain Type (2)", 49);
01245   }
01246   // stack: [faudes, Type variable]
01247   swig_lua_userdata* susr = (swig_lua_userdata*) lua_touserdata (pLL, -1);
01248   if(!susr) {
01249     lua_settop(pLL,savetop);
01250     throw Exception("LuaState::Push()", "failed to construct plain Type (3)", 49);
01251   }
01252   FD_DLB("LuaState::Push(): plain type is " << susr->type->name);
01253   // record swig type of faudes plain Type
01254   swig_type_info* stype =susr->type;
01255   lua_pop(pLL, 1); 
01256   // stack: [faudes]
01257   // construct my data in Lua
01258   const std::string& ftype= FaudesTypeName(*fdata);
01259   // special case: int as lua number
01260   if(ftype=="Integer") {
01261     lua_pushnumber(pLL,((const Integer&)*fdata));
01262     FD_DLB("LuaState::Push(): created ftype " << ftype);
01263   }
01264   // special case: bool as lua bool
01265   else if(ftype=="Boolean") {
01266     lua_pushboolean(pLL,((const Boolean&)*fdata));
01267     FD_DLB("LuaState::Push(): created ftype " << ftype);
01268   }
01269   // special case: str as lua string
01270   else if(ftype=="String") {
01271     lua_pushstring(pLL,((const String&)*fdata).CValue().c_str());
01272     FD_DLB("LuaState::Push(): created ftype " << ftype);
01273   }
01274   // std case: faudes type
01275   else {
01276     // construct 1
01277     lua_pushstring(pLL,ftype.c_str());
01278     lua_gettable(pLL,ftable);
01279     if(!lua_isfunction(pLL,-1)) {
01280       std::stringstream errstr;
01281       errstr << "failed to load constructor for \"" << ftype << "\"";
01282       lua_settop(pLL,savetop);
01283       throw Exception("LuaState::Push()", errstr.str(), 49);
01284     }
01285     // construct 2
01286     if(lua_pcall(pLL, 0, 1, 0) != 0) { 
01287       std::stringstream errstr;
01288       errstr << "failed to construct for \"" << ftype << "\" (1)";
01289       lua_settop(pLL,savetop);
01290       throw Exception("LuaState::Push()", errstr.str(), 49);
01291     }
01292     // test user data pointer
01293     swig_lua_userdata* susr = (swig_lua_userdata*) lua_touserdata (pLL, -1);
01294     if(!susr) {
01295       std::stringstream errstr;
01296       errstr << "failed to construct for\"" << ftype << "\" (2)";
01297       lua_settop(pLL,savetop);
01298       throw Exception("LuaState::Push()", errstr.str(), 49);
01299     }
01300     // inspect stack 
01301     FD_DLB("LuaState::Push(): created stype " << susr->type->name << " for ftype " << ftype);
01302     FD_DLB("LuaState::Push(): faudes parameter at " << ParamValue(i));
01303     FD_DLB("LuaState::Push(): swig usrdata ptr  " << susr->ptr);
01304     FD_DLB("LuaState::Push(): swig usrdata own flag  " << susr->own);
01305     // cast to plain Type
01306     void* fptr=SwigCastPtr(susr->ptr,susr->type,stype);
01307     FD_DLB("LuaState::Push(): faudes plain Type converted ptr " << fptr);
01308     if(!fptr) {
01309       std::stringstream errstr;
01310       errstr << "failed cast from " << ftype;
01311       lua_settop(pLL,savetop);
01312       throw Exception("LuaState::Push()", errstr.str(), 49);
01313     }
01314     ((Type*)fptr)->Assign(*fdata);
01315   }
01316   // stack: [faudes, fdata]
01317   lua_replace(pLL,-2);
01318   FD_DLB("LuaFunction::DoExecuteB(): done");
01319 }
01320 
01321 // pop a faudes typed object from the stack
01322 Type* LuaState::Pop(void) {
01323   return Pop(mpLL);
01324 }
01325 
01326 // pop a faudes typed object from the stack
01327 Type* LuaState::Pop(lua_State* pLL) {
01328   FD_DLB("LuaFunction::Pop()");
01329   int savetop=lua_gettop(pLL);
01330   Type* res=NULL;
01331   // stack: [fobject]
01332   // special cases: integer
01333   if(lua_isnumber(pLL,-1)) {
01334     res= new Integer(lua_tointeger(pLL,-1));
01335     lua_pop(pLL,1);
01336     return res;
01337   }
01338   // special cases: string
01339   if(lua_isstring(pLL,-1)) {
01340     res= new String(lua_tostring(pLL,-1));
01341     lua_pop(pLL,1);
01342     return res;
01343   }
01344   // special cases: string
01345   if(lua_isboolean(pLL,-1)) {
01346     res= new Boolean(lua_toboolean(pLL,-1));
01347     lua_pop(pLL,1);
01348     return res;
01349   }
01350   // stack: [fobject]
01351   // get the swig generated table of faudes functions
01352   lua_getglobal(pLL,"faudes");
01353   int ftable=lua_gettop(pLL);
01354   if(!lua_istable(pLL,-1)) {
01355     lua_settop(pLL,savetop);
01356     throw Exception("LuaState::Pop()", "failed to load faudes table", 49);
01357   }
01358   // stack: [fobject, faudes]
01359   // construct a plain Type usrdata 
01360   lua_pushstring(pLL,"Type");
01361   lua_gettable(pLL,ftable);
01362   if(!lua_isfunction(pLL,-1)) {
01363     lua_settop(pLL,savetop);
01364     throw Exception("LuaState::Pop()", "failed to construct plain Type (1)", 49);
01365   }
01366   // stack: [fobject, faudes, Type constructor]
01367   if(lua_pcall(pLL, 0, 1, 0) != 0) { 
01368     lua_settop(pLL,savetop);
01369     throw Exception("LuaState::Pop()", "failed to construct plain Type (2)", 49);
01370   }
01371   // stack: [fobject, faudes, Type variable]
01372   swig_lua_userdata* susr = (swig_lua_userdata*) lua_touserdata (pLL, -1);
01373   if(!susr) {
01374     lua_settop(pLL,savetop);
01375     throw Exception("LuaState::Pop()", "failed to construct plain Type (3)", 49);
01376   }
01377   FD_DLB("LuaState::Pop(): plain type is " << susr->type->name);
01378   // record swig type of faudes plain Type
01379   swig_type_info* stype =susr->type;
01380   lua_pop(pLL, 2); 
01381   // stack: [fobject]
01382   // test user data pointer 1 (this could be any user data, so we use SwigUserData to test)
01383   susr = SwigUserData(pLL, -1);
01384   if(!susr) {
01385     std::stringstream errstr;
01386     errstr << "unknown data type";
01387     lua_settop(pLL,savetop);
01388     throw Exception("LuaState::Pop()", errstr.str(), 49);
01389   }
01390   // cast to faudes Type
01391   void* fptr=SwigCastPtr(susr->ptr,susr->type,stype);
01392   FD_DLB("LuaState::Pop(): swig  usrdata ptr " << susr->ptr);
01393   FD_DLB("LuaState::Pop(): swig stype " << susr->type->name);
01394   FD_DLB("LuaState::Pop(): faudes::Type converted ptr " << fptr);
01395   if(!fptr) {
01396     std::stringstream errstr;
01397     errstr << "faild to cast stype \"" << susr->type->name << "\" to plain Type";
01398     lua_settop(pLL,savetop);
01399     throw Exception("LuaState::Pop()", errstr.str(), 49);
01400   }
01401   // copy data
01402   res=((Type*)fptr)->Copy();
01403   // stack: [fobject]
01404   lua_pop(pLL,1);
01405   FD_DLB("LuaFunction::Pop(): done");
01406   return res;
01407 }
01408 
01409 // access global variables
01410 Type* LuaState::Global(const std::string& gname, const Type* fdata) {
01411   return Global(mpLL,gname,fdata);
01412 }
01413 
01414 // access global variables
01415 Type* LuaState::Global(lua_State* pLL, const std::string& gname, const Type* fdata) {
01416   // get
01417   if(fdata==NULL) {
01418     lua_getfield(pLL, LUA_GLOBALSINDEX, gname.c_str()); 
01419     return Pop(pLL);
01420   }
01421   // set
01422   else {
01423     Push(pLL,fdata);
01424     lua_setfield(pLL, LUA_GLOBALSINDEX, gname.c_str());   
01425     return 0;
01426   }
01427 }
01428 
01429 
01430 // evaluate a Lua expression
01431 void LuaState::Evaluate(const std::string& expr) {
01432   Evaluate(mpLL,expr);
01433 }
01434 
01435 // evaluate a Lua expression
01436 void LuaState::Evaluate(lua_State* pLL, const std::string& expr) {
01437   FD_DLB("LuaFunction::Evaluate()");
01438 
01439   // record top of stack
01440   int top = lua_gettop(pLL);
01441 
01442   // load
01443   std::string cerr;
01444   if(cerr=="")
01445   if(luaL_loadbuffer(pLL, expr.c_str(), expr.size(), "string")) {
01446     cerr=std::string(lua_tostring(pLL, -1));
01447     lua_pop(pLL, 1);
01448   }
01449 
01450   // evaluate
01451   if(cerr=="")
01452   if(lua_pcall(pLL, 0, LUA_MULTRET, 0)){
01453     cerr=std::string(lua_tostring(pLL, -1));
01454     lua_pop(pLL, 1);
01455   }
01456 
01457   // fix stack (ignore results etc)
01458   lua_settop(pLL,top);
01459   lua_gc(pLL, LUA_GCCOLLECT, 0);
01460 
01461   // throw on error
01462   if(cerr!="") {
01463     lua_settop(pLL,top);
01464     throw Exception("LuaState::Evaluate()", cerr, 49);
01465   }
01466 
01467   return;
01468 }
01469 
01470 
01471 // completion
01472 std::list< std::string > LuaState::Complete(const std::string& word) {
01473   return Complete(mpLL,word);
01474 }
01475 
01476 // evaluate a Lua expression
01477 std::list< std::string >  LuaState::Complete(lua_State* pLL, const std::string& word) {
01478   FD_DLB("LuaFunction::Complete(" << word <<")");
01479   return luafaudes_rl_complete(pLL,word); 
01480 }
01481 
01482 
01483 
01484 } // namespace
01485 

libFAUDES 2.23h --- 2014.04.03 --- c++ api documentaion by doxygen