libFAUDES

Sections

Index

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 /* FAU Discrete Event Systems Library (libfaudes)
00004 
00005 Copyright (C) 2010 Thomas Moor
00006 
00007 This library is free software; you can redistribute it and/or
00008 modify it under the terms of the GNU Lesser General Public
00009 License as published by the Free Software Foundation; either
00010 version 2.1 of the License, or (at your option) any later version.
00011 
00012 This library is distributed in the hope that it will be useful,
00013 but WITHOUT ANY WARRANTY; without even the implied warranty of
00014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015 Lesser General Public License for more details.
00016 
00017 You should have received a copy of the GNU Lesser General Public
00018 License along with this library; if not, write to the Free Software
00019 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA */
00020 
00021 // my header
00022 #include "lbp_function.h"
00023 
00024 // all lua headers, incl luafaudes
00025 #include "libluafaudes.h"
00026 
00027 
00028 
00029 namespace faudes{
00030 
00031 /*
00032 ********************************************************************
00033 ********************************************************************
00034 ********************************************************************
00035 
00036 Implementation of class LuaFunctionDefinition
00037 
00038 ********************************************************************
00039 ********************************************************************
00040 ********************************************************************
00041 */
00042 
00043 // faudes type
00044 FAUDES_TYPE_IMPLEMENTATION(LuaFunctionDefinition,FunctionDefinition)
00045 
00046 // construct
00047 LuaFunctionDefinition::LuaFunctionDefinition(const std::string& name) : 
00048   FunctionDefinition(name) 
00049 {
00050   Prototype(new LuaFunction(0));
00051   FD_DLB("LuaFunctionDefinition::LuaFunctionDefinition("<<this<<"): name   " << name);
00052   FD_DLB("LuaFunctionDefinition::LuaFunctionDefinition("<<this<<"): proto   " << mpFunction);
00053   FD_DLB("LuaFunctionDefinition::LuaFunctionDefinition("<<this<<"): has def " << mpFunction->Definition());
00054 }
00055 
00056 // copy construct
00057 LuaFunctionDefinition::LuaFunctionDefinition(const LuaFunctionDefinition& rSrc) : 
00058   FunctionDefinition(rSrc.Name())
00059 {
00060   FD_DLB("LuaFunctionDefinition::LuaFunctionDefinition(copy)");
00061   DoAssign(rSrc);
00062 }
00063 
00064 // std faudes type
00065 LuaFunctionDefinition& LuaFunctionDefinition::DoAssign(const LuaFunctionDefinition& rSrc) {
00066   FD_DLB("LuaFunctionDefinition::DoAssign()");
00067   // assign base members
00068   FunctionDefinition::DoAssign(rSrc);
00069   // assign my members
00070   mLuaCode=rSrc.mLuaCode;
00071   mLuaFile=rSrc.mLuaFile;
00072   // special member
00073   pLuaFunction=dynamic_cast<LuaFunction*>(mpFunction);
00074   // report
00075   FD_DLB("LuaFunctionDefinition::DoAssign("<<this<<"): name   " << mName);
00076   FD_DLB("LuaFunctionDefinition::DoAssign("<<this<<"): proto   " << mpFunction);
00077   FD_DLB("LuaFunctionDefinition::DoAssign("<<this<<"): has def " << mpFunction->Definition())
00078   // done
00079   return *this;
00080 }
00081 
00082 // std faudes type
00083 bool LuaFunctionDefinition::DoEqual(const LuaFunctionDefinition& rOther) const {
00084   // test base members
00085   if(!FunctionDefinition::DoEqual(rOther)) return false;
00086   // test my members
00087   if(mLuaCode!=rOther.mLuaCode) return false;
00088   if(mLuaFile!=rOther.mLuaFile) return false;
00089   return true;
00090 }
00091 
00092 // clear (all but prototype)
00093 void LuaFunctionDefinition::Clear(){
00094   FD_DLB("LuaFunctionDefinition::Clear(): " << Name());
00095   // call base
00096   FunctionDefinition::Clear();
00097   // clear my data
00098   mLuaCode.clear();
00099 }
00100 
00101 
00102 // set prototype object
00103 void LuaFunctionDefinition::Prototype(Function* pFunc){
00104   FunctionDefinition::Prototype(pFunc);
00105   // set typed version
00106   pLuaFunction=dynamic_cast<LuaFunction*>(pFunc);
00107 }
00108 
00109 
00110 // get lua code
00111 const std::string& LuaFunctionDefinition::LuaCode(void) const {
00112   return mLuaCode;
00113 }
00114 
00115 // set lua code
00116 void LuaFunctionDefinition::LuaCode(const std::string& rCode) {
00117   mLuaCode=rCode;
00118 }
00119 
00120 
00121 // test all variants
00122 std::string LuaFunctionDefinition::SyntaxCheck(void) {
00123   // trivial case ... ok
00124   if(VariantsSize()==0) {
00125     FD_DLB("LuaFunctionDefinition::SyntaxCheck(): no variants defined, fine");
00126     return "";
00127   }    
00128   // allocate function
00129   faudes::LuaFunction* lfnct = pLuaFunction->New();
00130   // iterate variants
00131   std::string err = "";
00132   for(int i=0; i<lfnct->VariantsSize(); i++) {
00133     // select
00134     lfnct->Variant(i);
00135     FD_DLB("LuaFunctionDefinition::SyntaxCheck(): variant " << 
00136       lfnct->Variant()->Name());
00137     // allocate args (exception on unknown type, will lead to mem leak)
00138     try {
00139       lfnct->AllocateValues();
00140       // let luafunction have a go
00141       if(err=="") try {
00142         lfnct->SyntaxCheck();
00143       } catch(faudes::Exception ex)  {
00144         err = ex.What();
00145       }
00146       // free args
00147       lfnct->FreeValues();
00148     // alloc err
00149     } catch(faudes::Exception ex)  {
00150       err = "cannot allocate parameters for variant " + lfnct->Variant()->Name();
00151     }
00152   } // iterate variants
00153   delete lfnct;
00154   // done
00155   return err;
00156 }
00157 
00158 
00159 // token io
00160 void LuaFunctionDefinition::DoRead(TokenReader& rTr,  const std::string& rLabel, const Type* pContext) {
00161   FD_DLB("LuaFunctionDefinition::DoRead()");
00162   // ignore
00163   (void) pContext;
00164   // label
00165   std::string label=rLabel;
00166   if(label=="") label="LuaFunctionDefinition";
00167   // base can handle this
00168   Documentation::DoRead(rTr,label,pContext);
00169   // report
00170   FD_DLB("LuaFunctionDefinition::DoRead(): done " << mPlugIn << "::" << mName);
00171 }
00172 
00173 
00174 // token io
00175 void LuaFunctionDefinition::DoReadCore(TokenReader& rTr) {
00176   FD_DLB("LuaFunctionDefinition::DoReadCore()");
00177   // call base
00178   FunctionDefinition::DoReadCore(rTr);  
00179   // read my members
00180   Token token;
00181   rTr.Peek(token);
00182   // case a: embedded lua code
00183   if(token.Type()==Token::Begin)
00184   if(token.StringValue()=="LuaCode") {
00185     mLuaFile="";
00186     rTr.ReadBegin("LuaCode");
00187     mLuaCode=rTr.ReadString();
00188     rTr.ReadEnd("LuaCode");
00189   }
00190   // case b: lua file
00191   if(token.Type()==Token::Begin)
00192   if(token.StringValue()=="LuaFile") {
00193     rTr.ReadBegin("LuaFile");
00194     std::string mLuaFile=rTr.ReadString();
00195     // todo: read that file
00196     rTr.ReadEnd("LuaFile");
00197   }
00198 }
00199 
00200 
00201 // token io
00202 void LuaFunctionDefinition::DoWrite(TokenWriter& rTw,  const std::string& rLabel, const Type* pContext) const {
00203    // label
00204   std::string label=rLabel;
00205   if(label=="") label="LuaFunctionDefinition";
00206   // base can handle
00207   Documentation::DoWrite(rTw,label,pContext); 
00208 }
00209 
00210 // token io
00211 void LuaFunctionDefinition::DoWriteCore(TokenWriter& rTw) const {
00212   FD_DLB("LuaFunctionDefinition::DoWriteCore(): file " << rTw.FileName());
00213   // call base core
00214   FunctionDefinition::DoWriteCore(rTw);  
00215   // case a: embedded code
00216   if(mLuaFile=="") {
00217     rTw.WriteBegin("LuaCode");
00218     rTw.WriteVerbatim(mLuaCode);
00219     rTw.WriteEnd("LuaCode");
00220   }
00221   // case a: embedded code
00222   if(mLuaFile!="") {
00223     rTw.WriteBegin("LuaFile");
00224     rTw.WriteString(mLuaFile);
00225     rTw.WriteEnd("LuaFile");
00226     // todo: write that file
00227   }
00228 }
00229 
00230 /*
00231 ********************************************************************
00232 ********************************************************************
00233 ********************************************************************
00234 
00235 Implementation of class LuaFunction
00236 
00237 ********************************************************************
00238 ********************************************************************
00239 ********************************************************************
00240 */
00241 
00242 // Constructor 
00243 LuaFunction::LuaFunction(const LuaFunctionDefinition* fdef) : 
00244   Function(fdef),
00245   pLuaFuncDef(fdef)
00246 {
00247   FD_DLB("LuaFunction::LuaFunction(): fdef  " << pFuncDef);
00248 }
00249 
00250 // new on heap
00251 LuaFunction* LuaFunction::New(void) const {
00252   return new LuaFunction(pLuaFuncDef);
00253 }
00254 
00255 // set function definition
00256 void LuaFunction::Definition(const FunctionDefinition* fdef) {
00257   // cast and pass to base
00258   pLuaFuncDef = dynamic_cast<const LuaFunctionDefinition*>(fdef);
00259   Function::Definition(pLuaFuncDef);
00260 }
00261 
00262 // get function definition
00263 const LuaFunctionDefinition* LuaFunction::Definition(void) const {
00264   return pLuaFuncDef;
00265 }
00266 
00267 // implement typecheck
00268 bool LuaFunction::DoTypeCheck(int n) {
00269   FD_DLB("LuaFunction::DoTypeCheck("<< n << "): for " << Variant()->At(n).Type());
00270   const Type* proto = TypeRegistry::G()->Prototype(Variant()->At(n).Type()); 
00271   if(!proto) {
00272     FD_DLB("LuaFunction::DoTypeCheck("<< n << "): unknown type");
00273     return false;
00274   }
00275   if(!proto->Cast(ParamValue(n))) {
00276     FD_DLB("LuaFunction::DoTypeCheck("<< n << "): could not cast param value");
00277     return false;
00278   }
00279   return true;
00280 }
00281 
00282 
00283 // swigs version of user data (lua runtime version 4)
00284 typedef void *(*swig_converter_func)(void *, int *);
00285 typedef struct swig_type_info *(*swig_dycast_func)(void **);
00286 typedef struct swig_cast_info {
00287   swig_type_info         *type;     /* pointer to type that is equivalent to this type */
00288   swig_converter_func     converter;    /* function to cast the void pointers */
00289   struct swig_cast_info  *next;     /* pointer to next cast in linked list */
00290   struct swig_cast_info  *prev;     /* pointer to the previous cast */
00291 } swig_cast_info;
00292 
00293 typedef struct swig_type_info {
00294   const char             *name;     /* mangled name of this type */
00295   const char             *str;      /* human readable name of this type */
00296   swig_dycast_func        dcast;    /* dynamic cast function down a hierarchy */
00297   struct swig_cast_info  *cast;     /* linked list of types that can cast into this type */
00298   void                   *clientdata;   /* language specific type data */
00299   int                    owndata;   /* flag if the structure owns the clientdata */
00300 } swig_type_info;
00301 
00302 typedef struct {
00303   swig_type_info   *type;
00304   int     own;  
00305   void        *ptr;
00306 } swig_lua_userdata;
00307 
00308 
00309 
00310 
00311 
00312 // implement execute: run stages
00313 void LuaFunction::DoExecute(void) {
00314   FD_DLB("LuaFunction::DoExecute()");
00315   /*
00316   for(int i=0; i< Variant()->Size(); i++) {
00317     FD_DLB("LuaFunction::DoExecute(): value at #" << i);
00318     ParamValue(i)->Write();
00319   }
00320   */
00321   // have a state
00322   mpL = lua_open();    
00323   // run stages
00324   DoExecuteA();
00325   DoExecuteB();
00326   DoExecuteC();
00327   DoExecuteD();
00328   // clean stack
00329   lua_pop(mpL, 1); // table from stage A
00330   // done
00331   lua_close(mpL); 
00332   mpL=0;
00333 }
00334 
00335 // implement execute: syntaxcheck
00336 void LuaFunction::SyntaxCheck(void) {
00337   FD_DLB("LuaFunction::SyntaxCheck()");
00338   // have a state
00339   mpL = lua_open();    
00340   // run stages
00341   DoExecuteA();
00342   DoExecuteB();
00343   DoExecuteD();
00344   // clean stack
00345   lua_pop(mpL, 1); // function from stage B
00346   lua_pop(mpL, 1); // table from stage A
00347   // done
00348   lua_close(mpL); 
00349   mpL=0;
00350 }
00351 
00352 // implement execute: get function on the stack
00353 void LuaFunction::DoExecuteA(void) {
00354   FD_DLB("LuaFunction::DoExecuteA()");
00355   // prepare lua
00356   lua_gc(mpL, LUA_GCSTOP, 0);     // stop collector during initialization 
00357   luaL_openlibs(mpL);             // open libraries 
00358   luaopen_faudes_allplugins(mpL); // luafaudes: register
00359   //luafaudes_dotready();         // luafaudes: test dot
00360   lua_gc(mpL, LUA_GCRESTART, 0);  // start garbage collector
00361   // load my script
00362   const char* script = pLuaFuncDef->LuaCode().c_str();
00363   int script_len = pLuaFuncDef->LuaCode().size();
00364   int errload=luaL_loadbuffer(mpL, script, script_len, "luafaudes");
00365   if(errload!=0) {
00366     std::string lerr= std::string(lua_tostring(mpL, -1));
00367     int c1 = lerr.find_first_of(':');
00368     if(c1<0) c1=0;
00369     int c2 = lerr.find_first_of(':',c1+1);
00370     if(c2<0) c2=1;
00371     std::string line = lerr.substr(c1+1,c2-c1-1);  
00372     if(c2>1) {
00373       lerr="error in Lua script: line " + line + ": " + lerr.substr(c2+2);
00374     }
00375     lua_close(mpL); 
00376     mpL=0;    
00377     throw Exception("LuaFunction::DoExecuteA()", lerr, 49);
00378   }
00379   // run the script
00380   int errrun=lua_pcall(mpL, 0, 0, 0); 
00381   if(errrun!=0) {
00382     std::stringstream errstr;
00383     errstr << "failed to run script: ";
00384     errstr << std::string(lua_tostring(mpL, -1));
00385     lua_close(mpL); 
00386     mpL=0;
00387     throw Exception("LuaFunction::DoExecuteA()", errstr.str(), 49);
00388   }
00389   // get the swig generated table of faudes functions
00390   lua_getglobal(mpL,"faudes");
00391   mFtable=lua_gettop(mpL);
00392   if(!lua_istable(mpL,-1)) {
00393     std::stringstream errstr;
00394     errstr << "failed to load faudes table";
00395     lua_close(mpL);
00396     mpL=0; 
00397     throw Exception("LuaFunction::DoExecuteA()", errstr.str(), 49);
00398   }
00399   // mangle my function name
00400   std::string fname = Variant()->Name();
00401   unsigned int src=0;
00402   unsigned int dst=0;
00403   while(src<fname.length()) {
00404     if(isalnum(fname.at(src))) {fname[dst++]=fname[src++]; continue;}
00405     fname[dst++]='_';
00406     for(;src<fname.length();src++) 
00407       if(isalnum(fname.at(src))) break;
00408   }
00409   fname.resize(dst);
00410   // find my function
00411   lua_getglobal(mpL,fname.c_str()); 
00412   if(!lua_isfunction(mpL,-1)) {
00413     std::stringstream errstr;
00414     errstr << "missing function \"" << fname << "\"";
00415     lua_close(mpL);
00416     mpL=0; 
00417     throw Exception("LuaFunction::DoExecuteA()", errstr.str(), 49);
00418   }
00419 }
00420 
00421 // implement execute: prepare parameters
00422 void LuaFunction::DoExecuteB(void) {
00423   FD_DLB("LuaFunction::DoExecuteB()");
00424   // construct my parameters in lua
00425   for(int i=0; i< Variant()->Size(); i++) {
00426     const std::string& ftype= Variant()->At(i).Type();
00427     // special case: int as lua number
00428     if(ftype=="Integer") {
00429       lua_pushnumber(mpL,((Integer*)ParamValue(i))->CValue());
00430       FD_DLB("LuaFunction::DoExecuteB(): created type " << ftype);
00431       continue;
00432     }
00433     // special case: bool as lua bool
00434     if(ftype=="Boolean") {
00435       lua_pushboolean(mpL,((Boolean*)ParamValue(i))->CValue());
00436       FD_DLB("LuaFunction::DoExecuteB(): created type " << ftype);
00437       continue;
00438     }
00439     // special case: str as lua string
00440     if(ftype=="String") {
00441       lua_pushstring(mpL,((String*)ParamValue(i))->CValue().c_str());
00442       FD_DLB("LuaFunction::DoExecuteB(): created type " << ftype);
00443       continue;
00444     }
00445     // std case: faudes type: construct 1
00446     lua_pushstring(mpL,ftype.c_str());
00447     lua_gettable(mpL,mFtable);
00448     if(!lua_isfunction(mpL,-1)) {
00449       std::stringstream errstr;
00450       errstr << "failed load constructor for \"" << ftype << "\"";
00451       lua_close(mpL);
00452       mpL=0; 
00453       throw Exception("LuaFunction::DoExecuteB()", errstr.str(), 49);
00454     }
00455     // std case: faudes type: construct 2
00456     if(lua_pcall(mpL, 0, 1, 0) != 0) { 
00457       std::stringstream errstr;
00458       errstr << "failed to construct for \"" << ftype << "\" (1)";
00459       lua_close(mpL);
00460       mpL=0; 
00461       throw Exception("LuaFunction::DoExecuteB()", errstr.str(), 49);
00462     }
00463     swig_lua_userdata* susr = (swig_lua_userdata*) lua_touserdata (mpL, -1);
00464     // std case: test pointer
00465     if(!susr) {
00466       std::stringstream errstr;
00467       errstr << "failed to construct for\"" << ftype << "\" (2)";
00468       lua_close(mpL);
00469       mpL=0; 
00470       throw Exception("LuaFunction::DoExecuteB()", errstr.str(), 49);
00471     }
00472     FD_DLB("LuaFunction::DoExecuteB(): created type " << susr->type->name);
00473     // std case: reown to save rom garbadge collector
00474     if(susr->own) free(susr->ptr);
00475     susr->ptr = ParamValue(i);
00476     susr->own=0;
00477   }
00478 }
00479 
00480 // implement execute: execute the function
00481 void LuaFunction::DoExecuteC(void) {
00482   FD_DLB("LuaFunction::DoExecuteC()");
00483   // run my function
00484   if(lua_pcall(mpL, Variant()->Size(), Variant()->Size(), 0) != 0) { 
00485     std::string lerr= std::string(lua_tostring(mpL, -1));
00486     // user request ?
00487     if(lerr.find("break on application request")!=std::string::npos)
00488       lerr="break on application request";
00489     // have line number ?
00490     int c1 = lerr.find_first_of(':');
00491     if(c1<0) c1=0;
00492     int c2 = lerr.find_first_of(':',c1+1);
00493     if(c2<0) c2=1;
00494     std::string line = lerr.substr(c1+1,c2-c1-1);  
00495     if(c2>1) {
00496       lerr="error in Lua script: line " + line + ": " + lerr.substr(c2+2);
00497     }
00498     lua_close(mpL); 
00499     mpL=0;
00500     throw Exception("LuaFunction::DoExecuteC()", lerr, 49);
00501   }
00502 }
00503 
00504 // implement execute: retrieve results
00505 void LuaFunction::DoExecuteD(void) {
00506   FD_DLB("LuaFunction::DoExecuteD()");
00507   // retrieve results from stack
00508   for(int i=Variant()->Size()-1; i>=0; i--) {
00509     const std::string& ftype= Variant()->At(i).Type();
00510     // special case: int as lua number
00511     if(ftype=="Integer" && lua_isnumber(mpL,-1)) {
00512       FD_DLB("LuaFunction::DoExecuteD(): retrieve type " << ftype);
00513       ((Integer*)ParamValue(i))->CValue(lua_tonumber(mpL,-1));
00514       lua_pop(mpL, 1); 
00515       continue;
00516     }
00517     // special case: bool as lua bool
00518     if(ftype=="Boolean" && lua_isboolean(mpL,-1)) {
00519       ((Boolean*)ParamValue(i))->CValue(lua_toboolean(mpL,-1));
00520       FD_DLB("LuaFunction::DoExecuteD(): created type " << ftype);
00521       lua_pop(mpL, 1); 
00522       continue;
00523     }
00524     // special case: str as lua string
00525     if(ftype=="String" && lua_isstring(mpL,-1)) {
00526       ((String*)ParamValue(i))->CValue(lua_tostring(mpL,-1));
00527       FD_DLB("LuaFunction::DoExecuteD(): created type " << ftype);
00528       lua_pop(mpL, 1); 
00529       continue;
00530     }
00531     // std case: faudes types are dealt with by reference anyway
00532     if(lua_isuserdata(mpL,-1)) {
00533       FD_DLB("LuaFunction::DoExecuteD(): retrieve type " << ftype);
00534       lua_pop(mpL, 1); 
00535       continue;
00536     }
00537     // report error
00538     std::stringstream errstr;
00539     errstr << "invalid return values in \"" << Variant()->Name() << "\"";
00540     lua_close(mpL); 
00541     mpL=0;
00542     throw Exception("LuaFunction::DoExecuteD()", errstr.str(), 49);
00543   }
00544 } 
00545 
00546 
00547 } // namespace
00548 

libFAUDES 2.16b --- 2010-9-8 --- c++ source docu by doxygen 1.6.3