lbp_function.cppGo 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 |