开发者

Reading Lua table(s) from args in C - incorrect stack level?

开发者 https://www.devze.com 2023-04-03 01:28 出处:网络
The simple version is that I expect my __tostring method I have built in C to output \"glxy_object(100)\" when I print the object in Lua.It does this perfectly if I comment out the code between the \"

The simple version is that I expect my __tostring method I have built in C to output "glxy_object(100)" when I print the object in Lua. It does this perfectly if I comment out the code between the "problem code" comments (the bits that read the table data in from the new() method). Clearly I am not returning the stack to where it needs to go, but I've been staring at this code too long to see where the error is.

main.c

#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"

typedef struct {
  double x;
  double y;
  double z;
} glxy_vector3;

typedef struct {
  int id;
  glxy_vector3 position;
  glxy_vector3 rotation;
} glxy_object;

#define OBJNAME "glxy_object"

static int glxy_object_new(lua_State *L) {
  int n = lua_gettop(L);
  if (n != 2)
  开发者_运维知识库  return luaL_error(L, "Got %d arguments expected 2", n);

  size_t nbytes = sizeof(glxy_object);
  glxy_object *o = (glxy_object *)lua_newuserdata(L, nbytes);

  luaL_getmetatable(L, OBJNAME);
  lua_setmetatable(L, -2);

  // id
  o->id = luaL_checknumber(L, 1);

  // TROUBLE CODE
  lua_pop(L, 1);

  lua_pushstring(L, "position");
  lua_gettable(L, -2);
  lua_getfield(L, -1, "x");
  o->position.x = lua_tonumber(L, -1);
  lua_pop(L, 1);
  lua_getfield(L, -1, "y");
  o->position.y = lua_tonumber(L, -1);
  lua_pop(L, 1);
  lua_getfield(L, -1, "z");
  o->position.z = lua_tonumber(L, -1);
  lua_pop(L, 2);

  lua_pushstring(L, "rotation");
  lua_gettable(L, -2);
  lua_getfield(L, -1, "x");
  o->rotation.x = lua_tonumber(L, -1);
  lua_pop(L, 1);
  lua_getfield(L, -1, "y");
  o->rotation.y = lua_tonumber(L, -1);
  lua_pop(L, 1);
  lua_getfield(L, -1, "z");
  o->rotation.z = lua_tonumber(L, -1);
  lua_pop(L, 2);
  // END TROUBLE CODE

  // This actually prints the data just fine, so I am reading it correctly at least...
  printf("new() - id: %d - position: (%0.2f, %0.2f, %0.2f), rotation: (%0.2f, %0.2f, %0.2f)\n",
    o->id, o->position.x, o->position.y, o->position.z, o->rotation.x, o->rotation.y, o->rotation.z
  );

  return 1;
}

static glxy_object *glxy_object_check(lua_State *L) {
  luaL_checktype(L, 1, LUA_TUSERDATA);
  glxy_object *o = (glxy_object *)luaL_checkudata(L, 1, OBJNAME);
  if (o == NULL) luaL_typerror(L, 1, OBJNAME);
  return o;
}

static int glxy_object_tostring(lua_State *L) {
  glxy_object *o = (glxy_object *)lua_touserdata(L, 1);
  if (o == NULL) luaL_typerror(L, 1, OBJNAME);
  lua_pushfstring(L, "glxy_object(%d)", o->id);
  return 1;
}

static const struct luaL_reg glxy_object_f[] = {
  { "new", glxy_object_new },
  { NULL, NULL }
};

static const struct luaL_reg glxy_object_m[] = {
  { "__tostring", glxy_object_tostring },
  { NULL, NULL }
};

int glxy_register_object(lua_State *L) {
  luaL_openlib(L, OBJNAME, glxy_object_f, 0);
  luaL_newmetatable(L, OBJNAME);

  luaL_openlib(L, 0, glxy_object_m, 0);
  lua_pushliteral(L, "__index");
  lua_pushvalue(L, -3);
  lua_rawset(L, -3);
  lua_pushliteral(L, "__metatable");
  lua_pushvalue(L, -3);
  lua_rawset(L, -3);

  lua_pop(L, 1);
  return 1;
}

int main(void) {
  // setup lua
  L = luaL_newstate();
  luaL_openlibs(L);

  // register Lua accessable C objects
  glxy_register_object(L);
  lua_pop(L, 1);

  luaL_dofile(L, "main.lua");

  return 0;
}

main.lua

local o = glxy_object.new(100, { position={ x=1.0, y=2.0, z=3.0 }, rotation={ x=4.0, y=5.0, z=6.0 } })
print(o)

current output

new() - id: 100 - position: (1.00, 2.00, 3.00), rotation: (4.00, 5.00, 6.00)
table: 0x7fe702510b70

expected output / output when commenting out 'trouble code' (minus incorrect pos/rot values)

new() - id: 100 - position: (0.00, 0.00, 0.00), rotation: (0.00, 0.00, 0.00)
glxy_object(100)

I've trimmed/combined my code base down for readability.


The trouble with "trouble code" is on the first after line the comment: lua_pop(L, 1);. This pops the newly created userdata so glxy_object_new ends up returning its second parameter and not the created glxy_object.

There are two quick ways to fix this. The first one is to remove the lua_pop(L, 1); line and change both lines in the trouble code that say lua_gettable(L, -2); to lua_gettable(L, -3). The second one is to add another lua_pushuserdata(L, o) somewhere after the trouble code.

0

精彩评论

暂无评论...
验证码 换一张
取 消