summaryrefslogtreecommitdiff
path: root/lang_ext
diff options
context:
space:
mode:
authorJoshua Haberman <jhaberman@gmail.com>2011-07-31 17:30:06 -0700
committerJoshua Haberman <jhaberman@gmail.com>2011-07-31 17:30:06 -0700
commitc2c853fa212adcdc29dae4f4d01d6ac907d60c58 (patch)
tree6febbc922a9e9b0139e84ee7e33ae2cda37e1cb0 /lang_ext
parent57abebaaf902436f8de8e50f7054c25b391067ac (diff)
More work on Lua extension.
Diffstat (limited to 'lang_ext')
-rw-r--r--lang_ext/lua/test.lua8
-rw-r--r--lang_ext/lua/upb.c648
2 files changed, 339 insertions, 317 deletions
diff --git a/lang_ext/lua/test.lua b/lang_ext/lua/test.lua
index e5bf0ce..42bce25 100644
--- a/lang_ext/lua/test.lua
+++ b/lang_ext/lua/test.lua
@@ -21,16 +21,18 @@ print(B)
print(C)
a = A()
-print("YO! a.a=" .. tostring(a.a))
+a2 = upb.Message(A)
+print("YO! a.a=" .. tostring(a.a) .. ", a2.a=" .. tostring(a2.a))
a.a = 2
-print("YO! a.a=" .. tostring(a.a))
+a2.a = 3
+print("YO! a.a=" .. tostring(a.a) .. ", a2.a=" .. tostring(a2.a))
A = symtab:lookup("A")
if not A then
error("Could not find A")
end
-f = io.open("../../src/descriptor.pb")
+f = io.open("../../upb/descriptor.pb")
if not f then
error("Couldn't open descriptor.pb, try running 'make descriptorgen'")
end
diff --git a/lang_ext/lua/upb.c b/lang_ext/lua/upb.c
index 8adf14d..0cc6806 100644
--- a/lang_ext/lua/upb.c
+++ b/lang_ext/lua/upb.c
@@ -31,128 +31,6 @@ static uint32_t lupb_touint32(lua_State *L, int narg, const char *name) {
return n;
}
-//static void lupb_msg_getorcreate(lua_State *L, upb_msg *msg, upb_msgdef *md);
-static void lupb_fielddef_getorcreate(lua_State *L, upb_fielddef *f);
-
-// All the def types share the same C layout, even though they are different Lua
-// types with different metatables.
-typedef struct {
- upb_def *def;
-} lupb_def;
-
-typedef struct {
- upb_fielddef *field;
-} lupb_fielddef;
-
-static lupb_def *lupb_def_check(lua_State *L, int narg) {
- void *ldef = luaL_checkudata(L, narg, "upb.msgdef");
- if (!ldef) ldef = luaL_checkudata(L, narg, "upb.enumdef");
- luaL_argcheck(L, ldef != NULL, narg, "upb def expected");
- return ldef;
-}
-
-static lupb_fielddef *lupb_fielddef_check(lua_State *L, int narg) {
- lupb_fielddef *f = luaL_checkudata(L, narg, "upb.fielddef");
- luaL_argcheck(L, f != NULL, narg, "upb fielddef expected");
- return f;
-}
-
-void lupb_checkstatus(lua_State *L, upb_status *s) {
- if (!upb_ok(s)) {
- upb_status_print(s, stderr);
- // Need to copy the string to the stack, so we can free it and not leak
- // it (since luaL_error() does not return).
- char buf[strlen(s->str)+1];
- strcpy(buf, s->str);
- upb_status_uninit(s);
- luaL_error(L, "%s", buf);
- }
- upb_status_uninit(s);
-}
-
-
-/* object cache ***************************************************************/
-
-// We cache all the lua objects (userdata) we vend in a weak table, indexed by
-// the C pointer of the object they are caching.
-
-static void *lupb_cache_getorcreate_size(
- lua_State *L, void *cobj, const char *type, size_t size) {
- // Lookup our cache in the registry (we don't put our objects in the registry
- // directly because we need our cache to be a weak table).
- void **obj = NULL;
- lua_getfield(L, LUA_REGISTRYINDEX, "upb.objcache");
- assert(!lua_isnil(L, -1)); // Should have been created by luaopen_upb.
- lua_pushlightuserdata(L, cobj);
- lua_rawget(L, -2);
- // Stack: objcache, cached value.
- if (lua_isnil(L, -1)) {
- // Remove bad cached value and push new value.
- lua_pop(L, 1);
- // We take advantage of the fact that all of our objects are currently a
- // single pointer, and thus have the same layout.
- obj = lua_newuserdata(L, size);
- *obj = cobj;
- luaL_getmetatable(L, type);
- assert(!lua_isnil(L, -1)); // Should have been created by luaopen_upb.
- lua_setmetatable(L, -2);
-
- // Set it in the cache.
- lua_pushlightuserdata(L, cobj);
- lua_pushvalue(L, -2);
- lua_rawset(L, -4);
- }
- lua_insert(L, -2);
- lua_pop(L, 1);
- return obj;
-}
-
-// Most types are just 1 pointer and can use this helper.
-static bool lupb_cache_getorcreate(lua_State *L, void *cobj, const char *type) {
- return lupb_cache_getorcreate_size(L, cobj, type, sizeof(void*)) != NULL;
-}
-
-static void lupb_cache_create(lua_State *L, void *cobj, const char *type) {
- bool created =
- lupb_cache_getorcreate_size(L, cobj, type, sizeof(void*)) != NULL;
- (void)created; // For NDEBUG
- assert(created);
-}
-
-
-/* lupb_msg********************************************************************/
-
-// Messages are userdata where we store primitive values (numbers and bools)
-// right in the userdata. We also use integer entries in the environment table
-// like so:
-// {msgdef, <string, submessage, or array fields>}
-
-static void *lupb_msg_check(lua_State *L, int narg, upb_msgdef **md) {
- void *msg = luaL_checkudata(L, narg, "upb.msg");
- luaL_argcheck(L, msg != NULL, narg, "msg expected");
- // If going all the way to the environment table for the msgdef is an
- // efficiency issue, we could put the pointer right in the userdata.
- lua_getfenv(L, narg);
- lua_rawgeti(L, -1, 1);
- // Shouldn't have to check msgdef userdata validity, environment table can't
- // be accessed from Lua.
- lupb_def *lmd = lua_touserdata(L, -1);
- *md = upb_downcast_msgdef(lmd->def);
- return msg;
-}
-
-static void lupb_msg_pushnew(lua_State *L, upb_msgdef *md) {
- void *msg = lua_newuserdata(L, upb_msgdef_size(md));
- luaL_getmetatable(L, "upb.msg");
- assert(!lua_isnil(L, -1)); // Should have been created by luaopen_upb.
- lua_setmetatable(L, -2);
- upb_msg_clear(msg, md);
- lua_getfenv(L, -1);
- lupb_cache_getorcreate(L, md, "upb.msgdef");
- lua_rawseti(L, -2, 1);
- lua_pop(L, 1); // Pop the fenv.
-}
-
static void lupb_pushvalue(lua_State *L, upb_value val, upb_fielddef *f) {
switch (f->type) {
case UPB_TYPE(INT32):
@@ -243,204 +121,88 @@ static upb_value lupb_getvalue(lua_State *L, int narg, upb_fielddef *f,
return val;
}
-static int lupb_msg_index(lua_State *L) {
- assert(lua_gettop(L) == 2); // __index should always be called with 2 args.
- upb_msgdef *md;
- void *m = lupb_msg_check(L, 1, &md);
- const char *name = luaL_checkstring(L, 2);
- upb_fielddef *f = upb_msgdef_ntof(md, name);
- if (!f) luaL_error(L, "%s is not a field name", name);
- if (upb_isseq(f)) luaL_error(L, "NYI: access of repeated fields");
- upb_value val =
- upb_msg_has(m, f) ? upb_msg_get(m, f) : upb_fielddef_default(f);
- lupb_pushvalue(L, val, f);
- return 1;
-}
-
-static int lupb_msg_newindex(lua_State *L) {
- assert(lua_gettop(L) == 3); // __newindex should always be called with 3 args.
- upb_msgdef *md;
- void *m = lupb_msg_check(L, 1, &md);
- const char *name = luaL_checkstring(L, 2);
- upb_fielddef *f = upb_msgdef_ntof(md, name);
- if (!f) luaL_error(L, "%s is not a field name", name);
- upb_msg_set(m, f, lupb_getvalue(L, 3, f, NULL));
- return 0;
-}
-
-#if 0
-static int lupb_msg_clear(lua_State *L) {
- lupb_msg *m = lupb_msg_check(L, 1);
- upb_msg_clear(m->msg, m->msgdef);
- return 0;
-}
-
-static int lupb_msg_parse(lua_State *L) {
- lupb_msg *m = lupb_msg_check(L, 1);
- size_t len;
- const char *strbuf = luaL_checklstring(L, 2, &len);
- upb_string str = UPB_STACK_STRING_LEN(strbuf, len);
- upb_status status = UPB_STATUS_INIT;
- upb_strtomsg(&str, m->msg, m->msgdef, &status);
- lupb_checkstatus(L, &status);
- return 0;
-}
-
-static int lupb_msg_totext(lua_State *L) {
- lupb_msg *m = lupb_msg_check(L, 1);
- upb_string *str = upb_string_new();
- upb_msgtotext(str, m->msg, m->msgdef, false);
- lupb_pushstring(L, str);
- upb_string_unref(str);
- return 1;
-}
-#endif
-
-static const struct luaL_Reg lupb_msg_mm[] = {
- {"__index", lupb_msg_index},
- {"__newindex", lupb_msg_newindex},
- // Our __index mm will look up methods if the index isn't a field name.
- //{"Clear", lupb_msg_clear},
- //{"Parse", lupb_msg_parse},
- //{"ToText", lupb_msg_totext},
- {NULL, NULL}
-};
-
-
-/* lupb_msgdef ****************************************************************/
-
-static upb_msgdef *lupb_msgdef_check(lua_State *L, int narg) {
- lupb_def *ldef = luaL_checkudata(L, narg, "upb.msgdef");
- luaL_argcheck(L, ldef != NULL, narg, "upb msgdef expected");
- return upb_downcast_msgdef(ldef->def);
-}
-
-static int lupb_msgdef_gc(lua_State *L) {
- lupb_def *ldef = luaL_checkudata(L, 1, "upb.msgdef");
- upb_def_unref(ldef->def);
- return 0;
-}
+//static void lupb_msg_getorcreate(lua_State *L, upb_msg *msg, upb_msgdef *md);
+static void lupb_fielddef_getorcreate(lua_State *L, upb_fielddef *f);
+static upb_msgdef *lupb_msgdef_check(lua_State *L, int narg);
+static void lupb_msg_pushnew(lua_State *L, upb_msgdef *md);
-static int lupb_msgdef_call(lua_State *L) {
- upb_msgdef *md = lupb_msgdef_check(L, 1);
- lupb_msg_pushnew(L, md);
- return 1;
+void lupb_checkstatus(lua_State *L, upb_status *s) {
+ if (!upb_ok(s)) {
+ upb_status_print(s, stderr);
+ // Need to copy the string to the stack, so we can free it and not leak
+ // it (since luaL_error() does not return).
+ char buf[strlen(s->str)+1];
+ strcpy(buf, s->str);
+ upb_status_uninit(s);
+ luaL_error(L, "%s", buf);
+ }
+ upb_status_uninit(s);
}
-static int lupb_msgdef_new(lua_State *L) {
- upb_msgdef *md = upb_msgdef_new();
- lupb_cache_create(L, md, "upb.msgdef");
- if (lua_gettop(L) == 0) return 1;
+/* object cache ***************************************************************/
- // User can specify initialization values like so:
- // upb.MessageDef{fqname="MyMessage", extstart=8000, fields={...}}
- luaL_checktype(L, 1, LUA_TTABLE);
- // Iterate over table.
- lua_pushnil(L); // first key
- while (lua_next(L, 1)) {
- luaL_checktype(L, -2, LUA_TSTRING);
- const char *key = lua_tostring(L, -2);
+// We cache all the lua objects (userdata) we vend in a weak table, indexed by
+// the C pointer of the object they are caching.
- if (streql(key, "fqname")) { // fqname="MyMessage"
- const char *fqname = lua_tostring(L, -1);
- if (!fqname || !upb_def_setfqname(UPB_UPCAST(md), fqname))
- luaL_error(L, "Invalid fqname");
- } else if (streql(key, "fields")) { // fields={...}
- // Iterate over the list of fields.
- lua_pushnil(L);
- luaL_checktype(L, -2, LUA_TTABLE);
- while (lua_next(L, -2)) {
- lupb_fielddef *f = lupb_fielddef_check(L, -1);
- if (!upb_msgdef_addfield(md, f->field)) {
- // TODO: more specific error.
- luaL_error(L, "Could not add field.");
- }
- lua_pop(L, 1);
- }
- } else {
- // TODO: extrange=
- luaL_error(L, "Unknown initializer key '%s'", key);
- }
+static void *lupb_cache_getorcreate_size(
+ lua_State *L, void *cobj, const char *type, size_t size) {
+ // Lookup our cache in the registry (we don't put our objects in the registry
+ // directly because we need our cache to be a weak table).
+ void **obj = NULL;
+ lua_getfield(L, LUA_REGISTRYINDEX, "upb.objcache");
+ assert(!lua_isnil(L, -1)); // Should have been created by luaopen_upb.
+ lua_pushlightuserdata(L, cobj);
+ lua_rawget(L, -2);
+ // Stack: objcache, cached value.
+ if (lua_isnil(L, -1)) {
+ // Remove bad cached value and push new value.
lua_pop(L, 1);
- }
- return 1;
-}
-
-static int lupb_msgdef_fqname(lua_State *L) {
- upb_msgdef *m = lupb_msgdef_check(L, 1);
- lua_pushstring(L, m->base.fqname);
- return 1;
-}
-
-static int lupb_msgdef_fieldbyname(lua_State *L) {
- upb_msgdef *m = lupb_msgdef_check(L, 1);
- upb_fielddef *f = upb_msgdef_ntof(m, luaL_checkstring(L, 2));
- if (f) {
- lupb_fielddef_getorcreate(L, f);
- } else {
- lua_pushnil(L);
- }
- return 1;
-}
+ // We take advantage of the fact that all of our objects are currently a
+ // single pointer, and thus have the same layout.
+ obj = lua_newuserdata(L, size);
+ *obj = cobj;
+ luaL_getmetatable(L, type);
+ assert(!lua_isnil(L, -1)); // Should have been created by luaopen_upb.
+ lua_setmetatable(L, -2);
-static int lupb_msgdef_fieldbynum(lua_State *L) {
- upb_msgdef *m = lupb_msgdef_check(L, 1);
- int num = luaL_checkint(L, 2);
- upb_fielddef *f = upb_msgdef_itof(m, num);
- if (f) {
- lupb_fielddef_getorcreate(L, f);
- } else {
- lua_pushnil(L);
+ // Set it in the cache.
+ lua_pushlightuserdata(L, cobj);
+ lua_pushvalue(L, -2);
+ lua_rawset(L, -4);
}
- return 1;
-}
-
-static const struct luaL_Reg lupb_msgdef_mm[] = {
- {"__call", lupb_msgdef_call},
- {"__gc", lupb_msgdef_gc},
- {NULL, NULL}
-};
-
-static const struct luaL_Reg lupb_msgdef_m[] = {
- {"fieldbyname", lupb_msgdef_fieldbyname},
- {"fieldbynum", lupb_msgdef_fieldbynum},
- {"fqname", lupb_msgdef_fqname},
- {NULL, NULL}
-};
-
-
-/* lupb_enumdef ***************************************************************/
-
-static upb_enumdef *lupb_enumdef_check(lua_State *L, int narg) {
- lupb_def *ldef = luaL_checkudata(L, narg, "upb.enumdef");
- return upb_downcast_enumdef(ldef->def);
+ lua_insert(L, -2);
+ lua_pop(L, 1);
+ return obj;
}
-static int lupb_enumdef_gc(lua_State *L) {
- upb_enumdef *e = lupb_enumdef_check(L, 1);
- upb_def_unref(UPB_UPCAST(e));
- return 0;
+// Most types are just 1 pointer and can use this helper.
+static bool lupb_cache_getorcreate(lua_State *L, void *cobj, const char *type) {
+ return lupb_cache_getorcreate_size(L, cobj, type, sizeof(void*)) != NULL;
}
-static int lupb_enumdef_name(lua_State *L) {
- upb_enumdef *e = lupb_enumdef_check(L, 1);
- lua_pushstring(L, e->base.fqname);
- return 1;
+static void lupb_cache_create(lua_State *L, void *cobj, const char *type) {
+ bool created =
+ lupb_cache_getorcreate_size(L, cobj, type, sizeof(void*)) != NULL;
+ (void)created; // For NDEBUG
+ assert(created);
}
-static const struct luaL_Reg lupb_enumdef_mm[] = {
- {"__gc", lupb_enumdef_gc},
- {NULL, NULL}
-};
-static const struct luaL_Reg lupb_enumdef_m[] = {
- {"name", lupb_enumdef_name},
- {NULL, NULL}
-};
+/* lupb_def *******************************************************************/
+// All the def types share the same C layout, even though they are different Lua
+// types with different metatables.
+typedef struct {
+ upb_def *def;
+} lupb_def;
-/* lupb_def *******************************************************************/
+static lupb_def *lupb_def_check(lua_State *L, int narg) {
+ void *ldef = luaL_checkudata(L, narg, "upb.msgdef");
+ if (!ldef) ldef = luaL_checkudata(L, narg, "upb.enumdef");
+ luaL_argcheck(L, ldef != NULL, narg, "upb def expected");
+ return ldef;
+}
static void lupb_def_getorcreate(lua_State *L, upb_def *def, int owned) {
bool created = false;
@@ -464,6 +226,16 @@ static void lupb_def_getorcreate(lua_State *L, upb_def *def, int owned) {
/* lupb_fielddef **************************************************************/
+typedef struct {
+ upb_fielddef *field;
+} lupb_fielddef;
+
+static lupb_fielddef *lupb_fielddef_check(lua_State *L, int narg) {
+ lupb_fielddef *f = luaL_checkudata(L, narg, "upb.fielddef");
+ luaL_argcheck(L, f != NULL, narg, "upb fielddef expected");
+ return f;
+}
+
#if 0
static const upb_accessor lupb_accessor = {
upb_startfield_handler *appendseq; // Repeated fields only.
@@ -584,6 +356,138 @@ static const struct luaL_Reg lupb_fielddef_mm[] = {
};
+/* lupb_msgdef ****************************************************************/
+
+static upb_msgdef *lupb_msgdef_check(lua_State *L, int narg) {
+ lupb_def *ldef = luaL_checkudata(L, narg, "upb.msgdef");
+ luaL_argcheck(L, ldef != NULL, narg, "upb msgdef expected");
+ return upb_downcast_msgdef(ldef->def);
+}
+
+static int lupb_msgdef_gc(lua_State *L) {
+ lupb_def *ldef = luaL_checkudata(L, 1, "upb.msgdef");
+ upb_def_unref(ldef->def);
+ return 0;
+}
+
+static int lupb_msgdef_call(lua_State *L) {
+ upb_msgdef *md = lupb_msgdef_check(L, 1);
+ lupb_msg_pushnew(L, md);
+ return 1;
+}
+
+static int lupb_msgdef_new(lua_State *L) {
+ upb_msgdef *md = upb_msgdef_new();
+ lupb_cache_create(L, md, "upb.msgdef");
+
+ if (lua_gettop(L) == 0) return 1;
+
+ // User can specify initialization values like so:
+ // upb.MessageDef{fqname="MyMessage", extstart=8000, fields={...}}
+ luaL_checktype(L, 1, LUA_TTABLE);
+ // Iterate over table.
+ lua_pushnil(L); // first key
+ while (lua_next(L, 1)) {
+ luaL_checktype(L, -2, LUA_TSTRING);
+ const char *key = lua_tostring(L, -2);
+
+ if (streql(key, "fqname")) { // fqname="MyMessage"
+ const char *fqname = lua_tostring(L, -1);
+ if (!fqname || !upb_def_setfqname(UPB_UPCAST(md), fqname))
+ luaL_error(L, "Invalid fqname");
+ } else if (streql(key, "fields")) { // fields={...}
+ // Iterate over the list of fields.
+ lua_pushnil(L);
+ luaL_checktype(L, -2, LUA_TTABLE);
+ while (lua_next(L, -2)) {
+ lupb_fielddef *f = lupb_fielddef_check(L, -1);
+ if (!upb_msgdef_addfield(md, f->field)) {
+ // TODO: more specific error.
+ luaL_error(L, "Could not add field.");
+ }
+ lua_pop(L, 1);
+ }
+ } else {
+ // TODO: extrange=
+ luaL_error(L, "Unknown initializer key '%s'", key);
+ }
+ lua_pop(L, 1);
+ }
+ return 1;
+}
+
+static int lupb_msgdef_fqname(lua_State *L) {
+ upb_msgdef *m = lupb_msgdef_check(L, 1);
+ lua_pushstring(L, m->base.fqname);
+ return 1;
+}
+
+static int lupb_msgdef_fieldbyname(lua_State *L) {
+ upb_msgdef *m = lupb_msgdef_check(L, 1);
+ upb_fielddef *f = upb_msgdef_ntof(m, luaL_checkstring(L, 2));
+ if (f) {
+ lupb_fielddef_getorcreate(L, f);
+ } else {
+ lua_pushnil(L);
+ }
+ return 1;
+}
+
+static int lupb_msgdef_fieldbynum(lua_State *L) {
+ upb_msgdef *m = lupb_msgdef_check(L, 1);
+ int num = luaL_checkint(L, 2);
+ upb_fielddef *f = upb_msgdef_itof(m, num);
+ if (f) {
+ lupb_fielddef_getorcreate(L, f);
+ } else {
+ lua_pushnil(L);
+ }
+ return 1;
+}
+
+static const struct luaL_Reg lupb_msgdef_mm[] = {
+ {"__call", lupb_msgdef_call},
+ {"__gc", lupb_msgdef_gc},
+ {NULL, NULL}
+};
+
+static const struct luaL_Reg lupb_msgdef_m[] = {
+ {"fieldbyname", lupb_msgdef_fieldbyname},
+ {"fieldbynum", lupb_msgdef_fieldbynum},
+ {"fqname", lupb_msgdef_fqname},
+ {NULL, NULL}
+};
+
+
+/* lupb_enumdef ***************************************************************/
+
+static upb_enumdef *lupb_enumdef_check(lua_State *L, int narg) {
+ lupb_def *ldef = luaL_checkudata(L, narg, "upb.enumdef");
+ return upb_downcast_enumdef(ldef->def);
+}
+
+static int lupb_enumdef_gc(lua_State *L) {
+ upb_enumdef *e = lupb_enumdef_check(L, 1);
+ upb_def_unref(UPB_UPCAST(e));
+ return 0;
+}
+
+static int lupb_enumdef_name(lua_State *L) {
+ upb_enumdef *e = lupb_enumdef_check(L, 1);
+ lua_pushstring(L, e->base.fqname);
+ return 1;
+}
+
+static const struct luaL_Reg lupb_enumdef_mm[] = {
+ {"__gc", lupb_enumdef_gc},
+ {NULL, NULL}
+};
+
+static const struct luaL_Reg lupb_enumdef_m[] = {
+ {"name", lupb_enumdef_name},
+ {NULL, NULL}
+};
+
/* lupb_symtab ****************************************************************/
@@ -689,22 +593,10 @@ static int lupb_symtab_getdefs(lua_State *L) {
return 1;
}
-static int lupb_symtab_parsedesc(lua_State *L) {
- lupb_symtab *s = lupb_symtab_check(L, 1);
- size_t len;
- const char *str = luaL_checklstring(L, 2, &len);
- upb_status status = UPB_STATUS_INIT;
- upb_read_descriptor(s->symtab, str, len, &status);
- lupb_checkstatus(L, &status);
- return 0;
-}
-
static const struct luaL_Reg lupb_symtab_m[] = {
{"add", lupb_symtab_add},
{"getdefs", lupb_symtab_getdefs},
{"lookup", lupb_symtab_lookup},
- {"parsedesc", lupb_symtab_parsedesc},
- //{"resolve", lupb_symtab_resolve},
{NULL, NULL}
};
@@ -714,12 +606,138 @@ static const struct luaL_Reg lupb_symtab_mm[] = {
};
+/* lupb_msg********************************************************************/
+
+// Messages are userdata where we store primitive values (numbers and bools)
+// right in the userdata. We also use integer entries in the environment table
+// like so:
+// {msgdef, <string, submessage, or array fields>}
+
+static void *lupb_msg_check(lua_State *L, int narg, upb_msgdef **md) {
+ void *msg = luaL_checkudata(L, narg, "upb.msg");
+ luaL_argcheck(L, msg != NULL, narg, "msg expected");
+ // If going all the way to the environment table for the msgdef is an
+ // efficiency issue, we could put the pointer right in the userdata.
+ lua_getfenv(L, narg);
+ lua_rawgeti(L, -1, 1);
+ // Shouldn't have to check msgdef userdata validity, environment table can't
+ // be accessed from Lua.
+ lupb_def *lmd = lua_touserdata(L, -1);
+ *md = upb_downcast_msgdef(lmd->def);
+ return msg;
+}
+
+static void lupb_msg_pushnew(lua_State *L, upb_msgdef *md) {
+ void *msg = lua_newuserdata(L, upb_msgdef_size(md));
+ luaL_getmetatable(L, "upb.msg");
+ assert(!lua_isnil(L, -1)); // Should have been created by luaopen_upb.
+ lua_setmetatable(L, -2);
+ upb_msg_clear(msg, md);
+ lua_getfenv(L, -1);
+ lupb_cache_getorcreate(L, md, "upb.msgdef");
+ lua_rawseti(L, -2, 1);
+ lua_pop(L, 1); // Pop the fenv.
+}
+
+static int lupb_msg_new(lua_State *L) {
+ upb_msgdef *md = lupb_msgdef_check(L, 1);
+ lupb_msg_pushnew(L, md);
+ return 1;
+}
+
+static int lupb_msg_index(lua_State *L) {
+ assert(lua_gettop(L) == 2); // __index should always be called with 2 args.
+ upb_msgdef *md;
+ void *m = lupb_msg_check(L, 1, &md);
+ const char *name = luaL_checkstring(L, 2);
+ upb_fielddef *f = upb_msgdef_ntof(md, name);
+ if (!f) luaL_error(L, "%s is not a field name", name);
+ if (upb_isseq(f)) luaL_error(L, "NYI: access of repeated fields");
+ upb_value val =
+ upb_msg_has(m, f) ? upb_msg_get(m, f) : upb_fielddef_default(f);
+ lupb_pushvalue(L, val, f);
+ return 1;
+}
+
+static int lupb_msg_newindex(lua_State *L) {
+ assert(lua_gettop(L) == 3); // __newindex should always be called with 3 args.
+ upb_msgdef *md;
+ void *m = lupb_msg_check(L, 1, &md);
+ const char *name = luaL_checkstring(L, 2);
+ upb_fielddef *f = upb_msgdef_ntof(md, name);
+ if (!f) luaL_error(L, "%s is not a field name", name);
+ upb_msg_set(m, f, lupb_getvalue(L, 3, f, NULL));
+ return 0;
+}
+
+#if 0
+static int lupb_msg_parse(lua_State *L) {
+ lupb_msg *m = lupb_msg_check(L, 1);
+ size_t len;
+ const char *strbuf = luaL_checklstring(L, 2, &len);
+ upb_string str = UPB_STACK_STRING_LEN(strbuf, len);
+ upb_status status = UPB_STATUS_INIT;
+ upb_strtomsg(&str, m->msg, m->msgdef, &status);
+ lupb_checkstatus(L, &status);
+ return 0;
+}
+
+static int lupb_msg_totext(lua_State *L) {
+ lupb_msg *m = lupb_msg_check(L, 1);
+ upb_string *str = upb_string_new();
+ upb_msgtotext(str, m->msg, m->msgdef, false);
+ lupb_pushstring(L, str);
+ upb_string_unref(str);
+ return 1;
+}
+#endif
+
+static const struct luaL_Reg lupb_msg_mm[] = {
+ {"__index", lupb_msg_index},
+ {"__newindex", lupb_msg_newindex},
+ {NULL, NULL}
+};
+
+// Functions that operate on msgdefs but do not live in the msgdef namespace.
+static int lupb_clear(lua_State *L) {
+ upb_msgdef *md;
+ void *m = lupb_msg_check(L, 1, &md);
+ upb_msg_clear(m, md);
+ return 0;
+}
+
+static int lupb_has(lua_State *L) {
+ upb_msgdef *md;
+ void *m = lupb_msg_check(L, 1, &md);
+ const char *name = luaL_checkstring(L, 2);
+ upb_fielddef *f = upb_msgdef_ntof(md, name);
+ if (!f) luaL_error(L, "%s is not a field name", name);
+ lua_pushboolean(L, upb_msg_has(m, f));
+ return 1;
+}
+
+static int lupb_msgdef(lua_State *L) {
+ upb_msgdef *md;
+ lupb_msg_check(L, 1, &md);
+ lupb_def_getorcreate(L, UPB_UPCAST(md), false);
+ return 1;
+}
+
+
/* lupb toplevel **************************************************************/
static const struct luaL_Reg lupb_toplevel_m[] = {
{"SymbolTable", lupb_symtab_new},
{"MessageDef", lupb_msgdef_new},
{"FieldDef", lupb_fielddef_new},
+
+ {"Message", lupb_msg_new},
+ //{"Array", lupb_array_new},
+
+ {"clear", lupb_clear},
+ {"msgdef", lupb_msgdef},
+ {"has", lupb_has},
+
{NULL, NULL}
};
@@ -748,7 +766,9 @@ int luaopen_upb(lua_State *L) {
lupb_register_type(L, "upb.enumdef", lupb_enumdef_m, lupb_enumdef_mm);
lupb_register_type(L, "upb.fielddef", NULL, lupb_fielddef_mm);
lupb_register_type(L, "upb.symtab", lupb_symtab_m, lupb_symtab_mm);
+
lupb_register_type(L, "upb.msg", NULL, lupb_msg_mm);
+ lupb_register_type(L, "upb.array", NULL, lupb_msg_mm);
// Create our object cache.
lua_createtable(L, 0, 0);
generated by cgit on debian on lair
contact matthew@masot.net with questions or feedback