Created
September 24, 2022 15:54
-
-
Save ttvd/fc174fca5961742a89fdc3abd56ecd50 to your computer and use it in GitHub Desktop.
Quick lua c++ bindings
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
extern "C" { | |
#include "lauxlib.h" | |
#include "lualib.h" | |
} | |
#include <stdio.h> | |
#include <windows.h> | |
#include <vector> | |
struct Base | |
{ | |
Base() : | |
FieldInt(42), | |
FieldFloat(43.0f) | |
{ | |
} | |
virtual ~Base() | |
{ | |
} | |
int FieldInt; | |
float FieldFloat; | |
int InstanceMethodGetInt() const | |
{ | |
return FieldInt; | |
} | |
float InstanceMethodGetFloat() const | |
{ | |
return FieldFloat; | |
} | |
const char* InstanceMethodCall() const | |
{ | |
static const char* Value = "Base::InstanceMethodCall"; | |
return Value; | |
} | |
virtual const char* InstanceMethodCallOverloaded() const | |
{ | |
static const char* Value = "Base::InstanceMethodCallOverloaded"; | |
return Value; | |
} | |
static const char* StaticMethodCall() | |
{ | |
static const char* Value = "Base::StaticMethodCall"; | |
return Value; | |
} | |
virtual const char* ToString() const | |
{ | |
static const char* Value = "Base"; | |
return Value; | |
} | |
}; | |
int Base_Constructor(lua_State* LuaState) | |
{ | |
void* Ptr = lua_newuserdata(LuaState, sizeof(Base)); | |
Base* Value = new(Ptr) Base(); | |
luaL_getmetatable(LuaState, "MetaBase"); | |
lua_setmetatable(LuaState, -2); | |
return 1; | |
} | |
int Base_InstanceMethodGetInt(lua_State* LuaState) | |
{ | |
Base* Value = (Base*) lua_touserdata(LuaState, 1); | |
lua_pushinteger(LuaState, Value->FieldInt); | |
return 1; | |
} | |
int Base_InstanceMethodGetFloat(lua_State* LuaState) | |
{ | |
Base* Value = (Base*) lua_touserdata(LuaState, 1); | |
lua_pushnumber(LuaState, Value->FieldFloat); | |
return 1; | |
} | |
int Base_InstanceMethodCall(lua_State* LuaState) | |
{ | |
Base* Value = (Base*) lua_touserdata(LuaState, 1); | |
static const char* Str = "Base_InstanceMethodCall"; | |
lua_pushstring(LuaState, Str); | |
return 1; | |
} | |
int Base_InstanceMethodCallOverloaded(lua_State* LuaState) | |
{ | |
Base* Value = (Base*) lua_touserdata(LuaState, 1); | |
static const char* Str = "Base_InstanceMethodCallOverloaded"; | |
lua_pushstring(LuaState, Str); | |
return 1; | |
} | |
int Base_StaticMethodCall(lua_State* LuaState) | |
{ | |
static const char* Value = "Base_StaticMethodCall"; | |
lua_pushstring(LuaState, Value); | |
return 1; | |
} | |
int Base_ToString(lua_State* LuaState) | |
{ | |
static const char* Value = "Base"; | |
lua_pushstring(LuaState, Value); | |
return 1; | |
} | |
struct Derived : public Base | |
{ | |
Derived() : | |
Base(), | |
bFieldBoolean(true) | |
{ | |
FieldInt = 420; | |
FieldFloat = 430.0f; | |
} | |
bool bFieldBoolean; | |
bool InstanceMethodGetBool() const | |
{ | |
return bFieldBoolean; | |
} | |
virtual const char* InstanceMethodCallOverloaded() const override | |
{ | |
static const char* Value = "Derived::InstanceMethodCall"; | |
return Value; | |
} | |
virtual const char* ToString() const override | |
{ | |
static const char* Value = "Derived"; | |
return Value; | |
} | |
}; | |
int Derived_Constructor(lua_State* LuaState) | |
{ | |
void* Ptr = lua_newuserdata(LuaState, sizeof(Derived)); | |
Derived* Value = new(Ptr) Derived(); | |
luaL_getmetatable(LuaState, "MetaDerived"); | |
lua_setmetatable(LuaState, -2); | |
return 1; | |
} | |
int Derived_InstanceMethodCallOverloaded(lua_State* LuaState) | |
{ | |
Derived* Value = (Derived*) lua_touserdata(LuaState, 1); | |
static const char* Str = "Derived_InstanceMethodCallOverloaded"; | |
lua_pushstring(LuaState, Str); | |
return 1; | |
} | |
int Derived_InstanceMethodGetBool(lua_State* LuaState) | |
{ | |
Derived* Value = (Derived*) lua_touserdata(LuaState, 1); | |
lua_pushboolean(LuaState, Value->bFieldBoolean); | |
return 1; | |
} | |
int Derived_ToString(lua_State* LuaState) | |
{ | |
static const char* Value = "Derived"; | |
lua_pushstring(LuaState, Value); | |
return 1; | |
} | |
struct FurtherDerived : public Derived | |
{ | |
FurtherDerived() : | |
Derived() | |
{ | |
} | |
virtual const char* ToString() const override | |
{ | |
static const char* Value = "FurtherDerived"; | |
return Value; | |
} | |
}; | |
int FurtherDerived_Constructor(lua_State* LuaState) | |
{ | |
void* Ptr = lua_newuserdata(LuaState, sizeof(FurtherDerived)); | |
FurtherDerived* Value = new(Ptr) FurtherDerived(); | |
luaL_getmetatable(LuaState, "MetaFurtherDerived"); | |
lua_setmetatable(LuaState, -2); | |
return 1; | |
} | |
int FurtherDerived_ToString(lua_State* LuaState) | |
{ | |
static const char* Value = "FurtherDerived"; | |
lua_pushstring(LuaState, Value); | |
return 1; | |
} | |
int Print(lua_State* LuaState) | |
{ | |
const int NumArgs = lua_gettop(LuaState); | |
for(int Idx = 1; Idx <= NumArgs; ++Idx) | |
{ | |
size_t Len; | |
const char* Str = luaL_tolstring(LuaState, Idx, &Len); | |
OutputDebugStringA(Str); | |
} | |
OutputDebugStringA("\n"); | |
return 0; | |
} | |
int main(int argc, char** argv) | |
{ | |
lua_State* LuaState = luaL_newstate(); | |
luaL_openlibs(LuaState); | |
// Override global print. | |
{ | |
lua_getglobal(LuaState, "_G"); | |
lua_pushcfunction(LuaState, &Print); | |
lua_setfield(LuaState, -2, "print"); | |
} | |
// Our global namespace table. | |
{ | |
lua_newtable(LuaState); | |
lua_setglobal(LuaState, "BT"); | |
} | |
// Register a list of functions. | |
auto RegisterFunctions = [&LuaState](const std::vector<luaL_Reg>& Functions) | |
{ | |
for(const luaL_Reg& Func : Functions) | |
{ | |
lua_pushcfunction(LuaState, Func.func); | |
lua_setfield(LuaState, -2, Func.name); | |
} | |
}; | |
// Base type. | |
{ | |
// Meta table. | |
{ | |
luaL_newmetatable(LuaState, "MetaBase"); | |
{ | |
std::vector<luaL_Reg> InstaceMethods; | |
InstaceMethods.push_back({ "InstanceMethodGetInt", &Base_InstanceMethodGetInt }); | |
InstaceMethods.push_back({ "InstanceMethodGetFloat", &Base_InstanceMethodGetFloat }); | |
InstaceMethods.push_back({ "InstanceMethodCall", &Base_InstanceMethodCall }); | |
InstaceMethods.push_back({ "InstanceMethodCallOverloaded", &Base_InstanceMethodCallOverloaded }); | |
InstaceMethods.push_back({ "ToString", &Base_ToString }); | |
InstaceMethods.push_back({ "__tostring", &Base_ToString }); | |
InstaceMethods.push_back({ "__call", &Base_Constructor }); | |
RegisterFunctions(InstaceMethods); | |
} | |
// Set to itself. | |
lua_pushvalue(LuaState, -1); | |
lua_setfield(LuaState, -2, "__index"); | |
lua_pop(LuaState, 1); | |
} | |
// Base table. | |
{ | |
lua_getglobal(LuaState, "BT"); | |
lua_newtable(LuaState); | |
{ | |
std::vector<luaL_Reg> StaticMethods; | |
StaticMethods.push_back({ "StaticMethodCall", &Base_StaticMethodCall }); | |
RegisterFunctions(StaticMethods); | |
} | |
// Set meta table for this table. | |
luaL_getmetatable(LuaState, "MetaBase"); | |
lua_setmetatable(LuaState, -2); | |
// Store this table in global namespace. | |
lua_setfield(LuaState, -2, "Base"); | |
lua_pop(LuaState, 1); | |
} | |
} | |
// Derived type. | |
{ | |
// Meta table. | |
{ | |
luaL_newmetatable(LuaState, "MetaDerived"); | |
{ | |
std::vector<luaL_Reg> InstaceMethods; | |
InstaceMethods.push_back({ "InstanceMethodGetBool", &Derived_InstanceMethodGetBool }); | |
InstaceMethods.push_back({ "InstanceMethodCallOverloaded", &Derived_InstanceMethodCallOverloaded }); | |
InstaceMethods.push_back({ "ToString", &Derived_ToString }); | |
InstaceMethods.push_back({ "__tostring", &Derived_ToString }); | |
InstaceMethods.push_back({ "__call", &Derived_Constructor }); | |
RegisterFunctions(InstaceMethods); | |
} | |
// Set to itself. | |
lua_pushvalue(LuaState, -1); | |
//luaL_getmetatable(LuaState, "MetaBase"); | |
lua_setfield(LuaState, -2, "__index"); | |
luaL_getmetatable(LuaState, "MetaBase"); | |
lua_setmetatable(LuaState, -2); | |
lua_pop(LuaState, 1); | |
} | |
// Derived table. | |
{ | |
lua_getglobal(LuaState, "BT"); | |
lua_newtable(LuaState); | |
{ | |
std::vector<luaL_Reg> StaticMethods; | |
RegisterFunctions(StaticMethods); | |
} | |
// Set meta table for this table. | |
luaL_getmetatable(LuaState, "MetaDerived"); | |
lua_setmetatable(LuaState, -2); | |
// Store this table in global namespace. | |
lua_setfield(LuaState, -2, "Derived"); | |
lua_pop(LuaState, 1); | |
} | |
} | |
// FurtherDerived type. | |
{ | |
// Meta table. | |
{ | |
luaL_newmetatable(LuaState, "MetaFurtherDerived"); | |
{ | |
std::vector<luaL_Reg> InstaceMethods; | |
InstaceMethods.push_back({ "ToString", &FurtherDerived_ToString }); | |
InstaceMethods.push_back({ "__tostring", &FurtherDerived_ToString }); | |
InstaceMethods.push_back({ "__call", &FurtherDerived_Constructor }); | |
RegisterFunctions(InstaceMethods); | |
} | |
// Set to itself. | |
lua_pushvalue(LuaState, -1); | |
lua_setfield(LuaState, -2, "__index"); | |
luaL_getmetatable(LuaState, "MetaDerived"); | |
lua_setmetatable(LuaState, -2); | |
lua_pop(LuaState, 1); | |
} | |
// FurtherDerived table. | |
{ | |
lua_getglobal(LuaState, "BT"); | |
lua_newtable(LuaState); | |
{ | |
std::vector<luaL_Reg> StaticMethods; | |
RegisterFunctions(StaticMethods); | |
} | |
// Set meta table for this table. | |
luaL_getmetatable(LuaState, "MetaFurtherDerived"); | |
lua_setmetatable(LuaState, -2); | |
// Store this table in global namespace. | |
lua_setfield(LuaState, -2, "FurtherDerived"); | |
lua_pop(LuaState, 1); | |
} | |
} | |
const char* Code = "" | |
"local a = BT.Base()\n" | |
"print(a)\n" | |
"local r = BT.Base.StaticMethodCall()\n" | |
"print(\"BT.Base.StaticMethodCall() -> \" .. r)\n" | |
"local r = a:InstanceMethodGetInt()\n" | |
"print(\"a:InstanceMethodGetInt() -> \" .. r)\n" | |
"local r = a:InstanceMethodGetFloat()\n" | |
"print(\"a:InstanceMethodGetFloat() -> \" .. r)\n" | |
"local r = a:InstanceMethodCall()\n" | |
"print(\"a:InstanceMethodCall() -> \" .. r)\n" | |
"local r = a:InstanceMethodCallOverloaded()\n" | |
"print(\"a:InstanceMethodCallOverloaded() -> \" .. r)\n" | |
"local b = BT.Derived()\n" | |
"print(b)\n" | |
"local r = b:InstanceMethodGetBool()\n" | |
"print(\"b:InstanceMethodGetBool() -> \" .. tostring(r))\n" | |
"local r = b:InstanceMethodCallOverloaded()\n" | |
"print(\"b:InstanceMethodCallOverloaded() -> \" .. r)\n" | |
"local r = b:InstanceMethodGetInt()\n" | |
"print(\"b:InstanceMethodGetInt() -> \" .. r)\n" | |
"local c = BT.FurtherDerived()\n" | |
"print(c)\n" | |
"local r = c:InstanceMethodGetBool()\n" | |
"print(\"c:InstanceMethodGetBool() -> \" .. tostring(r))\n" | |
"local r = c:InstanceMethodCallOverloaded()\n" | |
"print(\"c:InstanceMethodCallOverloaded() -> \" .. r)\n" | |
"local r = c:InstanceMethodCall()\n" | |
"print(\"c:InstanceMethodCall() -> \" .. r)\n" | |
"local r = c:InstanceMethodGetInt()\n" | |
"print(\"c:InstanceMethodGetInt() -> \" .. r)\n" | |
""; | |
OutputDebugStringA("Executing\n"); | |
if(luaL_loadstring(LuaState, Code) == LUA_OK) | |
{ | |
if(lua_pcall(LuaState, 0, 0, 0) == LUA_OK) | |
{ | |
lua_pop(LuaState, lua_gettop(LuaState)); | |
lua_gc(LuaState, LUA_GCCOLLECT); | |
} | |
else | |
{ | |
const char* ErrorString = lua_tostring(LuaState, -1); | |
char Buf[512]; | |
snprintf(Buf, 512, "Error: %s\n", ErrorString); | |
OutputDebugStringA(Buf); | |
lua_pop(LuaState, 1); | |
} | |
} | |
lua_close(LuaState); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Executing
Base
BT.Base.StaticMethodCall() -> Base_StaticMethodCall
a:InstanceMethodGetInt() -> 42
a:InstanceMethodGetFloat() -> 43.0
a:InstanceMethodCall() -> Base_InstanceMethodCall
a:InstanceMethodCallOverloaded() -> Base_InstanceMethodCallOverloaded
Derived
b:InstanceMethodGetBool() -> true
b:InstanceMethodCallOverloaded() -> Derived_InstanceMethodCallOverloaded
b:InstanceMethodGetInt() -> 420
FurtherDerived
c:InstanceMethodGetBool() -> true
c:InstanceMethodCallOverloaded() -> Derived_InstanceMethodCallOverloaded
c:InstanceMethodCall() -> Base_InstanceMethodCall
c:InstanceMethodGetInt() -> 420