webmcp
view libraries/json/json.c @ 143:6f723e60acdc
Bugfixes in JSON library
| author | jbe | 
|---|---|
| date | Wed Jul 30 02:36:37 2014 +0200 (2014-07-30) | 
| parents | a686ed2ce967 | 
| children | 0690fe79b673 | 
 line source
     1 #include <lua.h>
     2 #include <lauxlib.h>
     3 #include <stdlib.h>
     4 #include <string.h>
     6 #define JSON_MAXDEPTH 100
     8 #define JSON_REGENT static char
     9 #define JSON_REGREF void *
    11 JSON_REGENT json_nullmark;
    12 JSON_REGENT json_shadowtbl;
    13 JSON_REGENT json_unknownmt;
    14 JSON_REGENT json_objectmt;
    15 JSON_REGENT json_arraymt;
    17 #define json_regfetch(L, x) (lua_pushlightuserdata((L), &(x)), lua_rawget((L), LUA_REGISTRYINDEX))
    19 #define json_regstore(L, x) (lua_pushlightuserdata(L, &(x)), lua_pushvalue(L, -2), lua_rawset(L, LUA_REGISTRYINDEX));
    21 // marks a table as JSON object or JSON array:
    22 // (returns its modified argument or a new table if argument is nil)
    23 static int json_mark(lua_State *L, JSON_REGREF mt) {
    24   // if argument is nil, then create new table:
    25   if (lua_isnoneornil(L, 1)) {
    26     lua_settop(L, 0);
    27     lua_newtable(L);
    28     // set shadow table:
    29     json_regfetch(L, json_shadowtbl);
    30     lua_pushvalue(L, 1);
    31     lua_newtable(L);
    32     lua_rawset(L, -3);
    33   } else {
    34     // check if shadow table already exists:
    35     json_regfetch(L, json_shadowtbl);
    36     lua_pushvalue(L, 1);
    37     lua_rawget(L, -2);
    38     if (lua_isnil(L, -1)) {
    39       // set shadow table and leave it on top of stack:
    40       lua_newtable(L);
    41       lua_pushvalue(L, 1);
    42       lua_pushvalue(L, -2);
    43       lua_rawset(L, -5);
    44     }
    45     for(lua_pushnil(L); lua_next(L, 1); lua_pop(L, 1)) {
    46       lua_pushvalue(L, -2);
    47       lua_pushnil(L);
    48       lua_rawset(L, 1);
    49       lua_pushvalue(L, -2);
    50       lua_pushvalue(L, -2);
    51       lua_rawset(L, -5);
    52     }
    53   }
    54   // discard everything but table to return:
    55   lua_settop(L, 1);
    56   // set metatable:
    57   json_regfetch(L, *mt);
    58   lua_setmetatable(L, 1);
    59   // return table:
    60   return 1;
    61 }
    63 // marks a table as JSON object:
    64 // (returns its modified argument or a new table if argument is nil)
    65 static int json_object(lua_State *L) {
    66   return json_mark(L, &json_objectmt);
    67 }
    69 // marks a table as JSON array:
    70 // (returns its modified argument or a new table if argument is nil)
    71 static int json_array(lua_State *L) {
    72   return json_mark(L, &json_arraymt);
    73 }
    75 #define JSON_STATE_VALUE 0
    76 #define JSON_STATE_OBJECT_KEY 1
    77 #define JSON_STATE_OBJECT_KEY_TERMINATOR 2
    78 #define JSON_STATE_OBJECT_VALUE 3
    79 #define JSON_STATE_OBJECT_SEPARATOR 4
    80 #define JSON_STATE_ARRAY_VALUE 5
    81 #define JSON_STATE_ARRAY_SEPARATOR 6
    82 #define JSON_STATE_END 7
    84 #define json_import_objectmt_idx 2
    85 #define json_import_arraymt_idx 3
    86 #define json_import_shadowtbl_idx 4
    87 #define json_import_nullmark_idx 5
    89 // decodes a JSON document:
    90 static int json_import(lua_State *L) {
    91   const char *str;   // string to parse
    92   size_t total;      // total length of string to parse
    93   size_t pos = 0;    // current position in string to parse
    94   size_t level = 0;  // nested levels of objects/arrays currently being processed
    95   int mode = JSON_STATE_VALUE;  // state of parser
    96   char c;              // variable to store a single character to be processed
    97   luaL_Buffer luabuf;  // Lua buffer to decode (possibly escaped) strings
    98   char *cbuf;          // C buffer to decode (possibly escaped) strings
    99   size_t writepos;     // write position of decoded strings in C buffer
   100   // limit stack to 1 element:
   101   lua_settop(L, 1);
   102   // push json_objectmt on stack position 2:
   103   json_regfetch(L, json_objectmt);
   104   // push json_arraymt on stack position 3:
   105   json_regfetch(L, json_arraymt);
   106   // push json_shadowtbl on stack position 4:
   107   json_regfetch(L, json_shadowtbl);
   108   // push json_nullmark on stack position 5:
   109   json_regfetch(L, json_nullmark);
   110   // require string as first argument:
   111   str = luaL_checklstring(L, 1, &total);
   112   // if string contains a NULL byte, this is a syntax error
   113   if (strlen(str) != total) goto json_import_syntax_error;
   114   // main loop of parser:
   115   json_import_loop:
   116   // skip whitespace and store next character in variable 'c':
   117   while (c = str[pos], c == ' ' || c == '\n' || c == '\r' || c == '\t' || c == '\f') pos++;
   118   // switch statement to handle certain (single) characters:
   119   switch (c) {
   120   // handle end of JSON document:
   121   case 0:
   122     // if end of JSON document was expected, then return top element of stack as result:
   123     if (mode == JSON_STATE_END) return 1;
   124     // otherwise, the JSON document was malformed:
   125     json_import_unexpected_eof:
   126     lua_pushnil(L);
   127     if (level == 0) lua_pushliteral(L, "Empty string");
   128     else lua_pushliteral(L, "Unexpected end of JSON document");
   129     return 2;
   130   // new JSON object:
   131   case '{':
   132     // if a JSON object is not expected here, then return an error:
   133     if (mode != JSON_STATE_VALUE && mode != JSON_STATE_OBJECT_VALUE && mode != JSON_STATE_ARRAY_VALUE)
   134       goto json_import_syntax_error;
   135     // create JSON object on stack:
   136     lua_newtable(L);
   137     // set metatable of JSON object:
   138     lua_pushvalue(L, json_import_objectmt_idx);
   139     lua_setmetatable(L, -2);
   140     // create internal shadow table on stack:
   141     lua_newtable(L);
   142     // register internal shadow table (and cleanup stack afterwards):
   143     lua_pushvalue(L, -2);
   144     lua_pushvalue(L, -2);
   145     lua_rawset(L, json_import_shadowtbl_idx);
   146     // expect object key (or end of object) and continue with loop:
   147     mode = JSON_STATE_OBJECT_KEY;
   148     goto json_import_open;
   149   // new JSON array:
   150   case '[':
   151     // if a JSON array is not expected here, then return an error:
   152     if (mode != JSON_STATE_VALUE && mode != JSON_STATE_OBJECT_VALUE && mode != JSON_STATE_ARRAY_VALUE)
   153       goto json_import_syntax_error;
   154     // create JSON array on stack:
   155     lua_newtable(L);
   156     // set metatable of JSON array:
   157     lua_pushvalue(L, json_import_arraymt_idx);
   158     lua_setmetatable(L, -2);
   159     // create internal shadow table on stack:
   160     lua_newtable(L);
   161     // register internal shadow table (and cleanup stack afterwards):
   162     lua_pushvalue(L, -2);
   163     lua_pushvalue(L, -2);
   164     lua_rawset(L, json_import_shadowtbl_idx);
   165     // add nil as key (needed to keep stack balance) and as magic to detect arrays:
   166     lua_pushnil(L);
   167     // expect array value (or end of array) and continue with loop:
   168     mode = JSON_STATE_ARRAY_VALUE;
   169     // continue with common code for opening JSON object and JSON array:
   170   // commn code for opening JSON object or JSON array:
   171   json_import_open:
   172     // limit nested levels:
   173     if (level >= JSON_MAXDEPTH) {
   174       lua_pushnil(L);
   175       lua_pushliteral(L, "Too many nested JSON levels");
   176       return 2;
   177     }
   178     // additional buffer overflow protection:
   179     if (!lua_checkstack(L, LUA_MINSTACK))
   180       return luaL_error(L, "Caught stack overflow in JSON import function (too many nested levels and stack size too small)");
   181     // increment level:
   182     level++;
   183     // consume input character:
   184     pos++;
   185     goto json_import_loop;
   186   // end of JSON object:
   187   case '}':
   188     // if end of JSON object is not expected here, then return an error:
   189     if (mode != JSON_STATE_OBJECT_KEY && mode != JSON_STATE_OBJECT_SEPARATOR)
   190       goto json_import_syntax_error;
   191     // jump to common code for end of JSON object and JSON array:
   192     goto json_import_close;
   193   // end of JSON array:
   194   case ']':
   195     // if end of JSON array is not expected here, then return an error:
   196     if (mode != JSON_STATE_ARRAY_VALUE && mode != JSON_STATE_ARRAY_SEPARATOR)
   197       goto json_import_syntax_error;
   198     // pop nil key/magic:
   199     lua_pop(L, 1);
   200     // continue with common code for end of JSON object and JSON array:
   201   // common code for end of JSON object or JSON array:
   202   json_import_close:
   203     // consume input character:
   204     pos++;
   205     // pop shadow table:
   206     lua_pop(L, 1);
   207     // check if nested:
   208     if (--level) {
   209       // if nested, then check if outer(!) structure is an array or object:
   210       if (lua_isnil(L, -2)) {
   211         // select array value processing:
   212         mode = JSON_STATE_ARRAY_VALUE;
   213       } else {
   214         // select object value processing:
   215         mode = JSON_STATE_OBJECT_VALUE;
   216       }
   217       // store value in outer structure:
   218       goto json_import_process_value;
   219     }
   220     // if not nested, then expect end of JSON document and continue with loop:
   221     mode = JSON_STATE_END;
   222     goto json_import_loop;
   223   // key terminator:
   224   case ':':
   225     // if key terminator is not expected here, then return an error:
   226     if (mode != JSON_STATE_OBJECT_KEY_TERMINATOR)
   227       goto json_import_syntax_error;
   228     // consume input character:
   229     pos++;
   230     // set state of parser and continue with loop:
   231     mode = JSON_STATE_OBJECT_VALUE;
   232     goto json_import_loop;
   233   // value terminator (NOTE: trailing comma at end of value or key-value list is tolerated by this parser)
   234   case ',':
   235     // change parser state accordingly:
   236     if (mode == JSON_STATE_OBJECT_SEPARATOR) {
   237       mode = JSON_STATE_OBJECT_KEY;
   238     } else if (mode == JSON_STATE_ARRAY_SEPARATOR) {
   239       mode = JSON_STATE_ARRAY_VALUE;
   240     } else {
   241        // if value terminator is not expected here, then return an error:
   242        goto json_import_syntax_error;
   243     }
   244     // consume input character:
   245     pos++;
   246     // continue with loop:
   247     goto json_import_loop;
   248   // string literal:
   249   case '"':
   250     // prepare buffer to decode string (with maximum possible length) and set write position to zero:
   251     cbuf = luaL_buffinitsize(L, &luabuf, total-pos);
   252     writepos = 0;
   253     // consume quote character:
   254     pos++;
   255     // read next character until encountering end quote:
   256     while ((c = str[pos++]) != '"') {
   257       if (c == 0) {
   258         // handle unexpected end-of-string:
   259         goto json_import_unexpected_eof;
   260       } else if (c < 32 || c == 127) {
   261         // do not allow ASCII control characters:
   262         // NOTE: illegal UTF-8 sequences and extended control characters are not sanitized
   263         //       by this parser to allow different encodings than Unicode
   264         lua_pushnil(L);
   265         lua_pushliteral(L, "Unexpected control character in JSON string");
   266         return 2;
   267       } else if (c == '\\') {
   268         // read next char after backslash escape:
   269         c = str[pos++];
   270         switch (c) {
   271         // unexpected end-of-string:
   272         case 0:
   273           goto json_import_unexpected_eof;
   274         // unescaping of quotation mark, slash, and backslash:
   275         case '"':
   276         case '/':
   277         case '\\':
   278           cbuf[writepos++] = c;
   279           break;
   280         // unescaping of backspace:
   281         case 'b':
   282           cbuf[writepos++] = '\b';
   283           break;
   284         // unescaping of form-feed:
   285         case 'f':
   286           cbuf[writepos++] = '\f';
   287           break;
   288         // unescaping of new-line:
   289         case 'n':
   290           cbuf[writepos++] = '\n';
   291           break;
   292         // unescaping of carriage-return:
   293         case 'r':
   294           cbuf[writepos++] = '\r';
   295           break;
   296         // unescaping of tabulator:
   297         case 't':
   298           cbuf[writepos++] = '\t';
   299           break;
   300         // unescaping of UTF-16 characters
   301         case 'u':
   302           lua_pushnil(L);
   303           lua_pushliteral(L, "JSON unicode escape sequences are not implemented yet");  // TODO
   304           return 2;
   305         // unexpected escape sequence:
   306         default:
   307           lua_pushnil(L);
   308           lua_pushliteral(L, "Unexpected string escape sequence in JSON document");
   309           return 2;
   310         }
   311       } else {
   312         // normal character:
   313         cbuf[writepos++] = c;
   314       }
   315     }
   316     // process buffer to Lua string:
   317     luaL_pushresultsize(&luabuf, writepos);
   318     // continue with processing of decoded string:
   319     goto json_import_process_value;
   320   }
   321   // process values whose type is is not deducible from a single character:
   322   if ((c >= '0' && c <= '9') || c == '-' || c == '+') {
   323     // numbers:
   324     char *endptr;
   325     double numval;
   326     numval = strtod(str+pos, &endptr);
   327     if (endptr == str+pos) goto json_import_syntax_error;
   328     pos += endptr - (str+pos);
   329     lua_pushnumber(L, numval);
   330   } else if (!strncmp(str+pos, "true", 4)) {
   331     // consume 4 input characters for "true":
   332     pos += 4;
   333     // put Lua true value on stack:
   334     lua_pushboolean(L, 1);
   335   } else if (!strncmp(str+pos, "false", 5)) {
   336     // consume 5 input characters for "false":
   337     pos += 5;
   338     // put Lua false value on stack:
   339     lua_pushboolean(L, 0);
   340   } else if (!strncmp(str+pos, "null", 4)) {
   341     // consume 4 input characters for "null":
   342     pos += 4;
   343     // put special null-marker on stack:
   344     lua_pushvalue(L, json_import_nullmark_idx);
   345   } else {
   346     // all other cases are a syntax error:
   347     goto json_import_syntax_error;
   348   }
   349   // process a decoded value or key value pair (expected on top of Lua stack):
   350   json_import_process_value:
   351   switch (mode) {
   352   // an object key has been read:
   353   case JSON_STATE_OBJECT_KEY:
   354     // if an object key is not a string, then this is a syntax error:
   355     if (lua_type(L, -1) != LUA_TSTRING) goto json_import_syntax_error;
   356     // expect key terminator and continue with loop:
   357     mode = JSON_STATE_OBJECT_KEY_TERMINATOR;
   358     goto json_import_loop;
   359   // a key value pair has been read:
   360   case JSON_STATE_OBJECT_VALUE:
   361     // store key value pair in outer shadow table:
   362     lua_rawset(L, -3);
   363     // expect value terminator (or end of object) and continue with loop:
   364     mode = JSON_STATE_OBJECT_SEPARATOR;
   365     goto json_import_loop;
   366   // an array value has been read:
   367   case JSON_STATE_ARRAY_VALUE:
   368     // store value in outer shadow table:
   369     lua_rawseti(L, -3, lua_rawlen(L, -3) + 1);
   370     // expect value terminator (or end of object) and continue with loop:
   371     mode = JSON_STATE_ARRAY_SEPARATOR;
   372     goto json_import_loop;
   373   // a single value has been read:
   374   case JSON_STATE_VALUE:
   375     // leave value on top of stack, expect end of JSON document, and continue with loop:
   376     mode = JSON_STATE_END;
   377     goto json_import_loop;
   378   }
   379   // syntax error handling (only reachable by goto statement):
   380   json_import_syntax_error:
   381   lua_pushnil(L);
   382   lua_pushliteral(L, "Syntax error in JSON document");
   383   return 2;
   384 }
   386 #define json_path_shadowtbl_idx 1
   387 #define json_path_nullmark_idx 2
   388 #define json_path_idxshift 2
   390 // gets a value or its type from a JSON document (first argument)
   391 // optionally using a path (variable number of keys after first argument):
   392 static int json_path(lua_State *L, int type_mode) {
   393   int stacktop;
   394   int idx = 2 + json_path_idxshift;
   395   // insert json_shadowtbl on stack at position 1:
   396   json_regfetch(L, json_shadowtbl);
   397   lua_insert(L, 1);
   398   // insert json_nullmark on stack at position 2:
   399   json_regfetch(L, json_nullmark);
   400   lua_insert(L, 2);
   401   // store number of arguments:
   402   stacktop = lua_gettop(L);
   403   // follow path, starting with first argument as "current value":
   404   lua_pushvalue(L, 1 + json_path_idxshift);
   405   // process each "path key":
   406   while (idx <= stacktop) {
   407     // if "current value" is nil, then the path cannot be walked and nil is returned:
   408     if (lua_isnil(L, -1)) return 1;
   409     // try to get shadow table of "current value":
   410     lua_pushvalue(L, -1);
   411     lua_rawget(L, json_path_shadowtbl_idx);
   412     if (lua_isnil(L, -1)) {
   413       // if no shadow table is found,
   414       // drop nil from stack:
   415       lua_pop(L, 1);
   416       if (lua_type(L, -1) == LUA_TTABLE) {
   417         // if "current value" is a table,
   418         // get "next value" using the "path key":
   419         lua_pushvalue(L, idx++);
   420         lua_gettable(L, -2);
   421       } else {
   422         // if "current value" is not a table,
   423         // then the path cannot be walked and nil is returned:
   424         lua_pushnil(L);
   425         return 1;
   426       }
   427     } else {
   428       // if a shadow table is found,
   429       // set "current value" to its shadow table:
   430       lua_replace(L, -2);
   431       // get "next value" using the "path key":
   432       lua_pushvalue(L, idx++);
   433       lua_rawget(L, -2);
   434     }
   435     // the "next value" replaces the "current value":
   436     lua_replace(L, -2);
   437   }
   438   if (!type_mode) {
   439     // if a value (and not its type) was requested,
   440     // check if value is the null-marker, and store nil on top of Lua stack in that case:
   441     if (lua_rawequal(L, -1, json_path_nullmark_idx)) lua_pushnil(L);
   442   } else {
   443     // if the type was requested,
   444     // check if value is the null-marker:
   445     if (lua_rawequal(L, -1, json_path_nullmark_idx)) {
   446       // if yes, store string "null" on top of Lua stack:
   447       lua_pushliteral(L, "null");
   448     } else {
   449       // otherwise,
   450       // check if metatable indicates "object" or "array":
   451       if (lua_getmetatable(L, -1)) {
   452         json_regfetch(L, json_objectmt);
   453         if (lua_rawequal(L, -2, -1)) {
   454           // return string "object":
   455           lua_pushliteral(L, "object");
   456           return 1;
   457         }
   458         json_regfetch(L, json_arraymt);
   459         if (lua_rawequal(L, -3, -1)) {
   460           // return string "array":
   461           lua_pushliteral(L, "array");
   462           return 1;
   463         }
   464         lua_pop(L, 3);
   465       }
   466       // otherwise, get the Lua type:
   467       lua_pushstring(L, lua_typename(L, lua_type(L, -1)));
   468     }
   469   }
   470   // return the top most value on the Lua stack:
   471   return 1;
   472 }
   474 // gets a value from a JSON document (first argument)
   475 // optionally using a path (variable number of keys after first argument):
   476 static int json_get(lua_State *L) {
   477   return json_path(L, 0);
   478 }
   480 // gets a value's type from a JSON document (first argument)
   481 // optionally using a path (variable number of keys after first argument):
   482 static int json_type(lua_State *L) {
   483   return json_path(L, 1);
   484 }
   486 // checks if a value in a JSON document (first argument) is null:
   487 static int json_isnull(lua_State *L) {
   488   const char *jsontype;
   489   lua_pushcfunction(L, json_type);
   490   lua_insert(L, 1);
   491   lua_call(L, lua_gettop(L) - 1, 1);
   492   jsontype = lua_tostring(L, -1);
   493   if (jsontype && !strcmp(jsontype, "null")) lua_pushboolean(L, 1);
   494   else lua_pushboolean(L, 0);
   495   return 1;
   496 }
   498 #define json_setnull_unknownmt_idx 3
   499 #define json_setnull_objectmt_idx 4
   500 #define json_setnull_arraymt_idx 5
   501 #define json_setnull_shadowtbl_idx 6
   503 static int json_setnull(lua_State *L) {
   504   // truncate stack to two elements:
   505   lua_settop(L, 2);
   506   // push json_unknownmt to stack position 3:
   507   json_regfetch(L, json_unknownmt);
   508   // push json_objectmt to stack position 4:
   509   json_regfetch(L, json_objectmt);
   510   // push json_arraymt to stack position 5:
   511   json_regfetch(L, json_arraymt);
   512   // push json_shadowtbl to stack position 6:
   513   json_regfetch(L, json_shadowtbl);
   514   //
   515   lua_getmetatable(L, 1);
   516   if (
   517     !lua_rawequal(L, -1, json_setnull_unknownmt_idx) &&
   518     !lua_rawequal(L, -1, json_setnull_objectmt_idx) &&
   519     !lua_rawequal(L, -1, json_setnull_arraymt_idx)
   520   ) {
   521     lua_pushvalue(L, json_setnull_unknownmt_idx);
   522     lua_setmetatable(L, 1);
   523   }
   524   lua_pushvalue(L, 1);
   525   lua_rawget(L, json_setnull_shadowtbl_idx);
   526   if (lua_isnil(L, -1)) {
   527     lua_newtable(L);
   528     lua_pushvalue(L, 1);
   529     lua_pushvalue(L, -2);
   530     lua_rawset(L, json_setnull_shadowtbl_idx);
   531   }
   532   lua_pushvalue(L, 2);
   533   json_regfetch(L, json_nullmark);
   534   lua_rawset(L, -3);
   535   return 0;
   536 }
   538 static int json_len(lua_State *L) {
   539   lua_settop(L, 1);
   540   json_regfetch(L, json_shadowtbl);
   541   lua_pushvalue(L, 1);
   542   lua_rawget(L, -2);
   543   lua_pushinteger(L, lua_rawlen(L, lua_isnil(L, -1) ? 1 : -1));
   544   return 1;
   545 }
   547 #define json_index_nullmark_idx 3
   548 #define json_index_shadowtbl_idx 4
   550 static int json_index(lua_State *L) {
   551   lua_settop(L, 2);
   552   json_regfetch(L, json_nullmark);  // on stack position 3
   553   json_regfetch(L, json_shadowtbl);
   554   lua_pushvalue(L, 1);
   555   lua_rawget(L, json_index_shadowtbl_idx);
   556   if (lua_isnil(L, -1)) return luaL_error(L, "Shadow table not found");
   557   lua_pushvalue(L, 2);
   558   lua_rawget(L, -2);
   559   if (lua_rawequal(L, -1, json_index_nullmark_idx)) lua_pushnil(L);
   560   return 1;
   561 }
   563 static int json_newindex(lua_State *L) {
   564   lua_settop(L, 3);
   565   json_regfetch(L, json_shadowtbl);
   566   lua_pushvalue(L, 1);
   567   lua_rawget(L, -2);
   568   if (lua_isnil(L, -1)) return luaL_error(L, "Shadow table not found");
   569   lua_replace(L, 1);
   570   lua_settop(L, 3);
   571   lua_rawset(L, 1);
   572   return 1;
   573 }
   575 #define json_pairs_iterfunc_nullmark_idx 3
   576 #define json_pairs_iterfunc_shadowtbl_idx 4
   578 static int json_pairs_iterfunc(lua_State *L) {
   579   lua_settop(L, 2);
   580   json_regfetch(L, json_nullmark);  // on stack position 3
   581   json_regfetch(L, json_shadowtbl);
   582   lua_pushvalue(L, 1);
   583   lua_rawget(L, json_pairs_iterfunc_shadowtbl_idx);
   584   if (lua_isnil(L, -1)) return luaL_error(L, "Shadow table not found");
   585   lua_pushvalue(L, 2);
   586   if (!lua_next(L, -2)) return 0;
   587   if (lua_rawequal(L, -1, json_pairs_iterfunc_nullmark_idx)) {
   588     lua_pop(L, 1);
   589     lua_pushnil(L);
   590   }
   591   return 2;
   592 }
   594 static int json_pairs(lua_State *L) {
   595   lua_pushcfunction(L, json_pairs_iterfunc);
   596   lua_pushvalue(L, 1);
   597   lua_pushnil(L);
   598   return 3;
   599 }
   601 #define json_ipairs_iterfunc_nullmark_idx 3
   602 #define json_ipairs_iterfunc_shadowtbl_idx 4
   604 static int json_ipairs_iterfunc(lua_State *L) {
   605   int idx;
   606   lua_settop(L, 2);
   607   json_regfetch(L, json_nullmark);  // on stack position 3
   608   json_regfetch(L, json_shadowtbl);
   609   idx = lua_tointeger(L, 2) + 1;
   610   lua_pushvalue(L, 1);
   611   lua_rawget(L, json_ipairs_iterfunc_shadowtbl_idx);
   612   if (lua_isnil(L, -1)) return luaL_error(L, "Shadow table not found");
   613   lua_rawgeti(L, -1, idx);
   614   if (lua_isnil(L, -1)) return 0;
   615   lua_pushinteger(L, idx);
   616   if (lua_rawequal(L, -2, json_ipairs_iterfunc_nullmark_idx)) lua_pushnil(L);
   617   else lua_pushvalue(L, -2);
   618   return 2;
   619 }
   621 static int json_ipairs(lua_State *L) {
   622   lua_pushcfunction(L, json_ipairs_iterfunc);
   623   lua_pushvalue(L, 1);
   624   lua_pushinteger(L, 0);
   625   return 3;
   626 }
   628 static const struct luaL_Reg json_module_functions[] = {
   629   {"object", json_object},
   630   {"array", json_array},
   631   {"import", json_import},
   632   {"get", json_get},
   633   {"type", json_type},
   634   {"isnull", json_isnull},
   635   {"setnull", json_setnull},
   636   {NULL, NULL}
   637 };
   639 static const struct luaL_Reg json_metatable_functions[] = {
   640   {"__len", json_len},
   641   {"__index", json_index},
   642   {"__newindex", json_newindex},
   643   {"__pairs", json_pairs},
   644   {"__ipairs", json_ipairs},
   645   {NULL, NULL}
   646 };
   648 int luaopen_json(lua_State *L) {
   649   lua_settop(L, 0);
   650   lua_newtable(L);  // library
   651   lua_newtable(L);
   652   luaL_setfuncs(L, json_metatable_functions, 0);
   653   json_regstore(L, json_unknownmt);
   654   lua_setfield(L, 1, "ambiguous_mt");
   655   lua_newtable(L);
   656   luaL_setfuncs(L, json_metatable_functions, 0);
   657   json_regstore(L, json_objectmt);
   658   lua_setfield(L, 1, "object_mt");
   659   lua_newtable(L);
   660   luaL_setfuncs(L, json_metatable_functions, 0);
   661   json_regstore(L, json_arraymt);
   662   lua_setfield(L, 1, "array_mt");
   663   lua_newtable(L);  // ephemeron table to store shadow tables for each JSON object/array to allow NULL values returned as nil
   664   lua_newtable(L);  // metatable for ephemeron table
   665   lua_pushliteral(L, "__mode");
   666   lua_pushliteral(L, "k");
   667   lua_rawset(L, -3);
   668   lua_setmetatable(L, -2);
   669   json_regstore(L, json_shadowtbl);
   670   lua_newtable(L);
   671   json_regstore(L, json_nullmark);
   672   lua_settop(L, 1);
   673   luaL_setfuncs(L, json_module_functions, 0);
   674   return 1;
   675 }
