LCOV - code coverage report
Current view: top level - ugbase/bindings/lua - bindings_lua.cpp (source / functions) Coverage Total Hit
Test: coverage.info Lines: 0.0 % 448 0
Test Date: 2025-09-21 23:31:46 Functions: 0.0 % 23 0

            Line data    Source code
       1              : /*
       2              :  * Copyright (c) 2010-2015:  G-CSC, Goethe University Frankfurt
       3              :  * Author: Sebastian Reiter
       4              :  * 
       5              :  * This file is part of UG4.
       6              :  * 
       7              :  * UG4 is free software: you can redistribute it and/or modify it under the
       8              :  * terms of the GNU Lesser General Public License version 3 (as published by the
       9              :  * Free Software Foundation) with the following additional attribution
      10              :  * requirements (according to LGPL/GPL v3 §7):
      11              :  * 
      12              :  * (1) The following notice must be displayed in the Appropriate Legal Notices
      13              :  * of covered and combined works: "Based on UG4 (www.ug4.org/license)".
      14              :  * 
      15              :  * (2) The following notice must be displayed at a prominent place in the
      16              :  * terminal output of covered works: "Based on UG4 (www.ug4.org/license)".
      17              :  * 
      18              :  * (3) The following bibliography is recommended for citation and must be
      19              :  * preserved in all covered files:
      20              :  * "Reiter, S., Vogel, A., Heppner, I., Rupp, M., and Wittum, G. A massively
      21              :  *   parallel geometric multigrid solver on hierarchically distributed grids.
      22              :  *   Computing and visualization in science 16, 4 (2013), 151-164"
      23              :  * "Vogel, A., Reiter, S., Rupp, M., Nägel, A., and Wittum, G. UG4 -- a novel
      24              :  *   flexible software system for simulating pde based models on high performance
      25              :  *   computers. Computing and visualization in science 16, 4 (2013), 165-179"
      26              :  * 
      27              :  * This program is distributed in the hope that it will be useful,
      28              :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      29              :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
      30              :  * GNU Lesser General Public License for more details.
      31              :  */
      32              : 
      33              : #include <sstream>
      34              : #include <cstring>
      35              : #include <cstdlib>
      36              : #include <queue>
      37              : #include "bindings_lua.h"
      38              : #include "registry/registry.h"
      39              : #include "registry/class_helper.h"
      40              : #include "common/common.h"
      41              : #include "info_commands.h"
      42              : #include "lua_util.h"
      43              : #include "lua_parsing.h"
      44              : #ifdef UG_PARALLEL
      45              : #include "pcl/pcl_base.h"
      46              : #endif
      47              : #include "bridge/bridge.h"
      48              : 
      49              : #include "common/util/stringify.h"
      50              : #include "lua_stack.h"
      51              : 
      52              : //#define __UG__BINDINGS_LUA__CATCH_UNKNOWN_EXCEPTIONS__
      53              : 
      54              : using namespace std;
      55              : using namespace ug::script;
      56              : using namespace ug::bridge;
      57              : 
      58              : //      a symbol preceding error messages
      59              : static const char* errSymb = " % ";
      60              : 
      61              : ///     throw mechanism for lua related errors.
      62              : #define UG_LUA_THROW_EMPTY(luaState)    luaL_error(luaState, "%s", "__UG__LUA__EMPTY__MSG__")
      63              : #define UG_LUA_THROW(luaState, msg)             luaL_error(luaState, "\n%s", msg)
      64              : 
      65              : #define UG_LUA_BINDINGS_THROW(L) \
      66              :                         ug_throw_error(); \
      67              :                         UG_LUA_THROW_EMPTY(L);
      68              : 
      69              : #define UG_LUA_BINDINGS_CATCH(msg, args)\
      70              :                 catch(LuaError& err){ \
      71              :                         UG_LUA_THROW(L, err.get_msg().c_str()); \
      72              :                 } \
      73              :                 catch(SoftAbort& err){ \
      74              :                         throw err; \
      75              :                 } \
      76              :                 catch(UGError& err){ \
      77              :                         ug::LogAssistant& la = ug::GetLogAssistant();\
      78              :                         la.set_output_process(la.get_process_rank());\
      79              :                         la.flush();\
      80              :                         UG_LOG((Stringify() << "\n" << errSymb << "EXCEPTION on Proc "<<la.get_process_rank()<<":" \
      81              :                                 << " UGError thrown\n" \
      82              :                                 << UGErrorTraceback(err) \
      83              :                                 << errSymb << msg << "\n" \
      84              :                                 << errSymb <<"   ARGS: ("<< args << ")\n" \
      85              :                                 << errSymb<<"In FILE: " << GetLuaFileAndLineNumber(L) << "\n" \
      86              :                                 << errSymb<<"At LINE: '" << GetLuaLine(L) << "'\n").str()); \
      87              :                         /*PrintLUACallStack();*/\
      88              :                         la.flush();\
      89              :                         UG_LUA_BINDINGS_THROW(L)\
      90              :                 }\
      91              :                 catch(std::exception& ex)\
      92              :                 {\
      93              :                         ug::LogAssistant& la = ug::GetLogAssistant();\
      94              :                         la.set_output_process(la.get_process_rank());\
      95              :                         la.flush();\
      96              :                         UG_LOG((Stringify() << "\n" << errSymb << "EXCEPTION on Proc "<<la.get_process_rank()<<":\n" \
      97              :                                 << ErrorStringFromStdException(&ex) << "\n" \
      98              :                                 << errSymb << msg << "\n" \
      99              :                                 << errSymb <<"   ARGS: ("<< args << ")\n" \
     100              :                                 << errSymb<<"In FILE: " << GetLuaFileAndLineNumber(L) << "\n" \
     101              :                                 << errSymb<<"At LINE: '" << GetLuaLine(L) << "'\n").str()); \
     102              :                         /*PrintLUACallStack();*/\
     103              :                         la.flush();\
     104              :                         UG_LUA_BINDINGS_THROW(L);\
     105              :                 }\
     106              :                 catch(...)\
     107              :                 {\
     108              :                         ug::LogAssistant& la = ug::GetLogAssistant();\
     109              :                         la.set_output_process(la.get_process_rank());\
     110              :                         la.flush();\
     111              :                         UG_LOG((Stringify() << "\n" << errSymb << "EXCEPTION on Proc "<<la.get_process_rank()<<":" \
     112              :                                 << " Unknown Exception thrown\n" \
     113              :                                 << errSymb << msg << "\n" \
     114              :                                 << errSymb <<"With ARGUMENTS: ("<< args << ")\n" \
     115              :                                 << errSymb<<"In FILE: " << GetLuaFileAndLineNumber(L) << "\n" \
     116              :                                 << errSymb<<"At LINE: '" << GetLuaLine(L) << "'\n").str()); \
     117              :                                 /*PrintLUACallStack();*/\
     118              :                                 la.flush();\
     119              :                         UG_LUA_BINDINGS_THROW(L);\
     120              :                 }
     121              : 
     122              : 
     123              : namespace ug{
     124              : namespace bridge{
     125              : namespace lua{
     126              : 
     127              : //      set this variable to true if smart-ptr arguments shall be automatically
     128              : //      converted to raw-ptrs where required.
     129              : const bool IMLPICIT_SMART_PTR_TO_PTR_CONVERSION = true;
     130              : 
     131              : 
     132            0 : std::string ParameterStackString(ParameterStack &s)
     133              : {
     134            0 :         std::stringstream ss;
     135            0 :         for(int i=0; i<s.size(); i++)
     136              :         {
     137            0 :                 if(i != 0) ss << ", ";
     138            0 :                 if(s.is_vector(i)){
     139              :                         // todo: more specific output for vectors
     140            0 :                         ss << "std::vector";
     141              :                 } else {
     142            0 :                         switch(s.type(i))
     143              :                         {
     144            0 :                                 case Variant::VT_INVALID: ss << "invalid"; break;
     145              :                                 case Variant::VT_BOOL: ss << "bool " << s.to<bool>(i); break;
     146            0 :                                 case Variant::VT_INT: ss << "int " << s.to<int>(i); break;
     147              :                                 case Variant::VT_SIZE_T: ss << "size_t " << s.to<size_t>(i); break;
     148              :                                 case Variant::VT_FLOAT: ss << "float " << s.to<float>(i); break;
     149              :                                 case Variant::VT_DOUBLE: ss << "double " << s.to<double>(i); break;
     150            0 :                                 case Variant::VT_CSTRING: ss << "cstring \"" << s.to<const char*>(i) << "\""; break;
     151            0 :                                 case Variant::VT_STDSTRING: ss << "std::string \"" << s.to<std::string>(i) << "\""; break;
     152              :                                 case Variant::VT_POINTER: ss << "pointer " << s.to<void*>(i); break;
     153            0 :                                 case Variant::VT_CONST_POINTER: ss << "ConstPointer " << s.class_name(i) << " " << s.to<const void*>(i); break;
     154            0 :                                 case Variant::VT_SMART_POINTER: ss << "SmartPtr<" << s.class_name(i) << "> " << s.to<SmartPtr<void> >(i).get(); break;
     155            0 :                                 case Variant::VT_CONST_SMART_POINTER: ss << "ConstSmartPtr<" << s.class_name(i) << "> " << s.to<ConstSmartPtr<void> >(i).get(); break;
     156              :                         #ifdef UG_FOR_LUA
     157            0 :                                 case Variant::VT_LUA_FUNCTION_HANDLE: ss << "LuaFunctionHandle " << s.to<LuaFunctionHandle>(i).ref; break;
     158            0 :                                 case Variant::VT_LUA_TABLE_HANDLE: ss << "LuaFunctionHandle " << s.to<LuaFunctionHandle>(i).ref; break;
     159              :                         #endif
     160            0 :                                 default: ss << "unknown"; break;
     161              :                         }
     162              :                 }
     163              :         }
     164            0 :         return ss.str();
     165            0 : }
     166              : 
     167              : ///     creates a new UserDataWrapper and associates it with ptr in luas registry
     168              : /**
     169              :  * Creates a new userdata in lua, which encapsulates the given pointer / smart-pointer.
     170              :  * It then assigns the specified metatable to the userdata.
     171              :  * When the function is done, the userdata is left on luas stack.
     172              :  * \{
     173              :  */
     174            0 : SmartUserDataWrapper* CreateNewUserData(lua_State* L, const SmartPtr<void>& ptr,
     175              :                                                                                           const char* metatableName)
     176              : {
     177              : //      create the userdata
     178            0 :         SmartUserDataWrapper* udata = (SmartUserDataWrapper*)lua_newuserdata(L,
     179              :                                                                                         sizeof(SmartUserDataWrapper));
     180              :         new(udata) SmartUserDataWrapper;
     181              : 
     182              : //      associate the object with the userdata.
     183            0 :         udata->smartPtr = ptr;
     184            0 :         udata->type = SMART_POINTER;
     185              : 
     186              : //      associate the metatable (userdata is already on the stack)
     187            0 :         luaL_getmetatable(L, metatableName);
     188            0 :         lua_setmetatable(L, -2);
     189              : 
     190            0 :         return udata;
     191              : }
     192              : 
     193            0 : ConstSmartUserDataWrapper* CreateNewUserData(lua_State* L, const ConstSmartPtr<void>& ptr,
     194              :                                                                                           const char* metatableName)
     195              : {
     196              : //      create the userdata
     197            0 :         ConstSmartUserDataWrapper* udata = (ConstSmartUserDataWrapper*)lua_newuserdata(L,
     198              :                                                                                         sizeof(ConstSmartUserDataWrapper));
     199              : 
     200              :         new(udata) ConstSmartUserDataWrapper;
     201              : 
     202              : //      associate the object with the userdata.
     203            0 :         udata->smartPtr = ptr;
     204            0 :         udata->type = SMART_POINTER | IS_CONST;
     205              : 
     206              : //      associate the metatable (userdata is already on the stack)
     207            0 :         luaL_getmetatable(L, metatableName);
     208            0 :         lua_setmetatable(L, -2);
     209              : 
     210            0 :         return udata;
     211              : }
     212              : 
     213            0 : RawUserDataWrapper* CreateNewUserData(lua_State* L, void* ptr,
     214              :                                                                                   const char* metatableName,
     215              :                                                                                   void (*deleteFunc)(const void*),
     216              :                                                                                   bool is_const)
     217              : {
     218              : //      create the userdata
     219            0 :         RawUserDataWrapper* udata = (RawUserDataWrapper*)lua_newuserdata(L,
     220              :                                                                                         sizeof(RawUserDataWrapper));
     221              : 
     222              :         new(udata) RawUserDataWrapper;
     223              : 
     224              : //      associate the object with the userdata.
     225            0 :         udata->obj = ptr;
     226            0 :         udata->deleteFunc = deleteFunc;
     227            0 :         udata->type = RAW_POINTER;
     228            0 :         if(is_const)
     229            0 :                 udata->type |= IS_CONST;
     230              :         
     231              : //      associate the metatable (userdata is already on the stack)
     232            0 :         luaL_getmetatable(L, metatableName);
     233            0 :         lua_setmetatable(L, -2);
     234              :         
     235            0 :         return udata;
     236              : }
     237              : /** \} */
     238              : 
     239              : /**
     240              :  *
     241              :  * \brief returns a String describing the parameters on the lua stack
     242              :  * ex. "GlobalMultiGridRefiner*, LuaUserNumber2d*, number, string"
     243              :  */
     244              : // returns a String describing the parameters on the lua stack
     245            0 : static string GetLuaParametersString(lua_State* L, int offsetToFirstParam = 0)
     246              : {
     247              :         string str;
     248              :         bool bFirst=true;
     249            0 :         int index = offsetToFirstParam + 1; // stack-indices start with 1
     250            0 :         for(; lua_type(L, index) != LUA_TNONE; index++)
     251              :         {
     252            0 :                 if(!bFirst) str.append(", "); else bFirst = false;
     253            0 :                 str.append(GetLuaTypeString(L, index));
     254              :         }
     255            0 :         return str;
     256              : }
     257              : 
     258              : 
     259              : /**
     260              :  * if one of the parameters is nil, this returns an error
     261              :  * to warn the user about not initialised variables
     262              :  * @param L                                             the lua state
     263              :  * @param offsetToFirstParam    offset to first param
     264              :  * @return error string or ""
     265              :  */
     266            0 : string GetNilWarning(lua_State* L, int offsetToFirstParam)
     267              : {
     268            0 :         int index = offsetToFirstParam + 1; // stack-indices start with 1
     269              :         std::vector<int> indices;
     270            0 :         for(; lua_type(L, index) != LUA_TNONE; index++)
     271            0 :                 if(lua_isnil(L, index))
     272            0 :                         indices.push_back(index-offsetToFirstParam);
     273              : 
     274            0 :         if(indices.size() > 0)
     275              :         {
     276            0 :                 std::stringstream ss;
     277              : 
     278            0 :                 if(indices.size() == 1)
     279            0 :                         ss << errSymb << "WARNING: Argument " << indices[0] << " is nil, it is ";
     280              :                 else
     281              :                 {
     282            0 :                         ss << errSymb << "WARNING: Arguments ";
     283            0 :                         for(size_t i=0; i<indices.size()-1; i++)
     284              :                         {
     285            0 :                                 if(i>0) ss << ", ";
     286            0 :                                 ss << indices[i];
     287              :                         }
     288            0 :                         ss << " and " << indices[indices.size()-1] << " are nil, they are ";
     289              :                 }
     290            0 :                 ss << "possibly not initialized or initialized with an error.\n";
     291              :                 return ss.str();
     292            0 :         }
     293            0 :         else return "";
     294            0 : }
     295              : 
     296              : 
     297              : /**
     298              :  * users sometimes use the . operator (like in myObject.the_method(parameter) ), which sometimes print very weird error messages.
     299              :  * this function tries to catch some of those errors.
     300              :  * NOTE: this function can NOT catch errors like approxSpace.print_statistic() ( note the wrong . )
     301              :  * @param name the name of the function. will be used to search "."+name in the code.
     302              :  * @return error string or ""
     303              :  */
     304            0 : std::string GetColonWarning(std::string name)
     305              : {
     306            0 :         std::string line = GetLuaLine(GetDefaultLuaState());
     307            0 :         if(line.find(std::string(".") + name) != std::string::npos)
     308            0 :                 return std::string(errSymb) + "WARNING: You seem to have used the point operator. Remember that for calling method b of an object A, you must use A:b(c), NOT A.b(c)\n";
     309              :         else
     310            0 :                 return "";
     311              : }
     312              : 
     313              : /**
     314              :  *
     315              :  * \returns     String describing the reason why LuaStackToParams failed.
     316              :  * \param paramsTempalte
     317              :  * \param L
     318              :  * \param offsetToFirstParam
     319              :  * \param badParamOneBased : return value as in LuaStackParams
     320              :  * \sa LuaStackToParams
     321              :  */
     322            0 : static string GetTypeMismatchString(const ParameterInfo& paramsTemplate,
     323              :                                                                         lua_State* L, int offsetToFirstParam,
     324              :                                                                         int badParamOneBased)
     325              : {
     326            0 :         std::stringstream ss;
     327              : 
     328            0 :         if(badParamOneBased == -1)
     329              :                 ss << "number of parameters did not match (got "
     330            0 :                         << lua_gettop(L) - offsetToFirstParam
     331            0 :                         << ", but needs " << paramsTemplate.size() << ").";
     332              :         else
     333              :         {
     334            0 :                 int i = badParamOneBased-1; // i is zero-based.
     335            0 :                 int index = (int)i + offsetToFirstParam + 1;
     336              :                 ss << "type mismatch in argument " << badParamOneBased
     337            0 :                         << ": expected " << ParameterToString(paramsTemplate, i)
     338            0 :                         << ", but given " << GetLuaTypeString(L, index);
     339              :         }
     340            0 :         return ss.str();
     341            0 : }
     342              : 
     343              : 
     344              : 
     345              : 
     346              : /**
     347              :  * @param err
     348              :  * @return traceback of errors in UGError err
     349              :  */
     350            0 : string UGErrorTraceback(UGError &err)
     351              : {
     352            0 :         std::stringstream ss;
     353              : //      header
     354            0 :         ss << errSymb<<"  Error traceback (innermost first): \n";
     355              : 
     356              : //      padding to insert
     357            0 :         std::string pad(errSymb); pad.append("     ");
     358              : 
     359              : //      print each message
     360            0 :         for(size_t i=0;i<err.num_msg();++i)
     361              :         {
     362              :         //      get copy of original string
     363              :                 std::string msg = err.get_msg(i);
     364              : 
     365              :         //      add paddings
     366              :                 std::string::size_type pos = 0;
     367              :                 while (1) {
     368            0 :                     pos = msg.find('\n', pos);
     369            0 :                     if (pos == std::string::npos) break;
     370            0 :                     pos++;
     371              :                     msg.insert(pos, pad);
     372              :                 }
     373              : 
     374              :         //      write message
     375            0 :                 ss << errSymb<<std::setw(3)<<i<<": "<<msg<<endl;
     376              : 
     377              :         //      write file and line
     378            0 :                 ss << pad << "[at "<<SnipStringFront(err.get_file(i), 62, 3);
     379            0 :                 ss<<":"<<err.get_line(i)<<"]"<<endl;
     380              :         }
     381            0 :         return ss.str();
     382            0 : }
     383              : 
     384              : /**
     385              :  * prints the LUA Call Stack, i.e.
     386              :  * the call stack of functions calls in LUA up to this point,
     387              :  * files and filelines.
     388              :  */
     389            0 : void PrintLUACallStack()
     390              : {
     391            0 :         std::string s = LuaStackTraceString();
     392            0 :         if(s.length())
     393              :         {
     394              :                 UG_LOG("Call Stack:\n" << s << "\n");
     395              :         }
     396            0 : }
     397              : 
     398              : /**
     399              :  * LuaProxyFunction handling calls to global functions.
     400              :  * Note that not the best matching, but the first matching overload is chosen!
     401              :  * @param L
     402              :  * @return The number of items pushed to the stack
     403              :  */
     404            0 : static int LuaProxyFunction(lua_State* L)
     405              : {
     406              :         const ExportedFunctionGroup* funcGrp = (const ExportedFunctionGroup*)
     407            0 :                                                                                         lua_touserdata(L, lua_upvalueindex(1));
     408              : //      we have to try each overload!
     409              :         int badParam = -2;
     410            0 :         for(size_t i = 0; i < funcGrp->num_overloads(); ++i){
     411            0 :                 const ExportedFunction* func = funcGrp->get_overload(i);
     412              : 
     413            0 :                 ParameterStack paramsIn;
     414            0 :                 ParameterStack paramsOut;
     415              : 
     416            0 :                 badParam = LuaStackToParams(paramsIn, func->params_in(), L, 0);
     417              : 
     418              :         //      check whether the parameter was correct
     419            0 :                 if(badParam != 0){
     420              :                 //      parameters didn't match. Try the next overload.
     421              :                         continue;
     422              :                 }
     423              : 
     424              :                 try{
     425              :                         func->execute(paramsIn, paramsOut);
     426              :                 }
     427            0 :                 UG_LUA_BINDINGS_CATCH("In CALL to function '" << FunctionInfo(*func) << "'", ParameterStackString(paramsIn));
     428              : 
     429              :         //      if we reach this point, then the method was successfully executed.
     430            0 :                 return ParamsToLuaStack(paramsOut, L);
     431            0 :         }
     432              : 
     433              :         if(badParam != 0)
     434              :         {
     435            0 :                 UG_LOG(errSymb<<"Error at "<<GetLuaFileAndLine(L) << ":\n");
     436            0 :                 UG_LOG(errSymb<<"ERROR occured when trying to call '"
     437              :                            << funcGrp->name() << "(" << GetLuaParametersString(L, 0) << "):'\n");
     438            0 :                 UG_LOG(GetNilWarning(L, 0));
     439              : 
     440            0 :                 UG_LOG(errSymb<<"No matching overload found! Candidates are:\n");
     441            0 :                 for(size_t i = 0; i < funcGrp->num_overloads(); ++i)
     442              :                 {
     443            0 :                         const ExportedFunction* func = funcGrp->get_overload(i);
     444            0 :                         ParameterStack paramsIn;
     445            0 :                         badParam = LuaStackToParams(paramsIn, func->params_in(), L, 0);
     446            0 :                         UG_LOG(errSymb<<" - ");
     447            0 :                         UG_LOG(FunctionInfo(*func));
     448            0 :                         UG_LOG(": " << GetTypeMismatchString(func->params_in(), L, 0, badParam) << "\n");
     449            0 :                 }
     450              : 
     451            0 :                 PrintLUACallStack();
     452              : 
     453            0 :                 UG_LUA_THROW_EMPTY(L);
     454              :         }
     455              : 
     456              : //      this point shouldn't be reached
     457            0 :         UG_LUA_THROW(L, "Unknown internal error!");
     458            0 :         return 0;
     459              : }
     460              : 
     461              : /**
     462              :  * Helper function of LuaProxyConstructor and LuaProxyGroupConstructor
     463              :  * @param L
     464              :  * @param c the class to create and object of
     465              :  * @param groupname if not nil, c is the default class of this group
     466              :  * @return The number of items pushed to the stack (should be one = 1 object).
     467              :  */
     468            0 : static int LuaConstructor(lua_State* L, IExportedClass* c, const char *groupname=nullptr)
     469              : {
     470              : //      try each constructor overlaod
     471              :         int badParam = -2;
     472            0 :         for(size_t i = 0; i < c->num_constructors(); ++i)
     473              :         {
     474              :         //      get overload
     475            0 :                 const ExportedConstructor& constr = c->get_constructor(i);
     476              : 
     477            0 :                 ParameterStack paramsIn;
     478            0 :                 badParam = LuaStackToParams(paramsIn, constr.params_in(), L, 0);
     479              : 
     480              :         //      check whether the parameter was correct
     481            0 :                 if(badParam != 0)
     482              :                 {
     483              :                 //      parameters didn't match. Try the next overload.
     484              :                         continue;
     485              :                 }
     486              : 
     487              :                 try{
     488            0 :                         if(c->construct_as_smart_pointer()){
     489            0 :                                 CreateNewUserData(L,
     490            0 :                                         SmartPtr<void>(constr.create(paramsIn), c->get_delete_function()),
     491            0 :                                         c->name().c_str());
     492              :                         }
     493              :                         else{
     494            0 :                                 CreateNewUserData(L, constr.create(paramsIn), c->name().c_str(),
     495            0 :                                                                   c->get_delete_function(), false);
     496              :                         }
     497              :                 }
     498            0 :                 UG_LUA_BINDINGS_CATCH("When CREATING class '"<< c->name()  << "'", ParameterStackString(paramsIn));
     499              : 
     500              :         //      object created
     501              :                 return 1;
     502            0 :         }
     503              : 
     504              : //      no matching overload found
     505              :         if(badParam != 0)
     506              :         {
     507            0 :                 UG_LOG(errSymb<<"Error at "<<GetLuaFileAndLine(L) << ":\n");
     508            0 :                 UG_LOG(errSymb<<"ERROR occured when trying to create object of ");
     509            0 :                 if(groupname)
     510            0 :                 {       UG_LOG("group " << groupname << " (default class " << c->name() << ") with constructor '" << c->name());      }
     511              :                 else
     512            0 :                 {       UG_LOG("class " << c->name() << " with constructor '" << c->name());        }
     513            0 :                 UG_LOG("(" << GetLuaParametersString(L, 0) << ")':\n");
     514            0 :                 UG_LOG(GetNilWarning(L, 0));
     515            0 :                 UG_LOG(errSymb<<"No matching overload found! Candidates are:\n");
     516            0 :                 for(size_t i = 0; i < c->num_constructors(); ++i)
     517              :                 {
     518            0 :                         const ExportedConstructor& constr = c->get_constructor(i);
     519            0 :                         ParameterStack paramsIn;
     520            0 :                         badParam = LuaStackToParams(paramsIn, constr.params_in(), L, 0);
     521            0 :                         UG_LOG(errSymb << " - ");
     522            0 :                         UG_LOG(ConstructorInfo(constr, c->name().c_str()));
     523            0 :                         UG_LOG(": " << GetTypeMismatchString(constr.params_in(), L, 0, badParam) << "\n");
     524            0 :                 }
     525            0 :                 PrintLUACallStack();
     526              :                 //UG_LOG(errSymb<<"Call stack:\n");     LuaStackTrace(L);
     527            0 :                 UG_LUA_THROW_EMPTY(L);
     528              :         }
     529              : 
     530              :         //UG_LOG(errSymb<<"Call stack:\n"); LuaStackTrace(L);
     531            0 :         UG_LUA_THROW_EMPTY(L);
     532              : 
     533            0 :         return 0;
     534              : }
     535              : 
     536              : /**
     537              :  * creates a object of a class
     538              :  * @param L
     539              :  * @return The number of items pushed to the stack (should be one = 1 object).
     540              :  */
     541            0 : static int LuaProxyConstructor(lua_State* L)
     542              : {
     543              : //      get class
     544            0 :         IExportedClass* c = (IExportedClass*)lua_touserdata(L, lua_upvalueindex(1));
     545            0 :         return LuaConstructor(L, c);
     546              : }
     547              : 
     548              : 
     549              : /**
     550              :  * creates the class which is set as default class for the specified group.
     551              :  * we assume that the first upvalue is a ClassGroupDesc*
     552              :  * @param L
     553              :  * @return The number of items pushed to the stack (should be one = 1 object).
     554              :  */
     555            0 : static int LuaProxyGroupConstructor(lua_State* L)
     556              : {
     557              : //      get the group and make sure that it contains data
     558            0 :         const ClassGroupDesc* group = (ClassGroupDesc*)lua_touserdata(L, lua_upvalueindex(1));
     559              : 
     560            0 :         if(group->empty()){
     561            0 :                 UG_LOG(errSymb<<"Error at "<<GetLuaFileAndLine(L) << ":\n")
     562            0 :                 UG_LOG(errSymb<<"Can't create default instance of group '" << group->name());
     563              :                 UG_LOG("': Group is empty!\n");
     564            0 :                 lua_pushnil(L);
     565            0 :                 return 1;
     566              :         }
     567              : 
     568              : //      get the associated default class
     569              :         IExportedClass* c = group->get_default_class();
     570              : 
     571            0 :         if(!c){
     572            0 :                 UG_LOG(errSymb<<"Error at "<<GetLuaFileAndLine(L) << ":\n")
     573            0 :                 UG_LOG(errSymb<<"Can't create default instance of group '" << group->name());
     574              :                 UG_LOG("': No default class set! (Have you called InitUG?)\n");
     575            0 :                 lua_pushnil(L);
     576            0 :                 return 1;
     577              :         }
     578              : 
     579            0 :         return LuaConstructor(L, c, group->name().c_str());
     580              : }
     581              : 
     582              : /**
     583              :  * This method is not called by lua, but a helper to LuaProxyMethod.
     584              :  * It recursively calls itself until a matching overload was found.
     585              :  * @param L
     586              :  * @param methodGrp
     587              :  * @param self
     588              :  * @param classNameNode
     589              :  * @param errorOutput
     590              :  * @return The number of items pushed to the stack
     591              :  */
     592            0 : static int ExecuteMethod(lua_State* L, const ExportedMethodGroup* methodGrp,
     593              :                                                 UserDataWrapper* self, const ClassNameNode* classNameNode,
     594              :                                                 bool errorOutput)
     595              : {
     596            0 :         ParameterStack paramsIn;;
     597            0 :         ParameterStack paramsOut;
     598              : 
     599              :         //int badParam = LuaStackToParams(paramsIn, m->params_in(), L, 1);
     600              : 
     601              : //      we have to try each overload!
     602              :         int badParam = -2;
     603            0 :         for(size_t i = 0; i < methodGrp->num_overloads(); ++i){
     604            0 :                 const ExportedMethod* m = methodGrp->get_overload(i);
     605              : 
     606            0 :                 ParameterStack paramsIn;
     607            0 :                 ParameterStack paramsOut;
     608              : 
     609            0 :                 badParam = LuaStackToParams(paramsIn, m->params_in(), L, 1);
     610              : 
     611              :         //      check whether the parameter was correct
     612            0 :                 if(badParam != 0){
     613              :                 //      parameters didn't match. Try the next overload.
     614              :                         continue;
     615              :                 }
     616              : 
     617              :                 try
     618              :                 {
     619              :                 //      raw pointer
     620            0 :                         if(self->is_raw_ptr())
     621              :                         {
     622              :                         //      cast to the needed base class
     623            0 :                                 void* objPtr = ClassCastProvider::cast_to_base_class(
     624              :                                                                                         ((RawUserDataWrapper*)self)->obj,
     625              :                                                                                         classNameNode, m->class_name().c_str());
     626              : 
     627              :                                 m->execute(objPtr, paramsIn, paramsOut);
     628              :                         }
     629              :                 //      smart pointer
     630            0 :                         else if(self->is_smart_ptr())
     631              :                         {
     632            0 :                                 if(self->is_const())
     633              :                                 {
     634              :                                 //      cast to the needed base class
     635            0 :                                         void* objPtr = ClassCastProvider::cast_to_base_class(
     636              :                                                                                                 (void*)((ConstSmartUserDataWrapper*)self)->smartPtr.get(),
     637              :                                                                                                 classNameNode, m->class_name().c_str());
     638              : 
     639              :                                         m->execute(objPtr, paramsIn, paramsOut);
     640              :                                 }
     641              :                                 else
     642              :                                 {
     643              :                                 //      cast to the needed base class
     644            0 :                                         void* objPtr = ClassCastProvider::cast_to_base_class(
     645              :                                                                                                 ((SmartUserDataWrapper*)self)->smartPtr.get(),
     646              :                                                                                                 classNameNode, m->class_name().c_str());
     647              : 
     648              :                                         m->execute(objPtr, paramsIn, paramsOut);
     649              :                                 }
     650              :                         }
     651              :                 }
     652            0 :                 UG_LUA_BINDINGS_CATCH("In CALL to method '" << LuaClassMethodInfo(L, 1, *m)  << "'", ParameterStackString(paramsIn));
     653              : 
     654              :         //      if we reach this point, then the method was successfully executed.
     655              :         //      return values to lua!
     656              : 
     657            0 :                 if(m->has_custom_return())           
     658              :                         return 1;               
     659              :                 
     660            0 :                 return ParamsToLuaStack(paramsOut, L);
     661            0 :         }
     662              : 
     663              : //      check whether the parameters were correct
     664              :         if(badParam != 0)
     665              :         {
     666              :         //      they were not. If the class has a base class, then we can try to
     667              :         //      to find a method-group in one of the base classes and recursively
     668              :         //      call this method.
     669            0 :                 if(classNameNode != nullptr){
     670              :                 //      check whether a base-class contains overloads of this method-group
     671              :                 //      push all base classes to this queue of class name nodes
     672              :                         std::queue<const ClassNameNode*> qClassNameNodes;
     673            0 :                         for(size_t i = 0; i < classNameNode->num_base_classes(); ++i)
     674            0 :                                 qClassNameNodes.push(&classNameNode->base_class(i));
     675              : 
     676              :                 //      now visit the whole base-class hierarchy to find overloads of
     677              :                 //      this method. Stop if one was successfully executed.
     678            0 :                         while(!qClassNameNodes.empty()){
     679            0 :                                 const ClassNameNode* curClassName = qClassNameNodes.front();
     680              :                                 qClassNameNodes.pop();
     681              : 
     682              :                         //      get the metatable of this class
     683            0 :                                 luaL_getmetatable(L, curClassName->name().c_str());
     684              : 
     685              :                         //      check whether the metatable contains a method-group with
     686              :                         //      the given name
     687              :                                 const ExportedMethodGroup* newMethodGrp = nullptr;
     688            0 :                                 if(!self->is_const()){
     689              :                                 //      access the table which stores method-groups
     690            0 :                                         lua_pushstring(L, "__method_grps");
     691            0 :                                         lua_rawget(L, -2);
     692              : 
     693            0 :                                         if(lua_istable(L, -1)){
     694            0 :                                                 lua_pushstring(L, methodGrp->name().c_str());
     695            0 :                                                 lua_rawget(L, -2);
     696              : 
     697              :                                         //      if we retrieved something != nil, we've found one.
     698            0 :                                                 if(!lua_isnil(L, -1)){
     699              :                                                         newMethodGrp = (const ExportedMethodGroup*)
     700            0 :                                                                                         lua_touserdata(L, -1);
     701              :                                                 }
     702              : 
     703              :                                         //      pop the result
     704            0 :                                                 lua_pop(L, 1);
     705              :                                         }
     706              :                                 //      pop the table
     707            0 :                                         lua_pop(L, 1);
     708              :                                 }
     709              : 
     710              :                         //      if the object is const or if no non-const member was found,
     711              :                         //      we'll check the const methods
     712            0 :                                 if(!newMethodGrp){
     713              :                                 //      the method is const
     714            0 :                                         lua_pushstring(L, "__const_method_grps");
     715            0 :                                         lua_rawget(L, -2);
     716              : 
     717            0 :                                         if(lua_istable(L, -1)){
     718              :                                         //      check whether the entry is contained in the table
     719            0 :                                                 lua_pushstring(L, methodGrp->name().c_str());
     720            0 :                                                 lua_rawget(L, -2);
     721              : 
     722              :                                         //      if we retrieved something != nil, we're done.
     723            0 :                                                 if(!lua_isnil(L, -1)){
     724              :                                                         newMethodGrp = (const ExportedMethodGroup*)
     725            0 :                                                                                         lua_touserdata(L, -1);
     726              :                                                 }
     727              : 
     728              :                                         //      remove result from stack
     729            0 :                                                 lua_pop(L, 1);
     730              :                                         }
     731              :                                 //      remove __const table from stack
     732            0 :                                         lua_pop(L, 1);
     733              :                                 }
     734              : 
     735              :                         //      remove metatable from stack
     736            0 :                                 lua_pop(L, 1);
     737              : 
     738              :                         //      if we found a base-implementation, call it now.
     739              :                         //      if not, add all base-classes to the queue again.
     740              :                         //      NOTE: If a base class contains the implementation, we
     741              :                         //      don't have to add it to the queue, since the method
     742              :                         //      is recursive.
     743            0 :                                 if(newMethodGrp){
     744            0 :                                         int retVal = ExecuteMethod(L, newMethodGrp, self,
     745              :                                                                                                 curClassName, errorOutput);
     746            0 :                                         if(retVal >= 0)
     747              :                                                 return retVal;
     748              :                                 }
     749              :                                 else{
     750            0 :                                         for(size_t i = 0; i < curClassName->num_base_classes(); ++i)
     751            0 :                                                 qClassNameNodes.push(&curClassName->base_class(i));
     752              :                                 }
     753              :                         }
     754              : 
     755              :                 }
     756              : 
     757              :         //      neither the given class nor one of its base classes contains a matching
     758              :         //      overload of the given method. We thus have to output errors.
     759              :         //      Here we only print the overload-infos. The rest is done in LuaProxyMethod.
     760            0 :                 if(errorOutput){
     761            0 :                         for(size_t i = 0; i < methodGrp->num_overloads(); ++i)
     762              :                         {
     763            0 :                                 const ExportedMethod* func = methodGrp->get_overload(i);
     764            0 :                                 ParameterStack paramsIn;
     765            0 :                                 badParam = LuaStackToParams(paramsIn, func->params_in(), L, 1);
     766            0 :                                 UG_LOG("- " << FunctionInfo(*func) << ": " << GetTypeMismatchString(func->params_in(), L, 1, badParam) << "\n");
     767            0 :                         }
     768              :                 }
     769              :         }
     770              :         
     771              :         return -1;
     772            0 : }
     773              : /**
     774              :  * a default __tostring method which shows classname: \<adress\>
     775              :  * __tostring is used in all print(object) and tostring(object) calls in LUA
     776              :  * @param L
     777              :  * @return nr of parameters (its one string)
     778              :  */
     779            0 : static int LuaToStringDefault(lua_State *L)
     780              : {
     781            0 :         IExportedClass* c = (IExportedClass*)lua_touserdata(L, lua_upvalueindex(1));
     782            0 :         ParameterStack out;
     783              :         char buf[255];
     784              :         try{
     785            0 :                 sprintf(buf, "[ %s: %p", c->name().c_str(), c);
     786              : 
     787              :         }
     788            0 :         catch(...)
     789              :         {
     790              :                 sprintf(buf, "%p", c);
     791              : 
     792            0 :         }
     793            0 :         string b = buf;
     794            0 :         out.push(b);
     795            0 :         return ParamsToLuaStack(out, L);
     796            0 : }
     797              : 
     798              : 
     799              : 
     800              : /**
     801              :  * member methods of classes are handled here
     802              :  * @param L the lua State
     803              :  * @return number of parameters returned
     804              :  */
     805            0 : static int LuaProxyMethod(lua_State* L)
     806              : {
     807              :         const ExportedMethodGroup* methodGrp = (const ExportedMethodGroup*)
     808            0 :                                                                                         lua_touserdata(L, lua_upvalueindex(1));
     809              : 
     810            0 :         if(!lua_isuserdata(L, 1))
     811              :         {
     812            0 :                 UG_LOG(GetColonWarning(methodGrp->name()));
     813            0 :                 UG_LOG(errSymb<<"Error at "<<GetLuaFileAndLine(L) << ":\n")
     814            0 :                 UG_LOG(errSymb<<"Error in call to LuaProxyMethod: No object specified in call to '");
     815            0 :                 UG_LOG(LuaClassMethodInfo(L, 1, *methodGrp->get_overload(0)));
     816              :                 UG_LOG("'.\n");
     817            0 :                 return 0;
     818              :         }
     819              : 
     820            0 :         UserDataWrapper* self = (UserDataWrapper*)lua_touserdata(L, 1);
     821              : 
     822              : //      get metatable of object and extract the class name node
     823            0 :         lua_getmetatable(L, 1);
     824            0 :         lua_pushstring(L, "class_name_node");
     825            0 :         lua_rawget(L, -2);
     826              :         const ClassNameNode* classNameNode
     827            0 :                 = (const ClassNameNode*) lua_touserdata(L, -1);
     828            0 :         lua_pop(L, 2);
     829              : 
     830            0 :         int retVal = ExecuteMethod(L, methodGrp, self, classNameNode, false);
     831            0 :         if(retVal >= 0)
     832              :                 return retVal;
     833              : 
     834              : //      The call failed. We have to output errors
     835              :         const char *classname = "(unknown class)";
     836            0 :         if(classNameNode != nullptr)
     837              :                 classname = classNameNode->name().c_str();
     838              : 
     839            0 :         UG_LOG(errSymb<<"Error at "<<GetLuaFileAndLine(L) << ":\n");
     840            0 :         UG_LOG(errSymb<<"There is no member function '"
     841              :                    << classname << ":" << methodGrp->name() << "(" <<
     842              :                    GetLuaParametersString(L, 1) << ")':\n");
     843              : 
     844            0 :         UG_LOG(GetNilWarning(L, 1));
     845            0 :         UG_LOG(GetColonWarning(methodGrp->name()));
     846            0 :         UG_LOG(errSymb<<"No matching overload found! Candidates in class "
     847              :                         << classname << " are:\n");
     848              : 
     849              : //      since no matching method was found, we'll run ExecuteMethod again, this
     850              : //      time outputting the errors
     851            0 :         ExecuteMethod(L, methodGrp, self, classNameNode, true);
     852              : 
     853            0 :         PrintLUACallStack();
     854              : 
     855              :         //UG_LOG(errSymb<<"Call stack:\n"); LuaStackTrace(L);
     856            0 :         UG_LUA_THROW_EMPTY(L);
     857              : 
     858            0 :         return 0;
     859              : }
     860              : 
     861              : /**
     862              :  * This function is used if the user enters a member function wrong and returns
     863              :  * the best guess what he means.
     864              :  * Also searches in base classes.
     865              :  * @param c                     (in) the class
     866              :  * @param name          (in) the name of the member function we are searching
     867              :  * @param minname       (out) the name of the closest match to name (in Levenshtein-Distance)
     868              :  * @param mind          (out) number of edits needed from name -> minname
     869              :  */
     870            0 : void GetBestMatchingMember(const IExportedClass *c, const char *name, std::string &minname, int &mind)
     871              : {
     872              :         const char *funcname;
     873            0 :         for(size_t i=0; i<c->num_const_methods(); i++)
     874              :         {
     875            0 :                 funcname = c->get_const_method(i).name().c_str();
     876            0 :                 int d = LevenshteinDistance(funcname, name );
     877            0 :                 if(d < mind)
     878              :                 {
     879              :                         minname = funcname;
     880            0 :                         mind = d;
     881              :                 }
     882              :         }
     883            0 :         for(size_t i=0; i<c->num_methods(); i++)
     884              :         {
     885            0 :                 funcname = c->get_method(i).name().c_str();
     886              : 
     887            0 :                 int d = LevenshteinDistance(funcname, name );
     888            0 :                 if(d < mind)
     889              :                 {
     890              :                         minname = funcname;
     891            0 :                         mind = d;
     892              :                 }
     893              :         }
     894              :         // search in the classes derived from
     895            0 :         const vector<const char *> *pNames = c->class_names();
     896            0 :         if(pNames)
     897              :         {
     898            0 :                 bridge::Registry &reg = ug::bridge::GetUGRegistry();
     899            0 :                 for(size_t i=1; i<pNames->size(); i++) // skip the class itself
     900            0 :                         GetBestMatchingMember(reg.get_class(pNames->at(i)), name, minname, mind);
     901              :         }
     902            0 : }
     903              : 
     904              : /**
     905              :  * @sa GetBestMatchingMember
     906              :  */
     907            0 : void GetBestMatchingMember(const char *classname, const char *name, std::string &minname, int &mind)
     908              : {
     909            0 :         bridge::Registry &reg = ug::bridge::GetUGRegistry();
     910            0 :         const IExportedClass *c = reg.get_class(classname);
     911              :         minname = "";
     912            0 :         mind = 10;
     913            0 :         GetBestMatchingMember(c, name, minname, mind);
     914            0 : }
     915              : 
     916              : //TODO: The metatable indexer could probably be integrated into ExecuteMethod,
     917              : //              (called by LuaProxyMethod) and thus be avoided completely.
     918              : //              Note that a recursion over the base classes is performed in
     919              : //              ExecuteMethod, too.
     920            0 : static int MetatableIndexer(lua_State*L)
     921              : {
     922              : //      the stack contains the object and the requested key (the method name).
     923              : //      we have to make sure to only call const methods on const objects
     924            0 :         bool is_const = ((UserDataWrapper*)lua_touserdata(L, 1))->is_const();
     925              :         
     926              : //      first we push the objects metatable onto the stack.
     927            0 :         lua_getmetatable(L, 1);
     928              : 
     929              : //      queue of class name nodes
     930              :         std::queue<const ClassNameNode*> qClassNameNodes;
     931              : 
     932              : //      now we have to traverse the class hierarchy
     933              :         while(1)
     934              :         {
     935              :         //      if the object is not const, check whether the key is in the current metatable
     936            0 :                 if(!is_const){
     937            0 :                         lua_pushvalue(L, 2);
     938            0 :                         lua_rawget(L, -2);
     939              :                 
     940              :                 //      if we retrieved something != nil, we're done.
     941            0 :                         if(!lua_isnil(L, -1))
     942              :                                 return 1;
     943              :         
     944            0 :                         lua_pop(L, 1);
     945              :                 }
     946              :                 
     947              :         //      the next thing to check are the const methods
     948            0 :                 lua_pushstring(L, "__const");
     949            0 :                 lua_rawget(L, -2);
     950            0 :                 if(!lua_isnil(L, -1)){
     951              :                 //      check whether the entry is contained in the table
     952            0 :                         lua_pushvalue(L, 2);
     953            0 :                         lua_rawget(L, -2);
     954              :                 
     955              :                 //      if we retrieved something != nil, we're done.
     956            0 :                         if(!lua_isnil(L, -1)){
     957              :                                 return 1;
     958              :                         }
     959              :                                 
     960              :                 //      remove nil from stack
     961            0 :                         lua_pop(L, 1);
     962              :                 }
     963            0 :                 lua_pop(L, 1);
     964              :                 
     965              :         //      the requested key has not been in the metatable.
     966              :         //      we thus have to check the parents metatable.
     967              : 
     968            0 :                 lua_pushstring(L, "class_name_node");
     969            0 :                 lua_rawget(L, -2);
     970            0 :                 const ClassNameNode* pClassNameNode = (const ClassNameNode*) lua_touserdata(L, -1);
     971            0 :                 lua_pop(L, 2);
     972              : 
     973              :         //      push all base classes to queue
     974            0 :                 for(size_t i = 0; i < pClassNameNode->num_base_classes(); ++i)
     975              :                 {
     976            0 :                         qClassNameNodes.push(&pClassNameNode->base_class(i));
     977              :                 }
     978              : 
     979              :         //      check if some base class left; if not, return nil
     980            0 :                 if(qClassNameNodes.empty())
     981              :                 {
     982            0 :                         lua_getmetatable(L, 1);
     983            0 :                         lua_pushstring(L, "class_name_node");
     984            0 :                         lua_rawget(L, -2);
     985            0 :                         const ClassNameNode* pClassNameNode = (const ClassNameNode*) lua_touserdata(L, -1);
     986            0 :                         lua_pop(L, 2);
     987              :                         const char *classname = pClassNameNode->name().c_str();
     988            0 :                         const char *funcname = lua_tostring(L, -1);
     989            0 :                         UG_LOG("LUA ERROR! Could not find member function \"" << funcname << "\" of class " << classname << ". ");
     990            0 :                         lua_pushnil(L);
     991              : 
     992              :                         std::string minname;
     993            0 :                         int mind =0;
     994            0 :                         GetBestMatchingMember(classname, funcname, minname, mind);
     995            0 :                         if(mind < (int)strlen(funcname)/2)
     996              :                         { UG_LOG("Did you mean " << minname << " ?\n"); }
     997              :                         else { UG_LOG("\n"); }
     998              :                         return 1;
     999              :                 }
    1000              : 
    1001              :         //      get metatable of first base class
    1002            0 :                 luaL_getmetatable(L, qClassNameNodes.front()->name().c_str());
    1003              :                 qClassNameNodes.pop();
    1004              :         }
    1005              : 
    1006              : //      this point should never be reached
    1007              :         return 0;
    1008              : }
    1009              : 
    1010            0 : static int LuaProxyRelease(lua_State* L)
    1011              : {
    1012            0 :         void* ptr = lua_touserdata(L, 1);
    1013              : //      we only proceed if the userdata encapsulates a smart pointer
    1014            0 :         if(((UserDataWrapper*)ptr)->is_smart_ptr()){
    1015              :         //      invalidate the associated smart-pointer
    1016            0 :                 if(((UserDataWrapper*)ptr)->is_const())
    1017            0 :                         ((ConstSmartUserDataWrapper*)ptr)->smartPtr.invalidate();
    1018              :                 else
    1019            0 :                         ((SmartUserDataWrapper*)ptr)->smartPtr.invalidate();
    1020              :         }
    1021            0 :         return 0;
    1022              : }
    1023              : 
    1024            0 : static int LuaProxyDelete(lua_State* L)
    1025              : {
    1026            0 :         void* ptr = lua_touserdata(L, 1);
    1027              : //      we perform delete if the user-data is a raw pointer
    1028            0 :         if(((UserDataWrapper*)ptr)->is_raw_ptr()){
    1029              :                 RawUserDataWrapper* udata = (RawUserDataWrapper*)ptr;
    1030            0 :                 if(udata->deleteFunc){
    1031            0 :                         udata->deleteFunc(udata->obj);
    1032            0 :                         ((RawUserDataWrapper*)ptr)->obj = nullptr;
    1033              :                 }
    1034              :                 else{
    1035              :                         UG_LOG("WARNING in LuaProxyDelete: Can't delete object, since"
    1036              :                                         "object was not created from script.\n");
    1037              :                 }
    1038              :         }
    1039            0 :         else if(((UserDataWrapper*)ptr)->is_smart_ptr()){
    1040              :         //      invalidate the associated smart-pointer
    1041            0 :                 if(((UserDataWrapper*)ptr)->is_const())
    1042            0 :                         ((ConstSmartUserDataWrapper*)ptr)->smartPtr.invalidate();
    1043              :                 else
    1044            0 :                         ((SmartUserDataWrapper*)ptr)->smartPtr.invalidate();
    1045              :         }
    1046            0 :         return 0;
    1047              : }
    1048              : 
    1049              : 
    1050              : 
    1051              : /**
    1052              :  * Registers a meta-object for each class and class group found in the ug registry reg.
    1053              :  * Global functions are registered for all GlobalFunction-objects in the registry reg.
    1054              :  * @param L the Lua State
    1055              :  * @param reg the ug registry
    1056              :  * @return true on success
    1057              :  */
    1058            0 : bool CreateBindings_LUA(lua_State* L, Registry& reg)
    1059              : {
    1060              : //      iterate through all registered objects
    1061              :         
    1062              : /*
    1063              : //      create the ug-table in which all our methods will go.
    1064              :         lua_newtable(L);
    1065              : //      set the name of the table
    1066              :         lua_setglobal(L, "ug");
    1067              :         */
    1068              : 
    1069              : ////////////////////////////////
    1070              : //      create some common methods
    1071            0 :         lua_getglobal(L, "delete");
    1072            0 :         if(!lua_isnil(L, -1)){
    1073              :         //      the method already exists. Don't recreate it.
    1074            0 :                 lua_pop(L, 1);
    1075              :         }
    1076              :         else{
    1077              :         //      the method doesn't exist yet. Create it.
    1078            0 :                 lua_pop(L, 1);
    1079            0 :                 lua_pushcfunction(L, LuaProxyDelete);
    1080            0 :                 lua_setglobal(L, "delete");
    1081              :         }
    1082              : 
    1083              : ////////////////////////////////
    1084              : //      create a method for each global function, which calls LuaProxyFunction with
    1085              : //      a an index to the function.
    1086            0 :         size_t numFuncs = reg.num_functions();
    1087              :         
    1088            0 :         for(size_t i = 0; i < numFuncs; ++i){
    1089            0 :                 ExportedFunctionGroup* funcGrp = &reg.get_function_group(i);
    1090              : 
    1091              :         //      check whether the function already exists
    1092            0 :                 lua_getglobal(L, funcGrp->name().c_str());
    1093            0 :                 if(!lua_isnil(L, -1)){
    1094              :                 //      the method already exists. Don't recreate it.
    1095            0 :                         lua_pop(L, 1);
    1096            0 :                         continue;
    1097              :                 }
    1098            0 :                 lua_pop(L, 1);
    1099              :                 
    1100              :         //      the function is new. Register it.
    1101            0 :                 lua_pushlightuserdata(L, funcGrp);
    1102            0 :                 lua_pushcclosure(L, LuaProxyFunction, 1);
    1103            0 :                 lua_setglobal(L, funcGrp->name().c_str());
    1104              :         }
    1105              : 
    1106              : 
    1107            0 :         size_t numClasses = reg.num_classes();
    1108            0 :         for(size_t i = 0; i < numClasses; ++i){
    1109            0 :                 const IExportedClass* c = &reg.get_class(i);
    1110              :                 
    1111              :         //      check whether the class already exists
    1112            0 :                 lua_getglobal(L, c->name().c_str());
    1113            0 :                 if(!lua_isnil(L, -1)){
    1114              :                 //      the class already exists. Don't recreate it.
    1115            0 :                         lua_pop(L, 1);
    1116            0 :                         continue;
    1117              :                 }
    1118            0 :                 lua_pop(L, 1);
    1119              :                 
    1120              :         //      The class is new. Register it.
    1121            0 :                 if(c->is_instantiable())
    1122              :                 {
    1123              :                 //      set the constructor-function
    1124            0 :                         lua_pushlightuserdata(L, (void*)c);
    1125            0 :                         lua_pushcclosure(L, LuaProxyConstructor, 1);
    1126            0 :                         lua_setglobal(L, c->name().c_str());
    1127              :                 }
    1128              : 
    1129              :         //      create the meta-table for the object
    1130              :         //      overwrite index and store the class-name
    1131            0 :                 luaL_newmetatable(L, c->name().c_str());
    1132              :         //      we use our custom indexing method to allow method-derivation
    1133            0 :                 lua_pushcfunction(L, MetatableIndexer);
    1134            0 :                 lua_setfield(L, -2, "__index");
    1135              :         //      in order to support smart-pointers we have to overload the garbage-collection
    1136            0 :                 lua_pushcfunction(L, LuaProxyRelease);
    1137            0 :                 lua_setfield(L, -2, "__gc");
    1138              :         //      we have to store the class-names of the class hierarchy
    1139            0 :                 lua_pushstring(L, "class_name_node");
    1140            0 :                 lua_pushlightuserdata(L, (void*)&(c->class_name_node()));
    1141            0 :                 lua_settable(L, -3);
    1142              : 
    1143              :         //      add class name hierarchy
    1144              :         //      \todo: REMOVE, only needed by info commands.
    1145            0 :                 lua_pushstring(L, "__names");
    1146            0 :                 lua_pushlightuserdata(L, (void*)c->class_names());
    1147            0 :                 lua_settable(L, -3);
    1148              : 
    1149              :                 bool bToStringFound =false;
    1150              : 
    1151              :         //      register methods
    1152              :         //      NOTE: A C-Closure is registered (a function-pointer with default argument)
    1153            0 :                 for(size_t j = 0; j < c->num_methods(); ++j){
    1154            0 :                         const ExportedMethodGroup& m = c->get_method_group(j);
    1155            0 :                         lua_pushstring(L, m.name().c_str());
    1156            0 :                         lua_pushlightuserdata(L, (void*)&m);
    1157            0 :                         lua_pushcclosure(L, LuaProxyMethod, 1);
    1158            0 :                         lua_settable(L, -3);
    1159            0 :                         if(m.name().compare("__tostring") == 0) bToStringFound = true;
    1160              :                 }
    1161              : 
    1162            0 :                 if(bToStringFound==false)
    1163              :                 {
    1164              :                         // we did not find a __tostring function for lua
    1165              :                         // for print(myObject) to use myObject:__tostring() it is necessary
    1166              :                         // that __tostring is in the direct metatable of myObject, and not in __const
    1167              :                         // (somehow lua does not use the metatable indexer provided here)
    1168              :                         // so if there is a __tostring() const function, but none non-const,
    1169              :                         // we also put the __tostring() const function in the non-const part,
    1170              :                         // which should be no harm, since a const function could also
    1171              :                         // be a non-const function (the reverse is not true)
    1172            0 :                         for(size_t j = 0; j < c->num_const_methods(); ++j)
    1173              :                         {
    1174            0 :                                 const ExportedMethodGroup& m = c->get_const_method_group(j);
    1175            0 :                                 if(m.name().compare("__tostring") == 0)
    1176              :                                 {
    1177            0 :                                         lua_pushstring(L, m.name().c_str());
    1178            0 :                                         lua_pushlightuserdata(L, (void*)&m);
    1179            0 :                                         lua_pushcclosure(L, LuaProxyMethod, 1);
    1180            0 :                                         lua_settable(L, -3);
    1181              :                                         bToStringFound = true;
    1182            0 :                                         break;
    1183              :                                 }
    1184              :                         }
    1185              :                 }
    1186              : 
    1187              :         //      register const-methods
    1188              :         //      NOTE: A C-Closure is registered (a function-pointer with default argument)
    1189            0 :                 if(c->num_const_methods() > 0)
    1190              :                 {
    1191              :                 //      create a new table in the meta-table and store it in the entry __const
    1192            0 :                         lua_newtable(L);
    1193            0 :                         for(size_t j = 0; j < c->num_const_methods(); ++j){
    1194            0 :                                 const ExportedMethodGroup& m = c->get_const_method_group(j);
    1195            0 :                                 lua_pushstring(L, m.name().c_str());
    1196            0 :                                 lua_pushlightuserdata(L, (void*)&m);
    1197            0 :                                 lua_pushcclosure(L, LuaProxyMethod, 1);
    1198            0 :                                 lua_settable(L, -3);
    1199              :                         }
    1200            0 :                         lua_setfield(L, -2, "__const");
    1201              :                 }
    1202              : 
    1203              :         //      register method-groups
    1204              :         //      NOTE: Pointers to ExportedMethodGroups are registered (lua userdatas)
    1205            0 :                 if(c->num_methods() > 0){
    1206            0 :                         lua_newtable(L);
    1207            0 :                         for(size_t j = 0; j < c->num_methods(); ++j){
    1208            0 :                                 const ExportedMethodGroup& m = c->get_method_group(j);
    1209            0 :                                 lua_pushstring(L, m.name().c_str());
    1210            0 :                                 lua_pushlightuserdata(L, (void*)&m);
    1211            0 :                                 lua_settable(L, -3);
    1212              :                         }
    1213            0 :                         lua_setfield(L, -2, "__method_grps");
    1214              :                 }
    1215              : 
    1216              :         //      register const-methods-groups
    1217              :         //      NOTE: Pointers to ExportedMethodGroups are registered (lua userdatas)
    1218            0 :                 if(c->num_const_methods() > 0)
    1219              :                 {
    1220              :                 //      create a new table in the meta-table and store it in the entry __const
    1221            0 :                         lua_newtable(L);
    1222            0 :                         for(size_t j = 0; j < c->num_const_methods(); ++j){
    1223            0 :                                 const ExportedMethodGroup& m = c->get_const_method_group(j);
    1224            0 :                                 lua_pushstring(L, m.name().c_str());
    1225            0 :                                 lua_pushlightuserdata(L, (void*)&m);
    1226            0 :                                 lua_settable(L, -3);
    1227              :                         }
    1228            0 :                         lua_setfield(L, -2, "__const_method_grps");
    1229              :                 }
    1230              :                 
    1231              :                 // if we did not find a __tostring function, we
    1232              :                 // add a default __tostring method which shows 
    1233              :                 // classname: <adress>
    1234            0 :                 if(bToStringFound == false)
    1235              :                 {
    1236            0 :                         lua_pushstring(L, "__tostring");
    1237            0 :                         lua_pushlightuserdata(L, (void*)c);
    1238            0 :                         lua_pushcclosure(L, LuaToStringDefault, 1);
    1239            0 :                         lua_settable(L, -3);
    1240              :                 }
    1241              :         //      pop the metatable from the stack.
    1242            0 :                 lua_pop(L, 1);
    1243              :         }
    1244              :         
    1245              : //      now register constructors for class-groups
    1246            0 :         size_t numClassGroups = reg.num_class_groups();
    1247            0 :         for(size_t i = 0; i < numClassGroups; ++i){
    1248            0 :                 const ClassGroupDesc* cg = reg.get_class_group(i);
    1249              : 
    1250              :         //      check whether the class-group already exists
    1251            0 :                 lua_getglobal(L, cg->name().c_str());
    1252            0 :                 if(!lua_isnil(L, -1)){
    1253              :                 //      the class-group already exists. Don't recreate it.
    1254            0 :                         lua_pop(L, 1);
    1255            0 :                         continue;
    1256              :                 }
    1257            0 :                 lua_pop(L, 1);
    1258              : 
    1259              :         //      The class-group is new. Register the proxy-constructor.
    1260            0 :                 lua_pushlightuserdata(L, (void*)cg);
    1261            0 :                 lua_pushcclosure(L, LuaProxyGroupConstructor, 1);
    1262            0 :                 lua_setglobal(L, cg->name().c_str());
    1263              :         }
    1264              : 
    1265            0 :         return true;
    1266              : }
    1267              : 
    1268              : }//     end of namespace
    1269              : }//     end of namespace
    1270              : }//     end of namespace
        

Generated by: LCOV version 2.0-1