webmcp

view libraries/json/json.c @ 122:ff39d4a310b9

Float parser for JSON library (non strict)
author jbe
date Fri Jul 25 22:50:12 2014 +0200 (2014-07-25)
parents 9ad1165cf3a1
children 402fce94f98c
line source
1 #include <lua.h>
2 #include <lauxlib.h>
3 #include <stdlib.h>
4 #include <string.h>
6 #define JSON_VALUE 0
7 #define JSON_OBJECT_KEY 1
8 #define JSON_OBJECT_KEY_TERMINATOR 2
9 #define JSON_OBJECT_VALUE 3
10 #define JSON_OBJECT_SEPARATOR 4
11 #define JSON_ARRAY_VALUE 5
12 #define JSON_ARRAY_SEPARATOR 6
13 #define JSON_END 7
15 static int json_import(lua_State *L) {
16 const char *str;
17 size_t total;
18 size_t pos = 0;
19 size_t level = 0;
20 int mode = JSON_VALUE;
21 char c;
22 luaL_Buffer luabuf;
23 char *cbuf;
24 size_t writepos;
25 int aryidx;
26 lua_settop(L, 1);
27 str = lua_tostring(L, 1);
28 total = strlen(str);
29 json_import_loop:
30 while (c = str[pos], c == ' ' || c == '\n' || c == '\r' || c == '\t' || c == '\f') pos++;
31 switch (c) {
32 case 0:
33 if (mode == JSON_END) return 1;
34 json_import_unexpected_eof:
35 lua_pushnil(L);
36 if (level == 0) lua_pushliteral(L, "Empty string");
37 else lua_pushliteral(L, "Unexpected end of JSON document");
38 return 2;
39 case '{':
40 if (mode != JSON_VALUE && mode != JSON_OBJECT_VALUE && mode != JSON_ARRAY_VALUE)
41 goto json_import_syntax_error;
42 pos++;
43 lua_newtable(L);
44 mode = JSON_OBJECT_KEY;
45 level++;
46 goto json_import_loop;
47 case '[':
48 if (mode != JSON_VALUE && mode != JSON_OBJECT_VALUE && mode != JSON_ARRAY_VALUE)
49 goto json_import_syntax_error;
50 pos++;
51 lua_newtable(L);
52 lua_pushinteger(L, 0); // length of array (since it may contain nil's)
53 mode = JSON_ARRAY_VALUE;
54 level++;
55 goto json_import_loop;
56 case '}':
57 if (mode != JSON_OBJECT_KEY && mode != JSON_OBJECT_SEPARATOR)
58 goto json_import_syntax_error;
59 goto json_import_close;
60 case ']':
61 if (mode != JSON_ARRAY_VALUE && mode != JSON_ARRAY_SEPARATOR)
62 goto json_import_syntax_error;
63 lua_pushvalue(L, -2); // use array table as key
64 lua_insert(L, -2); // use length of array as value
65 lua_rawset(L, lua_upvalueindex(1)); // store length in ephemeron table
66 // leaves array table on top of stack
67 json_import_close:
68 pos++;
69 if (--level) {
70 if (lua_type(L, -2) == LUA_TNUMBER) {
71 mode = JSON_ARRAY_VALUE;
72 } else {
73 mode = JSON_OBJECT_VALUE;
74 }
75 goto json_import_process_value;
76 } else {
77 mode = JSON_END;
78 }
79 goto json_import_loop;
80 case ':':
81 if (mode != JSON_OBJECT_KEY_TERMINATOR)
82 goto json_import_syntax_error;
83 pos++;
84 mode = JSON_OBJECT_VALUE;
85 goto json_import_loop;
86 case ',':
87 if (mode == JSON_OBJECT_SEPARATOR) {
88 mode = JSON_OBJECT_KEY;
89 } else if (mode == JSON_ARRAY_SEPARATOR) {
90 mode = JSON_ARRAY_VALUE;
91 } else {
92 goto json_import_syntax_error;
93 }
94 pos++;
95 goto json_import_loop;
96 case '"':
97 cbuf = luaL_buffinitsize(L, &luabuf, total-pos);
98 writepos = 0;
99 pos++;
100 while ((c = str[pos++]) != '"') {
101 if (c == 0) {
102 goto json_import_unexpected_eof;
103 } else if (c < 32 || c == 127) {
104 lua_pushnil(L);
105 lua_pushliteral(L, "Unexpected control character in JSON string");
106 return 2;
107 } else if (c == '\\') {
108 c = str[pos++];
109 switch (c) {
110 case 0:
111 goto json_import_unexpected_eof;
112 case '"':
113 case '/':
114 case '\\':
115 cbuf[writepos++] = c;
116 break;
117 case 'b':
118 cbuf[writepos++] = '\b';
119 break;
120 case 'f':
121 cbuf[writepos++] = '\f';
122 break;
123 case 'n':
124 cbuf[writepos++] = '\n';
125 break;
126 case 'r':
127 cbuf[writepos++] = '\r';
128 break;
129 case 't':
130 cbuf[writepos++] = '\t';
131 break;
132 case 'u':
133 lua_pushnil(L);
134 lua_pushliteral(L, "JSON unicode escape sequences are not implemented yet"); // TODO
135 return 2;
136 default:
137 lua_pushnil(L);
138 lua_pushliteral(L, "Unexpected string escape sequence in JSON document");
139 return 2;
140 }
141 } else {
142 cbuf[writepos++] = c;
143 }
144 }
145 if (!c) goto json_import_unexpected_eof;
146 luaL_pushresultsize(&luabuf, writepos);
147 goto json_import_process_value;
148 }
149 if (c == '-' || (c >= '0' && c <= '9')) {
150 char *endptr;
151 double numval;
152 numval = strtod(str+pos, &endptr);
153 if (endptr == str+pos) goto json_import_syntax_error;
154 pos += endptr - (str+pos);
155 lua_pushnumber(L, numval);
156 } else if (!strncmp(str+pos, "true", 4)) {
157 lua_pushboolean(L, 1);
158 pos += 4;
159 } else if (!strncmp(str+pos, "false", 5)) {
160 lua_pushboolean(L, 0);
161 pos += 5;
162 } else if (!strncmp(str+pos, "null", 4)) {
163 lua_pushnil(L);
164 pos += 4;
165 } else {
166 goto json_import_syntax_error;
167 }
168 json_import_process_value:
169 switch (mode) {
170 case JSON_OBJECT_KEY:
171 if (lua_type(L, -1) != LUA_TSTRING) goto json_import_syntax_error;
172 mode = JSON_OBJECT_KEY_TERMINATOR;
173 goto json_import_loop;
174 case JSON_OBJECT_VALUE:
175 lua_rawset(L, -3);
176 mode = JSON_OBJECT_SEPARATOR;
177 goto json_import_loop;
178 case JSON_ARRAY_VALUE:
179 aryidx = lua_tointeger(L, -2) + 1;
180 lua_rawseti(L, -3, aryidx);
181 lua_pop(L, 1);
182 lua_pushinteger(L, aryidx);
183 mode = JSON_ARRAY_SEPARATOR;
184 goto json_import_loop;
185 case JSON_VALUE:
186 mode = JSON_END;
187 goto json_import_loop;
188 }
189 json_import_syntax_error:
190 lua_pushnil(L);
191 lua_pushliteral(L, "Syntax error in JSON document");
192 return 2;
193 }
195 static int json_arylen(lua_State *L) {
196 lua_settop(L, 1);
197 lua_rawget(L, lua_upvalueindex(1));
198 return 1;
199 }
201 static const struct luaL_Reg json_module_functions[] = {
202 {"import", json_import},
203 {"arylen", json_arylen},
204 {NULL, NULL}
205 };
207 int luaopen_json(lua_State *L) {
208 lua_newtable(L); // library table
209 lua_newtable(L); // ephemeron table to store the length of arrays (that may contain nil's)
210 lua_newtable(L); // meta table for ephemeron table
211 lua_pushliteral(L, "__mode");
212 lua_pushliteral(L, "k");
213 lua_rawset(L, -3);
214 lua_setmetatable(L, -2);
215 luaL_setfuncs(L, json_module_functions, 1);
216 return 1;
217 }

Impressum / About Us