-
Notifications
You must be signed in to change notification settings - Fork 1
/
luawrap.cpp
361 lines (325 loc) · 10.6 KB
/
luawrap.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
#include "luawrap.h"
#include <cmath>
LuaWrap::LuaWrap(const char* file)
{
Lua = NULL;
//Initialization of the Lua State variable
Lua = luaL_newstate();
luaL_openlibs(Lua);
//Let's open the file!
if(luaL_loadfile(Lua, file))
{
std::cout << "Error loading Lua Script: " << file << std::endl;
}
path = file;
}
LuaWrap::~LuaWrap()
{
//Let's delete the Lua State and Argument Stack pointers
if(Lua)
lua_close(Lua);
if(argStack)
delete argStack;
}
bool LuaWrap::executeFunction(const std::string& funcName)
{
size_t argCount = 0;
int errStatus = 0;
if(hasResult)
{
ClearResult();
}
//Now, let's set the function!
lua_setglobal(Lua, funcName.c_str());
if(lua_isfunction(Lua, LUA_TOPITEM))
{
std::cout << "Error attempting to run function: " << funcName <<". Check that the name is a valid Lua function in the current Engine Version!"
<< std::endl;
return false;
}
//Check for the presence of arguments before deciding how to run the function!
if(!argStack->empty())
{
//Let's reverse the order of the stack. A queue would have done the same job, but I like stacks!
*argStack = reverseOrderStack(*argStack);
argCount = argStack->size();
while(!argStack->empty())
{
PushToLua(Lua, argStack->top());
argStack->pop();
}
}
//Let's run the function!
/*The following function uses a mixture of the Lua documentation (http://pgl.yoyo.org/luai/i/lua_pcall) and a stack overflow
question about how to extract the stacktrace from the pcall execution function
(http://stackoverflow.com/questions/12256455/print-stacktrace-from-c-code-with-embedded-lua)
*/
errStatus = lua_pcall(Lua, argCount, LUA_MULTRET, lua_gettop(Lua) - LUA_TOPITEM - argCount);
//Check status code
ErrF(Lua, errStatus);
return true;
}
//Argument methods
void LuaWrap::AddArgument(int argument)
{
fuzzy_obj tmp;
tmp.number = argument;
tmp.flag = 'i';
argStack->push(tmp);
}
void LuaWrap::AddArgument(const std::string& argument)
{
fuzzy_obj tmp;
tmp.str = argument;
tmp.flag = 's';
argStack->push(tmp);
}
void LuaWrap::AddArgument(char argument)
{
fuzzy_obj tmp;
tmp.c = argument;
tmp.flag = 'c';
argStack->push(tmp);
}
void LuaWrap::AddArgument(double argument)
{
fuzzy_obj tmp;
tmp.decimal = argument;
tmp.flag = 'd';
argStack->push(tmp);
}
void LuaWrap::AddArgument(unsigned int argument)
{
fuzzy_obj tmp;
tmp.uNumber = argument;
tmp.flag = 'u';
argStack->push(tmp);
}
void LuaWrap::AddArgument(bool argument)
{
fuzzy_obj tmp;
tmp.answer = argument;
tmp.flag = 'b';
argStack->push(tmp);
}
void LuaWrap::AddArgument(void_ptr argument)
{
fuzzy_obj tmp;
tmp.ptr = argument;
tmp.flag = 'v';
argStack->push(tmp);
}
int LuaWrap::lua_extractInt(lua_State* results) const
{
if(lua_isnumber(results, LUA_TOPITEM))
return lua_tointeger(results, LUA_TOPITEM);
std::cout << "Warning: Lua result is not an integer. Undefined behavior may occur! Warning in script: " << path
<< std::endl;
return 0;
}
double LuaWrap::lua_extractDouble(lua_State* results) const
{
if(lua_isnumber(results, LUA_TOPITEM))
return lua_tonumber(results, LUA_TOPITEM);
std::cout << "Warning: Lua result is not a double. Undefined behavior may occur! Warning in script: " << path
<< std::endl;
return 0.0f;
}
char LuaWrap::lua_extractChar(lua_State* results) const
{
if(lua_isstring(results, LUA_TOPITEM))
return lua_tostring(results, LUA_TOPITEM)[0];
std::cout << "Warning: Lua result is not a char. Undefined behavior may occur! Warning in script: " << path
<< std::endl;
return 0;
}
std::string LuaWrap::lua_extractStr(lua_State* results) const
{
if(lua_isstring(results, LUA_TOPITEM))
return lua_tostring(results, LUA_TOPITEM);
std::cout << "Warning: Lua result is not a string. Undefined behavior may occur! Warning in script: " << path
<< std::endl;
return "";
}
bool LuaWrap::lua_extractBool(lua_State* results) const
{
if(lua_isboolean(results, LUA_TOPITEM))
return bool(lua_tointeger(results, LUA_TOPITEM));
std::cout << "Warning: Lua result is not boolean. Undefined behavior may occur! Warning in script: " << path
<< std::endl;
return false;
}
void_ptr LuaWrap::lua_extractPtr(lua_State* results) const
{
return (void_ptr)lua_topointer(results, LUA_TOPITEM);
}
std::vector<fuzzy_obj> LuaWrap::GenerateListFromLuaTable()
{
/*If I read the documentation correctly, lua_next empties the table and I end up cleaning the pushed key-value
pairs, so I will flag this method as a single use method that calls clean stack and resets the state of result!
Make sure you limit your script-engine communication such that this method is called once or the spawning
script function is called multiple times!
*/
std::vector<fuzzy_obj> tmp;
lua_gettable(Lua, LUA_TOPITEM);//index of table
size_t t = lua_tointeger(Lua, 2);
if(lua_isnil(Lua, LUA_TOPITEM))//check the table is valid
return tmp;
lua_pushnil(Lua);//Push top key? http://pgl.yoyo.org/luai/i/lua_next //http://eliasdaler.wordpress.com/2013/10/20/lua_and_cpp_pt2/
while(lua_next(Lua, t))//Obtain key-value pairs
{
fuzzy_obj obj;
obj.flag = GetResultType(Lua);
switch(obj.flag)
{
case 'i':
obj.number = lua_extractInt(Lua);
break;
case 'd':
obj.decimal = lua_extractDouble(Lua);
break;
case 'b':
obj.answer = lua_extractBool(Lua);
break;
case 'c':
obj.c = lua_extractChar(Lua);
break;
case 's':
obj.str = lua_extractStr(Lua);
break;
case 'v':
obj.ptr = lua_extractPtr(Lua);
break;
default:
std::cout << "Error: Argument from array returned by script function is not a valid type! "
<< "Wow, the cake is a lie!" << std::endl;
}
tmp.push_back(obj);
}
//Let's clean the stack from the new items
ClearResult();
hasResult = false;//Flag the result as destroyed
//Return copy of the vector!
return tmp;
}
bool LuaWrap::isResultVoid() const
{
return lua_isnoneornil(Lua, lua_gettop(Lua));
}
char LuaWrap::GetResultType(lua_State* result) const
{
if(lua_isboolean(result, LUA_TOPITEM))
return 'b';
if(lua_isnumber(result, LUA_TOPITEM))
{
if(lua_tonumber(result, LUA_TOPITEM)/round(lua_tonumber(result, LUA_TOPITEM)))
return 'i';
else
return 'd';
}
if(lua_isstring(result, LUA_TOPITEM))
{
if(std::string(lua_tostring(result, LUA_TOPITEM)).length() == 1)
return 'c';
return 's';
}
return 'v';
}
lua_State* LuaWrap::GetInternalState() const
{
return Lua;
}
bool LuaWrap::ClearArgs(int n)
{
//Here I pop all of the elements in the Argument Stack!
//Passing -1 should yield a full stack cleanup because stackSize + n != argStack->size()--; use LUA_ERASE_ALL
size_t stackSize = argStack->size();
while(!argStack->empty() && (stackSize - n) != argStack->size())
{
argStack->pop();
}
}
void LuaWrap::ClearResult()
{
//This method is a just-in-case method. It may never get used.
//This method will pop the result from the lua state stack!
//This method also clears all other items from the stack!
lua_pop(Lua, lua_gettop(Lua));
}
size_t LuaWrap::GetResultSize() const
{
//This method is not 100% safe if the lua table conforms to some special cases
//(http://stackoverflow.com/questions/4815588/request-a-lua-table-size-in-c-before-iterating-it)!
return lua_rawlen(Lua, LUA_TOPITEM);
}
//Private methods
int LuaWrap::traceback(lua_State* lua)
{
/*This method was built using the different responses to a stack overflow question!
http://stackoverflow.com/questions/12256455/print-stacktrace-from-c-code-with-embedded-lua
*/
if (!lua_isstring(lua, 1)) /* 'message' not a string? */
return 1; /* keep it intact */
lua_getfield(lua, LUA_REGISTRYINDEX, "debug");//LUA_GLOBALINDEX for lua 5.1 and LUA_REGISTRYINDEX for > 5.2
//http://stackoverflow.com/questions/10087226/lua-5-2-lua-globalsindex-alternative
if (!lua_istable(lua, -1))
{
std::cerr << lua_tostring(lua, LUA_TOPITEM) << std::endl;/*Get item string for the stacktrace!*/
lua_pop(lua, 1);
return 1;
}
lua_getfield(lua, -1, "traceback");
if (!lua_isfunction(lua, -1))
{
std::cerr << lua_tostring(lua, LUA_TOPITEM) << std::endl;/*Get item string for the stacktrace!*/
lua_pop(lua, 2);
return 1;
}
lua_pushvalue(lua, 1); /* pass error message */
lua_pushinteger(lua, 2); /* skip this function and traceback */
lua_call(lua, 2, 1); /* call debug.traceback */
std::cerr << lua_tostring(lua, LUA_TOPITEM) << std::endl;/*Get item string for the stacktrace!*/
return 1;
}
void LuaWrap::ErrF(lua_State* result, int status)
{
/*This method will leave a notice in the standard output so the user checks the stacktrace.
It will let you know the status code regardless of whether a stacktrace was made for the
script!
*/
if(status)
{
std::cerr << lua_tostring(Lua, LUA_TOPITEM) << std::endl;/*Get item string for the stacktrace!*/
/*Leave an error notice in the standard output!*/
std::cout << "Error executing Lua script! Execution ended with status: " << status <<std::endl
<<"For more information, check the Lua documentation and the standard error stacktrace (cerr) if any!"
<< std::endl;
}
}
void LuaWrap::PushToLua(lua_State* lua, const fuzzy_obj& obj)
{
switch(obj.flag)
{
case 'i':
lua_pushinteger(Lua, obj.number);
break;
case 'd':
lua_pushnumber(Lua, obj.decimal);
break;
case 'b':
lua_pushboolean(Lua, obj.answer);
break;
case 's':
lua_pushstring(Lua, obj.str.c_str());
break;
case 'c':
lua_pushinteger(Lua, (int)obj.c);
break;
case 'u':
lua_pushinteger(Lua, reinterpret_cast<unsigned int>(obj.uNumber));
break;
default:
std::cout << "Warning: Argument object does not contain a valid flag or is empty (flag = 'n')! This object has the flag "
<< obj.flag << "!" << std::endl;
}
}