1

I think I have messed up my stack somewhere. Here's ultimately what's happening.

local tg = require "tgeasy"

local drawBuffer = tg.start();
tg.stop();

print(drawBuffer.pointer, getmetatable(drawBuffer.pointer).__name);
local charInfo = tg.CharInfo:new{char = "u"};
print(drawBuffer.pointer, getmetatable(drawBuffer.pointer).__name);

Output:

userdata: 0x7ff6f62032b0        TG.Buffer
userdata: 0x7ff6f62032b0        TG.CharInfo

There are a few layers to this:

1: The underlying c api bindings (Where I suspect the issue) 2: The "helper" lua script that goes between the raw c bindings and a user of the library ("tgeasy.lua") 3: The actual lua script (as seen above)

You have already seen 3, let's move to 2:

local tg = require "libtg"

local tgeasy = {
    lib = tg,
    VERSION = tg.VERSION,
    BINDING_VERSION = tg.BINDING_VERSION,
    stop = tg.TGEnd,
    EV_KEY = tg.EVENT_KEY,
    EV_MOUSE = tg.EVENT_MOUSE,
    EV_RESIZE = tg.EVENT_RESIZE,
    BLACK  = tg.BLACK,
    RED = tg.RED,
    GREEN = tg.GREEN,
    YELLOW = tg.YELLOW,
    BLUE = tg.BLUE,
    MAGENTA = tg.MAGENTA,
    CYAN = tg.CYAN,
    WHITE = tg.WHITE,
    color = tg.color
};

Buffer = {}

function Buffer:new(o)
    o = o or {};
    setmetatable(o, self);
    self.__index = self;

    if(o.width and o.height) then
        o.pointer = tg.bufferCreate(o.width, o.height);
    end

    return o;
end

function Buffer:getSize()
    return tg.bufferGetSize(self.pointer);
end

tgeasy.Buffer = Buffer;

function tgeasy.start()
    local context = tg.TG();
    return Buffer:new{ pointer = context.drawBuffer};
end

CharInfo = {}

function CharInfo:new(o)
    o = o or {};
    setmetatable(o, self);
    self.__index = self;

    if(o.char) then o.pointer = tg.charInfo(o.char) end

    return o;
end

tgeasy.CharInfo = CharInfo;

return tgeasy;

And now, for the part where I suspect the issue is, the c code (Section 1): (Please note that calls to the TG Library, such as TG() are not exposed to Lua whatsoever, and the implementations of these calls are therefore not included)

static int luatg_bufferCreate(lua_State* L){
    int width = luaL_checkinteger(L, 1);
    int height = luaL_checkinteger(L, 2);

    if(width < 0 || height < 0) luaL_error(L, "Invalid buffer dimensions");

    TGBuffer *buffer = malloc(sizeof(TGBuffer));
    *buffer = TGBufCreate(width, height);

    lua_pushlightuserdata(L, buffer);
    luaL_getmetatable(L, "TG.Buffer");
    lua_setmetatable(L, -2);

    return 1;
}

static int luatg_bufferGetSize(lua_State* L){
    // TODO: Make this a function where no args = return size, two args = set size
    TGBuffer *buffer = (TGBuffer *) luaL_checkudata(L, 1, "TG.Buffer");
    lua_pushinteger(L, buffer->size.X);
    lua_pushinteger(L, buffer->size.Y);
    return 2;
}

static int luatg_charInfo(lua_State* L){
    int character = luaL_checkstring(L, 1)[0];
    TGCharInfo *charInfo = malloc(sizeof(TGCharInfo));
    charInfo->UnicodeChar = character;
    charInfo->AsciiChar = character;
    lua_pushlightuserdata(L, charInfo);
    luaL_getmetatable(L, "TG.CharInfo");
    lua_setmetatable(L, -2);
    return 1;
}

static int luatg_tg(lua_State* L){
    lua_newtable(L); // Create a "context" table

    TGContext *context = TG();

    lua_pushliteral(L, "context"); // Push the actual context pointer, not that we reallyyyy need it
    lua_pushlightuserdata(L, context);
    luaL_getmetatable(L, "TG.Context"); // Declare this as a TG.Context Lua type
    lua_setmetatable(L, -2);
    lua_settable(L, -3);

    lua_pushliteral(L, "drawBuffer"); // Push the draw buffer, which we DO need
    lua_pushlightuserdata(L, &context->drawBuffer);
    luaL_getmetatable(L, "TG.Buffer"); // Declare this as a TG.Buffer Lua type
    lua_setmetatable(L, -2);
    lua_settable(L, -3);

    return 1;
}

static int luatg_end(lua_State* L){
    TGEnd();
    return 0;
}

static const luaL_Reg libtg[] = {
    {"bufferCreate", luatg_bufferCreate},
    {"bufferGetSize", luatg_bufferGetSize},
    {"charInfo", luatg_charInfo}

    {"TG", luatg_tg},
    {"TGEnd", luatg_end},
    {NULL, NULL}
};

LUALIB_API int luaopen_libtg(lua_State* L){

    lua_checkstack(L, 25); // Increase the stack size to at least 25

    luaL_newmetatable(L, "TG.Context");
    luaL_newmetatable(L, "TG.Buffer");
    luaL_newmetatable(L, "TG.Color");
    luaL_newmetatable(L, "TG.Attributes");
    luaL_newmetatable(L, "TG.CharInfo");
    luaL_newlib(L, libtg);

    lua_pushstring(L, TG_VERSION);
    lua_setfield(L, -2, "VERSION");

    lua_pushstring(L, "1.0.0");
    lua_setfield(L, -2, "BINDING_VERSION");

    lua_pushinteger(L, TG_EVENT_KEY);
    lua_setfield(L, -2, "EVENT_KEY");

    lua_pushinteger(L, TG_EVENT_MOUSE);
    lua_setfield(L, -2, "EVENT_MOUSE");

    lua_pushinteger(L, TG_EVENT_RESIZE);
    lua_setfield(L, -2, "EVENT_RESIZE");

    lua_pushinteger(L, TG_MOUSE_LEFT);
    lua_setfield(L, -2, "MOUSE_LEFT");

    lua_pushinteger(L, TG_MOUSE_RIGHT);
    lua_setfield(L, -2, "MOUSE_RIGHT");

    lua_pushinteger(L, TG_MMB);
    lua_setfield(L, -2, "MMB");

    lua_pushinteger(L, TG_MOUSE_MOVE);
    lua_setfield(L, -2, "MOUSE_MOVE");

    lua_pushinteger(L, TG_MOUSE_CLICK);
    lua_setfield(L, -2, "MOUSE_CLICK");

    lua_pushinteger(L, TG_BLACK);
    lua_setfield(L, -2, "BLACK");

    lua_pushinteger(L, TG_RED);
    lua_setfield(L, -2, "RED");

    lua_pushinteger(L, TG_GREEN);
    lua_setfield(L, -2, "GREEN");

    lua_pushinteger(L, TG_YELLOW);
    lua_setfield(L, -2, "YELLOW");

    lua_pushinteger(L, TG_BLUE);
    lua_setfield(L, -2, "BLUE");

    lua_pushinteger(L, TG_MAGENTA);
    lua_setfield(L, -2, "MAGENTA");

    lua_pushinteger(L, TG_CYAN);
    lua_setfield(L, -2, "CYAN");

    lua_pushinteger(L, TG_WHITE);
    lua_setfield(L, -2, "WHITE");

    return 1;
}
AlgoRythm
  • 1,196
  • 10
  • 31
  • 2
    Inside `luatg_charInfo()` you're trying to set a metatable for a light userdata. Only full userdata have individual metatables. All the light userdata in Lua VM share the same metatable. – Egor Skriptunoff Dec 30 '19 at 06:38
  • @EgorSkriptunoff I would believe you are right. Do you mind writing a solution or example with full userdata and perhaps an explanation of the difference as an answer and when I get home I will test & accept? – AlgoRythm Dec 30 '19 at 13:21
  • I've just spotted the mistake. It's up to you to rewrite your solution. – Egor Skriptunoff Dec 30 '19 at 13:49
  • @EgorSkriptunoff In truth, I just want to accept your answer, since you provided it as a comment – AlgoRythm Dec 30 '19 at 14:55

0 Answers0