# HG changeset patch # User jbe # Date 1406905919 -7200 # Node ID a8316439035518b6ad75438a09d76bd85af1df41 # Parent ce208edffcc9b12e3cadfb46bfa3ce59b2dbe091 Allow json.object and json.array functions to convert any Lua value using __pairs and __ipairs metamethods diff -r ce208edffcc9 -r a83164390355 libraries/json/json.c --- a/libraries/json/json.c Fri Aug 01 16:40:10 2014 +0200 +++ b/libraries/json/json.c Fri Aug 01 17:11:59 2014 +0200 @@ -45,6 +45,8 @@ #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 // converts a Lua table to a JSON object or JSON array: // (does never modify the argument, returns an empty object or array if argument is nil) @@ -112,8 +114,26 @@ } } } else { - // TODO: implement conversion using iterator metamethods - return luaL_error(L, "Using %s metamethod not implemented yet", array ? "__ipairs" : "__pairs"); + // 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, 1); + lua_call(L, 1, 3); + while (1) { + lua_pushvalue(L, json_convert_iterfun_idx); + lua_pushvalue(L, json_convert_itertbl_idx); + lua_pushvalue(L, -3); + lua_remove(L, -4); + lua_call(L, 2, 2); + if (lua_isnil(L, -2)) break; + if (lua_type(L, -2) == (array ? LUA_TNUMBER : LUA_TSTRING)) { + lua_pushvalue(L, -2); + lua_pushvalue(L, -2); + lua_rawset(L, json_convert_shadow_idx); + } + lua_pop(L, 1); + } } // let result table be on top of stack: lua_settop(L, json_convert_output_idx); @@ -740,6 +760,8 @@ // returns a triple such that 'for key, value in pairs(obj) do ... end' // iterates through all key value pairs (including JSON null keys represented as Lua nil): static int json_pairs(lua_State *L) { + // require one argument to function + luaL_checkany(L, 1); // return triple of function json_pairs_iterfunc, first argument, and nil: lua_pushcfunction(L, json_pairs_iterfunc); lua_pushvalue(L, 1); @@ -775,6 +797,8 @@ // returns a triple such that 'for idx, value in ipairs(ary) do ... end' // iterates through all values (including JSON null represented as Lua nil): static int json_ipairs(lua_State *L) { + // require one argument to function + luaL_checkany(L, 1); // return triple of function json_ipairs_iterfunc, first argument, and zero: lua_pushcfunction(L, json_ipairs_iterfunc); lua_pushvalue(L, 1);