Skip to content

Instantly share code, notes, and snippets.

@ttvd
Created September 24, 2022 15:54
Show Gist options
  • Save ttvd/fc174fca5961742a89fdc3abd56ecd50 to your computer and use it in GitHub Desktop.
Save ttvd/fc174fca5961742a89fdc3abd56ecd50 to your computer and use it in GitHub Desktop.
Quick lua c++ bindings
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;
}
@ttvd
Copy link
Author

ttvd commented Sep 24, 2022

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment