2 ** require("lua") -- A Lua extension for upb.
4 ** Exposes only the core library
5 ** (sub-libraries are exposed in other extensions).
7 ** 64-bit woes: Lua can only represent numbers of type lua_Number (which is
8 ** double unless the user specifically overrides this). Doubles can represent
9 ** the entire range of 64-bit integers, but lose precision once the integers are
12 ** Lua 5.3 is adding support for integers, which will allow for 64-bit
13 ** integers (which can be interpreted as signed or unsigned).
15 ** LuaJIT supports 64-bit signed and unsigned boxed representations
16 ** through its "cdata" mechanism, but this is not portable to regular Lua.
18 ** Hopefully Lua 5.3 will come soon enough that we can either use Lua 5.3
19 ** integer support or LuaJIT 64-bit cdata for users that need the entire
20 ** domain of [u]int64 values.
28 #include "upb/bindings/lua/upb.h"
29 #include "upb/handlers.h"
33 /* Lua compatibility code *****************************************************/
35 /* Lua 5.1 and Lua 5.2 have slightly incompatible APIs. A little bit of
36 * compatibility code can help hide the difference. Not too many people still
37 * use Lua 5.1 but LuaJIT uses the Lua 5.1 API in some ways. */
39 #if LUA_VERSION_NUM == 501
41 /* taken from lua 5.2's source. */
42 void *luaL_testudata(lua_State *L, int ud, const char *tname) {
43 void *p = lua_touserdata(L, ud);
44 if (p != NULL) { /* value is a userdata? */
45 if (lua_getmetatable(L, ud)) { /* does it have a metatable? */
46 luaL_getmetatable(L, tname); /* get correct metatable */
47 if (!lua_rawequal(L, -1, -2)) /* not the same? */
48 p = NULL; /* value is a userdata with wrong metatable */
49 lua_pop(L, 2); /* remove both metatables */
53 return NULL; /* value is not a userdata with a metatable */
56 static void lupb_newlib(lua_State *L, const char *name, const luaL_Reg *funcs) {
57 luaL_register(L, name, funcs);
60 #elif LUA_VERSION_NUM == 502
62 int luaL_typerror(lua_State *L, int narg, const char *tname) {
63 const char *msg = lua_pushfstring(L, "%s expected, got %s",
64 tname, luaL_typename(L, narg));
65 return luaL_argerror(L, narg, msg);
68 static void lupb_newlib(lua_State *L, const char *name, const luaL_Reg *funcs) {
69 /* Lua 5.2 modules are not expected to set a global variable, so "name" is
73 /* Can't use luaL_newlib(), because funcs is not the actual array.
74 * Could (micro-)optimize this a bit to count funcs for initial table size. */
75 lua_createtable(L, 0, 8);
76 luaL_setfuncs(L, funcs, 0);
80 #error Only Lua 5.1 and 5.2 are supported
83 /* Shims for upcoming Lua 5.3 functionality. */
84 bool lua_isinteger(lua_State *L, int argn) {
91 /* Utility functions **********************************************************/
93 /* We store our module table in the registry, keyed by ptr.
94 * For more info about the motivation/rationale, see this thread:
95 * http://thread.gmane.org/gmane.comp.lang.lua.general/110632 */
96 bool lupb_openlib(lua_State *L, void *ptr, const char *name,
97 const luaL_Reg *funcs) {
98 /* Lookup cached module table. */
99 lua_pushlightuserdata(L, ptr);
100 lua_rawget(L, LUA_REGISTRYINDEX);
101 if (!lua_isnil(L, -1)) {
105 lupb_newlib(L, name, funcs);
107 /* Save module table in cache. */
108 lua_pushlightuserdata(L, ptr);
109 lua_pushvalue(L, -2);
110 lua_rawset(L, LUA_REGISTRYINDEX);
115 void lupb_checkstatus(lua_State *L, upb_status *s) {
117 lua_pushstring(L, upb_status_errmsg(s));
122 /* Scalar type mapping ********************************************************/
124 /* Functions that convert scalar/primitive values (numbers, strings, bool)
125 * between Lua and C/upb. Handles type/range checking. */
127 bool lupb_checkbool(lua_State *L, int narg) {
128 if (!lua_isboolean(L, narg)) {
129 luaL_error(L, "must be true or false");
131 return lua_toboolean(L, narg);
134 /* Unlike luaL_checkstring(), this does not allow implicit conversion to
136 const char *lupb_checkstring(lua_State *L, int narg, size_t *len) {
137 if (lua_type(L, narg) != LUA_TSTRING) {
138 luaL_error(L, "Expected string");
141 return lua_tolstring(L, narg, len);
144 /* Unlike luaL_checkinteger, these do not implicitly convert from string or
145 * round an existing double value. We allow floating-point input, but only if
146 * the actual value is integral. */
147 #define INTCHECK(type, ctype) \
148 ctype lupb_check##type(lua_State *L, int narg) { \
151 if (lua_isinteger(L, narg)) { \
152 return lua_tointeger(L, narg); \
155 /* Prevent implicit conversion from string. */ \
156 luaL_checktype(L, narg, LUA_TNUMBER); \
157 n = lua_tonumber(L, narg); \
160 if ((double)i != n) { \
161 /* double -> ctype truncated or rounded. */ \
162 luaL_error(L, "number %f was not an integer or out of range for " #type, \
167 void lupb_push##type(lua_State *L, ctype val) { \
168 /* TODO: push integer for Lua >= 5.3, 64-bit cdata for LuaJIT. */ \
169 /* This is lossy for some [u]int64 values, which isn't great, but */ \
170 /* crashing when we encounter these values seems worse. */ \
171 lua_pushnumber(L, val); \
174 INTCHECK(int64, int64_t)
175 INTCHECK(int32, int32_t)
176 INTCHECK(uint64, uint64_t)
177 INTCHECK(uint32, uint32_t)
179 double lupb_checkdouble(lua_State *L, int narg) {
180 /* If we were being really hard-nosed here, we'd check whether the input was
181 * an integer that has no precise double representation. But doubles aren't
182 * generally expected to be exact like integers are, and worse this could
183 * cause data-dependent runtime errors: one run of the program could work fine
184 * because the integer calculations happened to be exactly representable in
185 * double, while the next could crash because of subtly different input. */
187 luaL_checktype(L, narg, LUA_TNUMBER); /* lua_tonumber() auto-converts. */
188 return lua_tonumber(L, narg);
191 float lupb_checkfloat(lua_State *L, int narg) {
192 /* We don't worry about checking whether the input can be exactly converted to
193 * float -- see above. */
195 luaL_checktype(L, narg, LUA_TNUMBER); /* lua_tonumber() auto-converts. */
196 return lua_tonumber(L, narg);
199 void lupb_pushdouble(lua_State *L, double d) {
200 lua_pushnumber(L, d);
203 void lupb_pushfloat(lua_State *L, float d) {
204 lua_pushnumber(L, d);
208 static const struct luaL_Reg lupb_toplevel_m[] = {
212 void lupb_register_type(lua_State *L, const char *name, const luaL_Reg *m,
213 const luaL_Reg *mm) {
214 luaL_newmetatable(L, name);
217 lupb_setfuncs(L, mm);
221 /* Methods go in the mt's __index method. This implies that you can'
222 * implement __index and also have methods. */
223 lua_getfield(L, -1, "__index");
224 lupb_assert(L, lua_isnil(L, -1));
227 lua_createtable(L, 0, 0);
229 lua_setfield(L, -2, "__index");
232 lua_pop(L, 1); /* The mt. */
235 int luaopen_upb_c(lua_State *L) {
236 static char module_key;
237 if (lupb_openlib(L, &module_key, "upb_c", lupb_toplevel_m)) {
241 lupb_def_registertypes(L);
242 lupb_msg_registertypes(L);
244 return 1; /* Return package table. */