aboutsummaryrefslogtreecommitdiff
path: root/LuaScript.cpp
blob: a47d5c44c353942837d22d43a90132ffda848a49 (plain)
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
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
// ---------------------------------------------------------------------------
// FILE NAME            : LuaScript.cpp
// ---------------------------------------------------------------------------
// DESCRIPTION :
//
// Simple debugging routines
// 
// ---------------------------------------------------------------------------
// VERSION              : 1.00
// DATE                 : 1-Sep-2005
// AUTHOR               : Richard Shephard
// ---------------------------------------------------------------------------
// LIBRARY INCLUDE FILES
#include <assert.h>
#include "luainc.h"
#include "luascript.h"
#include "luarestorestack.h"
#include "luathis.h"
// ---------------------------------------------------------------------------

#define BEGIN_LUA_CHECK(vm)   lua_State *state = (lua_State *) vm; \
                              if (vm.Ok ()) { 
#define END_LUA_CHECK         }


//============================================================================
// int LuaCallback
//---------------------------------------------------------------------------
// Lua C-API calling that figures out which object to hand over to
//
// Parameter   Dir      Description
// ---------   ---      -----------
// lua         IN       State variable
//
// Return
// ------
// Number of return varaibles on the stack
//
// Comments
// --------
// This is the function lua calls for each C-Function that is
// registered with lua. At the time of registering the function
// with lua, we make lua record the method "number" so we can
// know what method was actually called. The lua stack is the
// following structure:
// 0: 'this' (table)
// 1 - ...: parameters passed in
//
//============================================================================
static int LuaCallback (lua_State *lua)
{
   // Locate the psudo-index for the function number
   int iNumberIdx = lua_upvalueindex (1);
   int nRetsOnStack = 0;

   bool fSuccess = false;

   // Check for the "this" table
   if (lua_istable (lua, 1))
   {
      // Found the "this" table. The object pointer is at the index 0
      lua_rawgeti (lua, 1, 0);
      
      if (lua_islightuserdata (lua, -1))
      {
         // Found the pointer, need to cast it
         CLuaScript *pThis = (CLuaScript *) lua_touserdata (lua, -1);

         // Get the method index
         int iMethodIdx = (int) lua_tonumber (lua, iNumberIdx);

         // Check that the method is correct index
         assert (!(iMethodIdx > pThis->methods ()));

         // Reformat the stack so our parameters are correct
         // Clean up the "this" table
         lua_remove (lua, 1);
         // Clean up the pThis pointer
         lua_remove (lua, -1);

         // Call the class
         nRetsOnStack = pThis->ScriptCalling (pThis->vm (), iMethodIdx);

         fSuccess = true;
      }
   }

   if (fSuccess == false)
   {
      lua_pushstring (lua, "LuaCallback -> Failed to call the class function");
      lua_error (lua);
   }

   // Number of return variables
   return nRetsOnStack;
}


//============================================================================
// CLuaScript::CLuaScript
//---------------------------------------------------------------------------
// Constructor. Sets up the lua stack and the "this" table
//
// Parameter            Dir      Description
// ---------            ---      -----------
// CLuaVirtualMachine   IN       VM to run on
//
// Return
// ------
// None.
//
//============================================================================
CLuaScript::CLuaScript (CLuaVirtualMachine& vm)
 : m_vm (vm), m_nMethods (0), m_iThisRef (0), m_nArgs (0)
{
   BEGIN_LUA_CHECK (vm)
      // Create a reference to the "this" table. Each reference is unique
      lua_newtable (state);
      m_iThisRef = luaL_ref (state, LUA_REGISTRYINDEX);

      // Save the "this" table to index 0 of the "this" table
      CLuaRestoreStack rs (vm);
      lua_rawgeti (state, LUA_REGISTRYINDEX, m_iThisRef);
      lua_pushlightuserdata (state, (void *) this);
      lua_rawseti (state, -2, 0);
   END_LUA_CHECK
}

//============================================================================
// CLuaScript::~CLuaScript
//---------------------------------------------------------------------------
// Destructor
//
// Parameter   Dir      Description
// ---------   ---      -----------
// None.
//
// Return
// ------
// None.
//
//============================================================================
CLuaScript::~CLuaScript (void)
{
   CLuaRestoreStack rs (m_vm);

   BEGIN_LUA_CHECK (m_vm)
      // Get the reference "this" table
      lua_rawgeti (state, LUA_REGISTRYINDEX, m_iThisRef);

      // Clear index 0
      lua_pushnil (state);
      lua_rawseti (state, -2, 0);
   END_LUA_CHECK
	
}

//============================================================================
// bool CLuaScript::CompileBuffer
//---------------------------------------------------------------------------
// Compiles a given buffer
//
// Parameter   Dir      Description
// ---------   ---      -----------
// pbBuffer    IN       Data buffer
// szLen       IN       Length of buffer
//
// Return
// ------
// Success
//
//============================================================================
bool CLuaScript::CompileBuffer (unsigned char *pbBuffer, size_t szLen)
{
   assert (pbBuffer != NULL && "CLuaScript::CompileBuffer ->  pbBuffer == NULL");
   assert (szLen != 0 && "CLuaScript::CompileBuffer -> szLen == 0");
   assert (m_vm.Ok () && "VM Not OK");

   // Make sure we have the correct "this" table
   CLuaThis luaThis (m_vm, m_iThisRef);

   return m_vm.RunBuffer (pbBuffer, szLen);
}

//============================================================================
// bool CLuaScript::CompileBuffer
//---------------------------------------------------------------------------
// Compiles a given file
//
// Parameter   Dir      Description
// ---------   ---      -----------
// strFilename IN       File name to compile
//
// Return
// ------
// Success
//
//============================================================================
bool CLuaScript::CompileFile (const char *strFilename)
{
   assert (strFilename != NULL && "CLuaScript::CompileFile -> strFilename == NULL");
   assert (m_vm.Ok () && "VM Not OK");

   // Make sure we have the correct "this" table
   CLuaThis luaThis (m_vm, m_iThisRef);

   return m_vm.RunFile (strFilename);
}

//============================================================================
// int CLuaScript::RegisterFunction
//---------------------------------------------------------------------------
// Registers a function with Lua
//
// Parameter   Dir      Description
// ---------   ---      -----------
// strFuncName IN       Function name
//
// Return
// ------
// Success
//
//============================================================================
int CLuaScript::RegisterFunction (const char *strFuncName)
{
   assert (strFuncName != NULL && "CLuaScript::RegisterFunction -> strFuncName == NULL");
   assert (m_vm.Ok () && "VM Not OK");

   int iMethodIdx = -1;

   CLuaRestoreStack rs (m_vm);

   BEGIN_LUA_CHECK (m_vm)
      iMethodIdx = ++m_nMethods;

      // Register a function with the lua script. Added it to the "this" table
      lua_rawgeti (state, LUA_REGISTRYINDEX, m_iThisRef);

      // Push the function and parameters
      lua_pushstring (state, strFuncName);
      lua_pushnumber (state, (lua_Number) iMethodIdx);
      lua_pushcclosure (state, LuaCallback, 1);
      lua_settable (state, -3);

   END_LUA_CHECK

   return iMethodIdx;
}

//============================================================================
// bool CLuaScript::SelectScriptFunction
//---------------------------------------------------------------------------
// Selects a script function to run
//
// Parameter   Dir      Description
// ---------   ---      -----------
// strFuncName IN       Function name
//
// Return
// ------
// Success
//
//============================================================================
bool CLuaScript::SelectScriptFunction (const char *strFuncName)
{
   assert (strFuncName != NULL && "CLuaScript::SelectScriptFunction -> strFuncName == NULL");
   assert (m_vm.Ok () && "VM Not OK");

   bool fSuccess = true;

   BEGIN_LUA_CHECK (m_vm)
      // Look up function name
      lua_rawgeti (state, LUA_REGISTRYINDEX, m_iThisRef);
      lua_pushstring (state, strFuncName);
      lua_rawget (state, -2);
      lua_remove (state, -2);

      // Put the "this" table back
      lua_rawgeti (state, LUA_REGISTRYINDEX, m_iThisRef);

      // Check that we have a valid function
      if (!lua_isfunction (state, -2))
      {
         fSuccess = false;
         lua_pop (state, 2);
      }
      else
      {
         m_nArgs = 0;
         m_strFunctionName = strFuncName;
      }
   END_LUA_CHECK
   
   return fSuccess;
}

//============================================================================
// bool CLuaScript::ScriptHasFunction
//---------------------------------------------------------------------------
// Checks to see if a function exists
//
// Parameter      Dir      Description
// ---------      ---      -----------
// strScriptName  IN       Function name
//
// Return
// ------
// Success
//
//============================================================================
bool CLuaScript::ScriptHasFunction (const char *strScriptName)
{
   assert (strScriptName != NULL && "CLuaScript::ScriptHasFunction -> strScriptName == NULL");
   assert (m_vm.Ok () && "VM Not OK");

   CLuaRestoreStack rs (m_vm);

   bool fFoundFunc = false;

   BEGIN_LUA_CHECK (m_vm)
      lua_rawgeti (state, LUA_REGISTRYINDEX, m_iThisRef);
      lua_pushstring (state, strScriptName);
      lua_rawget (state, -2);
      lua_remove (state, -2);

      if (lua_isfunction (state, -1))
      {
         fFoundFunc = true;
      }
   END_LUA_CHECK

   return fFoundFunc;
}

//============================================================================
// void CLuaScript::AddParam
//---------------------------------------------------------------------------
// Adds a parameter to the parameter list
//
// Parameter   Dir      Description
// ---------   ---      -----------
// string      IN       string param
//
// Return
// ------
// None.
//
//============================================================================
void CLuaScript::AddParam (char *string)
{
   assert (string != NULL && "CLuaScript::AddParam -> string == NULL");
   assert (m_vm.Ok () && "VM Not OK");

   BEGIN_LUA_CHECK (m_vm)
      lua_pushstring (state, string);
      ++m_nArgs;
   END_LUA_CHECK
}

//============================================================================
// void CLuaScript::AddParam
//---------------------------------------------------------------------------
// Adds a parameter to the parameter list
//
// Parameter   Dir      Description
// ---------   ---      -----------
// iInt        IN       int param
//
// Return
// ------
// None.
//
//============================================================================
void CLuaScript::AddParam (int iInt)
{
   assert (m_vm.Ok () && "VM Not OK");

   BEGIN_LUA_CHECK (m_vm)
      lua_pushnumber (state, (lua_Number) iInt);
      ++m_nArgs;
   END_LUA_CHECK
}

//============================================================================
// void CLuaScript::AddParam
//---------------------------------------------------------------------------
// Adds a parameter to the parameter list
//
// Parameter   Dir      Description
// ---------   ---      -----------
// fFloat      IN       float param
//
// Return
// ------
// None.
//
//============================================================================
void CLuaScript::AddParam (float fFloat)
{
   assert (m_vm.Ok () && "VM Not OK");

   BEGIN_LUA_CHECK (m_vm)
      lua_pushnumber (state, (lua_Number) fFloat);
      ++m_nArgs;
   END_LUA_CHECK
}

//============================================================================
// bool CLuaScript::Go
//---------------------------------------------------------------------------
// Runs the selected script function
//
// Parameter   Dir      Description
// ---------   ---      -----------
// nReturns    IN       Number of expected returns
//
// Return
// ------
// None.
//
//============================================================================
bool CLuaScript::Go (int nReturns /* = 0 */)
{
   assert (m_vm.Ok () && "VM Not OK");

   // At this point there should be a parameters and a function on the
   // Lua stack. Each function get a "this" parameter as default and is
   // pushed onto the stack when the method is selected

   bool fSuccess = m_vm.CallFunction (m_nArgs + 1, nReturns);

   if (fSuccess == true && nReturns > 0)
   {
      // Check for returns
      HandleReturns (m_vm, m_strFunctionName);
      lua_pop ((lua_State *) m_vm, nReturns);
   }

   return fSuccess;
}