# HG changeset patch # User jbe # Date 1408989601 -7200 # Node ID eceb6f56e9ed85d5c35c6ba0e85812feabaa6475 # Parent 1a10fef86d97d6d5550bc81e225987df2fd51780 Use luaL_len and lua_gettable to read argument passed to json.array{...} diff -r 1a10fef86d97 -r eceb6f56e9ed libraries/json/json.c --- a/libraries/json/json.c Thu Aug 14 05:18:20 2014 +0200 +++ b/libraries/json/json.c Mon Aug 25 20:00:01 2014 +0200 @@ -48,19 +48,18 @@ return 1; } -#define json_convert_source_idx 1 -#define json_convert_iterator_idx 2 -#define json_convert_output_idx 3 -#define json_convert_shadow_idx 4 -#define json_convert_iterfun_idx 5 -#define json_convert_itertbl_idx 6 +#define json_object_source_idx 1 +#define json_object_iterator_idx 2 +#define json_object_output_idx 3 +#define json_object_shadow_idx 4 +#define json_object_iterfun_idx 5 +#define json_object_itertbl_idx 6 -// converts a Lua table (or any other iterable value) to a JSON object or JSON array: +// converts a Lua table (or any other iterable value) to a JSON object: // (does never modify the argument, returns an empty object or array if argument is nil) -static int json_convert(lua_State *L, int array) { - int arrayidx = 0; +static int json_object(lua_State *L) { // determine is argument is given: - if (lua_isnoneornil(L, json_convert_source_idx)) { + if (lua_isnoneornil(L, json_object_source_idx)) { // if no argument is given (or if argument is nil), // create proxy table with shadow table, and leave proxy table on top of stack: json_createproxy(L); @@ -71,15 +70,15 @@ // stack shall contain only one function argument: lua_settop(L, 1); // check if there is an iterator function in its metatable: - if (luaL_getmetafield(L, json_convert_source_idx, array ? "__ipairs" : "__pairs")) { + if (luaL_getmetafield(L, json_object_source_idx, "__pairs")) { // if there is an iterator function, // leave it on stack position 2 and verify its type: - if (lua_type(L, json_convert_iterator_idx) != LUA_TFUNCTION) - return luaL_error(L, "%s metamethod is not a function", array ? "__ipairs" : "__pairs"); + if (lua_type(L, json_object_iterator_idx) != LUA_TFUNCTION) + return luaL_error(L, "__pairs metamethod is not a function"); } else { // if there is no iterator function, // verify the type of the argument itself: - luaL_checktype(L, json_convert_source_idx, LUA_TTABLE); + luaL_checktype(L, json_object_source_idx, LUA_TTABLE); // push nil onto stack position 2: lua_pushnil(L); } @@ -90,58 +89,36 @@ lua_pushvalue(L, -1); json_setshadow(L, -3); // check if iterator function exists: - if (lua_isnil(L, json_convert_iterator_idx)) { + if (lua_isnil(L, json_object_iterator_idx)) { // if there is no iterator function, - // distinguish between objects and arrays: - if (array == 0) { - // for an object, copy all string key value pairs to shadow table: - for (lua_pushnil(L); lua_next(L, json_convert_source_idx); lua_pop(L, 1)) { - if (lua_type(L, -2) == LUA_TSTRING) { - lua_pushvalue(L, -2); - lua_pushvalue(L, -2); - lua_rawset(L, json_convert_shadow_idx); - } - } - } else { - // for an array, copy consecutive integer value pairs to shadow table: - while (1) { - // throw error if array would exceed INT_MAX elements: - // TODO: Lua 5.3 may support more elements - if (arrayidx == INT_MAX) { - lua_pushnumber(L, (size_t)INT_MAX+1); - lua_rawget(L, json_convert_source_idx); - if (lua_isnil(L, -1)) break; - return luaL_error(L, "Array exceeded length of %d elements", INT_MAX); - } - // get next array entry: - arrayidx++; - lua_rawgeti(L, json_convert_source_idx, arrayidx); - // break if value is nil: - if (lua_isnil(L, -1)) break; - // store value in shadow table: - lua_rawseti(L, json_convert_shadow_idx, arrayidx); + // copy all string key value pairs to shadow table: + for (lua_pushnil(L); lua_next(L, json_object_source_idx); lua_pop(L, 1)) { + if (lua_type(L, -2) == LUA_TSTRING) { + lua_pushvalue(L, -2); + lua_pushvalue(L, -2); + lua_rawset(L, json_object_shadow_idx); } } } else { // if there is an iterator function, // call iterator function with source value (first argument) // and store 3 result values on stack positions 5 through 7: - lua_pushvalue(L, json_convert_iterator_idx); + lua_pushvalue(L, json_object_iterator_idx); lua_pushvalue(L, 1); lua_call(L, 1, 3); // iterate through key value pairs and store some of them in shadow table // while replacing nil values with null-marker: while (1) { // call iterfun function: - lua_pushvalue(L, json_convert_iterfun_idx); - lua_pushvalue(L, json_convert_itertbl_idx); + lua_pushvalue(L, json_object_iterfun_idx); + lua_pushvalue(L, json_object_itertbl_idx); lua_pushvalue(L, -3); lua_remove(L, -4); lua_call(L, 2, 2); // break iteration loop if key is nil: if (lua_isnil(L, -2)) break; // store key value pair only if key type is correct: - if (lua_type(L, -2) == (array ? LUA_TNUMBER : LUA_TSTRING)) { + if (lua_type(L, -2) == LUA_TSTRING) { // if key type is correct, // push key onto stack: lua_pushvalue(L, -2); @@ -150,33 +127,73 @@ // else push value onto stack: else lua_pushvalue(L, -2); // set key value pair in shadow table: - lua_rawset(L, json_convert_shadow_idx); + lua_rawset(L, json_object_shadow_idx); } // pop value from stack, but leave key on stack: lua_pop(L, 1); } } // let result table be on top of stack: - lua_settop(L, json_convert_output_idx); + lua_settop(L, json_object_output_idx); } // set metatable (for result table on top of stack): - if (array == 0) json_regfetch(L, objectmt); - else json_regfetch(L, arraymt); + json_regfetch(L, objectmt); lua_setmetatable(L, -2); // return table on top of stack: return 1; } -// converts a Lua table (or any other iterable value) to a JSON object: -// (does never modify the argument, returns an empty object or array if argument is nil) -static int json_object(lua_State *L) { - return json_convert(L, 0); -} +#define json_array_source_idx 1 +#define json_array_output_idx 2 +#define json_array_shadow_idx 3 // converts a Lua table (or any other iterable value) to a JSON array: // (does never modify the argument, returns an empty object or array if argument is nil) static int json_array(lua_State *L) { - return json_convert(L, 1); + // determine is argument is given: + if (lua_isnoneornil(L, json_array_source_idx)) { + // if no argument is given (or if argument is nil), + // create proxy table with shadow table, and leave proxy table on top of stack: + json_createproxy(L); + lua_newtable(L); + json_setshadow(L, -2); + } else { + lua_Integer arrayidx, arraylen; + // if an argument was given, + // stack shall contain only one function argument: + lua_settop(L, 1); + // create result table on stack position 2: + json_createproxy(L); + // create shadow table on stack position 3: + lua_newtable(L); + lua_pushvalue(L, -1); + json_setshadow(L, -3); + // determine length of array: + arraylen = luaL_len(L, json_array_source_idx); + // for an array, copy consecutive integer value pairs to shadow table: + for (arrayidx=0; arrayidx