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 ® = 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 ® = 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 = ®.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 = ®.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
|