shithub: libmujs

Download patch

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)