Browse Source

small lua code refactor

undefined
Benjamin ‘Touky’ Huet Sam Hocevar <sam@hocevar.net> 9 years ago
parent
commit
77420f6b55
2 changed files with 3 additions and 513 deletions
  1. +2
    -163
      doc/tutorial/14_lol_lua.cpp
  2. +1
    -350
      src/application/baselua.h

+ 2
- 163
doc/tutorial/14_lol_lua.cpp View File

@@ -19,168 +19,10 @@
using namespace lol; using namespace lol;


//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
class FooTest
class FooTestLua : public Lolua::ObjectDef
{ {
public: public:
FooTest()
{
}
static int New(Lolua::State* l)
{
int n_args = lua_gettop(l); // Number of arguments

// We could actually allocate Foo itself as a user data but
// since user data can be GC'ed and we gain unity by using CRT's heap
// all along.
FooTest** udata = (FooTest**)lua_newuserdata(l, sizeof(FooTest*));
*udata = new FooTest();

// Usually, we'll just use "Foo" as the second parameter, but I
// say luaL_Foo here to distinguish the difference:
//
// This 2nd parameter here is an _internal label_ for luaL, it is
// _not_ exposed to Lua by default.
//
// Effectively, this metatable is not accessible by Lua by default.
//luaL_getmetatable(l, m_table_name);

// The Lua stack at this point looks like this:
//
// 3| metatable "luaL_foo" |-1
// 2| userdata |-2
// 1| string parameter |-3
//
// So the following line sets the metatable for the user data to the luaL_Foo
// metatable
//
// We must set the metatable here because Lua prohibits setting
// the metatable of a userdata in Lua. The only way to set a metatable
// of a userdata is to do it in C.
//lua_setmetatable(l, -2);

luaL_getmetatable(l, m_table2_name);
lua_setmetatable(l, -2);

// The Lua stack at this point looks like this:
//
// 2| userdata |-1
// 1| string parameter |-2
//
// We return 1 so Lua callsite will get the user data and
// Lua will clean the stack after that.

return 1;
}
static FooTest* Check(Lolua::State* l, int n)
{
// This checks that the argument is a userdata
// with the metatable "luaL_Foo"
return *(FooTest**)luaL_testudata(l, n, m_table2_name);
}
static int Del(Lolua::State * l)
{
FooTest* foo = Check(l, 1);
delete foo;

return 0;
}
static void Register(Lolua::State * l)
{
// Create a luaL metatable. This metatable is not
// exposed to Lua. The "luaL_Foo" label is used by luaL
// internally to identity things.
luaL_newmetatable(l, m_table2_name);
luaL_setfuncs(l, FooTest::m_statics2, 0);
lua_pushvalue(l, -1);
lua_setfield(l, -1, "__index");
//lua_setglobal(l, m_class2_name);
lua_pop(l, 1);

// Create a luaL metatable. This metatable is not
// exposed to Lua. The "luaL_Foo" label is used by luaL
// internally to identity things.
luaL_newmetatable(l, m_table_name);

// Register the C functions _into_ the metatable we just created.
luaL_setfuncs(l, FooTest::m_statics, 0);

// The Lua stack at this point looks like this:
//
// 1| metatable "luaL_Foo" |-1
lua_pushvalue(l, -1);

// The Lua stack at this point looks like this:
//
// 2| metatable "luaL_Foo" |-1
// 1| metatable "luaL_Foo" |-2

// Set the "__index" field of the metatable to point to itself
// This pops the stack
lua_setfield(l, -1, "__index");

// The Lua stack at this point looks like this:
//
// 1| metatable "luaL_Foo" |-1

// The luaL_Foo metatable now has the following fields
// - __gc
// - __index
// - new

// Now we use setglobal to officially expose the luaL_Foo metatable
// to Lua. And we use the name "Foo".
//
// This allows Lua scripts to _override_ the metatable of Foo.
// For high security code this may not be called for but
// we'll do this to get greater flexibility.
lua_setglobal(l, m_class_name);
}
static int Test1(Lolua::State* L)
{
Lolua::Var<int> i1(L, 1);
i1 += 5;
return i1.Return(L);
}
static int Test2(Lolua::State* L)
{
FooTest* foo = Check(L, 1);
Lolua::Var<float> i1(L, 2);
i1 = foo->Test2Inst(i1.V());
return i1.Return(L);
}
float Test2Inst(float f)
{
return (f + 10);
}

static const char m_class_name[];
static const char m_class2_name[];
static const char m_table_name[];
static const char m_table2_name[];
static const luaL_Reg m_statics[];
static const luaL_Reg m_statics2[];
static const luaL_Reg m_methods[];
};

const luaL_Reg FooTest::m_statics[] = {
{ "New", &FooTest::New },
{ "__gc", &FooTest::Del },
{ "Test1", &FooTest::Test1 },
{ NULL, NULL } };
const luaL_Reg FooTest::m_statics2[] = {
{ "Test2", &FooTest::Test2 },
{ NULL, NULL } };
const luaL_Reg FooTest::m_methods[] = { { NULL, NULL } };
const char FooTest::m_class_name[] = "FooTest";
const char FooTest::m_class2_name[] = "FooTest2";
const char FooTest::m_table_name[] = "FooTest_mt";
const char FooTest::m_table2_name[] = "FooTest_mt2";

typedef Lolua::ObjectDef<FooTest> FooTestLuaBase;
class FooTestLua : public FooTestLuaBase
{
public:
FooTestLua() : FooTestLuaBase() {}
FooTestLua() : Lolua::ObjectDef() {}
virtual ~FooTestLua() {} virtual ~FooTestLua() {}
static FooTestLua* New(Lolua::State* l, int arg_nb) static FooTestLua* New(Lolua::State* l, int arg_nb)
{ {
@@ -255,11 +97,8 @@ public:
int32_t TestValueInt = demo_loader->GetVar<int32_t>("TestValueInt"); int32_t TestValueInt = demo_loader->GetVar<int32_t>("TestValueInt");
uint32_t TestValueUint = demo_loader->GetVar<uint32_t>("TestValueUint"); uint32_t TestValueUint = demo_loader->GetVar<uint32_t>("TestValueUint");
String TestValueStr = demo_loader->GetVar<String>("TestValueStr"); String TestValueStr = demo_loader->GetVar<String>("TestValueStr");
//String test_return2 = demo_loader->GetVar<String>("test_return2");
//String test_return3 = demo_loader->GetVar<String>("test_return3");
int32_t testtruc_return = demo_loader->GetVar<int32_t>("footest_return"); int32_t testtruc_return = demo_loader->GetVar<int32_t>("footest_return");
float testtruc_return2 = demo_loader->GetVar<float>("footest_return2"); float testtruc_return2 = demo_loader->GetVar<float>("footest_return2");
//int32_t testtruc2_return = demo_loader->GetVar<int32_t>("testtruc_return2");


String::Printf("Lua Vars: TestValueNum: %.2f, TestValueInt: %i, TestValueUint: %i, TestValueStr: %s.", String::Printf("Lua Vars: TestValueNum: %.2f, TestValueInt: %i, TestValueUint: %i, TestValueStr: %s.",
TestValueNum, TestValueInt, TestValueUint, TestValueStr); TestValueNum, TestValueInt, TestValueUint, TestValueStr);


+ 1
- 350
src/application/baselua.h View File

@@ -28,13 +28,12 @@ typedef luaL_Reg ClassMethod;
typedef lua_State State; typedef lua_State State;


//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
template <typename T>
class ObjectDef class ObjectDef
{ {
public: public:
ObjectDef() { } ObjectDef() { }
virtual ~ObjectDef() { } virtual ~ObjectDef() { }
static ObjectDef<T>* New(State* l, int arg_nb)
static ObjectDef* New(State* l, int arg_nb)
{ {
UNUSED(l); UNUSED(l);
UNUSED(arg_nb); UNUSED(arg_nb);
@@ -46,9 +45,6 @@ public:
static const char* GetClassInstName() { ASSERT(false); return nullptr; } static const char* GetClassInstName() { ASSERT(false); return nullptr; }
static const ClassMethod* GetStaticMethods() { ASSERT(false); return nullptr; } static const ClassMethod* GetStaticMethods() { ASSERT(false); return nullptr; }
static const ClassMethod* GetInstanceMethods() { ASSERT(false); return nullptr; } static const ClassMethod* GetInstanceMethods() { ASSERT(false); return nullptr; }

protected:
T* m_instance = nullptr;
}; };


//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
@@ -285,351 +281,6 @@ private:
Lolua::State* m_lua_state; Lolua::State* m_lua_state;
}; };


//-----------------------------------------------------------------------------
//class T definition
//class T
//{
//public:
// int Ctor(lua_State* l) { return 0; }
// static const char* m_class_name;
// static const Class<T>::Variable* m_variables;
// static const Class<T>::Method* m_methods;
//};
/*
//-----------------------------------------------------------------------------
template<typename T>
class ClassTest
{
public:
//-----------------------------------------------------------------------------
struct Variable
{
const char* m_name;
int(*Getter)(lua_State*);
int(*Setter)(lua_State*);
};

//-----------------------------------------------------------------------------
struct Method
{
const char* m_name;
int(*Func)(lua_State*);
};

//Register: Register class in Lua. Leave library empty to store class in global scope.
static void Register(lua_State* l, const char *library = NULL)
{
if (library && strlen(library))
{
lua_getglobal(l, library);
//Create library if not present
if (lua_isnil(l, -1))
{
lua_newtable(l);
//Duplicate table pointer since setglobal pops the value
lua_pushvalue(l, -1);
lua_setglobal(l, library);
}
//lua_pushcfunction(l, &Class<T>::Ctor);
//lua_setfield(l, -2, T::m_class_name);
//lua_pop(l, 1);
}
else
{
//lua_pushcfunction(l, &Class<T>::Ctor);
//lua_setglobal(l, T::m_class_name);
}

luaL_newmetatable(l, T::m_class_name);
int metatable = lua_gettop(l);

//Register all m_methods: Register Name for fun_call and number for choice
for (int i = 0; T::m_methods[i].m_name; i++)
{
lua_pushstring(l, T::m_methods[i].m_name);
lua_pushcfunction(l, T::m_methods[i].Func);
lua_settable(l, metatable);
}

//lua_pushstring(l, "__gc");
//lua_pushcfunction(l, &Class<T>::Dtor);
//lua_settable(l, metatable);

//lua_pushstring(l, "__tostring");
//lua_pushcfunction(l, &Class<T>::ToString);
//lua_settable(l, metatable);

//lua_pushstring(l, "__eq");
//lua_pushcfunction(l, &Class<T>::Equals);
//lua_settable(l, metatable);

//lua_pushstring(l, "__index");
//lua_pushcfunction(l, &Class<T>::Getter);
//lua_settable(l, metatable);

//lua_pushstring(l, "__newindex");
//lua_pushcfunction(l, &Class<T>::Setter);
//lua_settable(l, metatable);

////Register all properties: Register Name for fun_call and number for choice
//for (int i = 0; T::m_variables[i].m_name; i++)
//{
// lua_pushstring(l, T::m_variables[i].m_name);
// lua_pushnumber(l, i);
// lua_settable(l, metatable);
//}

////Register all m_methods: Register Name for fun_call and number for choice
//for (int i = 0; T::m_methods[i].m_name; i++)
//{
// lua_pushstring(l, T::m_methods[i].m_name);
// //Add (1 << 8) to identify function on call
// lua_pushnumber(l, i | (1 << 8));
// lua_settable(l, metatable);
//}
}

};

//-----------------------------------------------------------------------------
template<typename T>
class Class
{
public:
//-----------------------------------------------------------------------------
struct Variable
{
const char* m_name;
int (T::*Getter)(lua_State*);
int (T::*Setter)(lua_State*);
};

//-----------------------------------------------------------------------------
struct Method
{
const char* m_name;
int (T::*Func)(lua_State*);
};

//-----------------------------------------------------------------------------
//Check: Raise an exception if FAIL
static T* Check(lua_State * l, int narg)
{
T** obj = static_cast <T **>(luaL_checkudata(l, narg, T::m_class_name));
return !obj ? nullptr : *obj;
}

//LightCheck: Returns nullptr if FAIL
static T* LightCheck(lua_State* l, int num_args)
{
T** obj = static_cast <T **>(luaL_testudata(l, num_args, T::m_class_name));
return !obj ? nullptr : *obj;
}

//Register: Register class in Lua. Leave library empty to store class in global scope.
static void Register(lua_State* l, const char *library = NULL)
{
if (library && strlen(library))
{
lua_getglobal(l, library);
//Create library if not present
if (lua_isnil(l, -1))
{
lua_newtable(l);
//Duplicate table pointer since setglobal pops the value
lua_pushvalue(l, -1);
lua_setglobal(l, library);
}
lua_pushcfunction(l, &Class<T>::Ctor);
lua_setfield(l, -2, T::m_class_name);
lua_pop(l, 1);
}
else
{
lua_pushcfunction(l, &Class<T>::Ctor);
lua_setglobal(l, T::m_class_name);
}

luaL_newmetatable(l, T::m_class_name);
int metatable = lua_gettop(l);

//lua_pushstring(l, "__gc");
//lua_pushcfunction(l, &Class<T>::Dtor);
//lua_settable(l, metatable);

//lua_pushstring(l, "__tostring");
//lua_pushcfunction(l, &Class<T>::ToString);
//lua_settable(l, metatable);

//lua_pushstring(l, "__eq");
//lua_pushcfunction(l, &Class<T>::Equals);
//lua_settable(l, metatable);

lua_pushstring(l, "__index");
lua_pushcfunction(l, &Class<T>::Getter);
lua_settable(l, metatable);

lua_pushstring(l, "__newindex");
lua_pushcfunction(l, &Class<T>::Setter);
lua_settable(l, metatable);

//Register all properties: Register Name for fun_call and number for choice
for (int i = 0; T::m_variables[i].m_name; i++)
{
lua_pushstring(l, T::m_variables[i].m_name);
lua_pushnumber(l, i);
lua_settable(l, metatable);
}

//Register all m_methods: Register Name for fun_call and number for choice
for (int i = 0; T::m_methods[i].m_name; i++)
{
lua_pushstring(l, T::m_methods[i].m_name);
//Add (1 << 8) to identify function on call
lua_pushnumber(l, i | (1 << 8));
lua_settable(l, metatable);
}
}

private:
//Ctor
static int Ctor(lua_State* l)
{
T* obj = new T(l);
T** lua_obj = static_cast<T**>(lua_newuserdata(l, sizeof(T*))); // Push value = userdata
*lua_obj = obj;

luaL_getmetatable(l, T::m_class_name); // Fetch global metatable T::classname
lua_setmetatable(l, -2);
return 1;
}

//Dtor
static int Dtor(lua_State* l)
{
T** lua_obj = static_cast<T**>(lua_touserdata(l, -1));
if (lua_obj && *lua_obj)
delete(*lua_obj);
return 0;
}

//AddInstance
static void AddInstance(lua_State* l, T* instance)
{
T** a = (T**)lua_newuserdata(l, sizeof(T*)); // Create userdata
*a = instance;

luaL_getmetatable(l, T::m_class_name);
lua_setmetatable(l, -2);
}

//----
static void GetVarIndex(lua_State* l)
{
lua_getmetatable(l, 1); //Look up the index of a m_name
lua_pushvalue(l, 2); //Push the m_name
lua_rawget(l, -2); //Get the index
}

//----
static void PrepareGetSet(lua_State* l)
{
lua_pop(l, 2); // Pop metatable and idx
lua_remove(l, 1); // Remove userdata
lua_remove(l, 1); // Remove [key]
}

//Getter: Call a func or a getter var
static int Getter(lua_State* l)
{
GetVarIndex(l);
//Check if we got a valid index
if (lua_isnumber(l, -1))
{
int idx = lua_tonumber(l, -1);
T** obj = static_cast<T**>(lua_touserdata(l, 1));
lua_pushvalue(l, 3);

//It's a method
if (idx & (1 << 8))
{
//Push the Method index and call the function
lua_pushnumber(l, idx ^ (1 << 8));
lua_pushlightuserdata(l, obj);
lua_pushcclosure(l, &Class<T>::CallMethod, 2);
// Return a Method
return 1;
}
else
{
PrepareGetSet(l);
return ((*obj)->*(T::m_variables[idx].Getter))(l);
}
}
return 1;
}

//Getter: Class a setter var or error if func
static int Setter(lua_State* l)
{
GetVarIndex(l);
//Check if we got a valid index
if (lua_isnumber(l, -1))
{
int idx = lua_tonumber(l, -1);
T** obj = static_cast<T**>(lua_touserdata(l, 1));
if (!obj || !*obj)
{
luaL_error(l, "Internal error, no object given!");
return 0;
}

//Try to set a Method - FAIL
if (idx & (1 << 8))
{
String s = String::Printf("Trying to set the method [%s] of class [%s]", (*obj)->T::m_methods[idx ^ (1 << 8)].m_name, T::m_class_name);
luaL_error(l, s.C());
return 0;
}
else
{
PrepareGetSet(l);
return ((*obj)->*(T::m_variables[idx].Setter))(l);
}
}
return 0;
}

//CallMethod: Actually calls the method on the object
static int CallMethod(lua_State* l)
{
int i = (int)lua_tonumber(l, lua_upvalueindex(1));
T** obj = static_cast <T**>(lua_touserdata(l, lua_upvalueindex(2)));
return ((*obj)->*(T::m_methods[i].Func))(l);
}

//ToString:
static int ToString(lua_State* l)
{
T** obj = static_cast<T**>(lua_touserdata(l, -1));
if (obj)
lua_pushfstring(l, "%s (%p)", T::m_class_name, (void*)*obj);
else
lua_pushstring(l, "Empty object");
return 1;
}

//Equals:
static int Equals(lua_State* l)
{
T** obj1 = static_cast<T**>(lua_touserdata(l, -1));
T** obj2 = static_cast<T**>(lua_touserdata(l, 1));
lua_pushboolean(l, *obj1 == *obj2);
return 1;
}
};
*/

} /* namespace Lolua */ } /* namespace Lolua */


} /* namespace lol */ } /* namespace lol */

Loading…
Cancel
Save