libFAUDES
Sections
Index
|
lbp_function.cppGo 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