ref: e676a871f07b0d80c6791a2db0b4b361f277d8e8
parent: 8e7d57959c9c69930d4cc5df8130ae4ebb87e5c0
author: Tor Andersson <tor.andersson@gmail.com>
date: Wed Apr 19 12:14:26 EDT 2017
JSON.stringify replacer callback.
--- a/json.c
+++ b/json.c
@@ -33,7 +33,7 @@
switch (J->lookahead) {
case TK_STRING:
- js_pushliteral(J, J->text);
+ js_pushstring(J, J->text);
jsonnext(J);
break;
@@ -208,27 +208,28 @@
static void fmtobject(js_State *J, js_Buffer **sb, js_Object *obj, const char *gap, int level)
{
- js_Property *ref;
+ const char *key;
int save;
int n = 0;
+ /* TODO: check stack for duplicate value (cyclical structure) */
+
js_putc(J, sb, '{');
- for (ref = obj->head; ref; ref = ref->next) {
- if (ref->atts & JS_DONTENUM)
- continue;
+ js_pushiterator(J, -1, 1);
+ while ((key = js_nextiterator(J, -1))) {
save = (*sb)->n;
if (n) js_putc(J, sb, ',');
if (gap) fmtindent(J, sb, gap, level + 1);
- fmtstr(J, sb, ref->name);
+ fmtstr(J, sb, key);
js_putc(J, sb, ':');
if (gap)
js_putc(J, sb, ' ');
- js_pushvalue(J, ref->value);
- if (!fmtvalue(J, sb, ref->name, gap, level + 1))
+ js_rot2(J);
+ if (!fmtvalue(J, sb, key, gap, level + 1))
(*sb)->n = save;
else
++n;
- js_pop(J, 1);
+ js_rot2(J);
}
if (gap && n) fmtindent(J, sb, gap, level);
js_putc(J, sb, '}');
@@ -239,17 +240,15 @@
int n, k;
char buf[32];
- n = js_getlength(J, -1);
+ /* TODO: check stack for duplicate value (cyclical structure) */
js_putc(J, sb, '[');
+ n = js_getlength(J, -1);
for (k = 0; k < n; ++k) {
if (k) js_putc(J, sb, ',');
if (gap) fmtindent(J, sb, gap, level + 1);
- js_itoa(buf, k);
- js_getproperty(J, -1, buf);
- if (!fmtvalue(J, sb, js_intern(J, buf), gap, level + 1))
+ if (!fmtvalue(J, sb, js_itoa(buf, k), gap, level + 1))
js_puts(J, sb, "null");
- js_pop(J, 1);
}
if (gap && n) fmtindent(J, sb, gap, level);
js_putc(J, sb, ']');
@@ -257,15 +256,16 @@
static int fmtvalue(js_State *J, js_Buffer **sb, const char *key, const char *gap, int level)
{
- if (js_try(J)) {
- js_free(J, *sb);
- js_throw(J);
- }
+ /* replacer is in 2 */
+ /* holder is in -1 */
+
+ js_getproperty(J, -1, key);
+
if (js_isobject(J, -1)) {
if (js_hasproperty(J, -1, "toJSON")) {
if (js_iscallable(J, -1)) {
js_copy(J, -2);
- js_pushliteral(J, key);
+ js_pushstring(J, key);
js_call(J, 1);
js_rot2pop1(J);
} else {
@@ -273,9 +273,15 @@
}
}
}
- js_endtry(J);
- /* TODO: replacer() */
+ if (js_iscallable(J, 2)) {
+ js_copy(J, 2); /* replacer function */
+ js_copy(J, -3); /* holder as this */
+ js_pushstring(J, key); /* name */
+ js_copy(J, -4); /* old value */
+ js_call(J, 2);
+ js_rot2pop1(J); /* pop old value, leave new value on stack */
+ }
if (js_isobject(J, -1) && !js_iscallable(J, -1)) {
js_Object *obj = js_toobject(J, -1);
@@ -295,9 +301,12 @@
fmtstr(J, sb, js_tostring(J, -1));
else if (js_isnull(J, -1))
js_puts(J, sb, "null");
- else
+ else {
+ js_pop(J, 1);
return 0;
+ }
+ js_pop(J, 1);
return 1;
}
@@ -326,23 +335,24 @@
if (n > 0) gap = buf;
}
- /* TODO: replacer */
+ if (js_try(J)) {
+ js_free(J, sb);
+ js_throw(J);
+ }
- if (js_isdefined(J, 1)) {
- js_copy(J, 1);
- if (fmtvalue(J, &sb, "", gap, 0)) {
- js_putc(J, &sb, 0);
- if (js_try(J)) {
- js_free(J, sb);
- js_throw(J);
- }
- js_pushstring(J, sb ? sb->s : "");
- js_endtry(J);
- js_free(J, sb);
- }
- } else {
+ js_newobject(J); /* wrapper */
+ js_copy(J, 1);
+ js_defproperty(J, -2, "", 0);
+ if (!fmtvalue(J, &sb, "", gap, 0)) {
js_pushundefined(J);
+ } else {
+ js_putc(J, &sb, 0);
+ js_pushstring(J, sb ? sb->s : "");
+ js_rot2pop1(J);
}
+
+ js_endtry(J);
+ js_free(J, sb);
}
void jsB_initjson(js_State *J)