webmcp

changeset 146:7912a05ebc3f

Moved lua_pop(L, 1) call to conditional expression and added documentation in JSON library
author jbe
date Wed Jul 30 20:54:42 2014 +0200 (2014-07-30)
parents 0edc2f05c66a
children da5ab2c226dc
files libraries/json/json.c
line diff
     1.1 --- a/libraries/json/json.c	Wed Jul 30 19:59:11 2014 +0200
     1.2 +++ b/libraries/json/json.c	Wed Jul 30 20:54:42 2014 +0200
     1.3 @@ -15,10 +15,9 @@
     1.4  #define json_regfetch(L, x) (json_regfetchpointer(L, json_regpointer(x)))
     1.5  #define json_regstore(L, x) (lua_pushlightuserdata(L, json_regpointer(x)), lua_pushvalue(L, -2), lua_rawset(L, LUA_REGISTRYINDEX));
     1.6  
     1.7 -// generate dummy memory addresses that represent Lua objects
     1.8 -// directly via lightuserdata values (not using the Lua registry):
     1.9 +// generate dummy memory addresses that represent non-modifiable lightuserdata (dummy) objects:
    1.10  static struct {
    1.11 -  JSON_REGENT nullmark;  // magic value to indicate JSON null value
    1.12 +  JSON_REGENT nullmark;  // magic value to indicate JSON null value in shadow table
    1.13  } json_reference;
    1.14  
    1.15  
    1.16 @@ -132,7 +131,14 @@
    1.17    // main loop of parser:
    1.18    json_import_loop:
    1.19    // skip whitespace and store next character in variable 'c':
    1.20 -  while (c = str[pos], c == ' ' || c == '\n' || c == '\r' || c == '\t' || c == '\f') pos++;
    1.21 +  while (c = str[pos],
    1.22 +    c == ' ' ||
    1.23 +    c == '\f' ||
    1.24 +    c == '\n' ||
    1.25 +    c == '\r' ||
    1.26 +    c == '\t' ||
    1.27 +    c == '\v'
    1.28 +  ) pos++;
    1.29    // switch statement to handle certain (single) characters:
    1.30    switch (c) {
    1.31    // handle end of JSON document:
    1.32 @@ -148,8 +154,11 @@
    1.33    // new JSON object:
    1.34    case '{':
    1.35      // if a JSON object is not expected here, then return an error:
    1.36 -    if (mode != JSON_STATE_VALUE && mode != JSON_STATE_OBJECT_VALUE && mode != JSON_STATE_ARRAY_VALUE)
    1.37 -      goto json_import_syntax_error;
    1.38 +    if (
    1.39 +      mode != JSON_STATE_VALUE &&
    1.40 +      mode != JSON_STATE_OBJECT_VALUE &&
    1.41 +      mode != JSON_STATE_ARRAY_VALUE
    1.42 +    ) goto json_import_syntax_error;
    1.43      // create JSON object on stack:
    1.44      lua_newtable(L);
    1.45      // set metatable of JSON object:
    1.46 @@ -157,18 +166,22 @@
    1.47      lua_setmetatable(L, -2);
    1.48      // create internal shadow table on stack:
    1.49      lua_newtable(L);
    1.50 -    // register internal shadow table (and cleanup stack afterwards):
    1.51 +    // register internal shadow table:
    1.52      lua_pushvalue(L, -2);
    1.53      lua_pushvalue(L, -2);
    1.54      lua_rawset(L, json_import_shadowtbl_idx);
    1.55 -    // expect object key (or end of object) and continue with loop:
    1.56 +    // expect object key (or end of object) to follow:
    1.57      mode = JSON_STATE_OBJECT_KEY;
    1.58 +    // jump to common code for opening JSON object and JSON array:
    1.59      goto json_import_open;
    1.60    // new JSON array:
    1.61    case '[':
    1.62      // if a JSON array is not expected here, then return an error:
    1.63 -    if (mode != JSON_STATE_VALUE && mode != JSON_STATE_OBJECT_VALUE && mode != JSON_STATE_ARRAY_VALUE)
    1.64 -      goto json_import_syntax_error;
    1.65 +    if (
    1.66 +      mode != JSON_STATE_VALUE &&
    1.67 +      mode != JSON_STATE_OBJECT_VALUE &&
    1.68 +      mode != JSON_STATE_ARRAY_VALUE
    1.69 +    ) goto json_import_syntax_error;
    1.70      // create JSON array on stack:
    1.71      lua_newtable(L);
    1.72      // set metatable of JSON array:
    1.73 @@ -176,16 +189,16 @@
    1.74      lua_setmetatable(L, -2);
    1.75      // create internal shadow table on stack:
    1.76      lua_newtable(L);
    1.77 -    // register internal shadow table (and cleanup stack afterwards):
    1.78 +    // register internal shadow table:
    1.79      lua_pushvalue(L, -2);
    1.80      lua_pushvalue(L, -2);
    1.81      lua_rawset(L, json_import_shadowtbl_idx);
    1.82      // add nil as key (needed to keep stack balance) and as magic to detect arrays:
    1.83      lua_pushnil(L);
    1.84 -    // expect array value (or end of array) and continue with loop:
    1.85 +    // expect array value (or end of array) to follow:
    1.86      mode = JSON_STATE_ARRAY_VALUE;
    1.87      // continue with common code for opening JSON object and JSON array:
    1.88 -  // commn code for opening JSON object or JSON array:
    1.89 +  // common code for opening JSON object or JSON array:
    1.90    json_import_open:
    1.91      // limit nested levels:
    1.92      if (level >= JSON_MAXDEPTH) {
    1.93 @@ -204,16 +217,20 @@
    1.94    // end of JSON object:
    1.95    case '}':
    1.96      // if end of JSON object is not expected here, then return an error:
    1.97 -    if (mode != JSON_STATE_OBJECT_KEY && mode != JSON_STATE_OBJECT_SEPARATOR)
    1.98 -      goto json_import_syntax_error;
    1.99 +    if (
   1.100 +      mode != JSON_STATE_OBJECT_KEY &&
   1.101 +      mode != JSON_STATE_OBJECT_SEPARATOR
   1.102 +    ) goto json_import_syntax_error;
   1.103      // jump to common code for end of JSON object and JSON array:
   1.104      goto json_import_close;
   1.105    // end of JSON array:
   1.106    case ']':
   1.107      // if end of JSON array is not expected here, then return an error:
   1.108 -    if (mode != JSON_STATE_ARRAY_VALUE && mode != JSON_STATE_ARRAY_SEPARATOR)
   1.109 -      goto json_import_syntax_error;
   1.110 -    // pop nil key/magic:
   1.111 +    if (
   1.112 +      mode != JSON_STATE_ARRAY_VALUE &&
   1.113 +      mode != JSON_STATE_ARRAY_SEPARATOR
   1.114 +    ) goto json_import_syntax_error;
   1.115 +    // pop nil key/magic (that was needed to keep stack balance):
   1.116      lua_pop(L, 1);
   1.117      // continue with common code for end of JSON object and JSON array:
   1.118    // common code for end of JSON object or JSON array:
   1.119 @@ -224,7 +241,8 @@
   1.120      lua_pop(L, 1);
   1.121      // check if nested:
   1.122      if (--level) {
   1.123 -      // if nested, then check if outer(!) structure is an array or object:
   1.124 +      // if nested,
   1.125 +      // check if outer(!) structure is an array or object:
   1.126        if (lua_isnil(L, -2)) {
   1.127          // select array value processing:
   1.128          mode = JSON_STATE_ARRAY_VALUE;
   1.129 @@ -245,15 +263,18 @@
   1.130        goto json_import_syntax_error;
   1.131      // consume input character:
   1.132      pos++;
   1.133 -    // set state of parser and continue with loop:
   1.134 +    // expect object value to follow:
   1.135      mode = JSON_STATE_OBJECT_VALUE;
   1.136 +    // continue with loop:
   1.137      goto json_import_loop;
   1.138    // value terminator (NOTE: trailing comma at end of value or key-value list is tolerated by this parser)
   1.139    case ',':
   1.140 -    // change parser state accordingly:
   1.141 +    // branch according to parser state:
   1.142      if (mode == JSON_STATE_OBJECT_SEPARATOR) {
   1.143 +      // expect an object key to follow:
   1.144        mode = JSON_STATE_OBJECT_KEY;
   1.145      } else if (mode == JSON_STATE_ARRAY_SEPARATOR) {
   1.146 +      // expect an array value to follow:
   1.147        mode = JSON_STATE_ARRAY_VALUE;
   1.148      } else {
   1.149         // if value terminator is not expected here, then return an error:
   1.150 @@ -265,15 +286,15 @@
   1.151      goto json_import_loop;
   1.152    // string literal:
   1.153    case '"':
   1.154 +    // consume quote character:
   1.155 +    pos++;
   1.156      // prepare buffer to decode string (with maximum possible length) and set write position to zero:
   1.157      cbuf = luaL_buffinitsize(L, &luabuf, total-pos);
   1.158      writepos = 0;
   1.159 -    // consume quote character:
   1.160 -    pos++;
   1.161 -    // read next character until encountering end quote:
   1.162 +    // loop through the characters until encountering end quote:
   1.163      while ((c = str[pos++]) != '"') {
   1.164        if (c == 0) {
   1.165 -        // handle unexpected end-of-string:
   1.166 +        // handle unexpected end of JSON document:
   1.167          goto json_import_unexpected_eof;
   1.168        } else if (c < 32 || c == 127) {
   1.169          // do not allow ASCII control characters:
   1.170 @@ -296,25 +317,15 @@
   1.171            cbuf[writepos++] = c;
   1.172            break;
   1.173          // unescaping of backspace:
   1.174 -        case 'b':
   1.175 -          cbuf[writepos++] = '\b';
   1.176 -          break;
   1.177 +        case 'b': cbuf[writepos++] = '\b'; break;
   1.178          // unescaping of form-feed:
   1.179 -        case 'f':
   1.180 -          cbuf[writepos++] = '\f';
   1.181 -          break;
   1.182 +        case 'f': cbuf[writepos++] = '\f'; break;
   1.183          // unescaping of new-line:
   1.184 -        case 'n':
   1.185 -          cbuf[writepos++] = '\n';
   1.186 -          break;
   1.187 +        case 'n': cbuf[writepos++] = '\n'; break;
   1.188          // unescaping of carriage-return:
   1.189 -        case 'r':
   1.190 -          cbuf[writepos++] = '\r';
   1.191 -          break;
   1.192 +        case 'r': cbuf[writepos++] = '\r'; break;
   1.193          // unescaping of tabulator:
   1.194 -        case 't':
   1.195 -          cbuf[writepos++] = '\t';
   1.196 -          break;
   1.197 +        case 't': cbuf[writepos++] = '\t'; break;
   1.198          // unescaping of UTF-16 characters
   1.199          case 'u':
   1.200            lua_pushnil(L);
   1.201 @@ -338,12 +349,16 @@
   1.202    }
   1.203    // process values whose type is is not deducible from a single character:
   1.204    if ((c >= '0' && c <= '9') || c == '-' || c == '+') {
   1.205 -    // numbers:
   1.206 +    // for numbers,
   1.207 +    // use strtod() call to parse a (double precision) floating point number:
   1.208      char *endptr;
   1.209      double numval;
   1.210      numval = strtod(str+pos, &endptr);
   1.211 +    // catch parsing errors:
   1.212      if (endptr == str+pos) goto json_import_syntax_error;
   1.213 +    // consume characters that were parsed:
   1.214      pos += endptr - (str+pos);
   1.215 +    // push parsed (double precision) floating point number on Lua stack:
   1.216      lua_pushnumber(L, numval);
   1.217    } else if (!strncmp(str+pos, "true", 4)) {
   1.218      // consume 4 input characters for "true":
   1.219 @@ -371,22 +386,25 @@
   1.220    case JSON_STATE_OBJECT_KEY:
   1.221      // if an object key is not a string, then this is a syntax error:
   1.222      if (lua_type(L, -1) != LUA_TSTRING) goto json_import_syntax_error;
   1.223 -    // expect key terminator and continue with loop:
   1.224 +    // expect key terminator to follow:
   1.225      mode = JSON_STATE_OBJECT_KEY_TERMINATOR;
   1.226 +    // continue with loop:
   1.227      goto json_import_loop;
   1.228    // a key value pair has been read:
   1.229    case JSON_STATE_OBJECT_VALUE:
   1.230      // store key value pair in outer shadow table:
   1.231      lua_rawset(L, -3);
   1.232 -    // expect value terminator (or end of object) and continue with loop:
   1.233 +    // expect value terminator (or end of object) to follow:
   1.234      mode = JSON_STATE_OBJECT_SEPARATOR;
   1.235 +    // continue with loop:
   1.236      goto json_import_loop;
   1.237    // an array value has been read:
   1.238    case JSON_STATE_ARRAY_VALUE:
   1.239      // store value in outer shadow table:
   1.240      lua_rawseti(L, -3, lua_rawlen(L, -3) + 1);
   1.241 -    // expect value terminator (or end of object) and continue with loop:
   1.242 +    // expect value terminator (or end of object) to follow:
   1.243      mode = JSON_STATE_ARRAY_SEPARATOR;
   1.244 +    // continue with loop
   1.245      goto json_import_loop;
   1.246    // a single value has been read:
   1.247    case JSON_STATE_VALUE:
   1.248 @@ -394,52 +412,54 @@
   1.249      mode = JSON_STATE_END;
   1.250      goto json_import_loop;
   1.251    }
   1.252 -  // syntax error handling (only reachable by goto statement):
   1.253 +  // syntax error handling (reachable by goto statement):
   1.254    json_import_syntax_error:
   1.255    lua_pushnil(L);
   1.256    lua_pushliteral(L, "Syntax error in JSON document");
   1.257    return 2;
   1.258  }
   1.259  
   1.260 +// special Lua stack indicies for json_path function:
   1.261  #define json_path_shadowtbl_idx 1
   1.262  #define json_path_nullmark_idx 2
   1.263 +
   1.264 +// stack offset of arguments to json_path function:
   1.265  #define json_path_idxshift 2
   1.266  
   1.267 -// gets a value or its type from a JSON document (first argument)
   1.268 -// optionally using a path (variable number of keys after first argument):
   1.269 +// gets a value or its type from a JSON document (passed as first argument)
   1.270 +// optionally using a path (passed as variable number of keys after first argument):
   1.271  static int json_path(lua_State *L, int type_mode) {
   1.272 -  int stacktop;
   1.273 -  int idx = 2 + json_path_idxshift;
   1.274 -  // insert json_shadowtbl on stack at position 1:
   1.275 +  int stacktop;                      // stack index of top of stack (after shifting)
   1.276 +  int idx = 2 + json_path_idxshift;  // stack index of current argument to process
   1.277 +  // insert json_shadowtbl on stack at position 1 (shifting the arguments):
   1.278    json_regfetch(L, shadowtbl);
   1.279    lua_insert(L, 1);
   1.280 -  // insert json_nullmark on stack at position 2:
   1.281 +  // insert json_nullmark on stack at position 2 (shifting the arguments):
   1.282    json_pushlightref(L, nullmark);
   1.283    lua_insert(L, 2);
   1.284 -  // store number of arguments:
   1.285 +  // store stack index of top of stack:
   1.286    stacktop = lua_gettop(L);
   1.287 -  // follow path, starting with first argument as "current value":
   1.288 +  // use first argument as "current value" (stored on top of stack):
   1.289    lua_pushvalue(L, 1 + json_path_idxshift);
   1.290 -  // process each "path key":
   1.291 +  // process each "path key" (2nd argument and following arguments):
   1.292    while (idx <= stacktop) {
   1.293 -    // if "current value" is nil, then the path cannot be walked and nil is returned:
   1.294 +    // if "current value" (on top of stack) is nil, then the path cannot be walked and nil is returned:
   1.295      if (lua_isnil(L, -1)) return 1;
   1.296      // try to get shadow table of "current value":
   1.297      lua_pushvalue(L, -1);
   1.298      lua_rawget(L, json_path_shadowtbl_idx);
   1.299      if (lua_isnil(L, -1)) {
   1.300        // if no shadow table is found,
   1.301 -      // drop nil from stack:
   1.302 -      lua_pop(L, 1);
   1.303        if (lua_type(L, -1) == LUA_TTABLE) {
   1.304 -        // if "current value" is a table,
   1.305 +        // and if "current value" is a table,
   1.306 +        // drop nil from stack:
   1.307 +        lua_pop(L, 1);
   1.308          // get "next value" using the "path key":
   1.309          lua_pushvalue(L, idx++);
   1.310          lua_gettable(L, -2);
   1.311        } else {
   1.312          // if "current value" is not a table,
   1.313 -        // then the path cannot be walked and nil is returned:
   1.314 -        lua_pushnil(L);
   1.315 +        // then the path cannot be walked and nil (already on top of stack) is returned:
   1.316          return 1;
   1.317        }
   1.318      } else {
   1.319 @@ -469,16 +489,19 @@
   1.320        if (lua_getmetatable(L, -1)) {
   1.321          json_regfetch(L, objectmt);
   1.322          if (lua_rawequal(L, -2, -1)) {
   1.323 +          // if value has metatable for JSON objects,
   1.324            // return string "object":
   1.325            lua_pushliteral(L, "object");
   1.326            return 1;
   1.327          }
   1.328          json_regfetch(L, arraymt);
   1.329          if (lua_rawequal(L, -3, -1)) {
   1.330 -          // return string "array":
   1.331 +          // if value has metatable for JSON arrays,
   1.332 +          // return string "object":
   1.333            lua_pushliteral(L, "array");
   1.334            return 1;
   1.335          }
   1.336 +        // remove 3 metatables (one of the value, two for comparison) from stack:
   1.337          lua_pop(L, 3);
   1.338        }
   1.339        // otherwise, get the Lua type:
   1.340 @@ -513,6 +536,7 @@
   1.341    return 1;
   1.342  }
   1.343  
   1.344 +// special Lua stack indicies for json_setnull function:
   1.345  #define json_setnull_unknownmt_idx 3
   1.346  #define json_setnull_objectmt_idx 4
   1.347  #define json_setnull_arraymt_idx 5
   1.348 @@ -562,6 +586,7 @@
   1.349    return 1;
   1.350  }
   1.351  
   1.352 +// special Lua stack indicies for json_index function:
   1.353  #define json_index_nullmark_idx 3
   1.354  #define json_index_shadowtbl_idx 4
   1.355  
   1.356 @@ -590,6 +615,7 @@
   1.357    return 1;
   1.358  }
   1.359  
   1.360 +// special Lua stack indicies for json_pairs_iterfunc function:
   1.361  #define json_pairs_iterfunc_nullmark_idx 3
   1.362  #define json_pairs_iterfunc_shadowtbl_idx 4
   1.363  
   1.364 @@ -616,6 +642,7 @@
   1.365    return 3;
   1.366  }
   1.367  
   1.368 +// special Lua stack indicies for json_ipairs_iterfunc function:
   1.369  #define json_ipairs_iterfunc_nullmark_idx 3
   1.370  #define json_ipairs_iterfunc_shadowtbl_idx 4
   1.371  

Impressum / About Us