# HG changeset patch # User jbe # Date 1406567072 -7200 # Node ID f490b78827d6f53b476fa642e2af46bafebb6fa1 # Parent 3cf5fcf2bd5f4376d95dbe1df0ba023199f95c44 More documentation in JSON library; Implement json.isnull(...) through json.type(...) == "null" diff -r 3cf5fcf2bd5f -r f490b78827d6 libraries/json/json.c --- a/libraries/json/json.c Mon Jul 28 17:16:34 2014 +0200 +++ b/libraries/json/json.c Mon Jul 28 19:04:32 2014 +0200 @@ -3,12 +3,13 @@ #include #include -#define JSON_UPVAL_NULLMARK lua_upvalueindex(1) -#define JSON_UPVAL_SHADOWTBL lua_upvalueindex(2) -#define JSON_UPVAL_TYPES lua_upvalueindex(3) -#define JSON_UPVAL_METATABLE lua_upvalueindex(4) -#define JSON_UPVAL_PAIRS_ITERFUNC lua_upvalueindex(5) -#define JSON_UPVAL_IPAIRS_ITERFUNC lua_upvalueindex(6) +#define JSON_UPVAL_LIBRARY lua_upvalueindex(1) +#define JSON_UPVAL_NULLMARK lua_upvalueindex(2) +#define JSON_UPVAL_SHADOWTBL lua_upvalueindex(3) +#define JSON_UPVAL_TYPES lua_upvalueindex(4) +#define JSON_UPVAL_METATABLE lua_upvalueindex(5) +#define JSON_UPVAL_PAIRS_ITERFUNC lua_upvalueindex(6) +#define JSON_UPVAL_IPAIRS_ITERFUNC lua_upvalueindex(7) // marks a table as JSON object or JSON array: // (returns its modified argument or a new table if argument is nil) @@ -347,68 +348,93 @@ return 2; } -#define JSON_PATH_GET 1 -#define JSON_PATH_TYPE 2 -#define JSON_PATH_ISNULL 3 - -// gets a value, its type, or information -static int json_path(lua_State *L, int mode) { +// gets a value or its type from a JSON document (first argument) +// optionally using a path (variable number of keys after first argument): +static int json_path(lua_State *L, int type_mode) { int argc; int idx = 2; + // store number of arguments: argc = lua_gettop(L); + // follow path, starting with first argument as "current value": lua_pushvalue(L, 1); + // process each "path key": while (idx <= argc) { - if (lua_isnil(L, -1)) { - if (mode == JSON_PATH_ISNULL) lua_pushboolean(L, 0); - return 1; - } + // if "current value" is nil, then the path cannot be walked and nil is returned: + if (lua_isnil(L, -1)) return 1; + // try to get shadow table of "current value": lua_pushvalue(L, -1); lua_rawget(L, JSON_UPVAL_SHADOWTBL); if (lua_isnil(L, -1)) { + // if no shadow table is found, + // drop nil from stack: lua_pop(L, 1); if (lua_type(L, -1) == LUA_TTABLE) { + // if "current value" is a table, + // get "next value" using the "path key": lua_pushvalue(L, idx++); lua_gettable(L, -2); } else { + // if "current value" is not a table, + // then the path cannot be walked and nil is returned: lua_pushnil(L); + return 1; } } else { + // if a shadow table is found, + // set "current value" to its shadow table: lua_replace(L, -2); + // get "next value" using the "path key": lua_pushvalue(L, idx++); lua_rawget(L, -2); } + // the "next value" replaces the "current value": lua_replace(L, -2); } - switch (mode) { - case JSON_PATH_GET: + if (!type_mode) { + // if a value (and not its type) was requested, + // check if value is the null-marker, and store nil on top of Lua stack in that case: if (lua_rawequal(L, -1, JSON_UPVAL_NULLMARK)) lua_pushnil(L); - return 1; - case JSON_PATH_TYPE: + } else { + // if the type was requested, + // check if value is the null-marker: if (lua_rawequal(L, -1, JSON_UPVAL_NULLMARK)) { + // if yes, store string "null" on top of Lua stack: lua_pushliteral(L, "null"); - return 1; + } else { + // otherwise, + // try to read type ("object" or "array") from internal type table: + lua_pushvalue(L, -1); + lua_rawget(L, JSON_UPVAL_TYPES); + // if no entry is found in the internal type table, get the Lua type: + if (lua_isnil(L, -1)) lua_pushstring(L, lua_typename(L, lua_type(L, -2))); } - lua_pushvalue(L, -1); - lua_rawget(L, JSON_UPVAL_TYPES); - if (lua_isnil(L, -1)) lua_pushstring(L, lua_typename(L, lua_type(L, -2))); - return 1; - case JSON_PATH_ISNULL: - lua_pushboolean(L, lua_rawequal(L, -1, JSON_UPVAL_NULLMARK)); - return 1; } - return 0; + // return the top most value on the Lua stack: + return 1; } +// gets a value from a JSON document (first argument) +// optionally using a path (variable number of keys after first argument): static int json_get(lua_State *L) { - return json_path(L, JSON_PATH_GET); + return json_path(L, 0); } +// gets a value's type from a JSON document (first argument) +// optionally using a path (variable number of keys after first argument): static int json_type(lua_State *L) { - return json_path(L, JSON_PATH_TYPE); + return json_path(L, 1); } +// checks if a value in a JSON document (first argument) is null: static int json_isnull(lua_State *L) { - return json_path(L, JSON_PATH_ISNULL); + const char *jsontype; + lua_getfield(L, JSON_UPVAL_LIBRARY, "type"); + lua_insert(L, 1); + lua_call(L, lua_gettop(L) - 1, 1); + jsontype = lua_tostring(L, -1); + if (jsontype && !strcmp(jsontype, "null")) lua_pushboolean(L, 1); + else lua_pushboolean(L, 0); + return 1; } static int json_setnull(lua_State *L) { @@ -524,37 +550,41 @@ int luaopen_json(lua_State *L) { lua_settop(L, 0); - lua_newtable(L); // 1: library table on stack position - lua_newtable(L); // 2: table used as JSON NULL value in internal shadow tables - lua_newtable(L); // 3: ephemeron table to store shadow tables for each JSON object/array to allow NULL values returned as nil - lua_newtable(L); // 4: ephemeron table to store the type of the JSON object/array - lua_newtable(L); // 5: metatable for ephemeron tables + lua_newtable(L); // 1: library table on stack position + lua_pushvalue(L, 1); // 2: copy of library table + lua_newtable(L); // 3: table used as JSON NULL value in internal shadow tables + lua_newtable(L); // 4: ephemeron table to store shadow tables for each JSON object/array to allow NULL values returned as nil + lua_newtable(L); // 5: ephemeron table to store the type of the JSON object/array + lua_newtable(L); // 6: metatable for ephemeron tables lua_pushliteral(L, "__mode"); lua_pushliteral(L, "k"); - lua_rawset(L, 5); - lua_pushvalue(L, 5); // 6: cloned metatable reference - lua_setmetatable(L, 3); + lua_rawset(L, 6); + lua_pushvalue(L, 6); // 7: cloned metatable reference lua_setmetatable(L, 4); - lua_newtable(L); // 5: metatable for JSON objects and JSON arrays + lua_setmetatable(L, 5); + lua_newtable(L); // 6: metatable for JSON objects and JSON arrays lua_pushvalue(L, 2); lua_pushvalue(L, 3); lua_pushvalue(L, 4); lua_pushvalue(L, 5); - lua_pushcclosure(L, json_pairs_iterfunc, 4); // 6: iteration function for pairs + lua_pushvalue(L, 6); + lua_pushcclosure(L, json_pairs_iterfunc, 5); // 7: iteration function for pairs lua_pushvalue(L, 2); lua_pushvalue(L, 3); lua_pushvalue(L, 4); lua_pushvalue(L, 5); - lua_pushcclosure(L, json_ipairs_iterfunc, 4); // 7: iteration function for ipairs - lua_pushvalue(L, 5); + lua_pushvalue(L, 6); + lua_pushcclosure(L, json_ipairs_iterfunc, 5); // 8: iteration function for ipairs + lua_pushvalue(L, 6); lua_pushvalue(L, 2); lua_pushvalue(L, 3); lua_pushvalue(L, 4); lua_pushvalue(L, 5); lua_pushvalue(L, 6); lua_pushvalue(L, 7); - luaL_setfuncs(L, json_metatable_functions, 6); + lua_pushvalue(L, 8); + luaL_setfuncs(L, json_metatable_functions, 7); lua_setfield(L, 1, "metatable"); - luaL_setfuncs(L, json_module_functions, 6); + luaL_setfuncs(L, json_module_functions, 7); return 1; }