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:

Impressum / About Us