webmcp

view libraries/json/json.c @ 140:641619d3fcb1

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

Impressum / About Us