| rev | line source | 
| jbe@121 | 1 #include <lua.h> | 
| jbe@121 | 2 #include <lauxlib.h> | 
| jbe@122 | 3 #include <stdlib.h> | 
| jbe@121 | 4 #include <string.h> | 
| jbe@121 | 5 | 
| jbe@130 | 6 #define JSON_UPVAL_NULLMARK  lua_upvalueindex(1) | 
| jbe@130 | 7 #define JSON_UPVAL_SHADOWTBL lua_upvalueindex(2) | 
| jbe@130 | 8 #define JSON_UPVAL_TYPES     lua_upvalueindex(3) | 
| jbe@130 | 9 #define JSON_UPVAL_METATABLE lua_upvalueindex(4) | 
| jbe@123 | 10 | 
| jbe@124 | 11 #define JSON_STATE_VALUE 0 | 
| jbe@124 | 12 #define JSON_STATE_OBJECT_KEY 1 | 
| jbe@124 | 13 #define JSON_STATE_OBJECT_KEY_TERMINATOR 2 | 
| jbe@124 | 14 #define JSON_STATE_OBJECT_VALUE 3 | 
| jbe@124 | 15 #define JSON_STATE_OBJECT_SEPARATOR 4 | 
| jbe@124 | 16 #define JSON_STATE_ARRAY_VALUE 5 | 
| jbe@124 | 17 #define JSON_STATE_ARRAY_SEPARATOR 6 | 
| jbe@124 | 18 #define JSON_STATE_END 7 | 
| jbe@121 | 19 | 
| jbe@133 | 20 static int json_object(lua_State *L) { | 
| jbe@133 | 21   lua_settop(L, 1); | 
| jbe@133 | 22   if (lua_isnil(L, 1)) { | 
| jbe@133 | 23     lua_settop(L, 0); | 
| jbe@133 | 24     lua_newtable(L); | 
| jbe@133 | 25   } | 
| jbe@133 | 26   lua_pushvalue(L, JSON_UPVAL_METATABLE); | 
| jbe@133 | 27   lua_setmetatable(L, 1); | 
| jbe@133 | 28   lua_pushvalue(L, 1); | 
| jbe@133 | 29   lua_newtable(L);  // internal shadow table | 
| jbe@133 | 30   lua_rawset(L, JSON_UPVAL_SHADOWTBL); | 
| jbe@133 | 31   lua_pushvalue(L, 1); | 
| jbe@133 | 32   lua_pushliteral(L, "object"); | 
| jbe@133 | 33   lua_rawset(L, JSON_UPVAL_TYPES); | 
| jbe@133 | 34   return 1; | 
| jbe@133 | 35 } | 
| jbe@133 | 36 | 
| jbe@133 | 37 static int json_array(lua_State *L) { | 
| jbe@133 | 38   lua_settop(L, 1); | 
| jbe@133 | 39   if (lua_isnil(L, 1)) { | 
| jbe@133 | 40     lua_settop(L, 0); | 
| jbe@133 | 41     lua_newtable(L); | 
| jbe@133 | 42   } | 
| jbe@133 | 43   lua_pushvalue(L, JSON_UPVAL_METATABLE); | 
| jbe@133 | 44   lua_setmetatable(L, 1); | 
| jbe@133 | 45   lua_pushvalue(L, 1); | 
| jbe@133 | 46   lua_newtable(L);  // internal shadow table | 
| jbe@133 | 47   lua_rawset(L, JSON_UPVAL_SHADOWTBL); | 
| jbe@133 | 48   lua_pushvalue(L, 1); | 
| jbe@133 | 49   lua_pushliteral(L, "array"); | 
| jbe@133 | 50   lua_rawset(L, JSON_UPVAL_TYPES); | 
| jbe@133 | 51   return 1; | 
| jbe@133 | 52 } | 
| jbe@133 | 53 | 
| jbe@121 | 54 static int json_import(lua_State *L) { | 
| jbe@121 | 55   const char *str; | 
| jbe@121 | 56   size_t total; | 
| jbe@121 | 57   size_t pos = 0; | 
| jbe@121 | 58   size_t level = 0; | 
| jbe@124 | 59   int mode = JSON_STATE_VALUE; | 
| jbe@121 | 60   char c; | 
| jbe@121 | 61   luaL_Buffer luabuf; | 
| jbe@121 | 62   char *cbuf; | 
| jbe@121 | 63   size_t writepos; | 
| jbe@121 | 64   lua_settop(L, 1); | 
| jbe@121 | 65   str = lua_tostring(L, 1); | 
| jbe@121 | 66   total = strlen(str); | 
| jbe@121 | 67 json_import_loop: | 
| jbe@121 | 68   while (c = str[pos], c == ' ' || c == '\n' || c == '\r' || c == '\t' || c == '\f') pos++; | 
| jbe@121 | 69   switch (c) { | 
| jbe@121 | 70   case 0: | 
| jbe@124 | 71     if (mode == JSON_STATE_END) return 1; | 
| jbe@121 | 72     json_import_unexpected_eof: | 
| jbe@121 | 73     lua_pushnil(L); | 
| jbe@121 | 74     if (level == 0) lua_pushliteral(L, "Empty string"); | 
| jbe@121 | 75     else lua_pushliteral(L, "Unexpected end of JSON document"); | 
| jbe@121 | 76     return 2; | 
| jbe@121 | 77   case '{': | 
| jbe@124 | 78     if (mode != JSON_STATE_VALUE && mode != JSON_STATE_OBJECT_VALUE && mode != JSON_STATE_ARRAY_VALUE) | 
| jbe@121 | 79       goto json_import_syntax_error; | 
| jbe@121 | 80     pos++; | 
| jbe@130 | 81     lua_newtable(L);  // the external JSON object representation | 
| jbe@125 | 82     lua_pushvalue(L, JSON_UPVAL_METATABLE); | 
| jbe@125 | 83     lua_setmetatable(L, -2); | 
| jbe@127 | 84     lua_pushvalue(L, -1); | 
| jbe@127 | 85     lua_pushliteral(L, "object"); | 
| jbe@127 | 86     lua_rawset(L, JSON_UPVAL_TYPES); | 
| jbe@130 | 87     lua_newtable(L);  // the internal shadow table | 
| jbe@123 | 88     lua_pushvalue(L, -2); | 
| jbe@123 | 89     lua_pushvalue(L, -2); | 
| jbe@130 | 90     lua_rawset(L, JSON_UPVAL_SHADOWTBL); | 
| jbe@124 | 91     mode = JSON_STATE_OBJECT_KEY; | 
| jbe@121 | 92     level++; | 
| jbe@121 | 93     goto json_import_loop; | 
| jbe@121 | 94   case '[': | 
| jbe@124 | 95     if (mode != JSON_STATE_VALUE && mode != JSON_STATE_OBJECT_VALUE && mode != JSON_STATE_ARRAY_VALUE) | 
| jbe@121 | 96       goto json_import_syntax_error; | 
| jbe@121 | 97     pos++; | 
| jbe@130 | 98     lua_newtable(L);  // the external JSON array representation | 
| jbe@125 | 99     lua_pushvalue(L, JSON_UPVAL_METATABLE); | 
| jbe@125 | 100     lua_setmetatable(L, -2); | 
| jbe@127 | 101     lua_pushvalue(L, -1); | 
| jbe@127 | 102     lua_pushliteral(L, "array"); | 
| jbe@127 | 103     lua_rawset(L, JSON_UPVAL_TYPES); | 
| jbe@130 | 104     lua_newtable(L);  // the internal shadow table | 
| jbe@123 | 105     lua_pushvalue(L, -2); | 
| jbe@123 | 106     lua_pushvalue(L, -2); | 
| jbe@130 | 107     lua_rawset(L, JSON_UPVAL_SHADOWTBL); | 
| jbe@130 | 108     lua_pushinteger(L, 0);  // magic integer to indicate an array | 
| jbe@124 | 109     mode = JSON_STATE_ARRAY_VALUE; | 
| jbe@121 | 110     level++; | 
| jbe@121 | 111     goto json_import_loop; | 
| jbe@121 | 112   case '}': | 
| jbe@124 | 113     if (mode != JSON_STATE_OBJECT_KEY && mode != JSON_STATE_OBJECT_SEPARATOR) | 
| jbe@121 | 114       goto json_import_syntax_error; | 
| jbe@121 | 115     goto json_import_close; | 
| jbe@121 | 116   case ']': | 
| jbe@124 | 117     if (mode != JSON_STATE_ARRAY_VALUE && mode != JSON_STATE_ARRAY_SEPARATOR) | 
| jbe@121 | 118       goto json_import_syntax_error; | 
| jbe@130 | 119     lua_pop(L, 1);  // pop magic integer | 
| jbe@121 | 120   json_import_close: | 
| jbe@121 | 121     pos++; | 
| jbe@130 | 122     lua_pop(L, 1);  // pop shadow table | 
| jbe@121 | 123     if (--level) { | 
| jbe@121 | 124       if (lua_type(L, -2) == LUA_TNUMBER) { | 
| jbe@124 | 125         mode = JSON_STATE_ARRAY_VALUE; | 
| jbe@121 | 126       } else { | 
| jbe@124 | 127         mode = JSON_STATE_OBJECT_VALUE; | 
| jbe@121 | 128       } | 
| jbe@121 | 129       goto json_import_process_value; | 
| jbe@121 | 130     } else { | 
| jbe@124 | 131       mode = JSON_STATE_END; | 
| jbe@121 | 132     } | 
| jbe@121 | 133     goto json_import_loop; | 
| jbe@121 | 134   case ':': | 
| jbe@124 | 135     if (mode != JSON_STATE_OBJECT_KEY_TERMINATOR) | 
| jbe@121 | 136       goto json_import_syntax_error; | 
| jbe@121 | 137     pos++; | 
| jbe@124 | 138     mode = JSON_STATE_OBJECT_VALUE; | 
| jbe@121 | 139     goto json_import_loop; | 
| jbe@121 | 140   case ',': | 
| jbe@124 | 141     if (mode == JSON_STATE_OBJECT_SEPARATOR) { | 
| jbe@124 | 142       mode = JSON_STATE_OBJECT_KEY; | 
| jbe@124 | 143     } else if (mode == JSON_STATE_ARRAY_SEPARATOR) { | 
| jbe@124 | 144       mode = JSON_STATE_ARRAY_VALUE; | 
| jbe@121 | 145     } else { | 
| jbe@121 | 146       goto json_import_syntax_error; | 
| jbe@121 | 147     } | 
| jbe@121 | 148     pos++; | 
| jbe@121 | 149     goto json_import_loop; | 
| jbe@121 | 150   case '"': | 
| jbe@121 | 151     cbuf = luaL_buffinitsize(L, &luabuf, total-pos); | 
| jbe@121 | 152     writepos = 0; | 
| jbe@121 | 153     pos++; | 
| jbe@121 | 154     while ((c = str[pos++]) != '"') { | 
| jbe@121 | 155       if (c == 0) { | 
| jbe@121 | 156         goto json_import_unexpected_eof; | 
| jbe@121 | 157       } else if (c < 32 || c == 127) { | 
| jbe@121 | 158         lua_pushnil(L); | 
| jbe@121 | 159         lua_pushliteral(L, "Unexpected control character in JSON string"); | 
| jbe@121 | 160         return 2; | 
| jbe@121 | 161       } else if (c == '\\') { | 
| jbe@121 | 162         c = str[pos++]; | 
| jbe@121 | 163         switch (c) { | 
| jbe@121 | 164         case 0: | 
| jbe@121 | 165           goto json_import_unexpected_eof; | 
| jbe@121 | 166         case '"': | 
| jbe@121 | 167         case '/': | 
| jbe@121 | 168         case '\\': | 
| jbe@121 | 169           cbuf[writepos++] = c; | 
| jbe@121 | 170           break; | 
| jbe@121 | 171         case 'b': | 
| jbe@121 | 172           cbuf[writepos++] = '\b'; | 
| jbe@121 | 173           break; | 
| jbe@121 | 174         case 'f': | 
| jbe@121 | 175           cbuf[writepos++] = '\f'; | 
| jbe@121 | 176           break; | 
| jbe@121 | 177         case 'n': | 
| jbe@121 | 178           cbuf[writepos++] = '\n'; | 
| jbe@121 | 179           break; | 
| jbe@121 | 180         case 'r': | 
| jbe@121 | 181           cbuf[writepos++] = '\r'; | 
| jbe@121 | 182           break; | 
| jbe@121 | 183         case 't': | 
| jbe@121 | 184           cbuf[writepos++] = '\t'; | 
| jbe@121 | 185           break; | 
| jbe@121 | 186         case 'u': | 
| jbe@121 | 187           lua_pushnil(L); | 
| jbe@121 | 188           lua_pushliteral(L, "JSON unicode escape sequences are not implemented yet");  // TODO | 
| jbe@121 | 189           return 2; | 
| jbe@121 | 190         default: | 
| jbe@121 | 191           lua_pushnil(L); | 
| jbe@121 | 192           lua_pushliteral(L, "Unexpected string escape sequence in JSON document"); | 
| jbe@121 | 193           return 2; | 
| jbe@121 | 194         } | 
| jbe@121 | 195       } else { | 
| jbe@121 | 196         cbuf[writepos++] = c; | 
| jbe@121 | 197       } | 
| jbe@121 | 198     } | 
| jbe@121 | 199     if (!c) goto json_import_unexpected_eof; | 
| jbe@121 | 200     luaL_pushresultsize(&luabuf, writepos); | 
| jbe@121 | 201     goto json_import_process_value; | 
| jbe@121 | 202   } | 
| jbe@122 | 203   if (c == '-' || (c >= '0' && c <= '9')) { | 
| jbe@122 | 204     char *endptr; | 
| jbe@122 | 205     double numval; | 
| jbe@122 | 206     numval = strtod(str+pos, &endptr); | 
| jbe@122 | 207     if (endptr == str+pos) goto json_import_syntax_error; | 
| jbe@122 | 208     pos += endptr - (str+pos); | 
| jbe@122 | 209     lua_pushnumber(L, numval); | 
| jbe@122 | 210   } else if (!strncmp(str+pos, "true", 4)) { | 
| jbe@121 | 211     lua_pushboolean(L, 1); | 
| jbe@121 | 212     pos += 4; | 
| jbe@121 | 213   } else if (!strncmp(str+pos, "false", 5)) { | 
| jbe@121 | 214     lua_pushboolean(L, 0); | 
| jbe@121 | 215     pos += 5; | 
| jbe@121 | 216   } else if (!strncmp(str+pos, "null", 4)) { | 
| jbe@130 | 217     lua_pushvalue(L, JSON_UPVAL_NULLMARK); | 
| jbe@121 | 218     pos += 4; | 
| jbe@121 | 219   } else { | 
| jbe@121 | 220     goto json_import_syntax_error; | 
| jbe@121 | 221   } | 
| jbe@121 | 222 json_import_process_value: | 
| jbe@121 | 223   switch (mode) { | 
| jbe@124 | 224   case JSON_STATE_OBJECT_KEY: | 
| jbe@121 | 225     if (lua_type(L, -1) != LUA_TSTRING) goto json_import_syntax_error; | 
| jbe@124 | 226     mode = JSON_STATE_OBJECT_KEY_TERMINATOR; | 
| jbe@121 | 227     goto json_import_loop; | 
| jbe@124 | 228   case JSON_STATE_OBJECT_VALUE: | 
| jbe@130 | 229     lua_rawset(L, -3); | 
| jbe@124 | 230     mode = JSON_STATE_OBJECT_SEPARATOR; | 
| jbe@121 | 231     goto json_import_loop; | 
| jbe@124 | 232   case JSON_STATE_ARRAY_VALUE: | 
| jbe@130 | 233     lua_rawseti(L, -3, lua_rawlen(L, -3) + 1); | 
| jbe@124 | 234     mode = JSON_STATE_ARRAY_SEPARATOR; | 
| jbe@121 | 235     goto json_import_loop; | 
| jbe@124 | 236   case JSON_STATE_VALUE: | 
| jbe@124 | 237     mode = JSON_STATE_END; | 
| jbe@121 | 238     goto json_import_loop; | 
| jbe@121 | 239   } | 
| jbe@121 | 240 json_import_syntax_error: | 
| jbe@121 | 241   lua_pushnil(L); | 
| jbe@121 | 242   lua_pushliteral(L, "Syntax error in JSON document"); | 
| jbe@121 | 243   return 2; | 
| jbe@121 | 244 } | 
| jbe@121 | 245 | 
| jbe@130 | 246 #define JSON_PATH_GET 1 | 
| jbe@130 | 247 #define JSON_PATH_TYPE 2 | 
| jbe@130 | 248 #define JSON_PATH_ISNULL 3 | 
| jbe@130 | 249 | 
| jbe@130 | 250 static int json_path(lua_State *L, int mode) { | 
| jbe@130 | 251   int argc; | 
| jbe@130 | 252   int idx = 2; | 
| jbe@130 | 253   argc = lua_gettop(L); | 
| jbe@126 | 254   lua_pushvalue(L, 1); | 
| jbe@130 | 255   while (idx <= argc) { | 
| jbe@132 | 256     if (lua_isnil(L, -1)) { | 
| jbe@132 | 257       if (mode == JSON_PATH_ISNULL) lua_pushboolean(L, 0); | 
| jbe@132 | 258       return 1; | 
| jbe@132 | 259     } | 
| jbe@130 | 260     lua_pushvalue(L, -1); | 
| jbe@130 | 261     lua_rawget(L, JSON_UPVAL_SHADOWTBL); | 
| jbe@126 | 262     if (lua_isnil(L, -1)) { | 
| jbe@126 | 263       lua_pop(L, 1); | 
| jbe@130 | 264       if (lua_type(L, -1) == LUA_TTABLE) { | 
| jbe@130 | 265         lua_pushvalue(L, idx++); | 
| jbe@130 | 266         lua_gettable(L, -2); | 
| jbe@130 | 267       } else { | 
| jbe@130 | 268         lua_pushnil(L); | 
| jbe@130 | 269       } | 
| jbe@130 | 270     } else { | 
| jbe@130 | 271       lua_replace(L, -2); | 
| jbe@130 | 272       lua_pushvalue(L, idx++); | 
| jbe@130 | 273       lua_rawget(L, -2); | 
| jbe@126 | 274     } | 
| jbe@130 | 275     lua_replace(L, -2); | 
| jbe@126 | 276   } | 
| jbe@130 | 277   switch (mode) { | 
| jbe@130 | 278   case JSON_PATH_GET: | 
| jbe@130 | 279     if (lua_rawequal(L, -1, JSON_UPVAL_NULLMARK)) lua_pushnil(L); | 
| jbe@130 | 280     return 1; | 
| jbe@130 | 281   case JSON_PATH_TYPE: | 
| jbe@130 | 282     if (lua_rawequal(L, -1, JSON_UPVAL_NULLMARK)) { | 
| jbe@130 | 283       lua_pushliteral(L, "null"); | 
| jbe@130 | 284       return 1; | 
| jbe@126 | 285     } | 
| jbe@130 | 286     lua_pushvalue(L, -1); | 
| jbe@130 | 287     lua_rawget(L, JSON_UPVAL_TYPES); | 
| jbe@130 | 288     if (lua_isnil(L, -1)) lua_pushstring(L, lua_typename(L, lua_type(L, -2))); | 
| jbe@130 | 289     return 1; | 
| jbe@130 | 290   case JSON_PATH_ISNULL: | 
| jbe@130 | 291     lua_pushboolean(L, lua_rawequal(L, -1, JSON_UPVAL_NULLMARK)); | 
| jbe@130 | 292     return 1; | 
| jbe@126 | 293   } | 
| jbe@130 | 294   return 0; | 
| jbe@130 | 295 } | 
| jbe@130 | 296 | 
| jbe@130 | 297 static int json_get(lua_State *L) { | 
| jbe@130 | 298   return json_path(L, JSON_PATH_GET); | 
| jbe@130 | 299 } | 
| jbe@130 | 300 | 
| jbe@130 | 301 static int json_type(lua_State *L) { | 
| jbe@130 | 302   return json_path(L, JSON_PATH_TYPE); | 
| jbe@130 | 303 } | 
| jbe@130 | 304 | 
| jbe@130 | 305 static int json_isnull(lua_State *L) { | 
| jbe@130 | 306   return json_path(L, JSON_PATH_ISNULL); | 
| jbe@130 | 307 } | 
| jbe@130 | 308 | 
| jbe@131 | 309 static int json_setnull(lua_State *L) { | 
| jbe@131 | 310   lua_settop(L, 2); | 
| jbe@131 | 311   lua_pushvalue(L, JSON_UPVAL_METATABLE); | 
| jbe@131 | 312   lua_setmetatable(L, 1); | 
| jbe@131 | 313   lua_pushvalue(L, 1); | 
| jbe@131 | 314   lua_rawget(L, JSON_UPVAL_SHADOWTBL); | 
| jbe@131 | 315   if (lua_isnil(L, -1)) { | 
| jbe@131 | 316     lua_newtable(L); | 
| jbe@131 | 317     lua_pushvalue(L, 1); | 
| jbe@131 | 318     lua_pushvalue(L, -2); | 
| jbe@131 | 319     lua_rawset(L, JSON_UPVAL_SHADOWTBL); | 
| jbe@131 | 320   } | 
| jbe@131 | 321   lua_pushvalue(L, 2); | 
| jbe@131 | 322   lua_pushvalue(L, JSON_UPVAL_NULLMARK); | 
| jbe@131 | 323   lua_rawset(L, -3); | 
| jbe@131 | 324   return 0; | 
| jbe@131 | 325 } | 
| jbe@131 | 326 | 
| jbe@130 | 327 static int json_len(lua_State *L) { | 
| jbe@130 | 328   lua_settop(L, 1); | 
| jbe@130 | 329   lua_pushvalue(L, 1); | 
| jbe@130 | 330   lua_rawget(L, JSON_UPVAL_SHADOWTBL); | 
| jbe@130 | 331   if (lua_isnil(L, -1)) lua_pop(L, 1); | 
| jbe@130 | 332   lua_pushinteger(L, lua_rawlen(L, -1)); | 
| jbe@123 | 333   return 1; | 
| jbe@123 | 334 } | 
| jbe@123 | 335 | 
| jbe@130 | 336 static int json_index(lua_State *L) { | 
| jbe@130 | 337   lua_settop(L, 2); | 
| jbe@130 | 338   lua_pushvalue(L, 1); | 
| jbe@130 | 339   lua_rawget(L, JSON_UPVAL_SHADOWTBL); | 
| jbe@130 | 340   if (lua_isnil(L, -1)) return 1; | 
| jbe@130 | 341   lua_pushvalue(L, 2); | 
| jbe@130 | 342   lua_rawget(L, -2); | 
| jbe@130 | 343   if (lua_rawequal(L, -1, JSON_UPVAL_NULLMARK)) lua_pushnil(L); | 
| jbe@127 | 344   return 1; | 
| jbe@127 | 345 } | 
| jbe@127 | 346 | 
| jbe@130 | 347 static int json_newindex(lua_State *L) { | 
| jbe@130 | 348   lua_settop(L, 3); | 
| jbe@123 | 349   lua_pushvalue(L, 1); | 
| jbe@130 | 350   lua_rawget(L, JSON_UPVAL_SHADOWTBL); | 
| jbe@130 | 351   if (lua_isnil(L, -1)) return luaL_error(L, "Shadow table not found"); | 
| jbe@130 | 352   lua_replace(L, 1); | 
| jbe@130 | 353   lua_rawset(L, 1); | 
| jbe@121 | 354   return 1; | 
| jbe@121 | 355 } | 
| jbe@121 | 356 | 
| jbe@121 | 357 static const struct luaL_Reg json_module_functions[] = { | 
| jbe@133 | 358   {"object", json_object}, | 
| jbe@133 | 359   {"array", json_array}, | 
| jbe@121 | 360   {"import", json_import}, | 
| jbe@130 | 361   {"get", json_get}, | 
| jbe@127 | 362   {"type", json_type}, | 
| jbe@123 | 363   {"isnull", json_isnull}, | 
| jbe@131 | 364   {"setnull", json_setnull}, | 
| jbe@121 | 365   {NULL, NULL} | 
| jbe@121 | 366 }; | 
| jbe@121 | 367 | 
| jbe@126 | 368 static const struct luaL_Reg json_metatable_functions[] = { | 
| jbe@130 | 369   {"__len", json_len}, | 
| jbe@130 | 370   {"__index", json_index}, | 
| jbe@130 | 371   {"__newindex", json_newindex}, | 
| jbe@126 | 372   {NULL, NULL} | 
| jbe@126 | 373 }; | 
| jbe@126 | 374 | 
| jbe@121 | 375 int luaopen_json(lua_State *L) { | 
| jbe@126 | 376   lua_settop(L, 0); | 
| jbe@126 | 377   lua_newtable(L);  // 1: library table on stack position | 
| jbe@130 | 378   lua_newtable(L);  // 2: table used as JSON NULL value in internal shadow tables | 
| jbe@130 | 379   lua_newtable(L);  // 3: ephemeron table to store shadow tables for each JSON object/array to allow NULL values returned as nil | 
| jbe@130 | 380   lua_newtable(L);  // 4: ephemeron table to store the type of the JSON object/array | 
| jbe@130 | 381   lua_newtable(L);  // 5: metatable for ephemeron tables | 
| jbe@121 | 382   lua_pushliteral(L, "__mode"); | 
| jbe@121 | 383   lua_pushliteral(L, "k"); | 
| jbe@130 | 384   lua_rawset(L, 5); | 
| jbe@130 | 385   lua_pushvalue(L, 5);  // 6: cloned metatable reference | 
| jbe@127 | 386   lua_setmetatable(L, 3); | 
| jbe@130 | 387   lua_setmetatable(L, 4); | 
| jbe@130 | 388   lua_newtable(L);  // 5: metatable for JSON objects and JSON arrays | 
| jbe@130 | 389   lua_pushvalue(L, 5); | 
| jbe@126 | 390   lua_setfield(L, 1, "metatable"); | 
| jbe@126 | 391   lua_pushvalue(L, 2); | 
| jbe@126 | 392   lua_pushvalue(L, 3); | 
| jbe@127 | 393   lua_pushvalue(L, 4); | 
| jbe@130 | 394   lua_pushvalue(L, 5); | 
| jbe@130 | 395   luaL_setfuncs(L, json_metatable_functions, 4); | 
| jbe@130 | 396   luaL_setfuncs(L, json_module_functions, 4); | 
| jbe@121 | 397   return 1; | 
| jbe@121 | 398 } |