About
User Reference
C++ API
luafaudes
Developer
Links
libFAUDES online
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 Borrow SWIG type system
00037 
00038 ********************************************************************
00039 ********************************************************************
00040 ********************************************************************
00041 */
00042 
00043 
00044 // swigs version of user data (lua runtime version 4, swig 1.3.36)
00045 typedef void *(*swig_converter_func)(void *, int *);
00046 typedef struct swig_type_info *(*swig_dycast_func)(void **);
00047 typedef struct swig_cast_info {
00048   swig_type_info         *type;     /* pointer to type that is equivalent to this type */
00049   swig_converter_func     converter;    /* function to cast the void pointers */
00050   struct swig_cast_info  *next;     /* pointer to next cast in linked list */
00051   struct swig_cast_info  *prev;     /* pointer to the previous cast */
00052 } swig_cast_info;
00053 typedef struct swig_type_info {
00054   const char             *name;     /* mangled name of this type */
00055   const char             *str;      /* human readable name of this type */
00056   swig_dycast_func        dcast;    /* dynamic cast function down a hierarchy */
00057   struct swig_cast_info  *cast;     /* linked list of types that can cast into this type */
00058   void                   *clientdata;   /* language specific type data */
00059   int                    owndata;   /* flag if the structure owns the clientdata */
00060 } swig_type_info;
00061 typedef struct {
00062   swig_type_info   *type;
00063   int               own;                        /* 1 <> owned by swig (garbadge collector wont destroy) */  
00064   void              *ptr;
00065 } swig_lua_userdata;
00066 
00067 
00068 
00069 /* Swig runtime sytem: dynamic cast of swig userdata pointers */
00070 /* We need this to cast swig's userdata to the faudes base type */
00071 /* faudes::Type. See SWIG runtime SWIG_ConvertPtr. */
00072 void* SwigCastPtr(void* ptr, swig_type_info *from, swig_type_info *ty) {
00073   void* res=ptr;
00074   if(!ptr) return res;
00075   if(!from) return res;
00076   if(!ty) return res;
00077   swig_cast_info *iter = ty->cast;
00078   while(iter) {
00079     if(iter->type == from) {
00080       if(iter == ty->cast) break;
00081       iter->prev->next = iter->next;
00082       if(iter->next)
00083         iter->next->prev = iter->prev;
00084       iter->next = ty->cast;
00085       iter->prev = 0;
00086       if(ty->cast) ty->cast->prev = iter;
00087       ty->cast = iter;
00088       break;
00089     }
00090     iter = iter->next;
00091   }
00092   if(!iter) return res;
00093   if(!iter->converter) return res;
00094   int nm;
00095   res= (*iter->converter)(ptr,&nm);
00096   return res;
00097 }
00098 
00099 
00100 /*
00101 ********************************************************************
00102 ********************************************************************
00103 ********************************************************************
00104 
00105 local helper, may go to cfl_helper.*
00106 
00107 ********************************************************************
00108 ********************************************************************
00109 ********************************************************************
00110 */
00111 
00112 std::string MangleString(const std::string& str) {
00113   std::string res=str;
00114   std::size_t src=0;
00115   std::size_t dst=0;
00116   while(src<res.length()) {
00117     if(isalnum(res.at(src))) {res[dst++]=res[src++]; continue;}
00118     res[dst++]='_';
00119     for(;src<res.length();src++) 
00120       if(isalnum(res.at(src))) break;
00121   }
00122   if(dst>2)
00123   if(res[dst-1]=='_')
00124     dst--;
00125   res.resize(dst);
00126   return res;
00127 }
00128 
00129 
00130 /*
00131 ********************************************************************
00132 ********************************************************************
00133 ********************************************************************
00134 
00135 Implementation of class LuaFunctionDefinition
00136 
00137 ********************************************************************
00138 ********************************************************************
00139 ********************************************************************
00140 */
00141 
00142 // faudes type
00143 FAUDES_TYPE_IMPLEMENTATION(LuaFunctionDefinition,LuaFunctionDefinition,FunctionDefinition)
00144 
00145 // construct
00146 LuaFunctionDefinition::LuaFunctionDefinition(const std::string& name) : 
00147   FunctionDefinition(name),
00148   pDefaultL(0) 
00149 {
00150   Prototype(new LuaFunction(0));
00151   FD_DLB("LuaFunctionDefinition::LuaFunctionDefinition("<<this<<"): name   " << name);
00152   FD_DLB("LuaFunctionDefinition::LuaFunctionDefinition("<<this<<"): proto   " << mpFunction);
00153   FD_DLB("LuaFunctionDefinition::LuaFunctionDefinition("<<this<<"): has def " << mpFunction->Definition());
00154 }
00155 
00156 // copy construct
00157 LuaFunctionDefinition::LuaFunctionDefinition(const LuaFunctionDefinition& rSrc) : 
00158   FunctionDefinition(rSrc.Name()),
00159   pDefaultL(0) 
00160 {
00161   FD_DLB("LuaFunctionDefinition::LuaFunctionDefinition(copy)");
00162   DoAssign(rSrc);
00163 }
00164 
00165 // std faudes type
00166 void LuaFunctionDefinition::DoAssign(const LuaFunctionDefinition& rSrc) {
00167   FD_DLB("LuaFunctionDefinition::DoAssign()");
00168   // assign base members
00169   FunctionDefinition::DoAssign(rSrc);
00170   // assign my members
00171   mLuaCode=rSrc.mLuaCode;
00172   mLuaFile=rSrc.mLuaFile;
00173   // special member
00174   pLuaFunction=dynamic_cast<LuaFunction*>(mpFunction);
00175   // report
00176   FD_DLB("LuaFunctionDefinition::DoAssign("<<this<<"): name   " << mName);
00177   FD_DLB("LuaFunctionDefinition::DoAssign("<<this<<"): proto   " << mpFunction);
00178   FD_DLB("LuaFunctionDefinition::DoAssign("<<this<<"): has def " << mpFunction->Definition())
00179 }
00180 
00181 // std faudes type
00182 bool LuaFunctionDefinition::DoEqual(const LuaFunctionDefinition& rOther) const {
00183   // test base members
00184   if(!FunctionDefinition::DoEqual(rOther)) return false;
00185   // test my members
00186   if(mLuaCode!=rOther.mLuaCode) return false;
00187   if(mLuaFile!=rOther.mLuaFile) return false;
00188   return true;
00189 }
00190 
00191 // clear (all but prototype)
00192 void LuaFunctionDefinition::Clear(){
00193   FD_DLB("LuaFunctionDefinition::Clear(): " << Name());
00194   // call base
00195   FunctionDefinition::Clear();
00196   // clear my data
00197   mLuaCode.clear();
00198 }
00199 
00200 
00201 // set prototype object
00202 void LuaFunctionDefinition::Prototype(Function* pFunc){
00203   FunctionDefinition::Prototype(pFunc);
00204   // set typed version
00205   pLuaFunction=dynamic_cast<LuaFunction*>(pFunc);
00206 }
00207 
00208 
00209 // get lua code
00210 const std::string& LuaFunctionDefinition::LuaCode(void) const {
00211   return mLuaCode;
00212 }
00213 
00214 // set lua code
00215 void LuaFunctionDefinition::LuaCode(const std::string& rCode) {
00216   mLuaCode=rCode;
00217 }
00218 
00219 // get/set default lua state
00220 LuaState* LuaFunctionDefinition::DefaultL(void) const {
00221   if(!pDefaultL)  return const_cast<LuaFunctionDefinition*>(this)->pDefaultL=LuaState::G();
00222   return pDefaultL;
00223 }
00224 
00225 // get/set default lua state
00226 void LuaFunctionDefinition::DefaultL(LuaState* pL) {
00227   pDefaultL=pL;
00228 }
00229 
00230 // test all variants
00231 std::string LuaFunctionDefinition::SyntaxCheck(void) {
00232   // trivial case ... ok
00233   if(VariantsSize()==0) {
00234     FD_DLB("LuaFunctionDefinition::SyntaxCheck(): no variants defined, fine");
00235     return "";
00236   }    
00237   // allocate function
00238   faudes::LuaFunction* lfnct = pLuaFunction->New();
00239   // iterate variants
00240   std::string err = "";
00241   for(int i=0; i<lfnct->VariantsSize(); i++) {
00242     // select
00243     lfnct->Variant(i);
00244     FD_DLB("LuaFunctionDefinition::SyntaxCheck(): variant " << 
00245       lfnct->Variant()->Name());
00246     // allocate args (exception on unknown type, will lead to mem leak)
00247     try {
00248       lfnct->AllocateValues();
00249       // let luafunction have a go
00250       if(err=="") try {
00251         lfnct->SyntaxCheck();
00252       } catch(faudes::Exception ex)  {
00253         err = ex.What();
00254       }
00255       // free args
00256       lfnct->FreeValues();
00257     // alloc err
00258     } catch(faudes::Exception ex)  {
00259       err = "cannot allocate parameters for variant " + lfnct->Variant()->Name();
00260     }
00261   } // iterate variants
00262   delete lfnct;
00263   // done
00264   return err;
00265 }
00266 
00267 
00268 // install myself to a lua state
00269 void LuaFunctionDefinition::Install(LuaState* pL) const {
00270   Install(pL->LL());
00271 }
00272 
00273 // install myself to a lua state
00274 void LuaFunctionDefinition::Install(lua_State* pLL) const {
00275   FD_DLB("LuaFunctionDefinition::Install(): " << Name());
00276 
00277   // bail out if no signature
00278   if(VariantsSize()==0) {
00279     FD_DLB("LuaFunctionDefinition::Install(): no signatures for fnct " << Name());
00280     return;
00281   }
00282 
00283   // function name (ctype overwrites name)
00284   std::string lfname = Name();  
00285   if(CType()!="") {
00286     size_t pos=CType().find("faudes::");
00287     if(pos!=std::string::npos) 
00288     lfname=CType().substr(std::string("faudes::").length());
00289   }
00290 
00291   // parse signatures, test consistence
00292   std::vector< std::string > lffnct;                          //fnct names
00293   std::vector< int > lfparcnt;                                // # actual parameters
00294   std::vector< std::vector<std::string> > lfparams;           // par names
00295   std::vector< std::vector<Parameter::ParamAttr> > lfattrib;  // par access
00296   std::vector< std::vector<bool> > lfretval;                  // actual return value
00297   std::vector< std::vector<bool> > lfparval;                  // actual parameter
00298   lffnct.resize(VariantsSize());
00299   lfparcnt.resize(VariantsSize());
00300   lfparams.resize(VariantsSize());
00301   lfattrib.resize(VariantsSize());
00302   lfretval.resize(VariantsSize());
00303   lfparval.resize(VariantsSize());
00304   for(int i=0; i<VariantsSize(); i++) {
00305     const Signature& sigi=Variant(i);
00306     int parcnt=0;
00307     for(int j=0; j<sigi.Size(); j++) {
00308       // retrieve faudes type and attrib
00309       std::string ftype=sigi.At(j).Type();
00310       Parameter::ParamAttr fattr=sigi.At(j).Attribute();
00311       // autodefault creturn flag
00312       bool fcret=false;
00313       if(fattr==Parameter::Out) fcret=true;
00314       if(fattr==Parameter::InOut) fcret=true;
00315       // get creturn from signature for non-elementary
00316       if(ftype!="Boolean")
00317       if(ftype!="Integer")
00318       if(ftype!="String")
00319          fcret=sigi.At(j).CReturn();  
00320       // bail out on non-out ret value
00321       if(fcret)
00322       if((fattr!=Parameter::Out) && (fattr!=Parameter::InOut)) 
00323         break;
00324       // bail out on unknown faudestype
00325       if(ftype!="Boolean")
00326       if(ftype!="Integer")
00327       if(ftype!="String")
00328       if(!TypeRegistry::G()->Exists(ftype)) 
00329         break;
00330       // figure and count actual parameters
00331       bool fcpar=true;
00332       if(fcret && fattr==Parameter::Out) fcpar=false;
00333       if(fcpar) parcnt++;
00334       // bail out on undef attribute
00335       if(fattr==Parameter::UnDef) break;
00336       // param ok
00337       lfparams.at(i).push_back(ftype);
00338       lfattrib.at(i).push_back(fattr);
00339       lfretval.at(i).push_back(fcret);
00340       lfparval.at(i).push_back(fcpar);
00341     } 
00342     // test for signature error
00343     if((int) lfparams.at(i).size()!=sigi.Size()) {
00344       FD_WARN("LuaFunctionDefinition::Install(): cannot interpret signature \"" << sigi.Name() << "\"");
00345       lffnct.resize(i);
00346       break;
00347     }
00348     // record function name
00349     lffnct.at(i)=MangleString(sigi.Name()); 
00350     lfparcnt.at(i)=parcnt;
00351   }
00352   FD_DLB("LuaFunctionDefinition::Install(): #" << lffnct.size() << " valid signatures");
00353 
00354   // todo: filter out doublets as in rti2code
00355   // prepare lua code for signature dispatch 
00356   std::vector< std::string > lftest1;
00357   std::vector< std::string > lftest2;
00358   std::vector< std::string > lfcall;
00359   std::vector< std::string > lfsig;
00360   for(unsigned int i=0; i<lffnct.size(); i++) {
00361     // create type conditional, part1: lua types
00362     std::string test1="(arg['n']==" + ToStringInteger(lfparcnt.at(i)) + ")" ;    
00363     unsigned int pj=0;    
00364     for(unsigned int j=0; j<lfparams.at(i).size(); j++) {
00365       if(!lfparval.at(i).at(j)) continue;
00366       pj++;
00367       test1=test1+" and ";
00368       std::string ltype="userdata";
00369       if(lfparams.at(i).at(j) == "Integer") ltype="number";
00370       if(lfparams.at(i).at(j) == "Boolean") ltype="bool";
00371       if(lfparams.at(i).at(j) == "String") ltype="string";
00372       test1=test1 + "(type(arg[" + ToStringInteger(pj) + "])=='" + ltype + "')";
00373     }
00374     lftest1.push_back(test1);
00375     // create type conditional, part2: faudes types
00376     std::string test2="";
00377     pj=0;    
00378     for(unsigned int j=0; j<lfparams.at(i).size(); j++) {
00379       if(!lfparval.at(i).at(j)) continue;
00380       pj++;
00381       if(lfparams.at(i).at(j) == "Integer") continue;
00382       if(lfparams.at(i).at(j) == "Boolean") continue;
00383       if(lfparams.at(i).at(j) == "String") continue;
00384       if(test2.size()>0) test2=test2+" and ";
00385       test2=test2 + "faudes.TypeTest(\"" + lfparams.at(i).at(j) + "\", arg[" + ToStringInteger(pj) + "])";
00386     }
00387     lftest2.push_back(test2);
00388     // create function call
00389     std::string call= lffnct.at(i) + "(";
00390     pj=0;
00391     for(unsigned int j=0; j<lfparams.at(i).size(); j++) {
00392       if(!lfparval.at(i).at(j)) continue;
00393       pj++;
00394       if(pj>1) call = call + ", ";
00395       call = call + "arg[" + ToStringInteger(pj) + "]";
00396     }
00397     call = call + ")";
00398     lfcall.push_back(call);
00399     // create nice signature. note: this should match the respective code in rti2code.cpp
00400     std::string nsig = " " + lfname + "(";
00401     bool leftcomma = false;
00402     bool rightcomma = false;
00403     for(unsigned int j=0; j<lfparams.at(i).size(); j++) {
00404       // return value
00405       if(lfretval.at(i).at(j)) {
00406         if(leftcomma) nsig = "," + nsig;
00407   nsig=lfparams.at(i).at(j) + nsig;
00408         leftcomma=true;
00409       }
00410       // parameter value
00411       if(lfparval.at(i).at(j)) {
00412         if(rightcomma) nsig += ", ";
00413         const Signature& sigi=Variant(i);
00414         nsig += sigi.At(j).Str();
00415         rightcomma=true;
00416       }
00417     }  
00418     nsig+=")";
00419     lfsig.push_back(nsig);
00420   }
00421  
00422   // add to help system
00423   if(TextDoc()!="") {
00424     for(unsigned int i=0; i< lfsig.size(); i++) {
00425       std::string topic= PlugIn();
00426       std::string key1=  KeywordAt(1);
00427       if(topic.length()>0) topic.at(0)=toupper(topic.at(0));
00428       if(key1.length()>0) key1.at(0)=toupper(key1.at(0));
00429       luafaudes_dict_insert_entry(topic,key1,lfsig.at(i));
00430     }
00431   }
00432 
00433 
00434   // set up wrapper frunction
00435   std::stringstream lfwrap;
00436   //lfwrap << "-- LuaFunctionDefinition.Install() " << Name() << std::endl;
00437   //lfwrap << std::endl;
00438   lfwrap << LuaCode();
00439   //lfwrap << std::endl;
00440   lfwrap << std::endl;
00441   //lfwrap << "-- LuaFunctionDefinition.Install(): dispatch / typecheck" << std::endl;
00442   lfwrap << "function faudes." << lfname << "(...)" << std::endl;
00443   for(unsigned int i=0; i< lftest1.size(); i++) {
00444     lfwrap << "  if (" << lftest1.at(i) << ") then " << std::endl;
00445     lfwrap << "  if (" << lftest2.at(i) << ") then " << std::endl;
00446     lfwrap << "    return faudes." << lfcall.at(i) << std::endl;
00447     lfwrap << "  end" << std::endl;
00448     lfwrap << "  end" << std::endl;
00449   }
00450   lfwrap << "  faudes.Error([[" << lfname << ": parameter mismatch: expected signature(s): " << std::endl;
00451   for(unsigned int i=0; i< lfsig.size(); i++) {
00452     lfwrap << lfsig.at(i) << std::endl;
00453   }
00454   lfwrap << "]])" << std::endl;
00455   lfwrap << "end" << std::endl;
00456 
00457 
00458   // debugging report
00459   FD_WARN("LuaFunctionDefinition:Install(): code:" << std::endl << lfwrap.str());
00460   FD_DLB("LuaFunctionDefinition:Install(): code: done");
00461 
00462   // finally install (aka run) the wrapper
00463   int errexec=luaL_dostring(pLL,lfwrap.str().c_str());  
00464   if(errexec!=0) {
00465     std::string lerr= std::string(lua_tostring(pLL, -1));
00466     int c1 = lerr.find_first_of(':');
00467     if(c1<0) c1=0;
00468     int c2 = lerr.find_first_of(':',c1+1);
00469     if(c2<0) c2=1;
00470     std::string line = lerr.substr(c1+1,c2-c1-1);  
00471     if(c2>1) {
00472       lerr="error in Lua script: line " + line + ": " + lerr.substr(c2+2);
00473     }
00474     throw Exception("LuaFunctionDefinition::Install(): " + Name(), lerr, 49);
00475   }
00476 }
00477 
00478 // token io
00479 void LuaFunctionDefinition::DoRead(TokenReader& rTr,  const std::string& rLabel, const Type* pContext) {
00480   FD_DLB("LuaFunctionDefinition::DoRead()");
00481   // ignore
00482   (void) pContext;
00483   // label
00484   std::string label=rLabel;
00485   if(label=="") label="LuaFunctionDefinition";
00486   // base can handle this
00487   FunctionDefinition::DoRead(rTr,label,pContext);
00488   // report
00489   FD_DLB("LuaFunctionDefinition::DoRead(): done " << mPlugIn << "::" << mName);
00490 }
00491 
00492 
00493 // token io
00494 void LuaFunctionDefinition::DoReadCore(TokenReader& rTr) {
00495   FD_DLB("LuaFunctionDefinition::DoReadCore()");
00496   // call base
00497   FunctionDefinition::DoReadCore(rTr);  
00498   // read my members
00499   Token token;
00500   rTr.Peek(token);
00501   // case a: embedded lua code
00502   if(token.IsBegin())
00503   if(token.StringValue()=="LuaCode") {
00504     mLuaFile="";
00505     mLuaCode="";
00506     rTr.ReadBegin("LuaCode");
00507     Token code;
00508     while(rTr.Peek(code)) {
00509       if(!code.IsString()) break;
00510       rTr.Get(code);
00511       mLuaCode.append(code.StringValue());
00512     }
00513     rTr.ReadEnd("LuaCode");
00514   }
00515   // case b: lua file
00516   if(token.IsBegin())
00517   if(token.StringValue()=="LuaFile") {
00518     rTr.ReadBegin("LuaFile");
00519     std::string mLuaFile=rTr.ReadString();
00520     // todo: read that file
00521     rTr.ReadEnd("LuaFile");
00522   }
00523 }
00524 
00525 
00526 // token io
00527 void LuaFunctionDefinition::DoWrite(TokenWriter& rTw,  const std::string& rLabel, const Type* pContext) const {
00528    // label
00529   std::string label=rLabel;
00530   if(label=="") label="LuaFunctionDefinition";
00531   // base can handle
00532   Documentation::DoWrite(rTw,label,pContext); 
00533 }
00534 
00535 // token io
00536 void LuaFunctionDefinition::DoWriteCore(TokenWriter& rTw) const {
00537   FD_DLB("LuaFunctionDefinition::DoWriteCore(): file " << rTw.FileName());
00538   // call base core
00539   FunctionDefinition::DoWriteCore(rTw);  
00540   // case a: embedded code
00541   if(mLuaFile=="") {
00542     rTw.WriteBegin("LuaCode");
00543     rTw.WriteVerbatim(mLuaCode);
00544     rTw.WriteEnd("LuaCode");
00545   }
00546   // case a: embedded code
00547   if(mLuaFile!="") {
00548     rTw.WriteBegin("LuaFile");
00549     rTw.WriteString(mLuaFile);
00550     rTw.WriteEnd("LuaFile");
00551     // todo: write that file
00552   }
00553 }
00554 
00555 /*
00556 ********************************************************************
00557 ********************************************************************
00558 ********************************************************************
00559 
00560 Implementation of class LuaFunction
00561 
00562 ********************************************************************
00563 ********************************************************************
00564 ********************************************************************
00565 */
00566 
00567 // Constructor 
00568 LuaFunction::LuaFunction(const LuaFunctionDefinition* fdef) : 
00569   Function(fdef),
00570   pLuaFuncDef(fdef),
00571   pL(0),
00572   pLL(0)
00573 {
00574   FD_DLB("LuaFunction::LuaFunction(): fdef  " << pFuncDef);
00575 }
00576 
00577 // new on heap
00578 LuaFunction* LuaFunction::New(void) const {
00579   return new LuaFunction(pLuaFuncDef);
00580 }
00581 
00582 // set function definition
00583 void LuaFunction::Definition(const FunctionDefinition* fdef) {
00584   // cast and pass to base
00585   pLuaFuncDef = dynamic_cast<const LuaFunctionDefinition*>(fdef);
00586   Function::Definition(pLuaFuncDef);
00587 }
00588 
00589 // get function definition
00590 const LuaFunctionDefinition* LuaFunction::Definition(void) const {
00591   return pLuaFuncDef;
00592 }
00593 
00594 // implement typecheck
00595 bool LuaFunction::DoTypeCheck(int n) {
00596   FD_DLB("LuaFunction::DoTypeCheck("<< n << "): for " << Variant()->At(n).Type());
00597   const Type* proto = TypeRegistry::G()->Prototype(Variant()->At(n).Type()); 
00598   if(!proto) {
00599     FD_DLB("LuaFunction::DoTypeCheck("<< n << "): unknown type");
00600     return false;
00601   }
00602   if(!proto->Cast(ParamValue(n))) {
00603     FD_DLB("LuaFunction::DoTypeCheck("<< n << "): could not cast param value");
00604     return false;
00605   }
00606   return true;
00607 }
00608 
00609 
00610 // get/set lua state
00611 LuaState* LuaFunction::L(void) {
00612   if(!pL) pL=Definition()->DefaultL();
00613   return pL;
00614 }
00615 
00616 // get/set default lua state
00617 void LuaFunction::L(LuaState* l) {
00618   pL=l;
00619 }
00620 
00621 
00622 // implement execute: run stages
00623 void LuaFunction::DoExecute(void) {
00624   FD_DLB("LuaFunction::DoExecute()");
00625   /*
00626   for(int i=0; i< Variant()->Size(); i++) {
00627     FD_DLB("LuaFunction::DoExecute(): value at #" << i);
00628     ParamValue(i)->Write();
00629   }
00630   */
00631   // use the global state
00632   if(!pL) pL=L();
00633   pLL=pL->LL();
00634   mEntryStack=lua_gettop(pLL);
00635   // run stages
00636   DoExecuteA();
00637   DoExecuteB();
00638   DoExecuteC();
00639   DoExecuteD();
00640   // done
00641   lua_settop(pLL,mEntryStack);
00642   FD_DLB("LuaFunction::DoExecute(): done");
00643 }
00644 
00645 // implement execute: syntaxcheck
00646 void LuaFunction::SyntaxCheck(void) {
00647   FD_DLB("LuaFunction::SyntaxCheck()");
00648   // use the global state
00649   if(!pL) pL=L();
00650   pLL=pL->LL();
00651   mEntryStack=lua_gettop(pLL);
00652   // run stages
00653   DoExecuteA();
00654   DoExecuteB();
00655   // done
00656   lua_settop(pLL,mEntryStack);
00657   FD_DLB("LuaFunction::SyntaxCheck(): done");
00658 }
00659 
00660 // implement execute: get function on the stack
00661 void LuaFunction::DoExecuteA(void) {
00662   FD_DLB("LuaFunction::DoExecuteA()");
00663   // Lua stack: empty
00664   // load my script 
00665   const char* script = pLuaFuncDef->LuaCode().c_str();
00666   int script_len = pLuaFuncDef->LuaCode().size();
00667   int errload=luaL_loadbuffer(pLL, script, script_len, "luafaudes");
00668   if(errload!=0) {
00669     std::string lerr= std::string(lua_tostring(pLL, -1));
00670     int c1 = lerr.find_first_of(':');
00671     if(c1<0) c1=0;
00672     int c2 = lerr.find_first_of(':',c1+1);
00673     if(c2<0) c2=1;
00674     std::string line = lerr.substr(c1+1,c2-c1-1);  
00675     if(c2>1) {
00676       lerr="error in Lua script: line " + line + ": " + lerr.substr(c2+2);
00677     }
00678     lua_settop(pLL,mEntryStack);
00679     throw Exception("LuaFunction::DoExecuteA()", lerr, 49);
00680   }
00681   // Lua stack: script
00682   // install all functions aka run the script
00683   int errrun=lua_pcall(pLL, 0, 0, 0); 
00684   if(errrun!=0) {
00685     std::stringstream errstr;
00686     errstr << "failed to run script: ";
00687     errstr << std::string(lua_tostring(pLL, -1));
00688     lua_settop(pLL,mEntryStack);
00689     throw Exception("LuaFunction::DoExecuteA()", errstr.str(), 49);
00690   }
00691   // stack: []
00692   // get the swig generated table of faudes functions
00693   lua_getglobal(pLL,"faudes");
00694   mFtable=lua_gettop(pLL);
00695   if(!lua_istable(pLL,-1)) {
00696     lua_settop(pLL,mEntryStack);
00697     throw Exception("LuaFunction::DoExecuteA()", "failed to load faudes table", 49);
00698   }
00699   // stack: [faudes]
00700   // find my function: look up in faudes name space ...
00701   std::string fname = MangleString(Variant()->Name());
00702   lua_pushstring(pLL,fname.c_str());
00703   lua_gettable(pLL,mFtable);
00704   if(!lua_isfunction(pLL,-1)) {
00705     lua_pop(pLL, 1); // pop nil.
00706     lua_getglobal(pLL,fname.c_str()); // ... or as global (compatibility with pre 2.19)
00707     if(!lua_isfunction(pLL,-1)) {
00708       std::stringstream errstr;
00709       errstr << "missing function \"" << fname << "\"";
00710       lua_settop(pLL,mEntryStack);
00711       throw Exception("LuaFunction::DoExecuteA()", errstr.str(), 49);
00712     }
00713   }
00714   // stack: [faudes, luafnct]
00715   // construct a plain Type usrdata 
00716   lua_pushstring(pLL,"Type");
00717   lua_gettable(pLL,mFtable);
00718   if(!lua_isfunction(pLL,-1)) {
00719     lua_settop(pLL,mEntryStack);
00720     throw Exception("LuaFunction::DoExecuteA():", "failed to construct plain Type (1)", 49);
00721   }
00722   // stack: [faudes, luafnct, Type constructor]
00723   if(lua_pcall(pLL, 0, 1, 0) != 0) { 
00724     lua_settop(pLL,mEntryStack);
00725     throw Exception("LuaFunction::DoExecuteA():", "failed to construct plain Type (2)", 49);
00726   }
00727   // stack: [faudes, luafnct, Type variable]
00728   swig_lua_userdata* susr = (swig_lua_userdata*) lua_touserdata (pLL, -1);
00729   if(!susr) {
00730     lua_settop(pLL,mEntryStack);
00731     throw Exception("LuaFunction::DoExecuteA():", "failed to construct plain Type (3)", 49);
00732   }
00733   FD_DLB("LuaFunction::DoExecuteA(): plain type is " << susr->type->name);
00734   // record swig type of faudes plain Type
00735   mFType=susr->type;
00736   lua_pop(pLL, 1); 
00737   // stack: [faudes, luafnct]
00738 }
00739 
00740 // implement execute: prepare parameters
00741 void LuaFunction::DoExecuteB(void) {
00742   FD_DLB("LuaFunction::DoExecuteB()");
00743   // interpret signature
00744   mLReturn.resize(Variant()->Size());
00745   mLParameter.resize(Variant()->Size());
00746   mLReturnCount=0;
00747   mLParameterCount=0;
00748   for(int i=0; i< Variant()->Size(); i++) {
00749     const std::string& ftype= Variant()->At(i).Type();
00750     // default: parameter except for explicit creturn && out
00751     mLParameter.at(i)= !(Variant()->At(i).CReturn() && (Variant()->At(i).Attribute()==Parameter::Out));
00752     // default: explicitly declared creturn 
00753     mLReturn.at(i)= Variant()->At(i).CReturn();
00754     // autofix elementary parameters 
00755     if((ftype=="Integer") || (ftype=="Boolean") || (ftype=="String")) {
00756       // ... out becomes return value only
00757       if(Variant()->At(i).Attribute()==Parameter::Out) {
00758         mLReturn.at(i)=true;
00759         mLParameter.at(i)=false;
00760       }
00761       // ... inout becomes return value and parameter
00762       if(Variant()->At(i).Attribute()==Parameter::InOut) {
00763         mLReturn.at(i)=true;
00764         mLParameter.at(i)=true;
00765       }
00766       // ... in becomes parameter only
00767       if(Variant()->At(i).Attribute()==Parameter::In) {
00768         mLReturn.at(i)=false;
00769         mLParameter.at(i)=true;
00770       }
00771     }
00772     // keep counts
00773     if(mLReturn.at(i)) mLReturnCount++;
00774     if(mLParameter.at(i)) mLParameterCount++;
00775   }
00776 
00777   FD_DLB("LuaFunction::DoExecuteA(): found " << mLReturnCount << " return values and " 
00778    << mLParameterCount << " parameters");
00779   // stack: [faudes, luafnct]
00780   // construct my parameters in Lua
00781   for(int i=0; i< Variant()->Size(); i++) {
00782     const std::string& ftype= Variant()->At(i).Type();
00783     // skip non-parameter 
00784     if(!mLParameter.at(i)) {
00785       FD_DLB("LuaFunction::DoExecuteB(): skip nonparameter value pos " << i);
00786       continue;
00787     }
00788     // special case: int as lua number
00789     if(ftype=="Integer") {
00790       lua_pushnumber(pLL,((Integer*)ParamValue(i))->CValue());
00791       FD_DLB("LuaFunction::DoExecuteB(): created ftype " << ftype);
00792       continue;
00793     }
00794     // special case: bool as lua bool
00795     if(ftype=="Boolean") {
00796       lua_pushboolean(pLL,((Boolean*)ParamValue(i))->CValue());
00797       FD_DLB("LuaFunction::DoExecuteB(): created ftype " << ftype);
00798       continue;
00799     }
00800     // special case: str as lua string
00801     if(ftype=="String") {
00802       lua_pushstring(pLL,((String*)ParamValue(i))->CValue().c_str());
00803       FD_DLB("LuaFunction::DoExecuteB(): created ftype " << ftype);
00804       continue;
00805     }
00806     // std case: faudes type: construct 1
00807     lua_pushstring(pLL,ftype.c_str());
00808     lua_gettable(pLL,mFtable);
00809     if(!lua_isfunction(pLL,-1)) {
00810       std::stringstream errstr;
00811       errstr << "failed to load constructor for \"" << ftype << "\"";
00812       lua_settop(pLL,mEntryStack);
00813       throw Exception("LuaFunction::DoExecuteB()", errstr.str(), 49);
00814     }
00815     // std case: faudes type: construct 2
00816     if(lua_pcall(pLL, 0, 1, 0) != 0) { 
00817       std::stringstream errstr;
00818       errstr << "failed to construct for \"" << ftype << "\" (1)";
00819       lua_settop(pLL,mEntryStack);
00820       throw Exception("LuaFunction::DoExecuteB()", errstr.str(), 49);
00821     }
00822     // std case: test user data pointer
00823     swig_lua_userdata* susr = (swig_lua_userdata*) lua_touserdata (pLL, -1);
00824     if(!susr) {
00825       std::stringstream errstr;
00826       errstr << "failed to construct for\"" << ftype << "\" (2)";
00827       lua_settop(pLL,mEntryStack);
00828       throw Exception("LuaFunction::DoExecuteB()", errstr.str(), 49);
00829     }
00830     // inspect stack 
00831     FD_DLB("LuaFunction::DoExecuteB(): created stype " << susr->type->name << " for ftype " << ftype);
00832     FD_DLB("LuaFunction::DoExecuteB(): faudes parameter at " << ParamValue(i));
00833     FD_DLB("LuaFunction::DoExecuteB(): swig usrdata ptr  " << susr->ptr);
00834     FD_DLB("LuaFunction::DoExecuteB(): swig usrdata own flag  " << susr->own);
00835     /*
00836     // variant a: copy parameter value
00837     void* fptr=SwigCastPtr(susr->ptr,susr->type,(swig_type_info*)mFType);
00838     FD_DLB("LuaFunction::DoExecuteB(): faudes::Type converted ptr " << fptr);
00839     if(Variant()->At(i).Attribute()!=Parameter::Out) {
00840       FD_DLB("LuaFunction::DoExecuteB(): copy parameter value");
00841       ((Type*)fptr)->Assign(*ParamValue(i));
00842     }
00843     */
00844     // variant b: use references
00845     if(susr->own) free(susr->ptr);
00846     susr->own=0;
00847     susr->ptr = dynamic_cast<void*>(ParamValue(i)); // dynamic-up-cast: needed for multiple inheritance (!!)
00848   }
00849   // stack: [faudes, luafnct, rp_1 ... rp_n]
00850   FD_DLB("LuaFunction::DoExecuteB(): done");
00851 }
00852 
00853 // implement execute: execute the function
00854 void LuaFunction::DoExecuteC(void) {
00855   FD_DLB("LuaFunction::DoExecuteC()");
00856   // stack: [faudes, luafnct, rp_1 ... rp_n]
00857   // duplicate all my parameters (incl. the actual function for convenience)
00858   // note: needed only for variant a to retrieve values of faudes typed parameters 
00859   // note: duplication is cheap since these are references
00860   int t1=lua_gettop(pLL)-mLParameterCount;
00861   int t2=lua_gettop(pLL);
00862   for(int i= t1; i<=t2; i++) {
00863     lua_pushvalue(pLL,i);
00864 #ifdef  FAUDES_DEBUG_LUABINDINGS
00865     // report user data
00866     swig_lua_userdata* susr = (swig_lua_userdata*) lua_touserdata (pLL, -1);
00867     if(!susr) continue;
00868     // inspect user data stack 
00869     FD_DLB("LuaFunction::DoExecuteC(): inspect stype " << susr->type->name);
00870     FD_DLB("LuaFunction::DoExecuteC(): swig usrdata ptr  " << susr->ptr);
00871     FD_DLB("LuaFunction::DoExecuteC(): swig usrdata own flag  " << susr->own);
00872     void* fptr=SwigCastPtr(susr->ptr,susr->type,(swig_type_info*)mFType);
00873     FD_DLB("LuaFunction::DoExecuteC(): faudes::Type converted ptr " << fptr);
00874 #endif
00875   }
00876   // stack: [faudes, luafnct, rp_1 ... rp_n, luafnct, rp_1 ... rp_n]
00877   // run my function
00878   if(lua_pcall(pLL, mLParameterCount, mLReturnCount, 0) != 0) { 
00879     FD_DLB("LuaFunction::DoExecuteC(): detect error");
00880     std::string lerr= std::string(lua_tostring(pLL, -1));
00881     // user request via loopback exception
00882     if(lerr.find("break on application request")!=std::string::npos) {
00883       lerr="break on application request";
00884     }
00885     // user request via explicit exception
00886     else if(lerr.find("luafaudes script:")!=std::string::npos) {
00887       std::size_t c1=lerr.find("luafaudes script:");
00888       lerr=lerr.substr(c1);
00889     }
00890     // have line number ?
00891     else if(lerr.size()>=2) {
00892       std::size_t c1 = lerr.find_first_of(':');
00893       if(c1==std::string::npos) c1=0;
00894       if(c1+1>=lerr.size()) c1=0;
00895       std::size_t c2 = lerr.find_first_of(':',c1+1);
00896       if(c2==std::string::npos) c2=c1+1;
00897       if(c2>c1+1) {
00898         std::string line = lerr.substr(c1+1,c2-c1-1);  
00899         lerr="error in Lua script: line " + line + ": " + lerr.substr(c2+2);
00900       }
00901     }
00902     // anyway: fix stack
00903     lua_settop(pLL,mEntryStack);
00904     throw Exception("LuaFunction::DoExecuteC()", lerr, 49);
00905   }
00906   FD_DLB("LuaFunction::DoExecuteC():done ");
00907   // stack: [faudes, luafnct, rp_1 ... rp_n, lp1 ... lpm]
00908 }
00909 
00910 // implement execute: retrieve results
00911 void LuaFunction::DoExecuteD(void) {
00912   FD_DLB("LuaFunction::DoExecuteD()");
00913   // stack: [faudes, luafnct, rp_1 ... rp_n, lp1 ... lpm]
00914   // retrieve results from stack: return values
00915   for(int i=Variant()->Size()-1; i>=0; i--) {
00916     // skip non-return values
00917     if(!mLReturn.at(i)) continue;
00918     // switch on ftype
00919     const std::string& ftype= Variant()->At(i).Type();
00920     // int as lua number
00921     if(ftype=="Integer" && lua_isnumber(pLL,-1)) {
00922       FD_DLB("LuaFunction::DoExecuteD(): retrieve type " << ftype);
00923       ((Integer*)ParamValue(i))->CValue(lua_tonumber(pLL,-1));
00924       lua_pop(pLL, 1); 
00925       continue;
00926     }
00927     // bool as lua bool
00928     if(ftype=="Boolean" && lua_isboolean(pLL,-1)) {
00929       ((Boolean*)ParamValue(i))->CValue(lua_toboolean(pLL,-1));
00930       FD_DLB("LuaFunction::DoExecuteD(): retrieved type " << ftype);
00931       lua_pop(pLL, 1); 
00932       continue;
00933     }
00934     // str as lua string
00935     if(ftype=="String" && lua_isstring(pLL,-1)) {
00936       ((String*)ParamValue(i))->CValue(lua_tostring(pLL,-1));
00937       FD_DLB("LuaFunction::DoExecuteD(): retrieved type " << ftype);
00938       lua_pop(pLL, 1); 
00939       continue;
00940     }
00941     // report error
00942     std::stringstream errstr;
00943     errstr << "invalid return values in \"" << Variant()->Name() << "\"";
00944     lua_settop(pLL,mEntryStack);
00945     throw Exception("LuaFunction::DoExecuteD()", errstr.str(), 49);
00946   }
00947 
00948   // stack: [faudes, luafnct, rp_1 ... rp_n]
00949 
00950   /*
00951   // variant a: need to copy results
00952 
00953   // retrieve results from stack: duplicate references to parameters
00954   for(int i=Variant()->Size()-1; i>=0; i--) {
00955     // skip return values
00956     if(mLReturn.at(i)) continue;
00957     // switch on type type
00958     const std::string& ftype= Variant()->At(i).Type();
00959     // discrad/ignore duplicate parameters with access In
00960     if(Variant()->At(i).Attribute()==Parameter::In) {
00961       FD_DLB("LuaFunction::DoExecuteD(): ignore in-paremeter of type " << ftype);
00962       lua_pop(pLL, 1); 
00963       continue;
00964     }
00965     // discrad/ignore elementary types (lua call by value)
00966     if((ftype=="Integer") || (ftype=="Boolean") || (ftype=="String")) {
00967       FD_DLB("LuaFunction::DoExecuteD(): ignore elementary type parameter " << ftype);
00968       lua_pop(pLL, 1); 
00969       continue;
00970     }
00971     // std case: get updated value
00972     if(lua_isuserdata(pLL,-1)) {
00973       FD_DLB("LuaFunction::DoExecuteD(): try to retrieve type " << ftype);
00974       swig_lua_userdata* susr = (swig_lua_userdata*) lua_touserdata(pLL, -1);
00975       if(susr) {
00976         FD_DLB("LuaFunction::DoExecuteD(): found swig type " << susr->type->name << " at " << susr->ptr);
00977         FD_DLB("LuaFunction::DoExecuteD(): swig usrdata ptr " << susr->ptr);
00978         FD_DLB("LuaFunction::DoExecuteD(): swig usrdata own flag " << susr->own);
00979         void* fptr=SwigCastPtr(susr->ptr,susr->type,(swig_type_info*)mFType);
00980         FD_DLB("LuaFunction::DoExecuteD(): swig usrdata ptr faudes::Type converted " << fptr);
00981         FD_DLB("LuaFunction::DoExecuteD(): parameter value " << ParamValue(i));
00982         FD_DLB("LuaFunction::DoExecuteD(): copy parameter value");
00983         ParamValue(i)->Assign(*((Type*)fptr));
00984         // pop
00985         lua_pop(pLL, 1); 
00986         continue;
00987       }
00988     }
00989 
00990   */
00991 
00992   // variant b: discard duplicate parameters (did not need them for variant b anyway)
00993   for(int i=Variant()->Size()-1; i>=0; i--) {
00994     if(mLReturn.at(i)) continue;
00995     lua_pop(pLL, 1); 
00996   }
00997 
00998 } 
00999 
01000 
01001 
01002 
01003 /*
01004 ********************************************************************
01005 ********************************************************************
01006 ********************************************************************
01007 
01008 LuaState implementation
01009 
01010 ********************************************************************
01011 ********************************************************************
01012 ********************************************************************
01013 */
01014 
01015 // construct/destruct
01016 LuaState::LuaState(void) : mpLL(0) { Open(); }
01017 LuaState::~LuaState(void) { Close(); }   
01018 
01019 //access
01020 lua_State* LuaState::LL(void) { return mpLL; }
01021 
01022 // reinit
01023 void LuaState::Reset(void) { Close(); Open(); }
01024 
01025 // install extension
01026 void LuaState::Install(const std::string& rFilename) {
01027   Install(mpLL, rFilename);
01028 }
01029 
01030 // static state (convenience)
01031 LuaState* LuaState::G(void) {
01032   static LuaState* sls=NULL;
01033   if(!sls) sls=new LuaState();
01034   return sls;
01035 }
01036 
01037 // open/close lua state
01038 void LuaState::Open(void) {
01039   Close();
01040   FD_DLB("LuaState::Open()");
01041   mpLL=lua_open();
01042   Initialize(mpLL);
01043   FD_DLB("LuaState::Done()");
01044 }
01045 
01046 // open/close lua state
01047 void LuaState::Close(void) {
01048   if(!mpLL) return;
01049   FD_DLB("LuaState::Close()");
01050   lua_close(mpLL);
01051   mpLL=NULL;
01052 }
01053 
01054 // lua style interface to initialize lua state
01055 void LuaState::Initialize(lua_State* pLL) {
01056   lua_gc(pLL, LUA_GCSTOP, 0);     /* stop collector during initialization */
01057   luaL_openlibs(pLL);             /* open libraries */
01058   luaopen_faudes_allplugins(pLL); /* install my namespace */
01059   lua_gc(pLL, LUA_GCRESTART, 0);  /* restart collector */
01060 }
01061 
01062 
01063 
01064 // convenience function: load all luafunctions defined in a file
01065 void LuaState::Install(lua_State* pLL, const std::string& rFilename) {
01066   FD_DLB("LuaState::Insatll(): file " << rFilename);
01067   TokenReader tr(rFilename);
01068   Token token;
01069   while(tr.Peek(token)) {
01070     // todo: figure title  and ... luafaudes_dict_insert_topic(const std::string& topic, const std::string& text);
01071     if(!token.IsBegin("LuaFunctionDefinition")) {
01072       tr.Get(token);
01073       continue;
01074     }
01075     LuaFunctionDefinition lfd;
01076     lfd.Read(tr);
01077     FD_DLB("LuaState::Install(): found " << lfd.Name());
01078     lfd.Install(pLL);
01079   }
01080 }
01081 
01082 // convenience function: reister all luafunctions defined in a file
01083 void LuaState::Register(const std::string& rFilename) {
01084   FD_DLB("LuaState::Register(): file " << rFilename);
01085   TokenReader tr(rFilename);
01086   Token token;
01087   while(tr.Peek(token)) {
01088     if(!token.IsBegin("LuaFunctionDefinition")) {
01089       tr.Get(token);
01090       continue;
01091     }
01092     LuaFunctionDefinition*  plfd = new LuaFunctionDefinition();
01093     plfd->Read(tr);
01094     FD_DLB("LuaState::Register(): found " << plfd->Name());
01095     if(FunctionRegistry::G()->Exists(plfd->Name())) {
01096       FD_DLB("LuaState::Register(): skipping doublet " << plfd->Name());
01097       delete plfd;
01098       continue;
01099     }
01100     // Registry takes ownership
01101     FunctionRegistry::G()->Insert(plfd);
01102   }
01103 }
01104 
01105 
01106 } // namespace
01107 

libFAUDES 2.20d --- 2011.04.26 --- c++ source docu by doxygen