webmcp
diff libraries/json/json.c @ 121:9ad1165cf3a1
Started work on a JSON library
author | jbe |
---|---|
date | Fri Jul 25 22:25:53 2014 +0200 (2014-07-25) |
parents | |
children | ff39d4a310b9 |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/libraries/json/json.c Fri Jul 25 22:25:53 2014 +0200 1.3 @@ -0,0 +1,209 @@ 1.4 +#include <lua.h> 1.5 +#include <lauxlib.h> 1.6 +#include <string.h> 1.7 + 1.8 +#define JSON_VALUE 0 1.9 +#define JSON_OBJECT_KEY 1 1.10 +#define JSON_OBJECT_KEY_TERMINATOR 2 1.11 +#define JSON_OBJECT_VALUE 3 1.12 +#define JSON_OBJECT_SEPARATOR 4 1.13 +#define JSON_ARRAY_VALUE 5 1.14 +#define JSON_ARRAY_SEPARATOR 6 1.15 +#define JSON_END 7 1.16 + 1.17 +static int json_import(lua_State *L) { 1.18 + const char *str; 1.19 + size_t total; 1.20 + size_t pos = 0; 1.21 + size_t level = 0; 1.22 + int mode = JSON_VALUE; 1.23 + char c; 1.24 + luaL_Buffer luabuf; 1.25 + char *cbuf; 1.26 + size_t writepos; 1.27 + int aryidx; 1.28 + lua_settop(L, 1); 1.29 + str = lua_tostring(L, 1); 1.30 + total = strlen(str); 1.31 +json_import_loop: 1.32 + while (c = str[pos], c == ' ' || c == '\n' || c == '\r' || c == '\t' || c == '\f') pos++; 1.33 + switch (c) { 1.34 + case 0: 1.35 + if (mode == JSON_END) return 1; 1.36 + json_import_unexpected_eof: 1.37 + lua_pushnil(L); 1.38 + if (level == 0) lua_pushliteral(L, "Empty string"); 1.39 + else lua_pushliteral(L, "Unexpected end of JSON document"); 1.40 + return 2; 1.41 + case '{': 1.42 + if (mode != JSON_VALUE && mode != JSON_OBJECT_VALUE && mode != JSON_ARRAY_VALUE) 1.43 + goto json_import_syntax_error; 1.44 + pos++; 1.45 + lua_newtable(L); 1.46 + mode = JSON_OBJECT_KEY; 1.47 + level++; 1.48 + goto json_import_loop; 1.49 + case '[': 1.50 + if (mode != JSON_VALUE && mode != JSON_OBJECT_VALUE && mode != JSON_ARRAY_VALUE) 1.51 + goto json_import_syntax_error; 1.52 + pos++; 1.53 + lua_newtable(L); 1.54 + lua_pushinteger(L, 0); // length of array (since it may contain nil's) 1.55 + mode = JSON_ARRAY_VALUE; 1.56 + level++; 1.57 + goto json_import_loop; 1.58 + case '}': 1.59 + if (mode != JSON_OBJECT_KEY && mode != JSON_OBJECT_SEPARATOR) 1.60 + goto json_import_syntax_error; 1.61 + goto json_import_close; 1.62 + case ']': 1.63 + if (mode != JSON_ARRAY_VALUE && mode != JSON_ARRAY_SEPARATOR) 1.64 + goto json_import_syntax_error; 1.65 + lua_pushvalue(L, -2); // use array table as key 1.66 + lua_insert(L, -2); // use length of array as value 1.67 + lua_rawset(L, lua_upvalueindex(1)); // store length in ephemeron table 1.68 + // leaves array table on top of stack 1.69 + json_import_close: 1.70 + pos++; 1.71 + if (--level) { 1.72 + if (lua_type(L, -2) == LUA_TNUMBER) { 1.73 + mode = JSON_ARRAY_VALUE; 1.74 + } else { 1.75 + mode = JSON_OBJECT_VALUE; 1.76 + } 1.77 + goto json_import_process_value; 1.78 + } else { 1.79 + mode = JSON_END; 1.80 + } 1.81 + goto json_import_loop; 1.82 + case ':': 1.83 + if (mode != JSON_OBJECT_KEY_TERMINATOR) 1.84 + goto json_import_syntax_error; 1.85 + pos++; 1.86 + mode = JSON_OBJECT_VALUE; 1.87 + goto json_import_loop; 1.88 + case ',': 1.89 + if (mode == JSON_OBJECT_SEPARATOR) { 1.90 + mode = JSON_OBJECT_KEY; 1.91 + } else if (mode == JSON_ARRAY_SEPARATOR) { 1.92 + mode = JSON_ARRAY_VALUE; 1.93 + } else { 1.94 + goto json_import_syntax_error; 1.95 + } 1.96 + pos++; 1.97 + goto json_import_loop; 1.98 + case '"': 1.99 + cbuf = luaL_buffinitsize(L, &luabuf, total-pos); 1.100 + writepos = 0; 1.101 + pos++; 1.102 + while ((c = str[pos++]) != '"') { 1.103 + if (c == 0) { 1.104 + goto json_import_unexpected_eof; 1.105 + } else if (c < 32 || c == 127) { 1.106 + lua_pushnil(L); 1.107 + lua_pushliteral(L, "Unexpected control character in JSON string"); 1.108 + return 2; 1.109 + } else if (c == '\\') { 1.110 + c = str[pos++]; 1.111 + switch (c) { 1.112 + case 0: 1.113 + goto json_import_unexpected_eof; 1.114 + case '"': 1.115 + case '/': 1.116 + case '\\': 1.117 + cbuf[writepos++] = c; 1.118 + break; 1.119 + case 'b': 1.120 + cbuf[writepos++] = '\b'; 1.121 + break; 1.122 + case 'f': 1.123 + cbuf[writepos++] = '\f'; 1.124 + break; 1.125 + case 'n': 1.126 + cbuf[writepos++] = '\n'; 1.127 + break; 1.128 + case 'r': 1.129 + cbuf[writepos++] = '\r'; 1.130 + break; 1.131 + case 't': 1.132 + cbuf[writepos++] = '\t'; 1.133 + break; 1.134 + case 'u': 1.135 + lua_pushnil(L); 1.136 + lua_pushliteral(L, "JSON unicode escape sequences are not implemented yet"); // TODO 1.137 + return 2; 1.138 + default: 1.139 + lua_pushnil(L); 1.140 + lua_pushliteral(L, "Unexpected string escape sequence in JSON document"); 1.141 + return 2; 1.142 + } 1.143 + } else { 1.144 + cbuf[writepos++] = c; 1.145 + } 1.146 + } 1.147 + if (!c) goto json_import_unexpected_eof; 1.148 + luaL_pushresultsize(&luabuf, writepos); 1.149 + goto json_import_process_value; 1.150 + } 1.151 + if (!strncmp(str+pos, "true", 4)) { 1.152 + lua_pushboolean(L, 1); 1.153 + pos += 4; 1.154 + } else if (!strncmp(str+pos, "false", 5)) { 1.155 + lua_pushboolean(L, 0); 1.156 + pos += 5; 1.157 + } else if (!strncmp(str+pos, "null", 4)) { 1.158 + lua_pushnil(L); 1.159 + pos += 4; 1.160 + } else { 1.161 + goto json_import_syntax_error; 1.162 + } 1.163 +json_import_process_value: 1.164 + switch (mode) { 1.165 + case JSON_OBJECT_KEY: 1.166 + if (lua_type(L, -1) != LUA_TSTRING) goto json_import_syntax_error; 1.167 + mode = JSON_OBJECT_KEY_TERMINATOR; 1.168 + goto json_import_loop; 1.169 + case JSON_OBJECT_VALUE: 1.170 + lua_rawset(L, -3); 1.171 + mode = JSON_OBJECT_SEPARATOR; 1.172 + goto json_import_loop; 1.173 + case JSON_ARRAY_VALUE: 1.174 + aryidx = lua_tointeger(L, -2) + 1; 1.175 + lua_rawseti(L, -3, aryidx); 1.176 + lua_pop(L, 1); 1.177 + lua_pushinteger(L, aryidx); 1.178 + mode = JSON_ARRAY_SEPARATOR; 1.179 + goto json_import_loop; 1.180 + case JSON_VALUE: 1.181 + mode = JSON_END; 1.182 + goto json_import_loop; 1.183 + } 1.184 +json_import_syntax_error: 1.185 + lua_pushnil(L); 1.186 + lua_pushliteral(L, "Syntax error in JSON document"); 1.187 + return 2; 1.188 +} 1.189 + 1.190 +static int json_arylen(lua_State *L) { 1.191 + lua_settop(L, 1); 1.192 + lua_rawget(L, lua_upvalueindex(1)); 1.193 + return 1; 1.194 +} 1.195 + 1.196 +static const struct luaL_Reg json_module_functions[] = { 1.197 + {"import", json_import}, 1.198 + {"arylen", json_arylen}, 1.199 + {NULL, NULL} 1.200 +}; 1.201 + 1.202 +int luaopen_json(lua_State *L) { 1.203 + lua_newtable(L); // library table 1.204 + lua_newtable(L); // ephemeron table to store the length of arrays (that may contain nil's) 1.205 + lua_newtable(L); // meta table for ephemeron table 1.206 + lua_pushliteral(L, "__mode"); 1.207 + lua_pushliteral(L, "k"); 1.208 + lua_rawset(L, -3); 1.209 + lua_setmetatable(L, -2); 1.210 + luaL_setfuncs(L, json_module_functions, 1); 1.211 + return 1; 1.212 +}