8 static void jsonnext(js_State *J)
10 J->lookahead = jsY_lexjson(J);
13 static int jsonaccept(js_State *J, int t)
15 if (J->lookahead == t) {
22 static void jsonexpect(js_State *J, int t)
24 if (!jsonaccept(J, t))
25 js_syntaxerror(J, "JSON: unexpected token: %s (expected %s)",
26 jsY_tokenstring(J->lookahead), jsY_tokenstring(t));
29 static void jsonvalue(js_State *J)
34 switch (J->lookahead) {
36 js_pushliteral(J, J->text);
41 js_pushnumber(J, J->number);
48 if (jsonaccept(J, '}'))
51 if (J->lookahead != TK_STRING)
52 js_syntaxerror(J, "JSON: unexpected token: %s (expected string)", jsY_tokenstring(J->lookahead));
57 js_setproperty(J, -2, name);
58 } while (jsonaccept(J, ','));
66 if (jsonaccept(J, ']'))
70 js_setindex(J, -2, i++);
71 } while (jsonaccept(J, ','));
91 js_syntaxerror(J, "JSON: unexpected token: %s", jsY_tokenstring(J->lookahead));
95 static void JSON_parse(js_State *J)
97 const char *source = js_tostring(J, 1);
98 jsY_initlex(J, "JSON", source);
101 // TODO: reviver Walk()
104 static void fmtnum(js_State *J, js_Buffer **sb, double n)
106 if (isnan(n)) js_puts(J, sb, "null");
107 else if (isinf(n)) js_puts(J, sb, "null");
108 else if (n == 0) js_puts(J, sb, "0");
111 sprintf(buf, "%.17g", n);
116 static void fmtstr(js_State *J, js_Buffer **sb, const char *s)
118 static const char *HEX = "0123456789ABCDEF";
122 s += chartorune(&c, s);
124 case '"': js_puts(J, sb, "\\\""); break;
125 case '\\': js_puts(J, sb, "\\\\"); break;
126 case '\b': js_puts(J, sb, "\\b"); break;
127 case '\f': js_puts(J, sb, "\\f"); break;
128 case '\n': js_puts(J, sb, "\\n"); break;
129 case '\r': js_puts(J, sb, "\\r"); break;
130 case '\t': js_puts(J, sb, "\\t"); break;
133 js_puts(J, sb, "\\u");
134 js_putc(J, sb, HEX[(c>>12)&15]);
135 js_putc(J, sb, HEX[(c>>8)&15]);
136 js_putc(J, sb, HEX[(c>>4)&15]);
137 js_putc(J, sb, HEX[c&15]);
139 js_putc(J, sb, c); break;
146 static void fmtindent(js_State *J, js_Buffer **sb, const char *gap, int level)
148 js_putc(J, sb, '\n');
153 static int fmtvalue(js_State *J, js_Buffer **sb, const char *key, const char *gap, int level);
155 static void fmtobject(js_State *J, js_Buffer **sb, js_Object *obj, const char *gap, int level)
162 for (ref = obj->head; ref; ref = ref->next) {
163 if (ref->atts & JS_DONTENUM)
166 if (n) js_putc(J, sb, ',');
167 if (gap) fmtindent(J, sb, gap, level + 1);
168 fmtstr(J, sb, ref->name);
172 js_pushvalue(J, ref->value);
173 if (!fmtvalue(J, sb, ref->name, gap, level + 1))
179 if (gap && n) fmtindent(J, sb, gap, level);
183 static void fmtarray(js_State *J, js_Buffer **sb, const char *gap, int level)
188 n = js_getlength(J, -1);
191 for (k = 0; k < n; ++k) {
192 if (k) js_putc(J, sb, ',');
193 if (gap) fmtindent(J, sb, gap, level + 1);
195 js_getproperty(J, -1, buf);
196 if (!fmtvalue(J, sb, js_intern(J, buf), gap, level + 1))
197 js_puts(J, sb, "null");
200 if (gap && n) fmtindent(J, sb, gap, level);
204 static int fmtvalue(js_State *J, js_Buffer **sb, const char *key, const char *gap, int level)
210 if (js_isobject(J, -1)) {
211 if (js_hasproperty(J, -1, "toJSON")) {
212 if (js_iscallable(J, -1)) {
214 js_pushliteral(J, key);
226 if (js_isobject(J, -1) && !js_iscallable(J, -1)) {
227 js_Object *obj = js_toobject(J, -1);
229 case JS_CNUMBER: fmtnum(J, sb, obj->u.number); break;
230 case JS_CSTRING: fmtstr(J, sb, obj->u.s.string); break;
231 case JS_CBOOLEAN: js_puts(J, sb, obj->u.boolean ? "true" : "false"); break;
232 case JS_CARRAY: fmtarray(J, sb, gap, level); break;
233 default: fmtobject(J, sb, obj, gap, level); break;
236 else if (js_isboolean(J, -1))
237 js_puts(J, sb, js_toboolean(J, -1) ? "true" : "false");
238 else if (js_isnumber(J, -1))
239 fmtnum(J, sb, js_tonumber(J, -1));
240 else if (js_isstring(J, -1))
241 fmtstr(J, sb, js_tostring(J, -1));
242 else if (js_isnull(J, -1))
243 js_puts(J, sb, "null");
250 static void JSON_stringify(js_State *J)
252 js_Buffer *sb = NULL;
259 if (js_isnumber(J, 3)) {
260 n = js_tointeger(J, 3);
265 if (n > 0) gap = buf;
266 } else if (js_isstring(J, 3)) {
267 s = js_tostring(J, 3);
272 if (n > 0) gap = buf;
277 if (js_isdefined(J, 1)) {
279 if (fmtvalue(J, &sb, "", gap, 0)) {
285 js_pushstring(J, sb ? sb->s : "");
294 void jsB_initjson(js_State *J)
296 js_pushobject(J, jsV_newobject(J, JS_CJSON, J->Object_prototype));
298 jsB_propf(J, "parse", JSON_parse, 2);
299 jsB_propf(J, "stringify", JSON_stringify, 3);
301 js_defglobal(J, "JSON", JS_DONTENUM);