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