webmcp

changeset 137:f490b78827d6

More documentation in JSON library; Implement json.isnull(...) through json.type(...) == "null"
author jbe
date Mon Jul 28 19:04:32 2014 +0200 (2014-07-28)
parents 3cf5fcf2bd5f
children 8a533f370038
files libraries/json/json.c
line diff
     1.1 --- a/libraries/json/json.c	Mon Jul 28 17:16:34 2014 +0200
     1.2 +++ b/libraries/json/json.c	Mon Jul 28 19:04:32 2014 +0200
     1.3 @@ -3,12 +3,13 @@
     1.4  #include <stdlib.h>
     1.5  #include <string.h>
     1.6  
     1.7 -#define JSON_UPVAL_NULLMARK  lua_upvalueindex(1)
     1.8 -#define JSON_UPVAL_SHADOWTBL lua_upvalueindex(2)
     1.9 -#define JSON_UPVAL_TYPES     lua_upvalueindex(3)
    1.10 -#define JSON_UPVAL_METATABLE lua_upvalueindex(4)
    1.11 -#define JSON_UPVAL_PAIRS_ITERFUNC  lua_upvalueindex(5)
    1.12 -#define JSON_UPVAL_IPAIRS_ITERFUNC lua_upvalueindex(6)
    1.13 +#define JSON_UPVAL_LIBRARY   lua_upvalueindex(1)
    1.14 +#define JSON_UPVAL_NULLMARK  lua_upvalueindex(2)
    1.15 +#define JSON_UPVAL_SHADOWTBL lua_upvalueindex(3)
    1.16 +#define JSON_UPVAL_TYPES     lua_upvalueindex(4)
    1.17 +#define JSON_UPVAL_METATABLE lua_upvalueindex(5)
    1.18 +#define JSON_UPVAL_PAIRS_ITERFUNC  lua_upvalueindex(6)
    1.19 +#define JSON_UPVAL_IPAIRS_ITERFUNC lua_upvalueindex(7)
    1.20  
    1.21  // marks a table as JSON object or JSON array:
    1.22  // (returns its modified argument or a new table if argument is nil)
    1.23 @@ -347,68 +348,93 @@
    1.24    return 2;
    1.25  }
    1.26  
    1.27 -#define JSON_PATH_GET 1
    1.28 -#define JSON_PATH_TYPE 2
    1.29 -#define JSON_PATH_ISNULL 3
    1.30 -
    1.31 -// gets a value, its type, or information 
    1.32 -static int json_path(lua_State *L, int mode) {
    1.33 +// gets a value or its type from a JSON document (first argument)
    1.34 +// optionally using a path (variable number of keys after first argument):
    1.35 +static int json_path(lua_State *L, int type_mode) {
    1.36    int argc;
    1.37    int idx = 2;
    1.38 +  // store number of arguments:
    1.39    argc = lua_gettop(L);
    1.40 +  // follow path, starting with first argument as "current value":
    1.41    lua_pushvalue(L, 1);
    1.42 +  // process each "path key":
    1.43    while (idx <= argc) {
    1.44 -    if (lua_isnil(L, -1)) {
    1.45 -      if (mode == JSON_PATH_ISNULL) lua_pushboolean(L, 0);
    1.46 -      return 1;
    1.47 -    }
    1.48 +    // if "current value" is nil, then the path cannot be walked and nil is returned:
    1.49 +    if (lua_isnil(L, -1)) return 1;
    1.50 +    // try to get shadow table of "current value":
    1.51      lua_pushvalue(L, -1);
    1.52      lua_rawget(L, JSON_UPVAL_SHADOWTBL);
    1.53      if (lua_isnil(L, -1)) {
    1.54 +      // if no shadow table is found,
    1.55 +      // drop nil from stack:
    1.56        lua_pop(L, 1);
    1.57        if (lua_type(L, -1) == LUA_TTABLE) {
    1.58 +        // if "current value" is a table,
    1.59 +        // get "next value" using the "path key":
    1.60          lua_pushvalue(L, idx++);
    1.61          lua_gettable(L, -2);
    1.62        } else {
    1.63 +        // if "current value" is not a table,
    1.64 +        // then the path cannot be walked and nil is returned:
    1.65          lua_pushnil(L);
    1.66 +        return 1;
    1.67        }
    1.68      } else {
    1.69 +      // if a shadow table is found,
    1.70 +      // set "current value" to its shadow table:
    1.71        lua_replace(L, -2);
    1.72 +      // get "next value" using the "path key":
    1.73        lua_pushvalue(L, idx++);
    1.74        lua_rawget(L, -2);
    1.75      }
    1.76 +    // the "next value" replaces the "current value":
    1.77      lua_replace(L, -2);
    1.78    }
    1.79 -  switch (mode) {
    1.80 -  case JSON_PATH_GET:
    1.81 +  if (!type_mode) {
    1.82 +    // if a value (and not its type) was requested,
    1.83 +    // check if value is the null-marker, and store nil on top of Lua stack in that case:
    1.84      if (lua_rawequal(L, -1, JSON_UPVAL_NULLMARK)) lua_pushnil(L);
    1.85 -    return 1;
    1.86 -  case JSON_PATH_TYPE:
    1.87 +  } else {
    1.88 +    // if the type was requested,
    1.89 +    // check if value is the null-marker:
    1.90      if (lua_rawequal(L, -1, JSON_UPVAL_NULLMARK)) {
    1.91 +      // if yes, store string "null" on top of Lua stack:
    1.92        lua_pushliteral(L, "null");
    1.93 -      return 1;
    1.94 +    } else {
    1.95 +      // otherwise,
    1.96 +      // try to read type ("object" or "array") from internal type table:
    1.97 +      lua_pushvalue(L, -1);
    1.98 +      lua_rawget(L, JSON_UPVAL_TYPES);
    1.99 +      // if no entry is found in the internal type table, get the Lua type:
   1.100 +      if (lua_isnil(L, -1)) lua_pushstring(L, lua_typename(L, lua_type(L, -2)));
   1.101      }
   1.102 -    lua_pushvalue(L, -1);
   1.103 -    lua_rawget(L, JSON_UPVAL_TYPES);
   1.104 -    if (lua_isnil(L, -1)) lua_pushstring(L, lua_typename(L, lua_type(L, -2)));
   1.105 -    return 1;
   1.106 -  case JSON_PATH_ISNULL:
   1.107 -    lua_pushboolean(L, lua_rawequal(L, -1, JSON_UPVAL_NULLMARK));
   1.108 -    return 1;
   1.109    }
   1.110 -  return 0;
   1.111 +  // return the top most value on the Lua stack:
   1.112 +  return 1;
   1.113  }
   1.114  
   1.115 +// gets a value from a JSON document (first argument)
   1.116 +// optionally using a path (variable number of keys after first argument):
   1.117  static int json_get(lua_State *L) {
   1.118 -  return json_path(L, JSON_PATH_GET);
   1.119 +  return json_path(L, 0);
   1.120  }
   1.121  
   1.122 +// gets a value's type from a JSON document (first argument)
   1.123 +// optionally using a path (variable number of keys after first argument):
   1.124  static int json_type(lua_State *L) {
   1.125 -  return json_path(L, JSON_PATH_TYPE);
   1.126 +  return json_path(L, 1);
   1.127  }
   1.128  
   1.129 +// checks if a value in a JSON document (first argument) is null:
   1.130  static int json_isnull(lua_State *L) {
   1.131 -  return json_path(L, JSON_PATH_ISNULL);
   1.132 +  const char *jsontype;
   1.133 +  lua_getfield(L, JSON_UPVAL_LIBRARY, "type");
   1.134 +  lua_insert(L, 1);
   1.135 +  lua_call(L, lua_gettop(L) - 1, 1);
   1.136 +  jsontype = lua_tostring(L, -1);
   1.137 +  if (jsontype && !strcmp(jsontype, "null")) lua_pushboolean(L, 1);
   1.138 +  else lua_pushboolean(L, 0);
   1.139 +  return 1;
   1.140  }
   1.141  
   1.142  static int json_setnull(lua_State *L) {
   1.143 @@ -524,37 +550,41 @@
   1.144  
   1.145  int luaopen_json(lua_State *L) {
   1.146    lua_settop(L, 0);
   1.147 -  lua_newtable(L);  // 1: library table on stack position
   1.148 -  lua_newtable(L);  // 2: table used as JSON NULL value in internal shadow tables
   1.149 -  lua_newtable(L);  // 3: ephemeron table to store shadow tables for each JSON object/array to allow NULL values returned as nil
   1.150 -  lua_newtable(L);  // 4: ephemeron table to store the type of the JSON object/array
   1.151 -  lua_newtable(L);  // 5: metatable for ephemeron tables
   1.152 +  lua_newtable(L);      // 1: library table on stack position
   1.153 +  lua_pushvalue(L, 1);  // 2: copy of library table
   1.154 +  lua_newtable(L);      // 3: table used as JSON NULL value in internal shadow tables
   1.155 +  lua_newtable(L);      // 4: ephemeron table to store shadow tables for each JSON object/array to allow NULL values returned as nil
   1.156 +  lua_newtable(L);      // 5: ephemeron table to store the type of the JSON object/array
   1.157 +  lua_newtable(L);      // 6: metatable for ephemeron tables
   1.158    lua_pushliteral(L, "__mode");
   1.159    lua_pushliteral(L, "k");
   1.160 -  lua_rawset(L, 5);
   1.161 -  lua_pushvalue(L, 5);  // 6: cloned metatable reference
   1.162 -  lua_setmetatable(L, 3);
   1.163 +  lua_rawset(L, 6);
   1.164 +  lua_pushvalue(L, 6);  // 7: cloned metatable reference
   1.165    lua_setmetatable(L, 4);
   1.166 -  lua_newtable(L);  // 5: metatable for JSON objects and JSON arrays
   1.167 +  lua_setmetatable(L, 5);
   1.168 +  lua_newtable(L);      // 6: metatable for JSON objects and JSON arrays
   1.169    lua_pushvalue(L, 2);
   1.170    lua_pushvalue(L, 3);
   1.171    lua_pushvalue(L, 4);
   1.172    lua_pushvalue(L, 5);
   1.173 -  lua_pushcclosure(L, json_pairs_iterfunc, 4);  // 6: iteration function for pairs
   1.174 +  lua_pushvalue(L, 6);
   1.175 +  lua_pushcclosure(L, json_pairs_iterfunc, 5);  // 7: iteration function for pairs
   1.176    lua_pushvalue(L, 2);
   1.177    lua_pushvalue(L, 3);
   1.178    lua_pushvalue(L, 4);
   1.179    lua_pushvalue(L, 5);
   1.180 -  lua_pushcclosure(L, json_ipairs_iterfunc, 4);  // 7: iteration function for ipairs
   1.181 -  lua_pushvalue(L, 5);
   1.182 +  lua_pushvalue(L, 6);
   1.183 +  lua_pushcclosure(L, json_ipairs_iterfunc, 5);  // 8: iteration function for ipairs
   1.184 +  lua_pushvalue(L, 6);
   1.185    lua_pushvalue(L, 2);
   1.186    lua_pushvalue(L, 3);
   1.187    lua_pushvalue(L, 4);
   1.188    lua_pushvalue(L, 5);
   1.189    lua_pushvalue(L, 6);
   1.190    lua_pushvalue(L, 7);
   1.191 -  luaL_setfuncs(L, json_metatable_functions, 6);
   1.192 +  lua_pushvalue(L, 8);
   1.193 +  luaL_setfuncs(L, json_metatable_functions, 7);
   1.194    lua_setfield(L, 1, "metatable");
   1.195 -  luaL_setfuncs(L, json_module_functions, 6);
   1.196 +  luaL_setfuncs(L, json_module_functions, 7);
   1.197    return 1;
   1.198  }

Impressum / About Us