webmcp
changeset 202:eceb6f56e9ed
Use luaL_len and lua_gettable to read argument passed to json.array{...}
author | jbe |
---|---|
date | Mon Aug 25 20:00:01 2014 +0200 (2014-08-25) |
parents | 1a10fef86d97 |
children | c6ef9991b911 |
files | libraries/json/json.c |
line diff
1.1 --- a/libraries/json/json.c Thu Aug 14 05:18:20 2014 +0200 1.2 +++ b/libraries/json/json.c Mon Aug 25 20:00:01 2014 +0200 1.3 @@ -48,19 +48,18 @@ 1.4 return 1; 1.5 } 1.6 1.7 -#define json_convert_source_idx 1 1.8 -#define json_convert_iterator_idx 2 1.9 -#define json_convert_output_idx 3 1.10 -#define json_convert_shadow_idx 4 1.11 -#define json_convert_iterfun_idx 5 1.12 -#define json_convert_itertbl_idx 6 1.13 +#define json_object_source_idx 1 1.14 +#define json_object_iterator_idx 2 1.15 +#define json_object_output_idx 3 1.16 +#define json_object_shadow_idx 4 1.17 +#define json_object_iterfun_idx 5 1.18 +#define json_object_itertbl_idx 6 1.19 1.20 -// converts a Lua table (or any other iterable value) to a JSON object or JSON array: 1.21 +// converts a Lua table (or any other iterable value) to a JSON object: 1.22 // (does never modify the argument, returns an empty object or array if argument is nil) 1.23 -static int json_convert(lua_State *L, int array) { 1.24 - int arrayidx = 0; 1.25 +static int json_object(lua_State *L) { 1.26 // determine is argument is given: 1.27 - if (lua_isnoneornil(L, json_convert_source_idx)) { 1.28 + if (lua_isnoneornil(L, json_object_source_idx)) { 1.29 // if no argument is given (or if argument is nil), 1.30 // create proxy table with shadow table, and leave proxy table on top of stack: 1.31 json_createproxy(L); 1.32 @@ -71,15 +70,15 @@ 1.33 // stack shall contain only one function argument: 1.34 lua_settop(L, 1); 1.35 // check if there is an iterator function in its metatable: 1.36 - if (luaL_getmetafield(L, json_convert_source_idx, array ? "__ipairs" : "__pairs")) { 1.37 + if (luaL_getmetafield(L, json_object_source_idx, "__pairs")) { 1.38 // if there is an iterator function, 1.39 // leave it on stack position 2 and verify its type: 1.40 - if (lua_type(L, json_convert_iterator_idx) != LUA_TFUNCTION) 1.41 - return luaL_error(L, "%s metamethod is not a function", array ? "__ipairs" : "__pairs"); 1.42 + if (lua_type(L, json_object_iterator_idx) != LUA_TFUNCTION) 1.43 + return luaL_error(L, "__pairs metamethod is not a function"); 1.44 } else { 1.45 // if there is no iterator function, 1.46 // verify the type of the argument itself: 1.47 - luaL_checktype(L, json_convert_source_idx, LUA_TTABLE); 1.48 + luaL_checktype(L, json_object_source_idx, LUA_TTABLE); 1.49 // push nil onto stack position 2: 1.50 lua_pushnil(L); 1.51 } 1.52 @@ -90,58 +89,36 @@ 1.53 lua_pushvalue(L, -1); 1.54 json_setshadow(L, -3); 1.55 // check if iterator function exists: 1.56 - if (lua_isnil(L, json_convert_iterator_idx)) { 1.57 + if (lua_isnil(L, json_object_iterator_idx)) { 1.58 // if there is no iterator function, 1.59 - // distinguish between objects and arrays: 1.60 - if (array == 0) { 1.61 - // for an object, copy all string key value pairs to shadow table: 1.62 - for (lua_pushnil(L); lua_next(L, json_convert_source_idx); lua_pop(L, 1)) { 1.63 - if (lua_type(L, -2) == LUA_TSTRING) { 1.64 - lua_pushvalue(L, -2); 1.65 - lua_pushvalue(L, -2); 1.66 - lua_rawset(L, json_convert_shadow_idx); 1.67 - } 1.68 - } 1.69 - } else { 1.70 - // for an array, copy consecutive integer value pairs to shadow table: 1.71 - while (1) { 1.72 - // throw error if array would exceed INT_MAX elements: 1.73 - // TODO: Lua 5.3 may support more elements 1.74 - if (arrayidx == INT_MAX) { 1.75 - lua_pushnumber(L, (size_t)INT_MAX+1); 1.76 - lua_rawget(L, json_convert_source_idx); 1.77 - if (lua_isnil(L, -1)) break; 1.78 - return luaL_error(L, "Array exceeded length of %d elements", INT_MAX); 1.79 - } 1.80 - // get next array entry: 1.81 - arrayidx++; 1.82 - lua_rawgeti(L, json_convert_source_idx, arrayidx); 1.83 - // break if value is nil: 1.84 - if (lua_isnil(L, -1)) break; 1.85 - // store value in shadow table: 1.86 - lua_rawseti(L, json_convert_shadow_idx, arrayidx); 1.87 + // copy all string key value pairs to shadow table: 1.88 + for (lua_pushnil(L); lua_next(L, json_object_source_idx); lua_pop(L, 1)) { 1.89 + if (lua_type(L, -2) == LUA_TSTRING) { 1.90 + lua_pushvalue(L, -2); 1.91 + lua_pushvalue(L, -2); 1.92 + lua_rawset(L, json_object_shadow_idx); 1.93 } 1.94 } 1.95 } else { 1.96 // if there is an iterator function, 1.97 // call iterator function with source value (first argument) 1.98 // and store 3 result values on stack positions 5 through 7: 1.99 - lua_pushvalue(L, json_convert_iterator_idx); 1.100 + lua_pushvalue(L, json_object_iterator_idx); 1.101 lua_pushvalue(L, 1); 1.102 lua_call(L, 1, 3); 1.103 // iterate through key value pairs and store some of them in shadow table 1.104 // while replacing nil values with null-marker: 1.105 while (1) { 1.106 // call iterfun function: 1.107 - lua_pushvalue(L, json_convert_iterfun_idx); 1.108 - lua_pushvalue(L, json_convert_itertbl_idx); 1.109 + lua_pushvalue(L, json_object_iterfun_idx); 1.110 + lua_pushvalue(L, json_object_itertbl_idx); 1.111 lua_pushvalue(L, -3); 1.112 lua_remove(L, -4); 1.113 lua_call(L, 2, 2); 1.114 // break iteration loop if key is nil: 1.115 if (lua_isnil(L, -2)) break; 1.116 // store key value pair only if key type is correct: 1.117 - if (lua_type(L, -2) == (array ? LUA_TNUMBER : LUA_TSTRING)) { 1.118 + if (lua_type(L, -2) == LUA_TSTRING) { 1.119 // if key type is correct, 1.120 // push key onto stack: 1.121 lua_pushvalue(L, -2); 1.122 @@ -150,33 +127,73 @@ 1.123 // else push value onto stack: 1.124 else lua_pushvalue(L, -2); 1.125 // set key value pair in shadow table: 1.126 - lua_rawset(L, json_convert_shadow_idx); 1.127 + lua_rawset(L, json_object_shadow_idx); 1.128 } 1.129 // pop value from stack, but leave key on stack: 1.130 lua_pop(L, 1); 1.131 } 1.132 } 1.133 // let result table be on top of stack: 1.134 - lua_settop(L, json_convert_output_idx); 1.135 + lua_settop(L, json_object_output_idx); 1.136 } 1.137 // set metatable (for result table on top of stack): 1.138 - if (array == 0) json_regfetch(L, objectmt); 1.139 - else json_regfetch(L, arraymt); 1.140 + json_regfetch(L, objectmt); 1.141 lua_setmetatable(L, -2); 1.142 // return table on top of stack: 1.143 return 1; 1.144 } 1.145 1.146 -// converts a Lua table (or any other iterable value) to a JSON object: 1.147 -// (does never modify the argument, returns an empty object or array if argument is nil) 1.148 -static int json_object(lua_State *L) { 1.149 - return json_convert(L, 0); 1.150 -} 1.151 +#define json_array_source_idx 1 1.152 +#define json_array_output_idx 2 1.153 +#define json_array_shadow_idx 3 1.154 1.155 // converts a Lua table (or any other iterable value) to a JSON array: 1.156 // (does never modify the argument, returns an empty object or array if argument is nil) 1.157 static int json_array(lua_State *L) { 1.158 - return json_convert(L, 1); 1.159 + // determine is argument is given: 1.160 + if (lua_isnoneornil(L, json_array_source_idx)) { 1.161 + // if no argument is given (or if argument is nil), 1.162 + // create proxy table with shadow table, and leave proxy table on top of stack: 1.163 + json_createproxy(L); 1.164 + lua_newtable(L); 1.165 + json_setshadow(L, -2); 1.166 + } else { 1.167 + lua_Integer arrayidx, arraylen; 1.168 + // if an argument was given, 1.169 + // stack shall contain only one function argument: 1.170 + lua_settop(L, 1); 1.171 + // create result table on stack position 2: 1.172 + json_createproxy(L); 1.173 + // create shadow table on stack position 3: 1.174 + lua_newtable(L); 1.175 + lua_pushvalue(L, -1); 1.176 + json_setshadow(L, -3); 1.177 + // determine length of array: 1.178 + arraylen = luaL_len(L, json_array_source_idx); 1.179 + // for an array, copy consecutive integer value pairs to shadow table: 1.180 + for (arrayidx=0; arrayidx<arraylen; ) { 1.181 + // increment arrayidx at head of loop: 1.182 + arrayidx++; 1.183 + // get next array entry: 1.184 + lua_pushinteger(L, arrayidx); 1.185 + lua_gettable(L, json_array_source_idx); 1.186 + // check if value is nil: 1.187 + if (lua_isnil(L, -1)) { 1.188 + // if yes, replace it with null-marker: 1.189 + lua_pop(L, 1); 1.190 + json_pushnullmark(L); 1.191 + } 1.192 + // store value in shadow table: 1.193 + lua_rawseti(L, json_array_shadow_idx, arrayidx); 1.194 + } 1.195 + // let result table be on top of stack: 1.196 + lua_settop(L, json_array_output_idx); 1.197 + } 1.198 + // set metatable (for result table on top of stack): 1.199 + json_regfetch(L, arraymt); 1.200 + lua_setmetatable(L, -2); 1.201 + // return table on top of stack: 1.202 + return 1; 1.203 } 1.204 1.205 // internal states of JSON parser: