# HG changeset patch # User jbe # Date 1406862741 -7200 # Node ID 681367a16657f9492ea43466dab1c8cf1f105054 # Parent e618ccd017a3217b343b332076fa228fd8c71eed json.array and json.object functions create a new container rather than marking a table diff -r e618ccd017a3 -r 681367a16657 libraries/json/json.c --- a/libraries/json/json.c Fri Aug 01 02:48:18 2014 +0200 +++ b/libraries/json/json.c Fri Aug 01 05:12:21 2014 +0200 @@ -41,63 +41,67 @@ return 1; } -// marks a Lua table as JSON object or JSON array: -// (returns its modified argument or a new table if argument is nil) -static int json_mark(lua_State *L, JSON_REGPOINTER mt) { - // check if argument is nil - if (lua_isnoneornil(L, 1)) { - // create new table at stack position 1: - lua_settop(L, 0); - lua_newtable(L); - // create shadow table (leaving previously created table on stack position 1): - json_regfetch(L, shadowtbl); - lua_pushvalue(L, 1); - lua_newtable(L); - lua_rawset(L, -3); - } else { - // require argument to be a table: - luaL_checktype(L, 1, LUA_TTABLE); - // push shadow table on top of stack: +#define json_convert_source_idx 1 +#define json_convert_iterator_idx 2 +#define json_convert_output_idx 3 +#define json_convert_shadow_idx 4 + +// converts a Lua table to a JSON object or JSON array: +// (does never modify the argument, returns an empty object or array if argument is nil) +static int json_convert(lua_State *L, int array) { + lua_settop(L, 1); + if (lua_isnoneornil(L, json_convert_source_idx)) { json_regfetch(L, shadowtbl); - lua_pushvalue(L, 1); - lua_rawget(L, -2); - // if shadow table does not exist: - if (lua_isnil(L, -1)) { - // create shadow table and leave it on top of stack: - lua_newtable(L); - lua_pushvalue(L, 1); - lua_pushvalue(L, -2); - lua_rawset(L, -5); + lua_newtable(L); + lua_pushvalue(L, -1); + lua_newtable(L); + lua_rawset(L, -4); + } else { + // push iterator function on stack position 2 if existent, + // else push null for normal tables: + if (lua_getmetatable(L, json_convert_source_idx)) { + lua_getfield(L, -1, array ? "__ipairs" : "__pairs"); + if (lua_isnil(L, -1)) luaL_checktype(L, 1, LUA_TTABLE); + else if (lua_type(L, -1) != LUA_TFUNCTION) + return luaL_error(L, "%s metamethod is not a function", array ? "__ipairs" : "__pairs"); + lua_replace(L, -2); + } else { + lua_pushnil(L); } - // move elements from original table to shadow table (that's expected on top of stack): - for(lua_pushnil(L); lua_next(L, 1); lua_pop(L, 1)) { - lua_pushvalue(L, -2); - lua_pushnil(L); - lua_rawset(L, 1); - lua_pushvalue(L, -2); - lua_pushvalue(L, -2); - lua_rawset(L, -5); + // create table on stack position 3: + lua_newtable(L); + // create shadow table on stack position 4: + json_regfetch(L, shadowtbl); + lua_newtable(L); + lua_pushvalue(L, json_convert_output_idx); + lua_pushvalue(L, -2); + lua_rawset(L, -4); + lua_replace(L, -2); + if (lua_isnil(L, json_convert_iterator_idx)) { + for (lua_pushnil(L); lua_next(L, json_convert_source_idx); lua_pop(L, 1)) { + lua_pushvalue(L, -2); + lua_pushvalue(L, -2); + lua_rawset(L, json_convert_shadow_idx); + } + } else { + return luaL_error(L, "Using %s metamethod not implemented yet", array ? "__ipairs" : "__pairs"); } + lua_settop(L, json_convert_output_idx); } - // discard everything but table to return: - lua_settop(L, 1); // set metatable: - json_regfetchpointer(L, mt); - lua_setmetatable(L, 1); + if (array) json_regfetch(L, arraymt); + else json_regfetch(L, objectmt); + lua_setmetatable(L, -2); // return table: return 1; } -// marks a table as JSON object: -// (returns its modified argument or a new table if argument is nil) static int json_object(lua_State *L) { - return json_mark(L, json_regpointer(objectmt)); + return json_convert(L, 0); } -// marks a table as JSON array: -// (returns its modified argument or a new table if argument is nil) static int json_array(lua_State *L) { - return json_mark(L, json_regpointer(arraymt)); + return json_convert(L, 1); } // internal states of JSON parser: