cLuaState has reference management, param checking and a fixed destructor.
References are now managed as RAII objects, cLuaState::cRef. Destructor now calls correct function, either Close() or Detach(), based on the owned-ness of the lua_State *.
This commit is contained in:
parent
c55fabb5ad
commit
9b839aa32e
@ -63,7 +63,14 @@ cLuaState::~cLuaState()
|
||||
{
|
||||
if (IsValid())
|
||||
{
|
||||
Close();
|
||||
if (m_IsOwned)
|
||||
{
|
||||
Close();
|
||||
}
|
||||
else
|
||||
{
|
||||
Detach();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -236,6 +243,35 @@ bool cLuaState::PushFunctionFromRegistry(int a_FnRef)
|
||||
|
||||
|
||||
|
||||
bool cLuaState::PushFunctionFromRefTable(cRef & a_TableRef, const char * a_FnName)
|
||||
{
|
||||
ASSERT(IsValid());
|
||||
ASSERT(m_NumCurrentFunctionArgs == -1); // If not, there's already something pushed onto the stack
|
||||
|
||||
lua_rawgeti(m_LuaState, LUA_REGISTRYINDEX, a_TableRef); // Get the table ref
|
||||
if (!lua_istable(m_LuaState, -1))
|
||||
{
|
||||
// Not a table, bail out
|
||||
lua_pop(m_LuaState, 1);
|
||||
return false;
|
||||
}
|
||||
lua_getfield(m_LuaState, -1, a_FnName);
|
||||
if (lua_isnil(m_LuaState, -1) || !lua_isfunction(m_LuaState, -1))
|
||||
{
|
||||
// Not a valid function, bail out
|
||||
lua_pop(m_LuaState, 2);
|
||||
return false;
|
||||
}
|
||||
lua_remove(m_LuaState, -2); // Remove the table ref from the stack
|
||||
m_CurrentFunctionName = "<table_callback>";
|
||||
m_NumCurrentFunctionArgs = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void cLuaState::PushStringVector(const AStringVector & a_Vector)
|
||||
{
|
||||
ASSERT(IsValid());
|
||||
@ -434,6 +470,125 @@ bool cLuaState::CallFunction(int a_NumResults)
|
||||
|
||||
|
||||
|
||||
bool cLuaState::CheckParamUserType(int a_StartParam, const char * a_UserType, int a_EndParam)
|
||||
{
|
||||
ASSERT(IsValid());
|
||||
|
||||
if (a_EndParam < 0)
|
||||
{
|
||||
a_EndParam = a_StartParam;
|
||||
}
|
||||
|
||||
tolua_Error tolua_err;
|
||||
for (int i = a_StartParam; i <= a_EndParam; i++)
|
||||
{
|
||||
if (tolua_isusertype(m_LuaState, i, a_UserType, 0, &tolua_err))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
// Not the correct parameter
|
||||
lua_Debug entry;
|
||||
VERIFY(lua_getstack(m_LuaState, 0, &entry));
|
||||
VERIFY(lua_getinfo (m_LuaState, "n", &entry));
|
||||
AString ErrMsg = Printf("#ferror in function '%s'.", (entry.name != NULL) ? entry.name : "?");
|
||||
tolua_error(m_LuaState, ErrMsg.c_str(), &tolua_err);
|
||||
return false;
|
||||
} // for i - Param
|
||||
|
||||
// All params checked ok
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
bool cLuaState::CheckParamTable(int a_StartParam, int a_EndParam)
|
||||
{
|
||||
ASSERT(IsValid());
|
||||
|
||||
if (a_EndParam < 0)
|
||||
{
|
||||
a_EndParam = a_StartParam;
|
||||
}
|
||||
|
||||
tolua_Error tolua_err;
|
||||
for (int i = a_StartParam; i <= a_EndParam; i++)
|
||||
{
|
||||
if (tolua_istable(m_LuaState, i, 0, &tolua_err))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
// Not the correct parameter
|
||||
lua_Debug entry;
|
||||
VERIFY(lua_getstack(m_LuaState, 0, &entry));
|
||||
VERIFY(lua_getinfo (m_LuaState, "n", &entry));
|
||||
AString ErrMsg = Printf("#ferror in function '%s'.", (entry.name != NULL) ? entry.name : "?");
|
||||
tolua_error(m_LuaState, ErrMsg.c_str(), &tolua_err);
|
||||
return false;
|
||||
} // for i - Param
|
||||
|
||||
// All params checked ok
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
bool cLuaState::CheckParamNumber(int a_StartParam, int a_EndParam)
|
||||
{
|
||||
ASSERT(IsValid());
|
||||
|
||||
if (a_EndParam < 0)
|
||||
{
|
||||
a_EndParam = a_StartParam;
|
||||
}
|
||||
|
||||
tolua_Error tolua_err;
|
||||
for (int i = a_StartParam; i <= a_EndParam; i++)
|
||||
{
|
||||
if (tolua_isnumber(m_LuaState, i, 0, &tolua_err))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
// Not the correct parameter
|
||||
lua_Debug entry;
|
||||
VERIFY(lua_getstack(m_LuaState, 0, &entry));
|
||||
VERIFY(lua_getinfo (m_LuaState, "n", &entry));
|
||||
AString ErrMsg = Printf("#ferror in function '%s'.", (entry.name != NULL) ? entry.name : "?");
|
||||
tolua_error(m_LuaState, ErrMsg.c_str(), &tolua_err);
|
||||
return false;
|
||||
} // for i - Param
|
||||
|
||||
// All params checked ok
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
bool cLuaState::CheckParamEnd(int a_Param)
|
||||
{
|
||||
tolua_Error tolua_err;
|
||||
if (tolua_isnoobj(m_LuaState, a_Param, &tolua_err))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
// Not the correct parameter
|
||||
lua_Debug entry;
|
||||
VERIFY(lua_getstack(m_LuaState, 0, &entry));
|
||||
VERIFY(lua_getinfo (m_LuaState, "n", &entry));
|
||||
AString ErrMsg = Printf("#ferror in function '%s': Too many arguments.", (entry.name != NULL) ? entry.name : "?");
|
||||
tolua_error(m_LuaState, ErrMsg.c_str(), &tolua_err);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
bool cLuaState::ReportErrors(int a_Status)
|
||||
{
|
||||
return ReportErrors(m_LuaState, a_Status);
|
||||
@ -459,3 +614,33 @@ bool cLuaState::ReportErrors(lua_State * a_LuaState, int a_Status)
|
||||
|
||||
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// cLuaState::cRef:
|
||||
|
||||
cLuaState::cRef::cRef(cLuaState & a_LuaState, int a_StackPos) :
|
||||
m_LuaState(a_LuaState)
|
||||
{
|
||||
ASSERT(m_LuaState.IsValid());
|
||||
|
||||
lua_pushvalue(m_LuaState, a_StackPos); // Push a copy of the value at a_StackPos onto the stack
|
||||
m_Ref = luaL_ref(m_LuaState, LUA_REGISTRYINDEX);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
cLuaState::cRef::~cRef()
|
||||
{
|
||||
ASSERT(m_LuaState.IsValid());
|
||||
|
||||
if (IsValid())
|
||||
{
|
||||
luaL_unref(m_LuaState, LUA_REGISTRYINDEX, m_Ref);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -13,6 +13,10 @@ Calling a Lua function is done by pushing the function, either by PushFunction()
|
||||
then pushing the arguments (PushString(), PushNumber(), PushUserData() etc.) and finally
|
||||
executing CallFunction(). cLuaState automatically keeps track of the number of arguments and the name of the
|
||||
function (for logging purposes), which makes the call less error-prone.
|
||||
|
||||
Reference management is provided by the cLuaState::cRef class. This is used when you need to hold a reference to
|
||||
any Lua object across several function calls; usually this is used for callbacks. The class is RAII-like, with
|
||||
automatic resource management.
|
||||
*/
|
||||
|
||||
|
||||
@ -20,12 +24,14 @@ function (for logging purposes), which makes the call less error-prone.
|
||||
|
||||
#pragma once
|
||||
|
||||
extern "C"
|
||||
{
|
||||
#include "lauxlib.h"
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// fwd: lua.h
|
||||
struct lua_State;
|
||||
|
||||
class cWorld;
|
||||
class cPlayer;
|
||||
@ -39,9 +45,31 @@ class cPickup;
|
||||
|
||||
|
||||
|
||||
/// Encapsulates a Lua state and provides some syntactic sugar for common operations
|
||||
class cLuaState
|
||||
{
|
||||
public:
|
||||
|
||||
/// Used for storing references to object in the global registry
|
||||
class cRef
|
||||
{
|
||||
public:
|
||||
/// Creates a reference in the specified LuaState for object at the specified StackPos
|
||||
cRef(cLuaState & a_LuaState, int a_StackPos);
|
||||
~cRef();
|
||||
|
||||
/// Returns true if the reference is valid
|
||||
bool IsValid(void) const {return (m_Ref != LUA_REFNIL); }
|
||||
|
||||
/// Allows to use this class wherever an int (i. e. ref) is to be used
|
||||
operator int(void) { return m_Ref; }
|
||||
|
||||
protected:
|
||||
cLuaState & m_LuaState;
|
||||
int m_Ref;
|
||||
} ;
|
||||
|
||||
|
||||
/** Creates a new instance. The LuaState is not initialized.
|
||||
a_SubsystemName is used for reporting problems in the console, it is "plugin %s" for plugins,
|
||||
or "LuaScript" for the cLuaScript template
|
||||
@ -90,6 +118,11 @@ public:
|
||||
*/
|
||||
bool PushFunctionFromRegistry(int a_FnRef);
|
||||
|
||||
/** Pushes a function that is stored in a table ref.
|
||||
Returns true if successful, false on failure. Doesn't log failure.
|
||||
*/
|
||||
bool PushFunctionFromRefTable(cRef & a_TableRef, const char * a_FnName);
|
||||
|
||||
/// Pushes a string vector, as a table, onto the stack
|
||||
void PushStringVector(const AStringVector & a_Vector);
|
||||
|
||||
@ -123,7 +156,19 @@ public:
|
||||
Returns true if successful, logs a warning on failure.
|
||||
*/
|
||||
bool CallFunction(int a_NumReturnValues);
|
||||
|
||||
|
||||
/// Returns true if the specified parameters on the stack are of the specified usertype; also logs warning if not
|
||||
bool CheckParamUserType(int a_StartParam, const char * a_UserType, int a_EndParam = -1);
|
||||
|
||||
/// Returns true if the specified parameters on the stack are a table; also logs warning if not
|
||||
bool CheckParamTable(int a_StartParam, int a_EndParam = -1);
|
||||
|
||||
/// Returns true if the specified parameters on the stack are a number; also logs warning if not
|
||||
bool CheckParamNumber(int a_StartParam, int a_EndParam = -1);
|
||||
|
||||
/// Returns true if the specified parameter on the stack is nil (indicating an end-of-parameters)
|
||||
bool CheckParamEnd(int a_Param);
|
||||
|
||||
/// If the status is nonzero, prints the text on the top of Lua stack and returns true
|
||||
bool ReportErrors(int status);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user