webmcp
changeset 121:9ad1165cf3a1
Started work on a JSON library
author | jbe |
---|---|
date | Fri Jul 25 22:25:53 2014 +0200 (2014-07-25) |
parents | b07438523a9d |
children | ff39d4a310b9 |
files | libraries/json/Makefile libraries/json/json.c |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/libraries/json/Makefile Fri Jul 25 22:25:53 2014 +0200 1.3 @@ -0,0 +1,10 @@ 1.4 +include ../../Makefile.options 1.5 + 1.6 +json.so: json.o 1.7 + $(LD) $(LDFLAGS) -o json.$(SLIB_EXT) json.o 1.8 + 1.9 +json.o: json.c 1.10 + $(CC) -c $(CFLAGS) -o json.o json.c 1.11 + 1.12 +clean:: 1.13 + rm -f json.so json.o
2.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 2.2 +++ b/libraries/json/json.c Fri Jul 25 22:25:53 2014 +0200 2.3 @@ -0,0 +1,209 @@ 2.4 +#include <lua.h> 2.5 +#include <lauxlib.h> 2.6 +#include <string.h> 2.7 + 2.8 +#define JSON_VALUE 0 2.9 +#define JSON_OBJECT_KEY 1 2.10 +#define JSON_OBJECT_KEY_TERMINATOR 2 2.11 +#define JSON_OBJECT_VALUE 3 2.12 +#define JSON_OBJECT_SEPARATOR 4 2.13 +#define JSON_ARRAY_VALUE 5 2.14 +#define JSON_ARRAY_SEPARATOR 6 2.15 +#define JSON_END 7 2.16 + 2.17 +static int json_import(lua_State *L) { 2.18 + const char *str; 2.19 + size_t total; 2.20 + size_t pos = 0; 2.21 + size_t level = 0; 2.22 + int mode = JSON_VALUE; 2.23 + char c; 2.24 + luaL_Buffer luabuf; 2.25 + char *cbuf; 2.26 + size_t writepos; 2.27 + int aryidx; 2.28 + lua_settop(L, 1); 2.29 + str = lua_tostring(L, 1); 2.30 + total = strlen(str); 2.31 +json_import_loop: 2.32 + while (c = str[pos], c == ' ' || c == '\n' || c == '\r' || c == '\t' || c == '\f') pos++; 2.33 + switch (c) { 2.34 + case 0: 2.35 + if (mode == JSON_END) return 1; 2.36 + json_import_unexpected_eof: 2.37 + lua_pushnil(L); 2.38 + if (level == 0) lua_pushliteral(L, "Empty string"); 2.39 + else lua_pushliteral(L, "Unexpected end of JSON document"); 2.40 + return 2; 2.41 + case '{': 2.42 + if (mode != JSON_VALUE && mode != JSON_OBJECT_VALUE && mode != JSON_ARRAY_VALUE) 2.43 + goto json_import_syntax_error; 2.44 + pos++; 2.45 + lua_newtable(L); 2.46 + mode = JSON_OBJECT_KEY; 2.47 + level++; 2.48 + goto json_import_loop; 2.49 + case '[': 2.50 + if (mode != JSON_VALUE && mode != JSON_OBJECT_VALUE && mode != JSON_ARRAY_VALUE) 2.51 + goto json_import_syntax_error; 2.52 + pos++; 2.53 + lua_newtable(L); 2.54 + lua_pushinteger(L, 0); // length of array (since it may contain nil's) 2.55 + mode = JSON_ARRAY_VALUE; 2.56 + level++; 2.57 + goto json_import_loop; 2.58 + case '}': 2.59 + if (mode != JSON_OBJECT_KEY && mode != JSON_OBJECT_SEPARATOR) 2.60 + goto json_import_syntax_error; 2.61 + goto json_import_close; 2.62 + case ']': 2.63 + if (mode != JSON_ARRAY_VALUE && mode != JSON_ARRAY_SEPARATOR) 2.64 + goto json_import_syntax_error; 2.65 + lua_pushvalue(L, -2); // use array table as key 2.66 + lua_insert(L, -2); // use length of array as value 2.67 + lua_rawset(L, lua_upvalueindex(1)); // store length in ephemeron table 2.68 + // leaves array table on top of stack 2.69 + json_import_close: 2.70 + pos++; 2.71 + if (--level) { 2.72 + if (lua_type(L, -2) == LUA_TNUMBER) { 2.73 + mode = JSON_ARRAY_VALUE; 2.74 + } else { 2.75 + mode = JSON_OBJECT_VALUE; 2.76 + } 2.77 + goto json_import_process_value; 2.78 + } else { 2.79 + mode = JSON_END; 2.80 + } 2.81 + goto json_import_loop; 2.82 + case ':': 2.83 + if (mode != JSON_OBJECT_KEY_TERMINATOR) 2.84 + goto json_import_syntax_error; 2.85 + pos++; 2.86 + mode = JSON_OBJECT_VALUE; 2.87 + goto json_import_loop; 2.88 + case ',': 2.89 + if (mode == JSON_OBJECT_SEPARATOR) { 2.90 + mode = JSON_OBJECT_KEY; 2.91 + } else if (mode == JSON_ARRAY_SEPARATOR) { 2.92 + mode = JSON_ARRAY_VALUE; 2.93 + } else { 2.94 + goto json_import_syntax_error; 2.95 + } 2.96 + pos++; 2.97 + goto json_import_loop; 2.98 + case '"': 2.99 + cbuf = luaL_buffinitsize(L, &luabuf, total-pos); 2.100 + writepos = 0; 2.101 + pos++; 2.102 + while ((c = str[pos++]) != '"') { 2.103 + if (c == 0) { 2.104 + goto json_import_unexpected_eof; 2.105 + } else if (c < 32 || c == 127) { 2.106 + lua_pushnil(L); 2.107 + lua_pushliteral(L, "Unexpected control character in JSON string"); 2.108 + return 2; 2.109 + } else if (c == '\\') { 2.110 + c = str[pos++]; 2.111 + switch (c) { 2.112 + case 0: 2.113 + goto json_import_unexpected_eof; 2.114 + case '"': 2.115 + case '/': 2.116 + case '\\': 2.117 + cbuf[writepos++] = c; 2.118 + break; 2.119 + case 'b': 2.120 + cbuf[writepos++] = '\b'; 2.121 + break; 2.122 + case 'f': 2.123 + cbuf[writepos++] = '\f'; 2.124 + break; 2.125 + case 'n': 2.126 + cbuf[writepos++] = '\n'; 2.127 + break; 2.128 + case 'r': 2.129 + cbuf[writepos++] = '\r'; 2.130 + break; 2.131 + case 't': 2.132 + cbuf[writepos++] = '\t'; 2.133 + break; 2.134 + case 'u': 2.135 + lua_pushnil(L); 2.136 + lua_pushliteral(L, "JSON unicode escape sequences are not implemented yet"); // TODO 2.137 + return 2; 2.138 + default: 2.139 + lua_pushnil(L); 2.140 + lua_pushliteral(L, "Unexpected string escape sequence in JSON document"); 2.141 + return 2; 2.142 + } 2.143 + } else { 2.144 + cbuf[writepos++] = c; 2.145 + } 2.146 + } 2.147 + if (!c) goto json_import_unexpected_eof; 2.148 + luaL_pushresultsize(&luabuf, writepos); 2.149 + goto json_import_process_value; 2.150 + } 2.151 + if (!strncmp(str+pos, "true", 4)) { 2.152 + lua_pushboolean(L, 1); 2.153 + pos += 4; 2.154 + } else if (!strncmp(str+pos, "false", 5)) { 2.155 + lua_pushboolean(L, 0); 2.156 + pos += 5; 2.157 + } else if (!strncmp(str+pos, "null", 4)) { 2.158 + lua_pushnil(L); 2.159 + pos += 4; 2.160 + } else { 2.161 + goto json_import_syntax_error; 2.162 + } 2.163 +json_import_process_value: 2.164 + switch (mode) { 2.165 + case JSON_OBJECT_KEY: 2.166 + if (lua_type(L, -1) != LUA_TSTRING) goto json_import_syntax_error; 2.167 + mode = JSON_OBJECT_KEY_TERMINATOR; 2.168 + goto json_import_loop; 2.169 + case JSON_OBJECT_VALUE: 2.170 + lua_rawset(L, -3); 2.171 + mode = JSON_OBJECT_SEPARATOR; 2.172 + goto json_import_loop; 2.173 + case JSON_ARRAY_VALUE: 2.174 + aryidx = lua_tointeger(L, -2) + 1; 2.175 + lua_rawseti(L, -3, aryidx); 2.176 + lua_pop(L, 1); 2.177 + lua_pushinteger(L, aryidx); 2.178 + mode = JSON_ARRAY_SEPARATOR; 2.179 + goto json_import_loop; 2.180 + case JSON_VALUE: 2.181 + mode = JSON_END; 2.182 + goto json_import_loop; 2.183 + } 2.184 +json_import_syntax_error: 2.185 + lua_pushnil(L); 2.186 + lua_pushliteral(L, "Syntax error in JSON document"); 2.187 + return 2; 2.188 +} 2.189 + 2.190 +static int json_arylen(lua_State *L) { 2.191 + lua_settop(L, 1); 2.192 + lua_rawget(L, lua_upvalueindex(1)); 2.193 + return 1; 2.194 +} 2.195 + 2.196 +static const struct luaL_Reg json_module_functions[] = { 2.197 + {"import", json_import}, 2.198 + {"arylen", json_arylen}, 2.199 + {NULL, NULL} 2.200 +}; 2.201 + 2.202 +int luaopen_json(lua_State *L) { 2.203 + lua_newtable(L); // library table 2.204 + lua_newtable(L); // ephemeron table to store the length of arrays (that may contain nil's) 2.205 + lua_newtable(L); // meta table for ephemeron table 2.206 + lua_pushliteral(L, "__mode"); 2.207 + lua_pushliteral(L, "k"); 2.208 + lua_rawset(L, -3); 2.209 + lua_setmetatable(L, -2); 2.210 + luaL_setfuncs(L, json_module_functions, 1); 2.211 + return 1; 2.212 +}