414 lines · 8.7 KB · C
RawDownload
#include "jsi.h"#include "jslex.h"#include "jsvalue.h"#include "jsbuiltin.h" #include "utf.h" int js_isnumberobject(js_State *J, int idx){	return js_isobject(J, idx) && js_toobject(J, idx)->type == JS_CNUMBER;} int js_isstringobject(js_State *J, int idx){	return js_isobject(J, idx) && js_toobject(J, idx)->type == JS_CSTRING;} static void jsonnext(js_State *J){	J->lookahead = jsY_lexjson(J);} static int jsonaccept(js_State *J, int t){	if (J->lookahead == t) {		jsonnext(J);		return 1;	}	return 0;} static void jsonexpect(js_State *J, int t){	if (!jsonaccept(J, t))		js_syntaxerror(J, "JSON: unexpected token: %s (expected %s)",				jsY_tokenstring(J->lookahead), jsY_tokenstring(t));} static void jsonvalue(js_State *J){	int i;	const char *name; 	switch (J->lookahead) {	case TK_STRING:		js_pushstring(J, J->text);		jsonnext(J);		break; 	case TK_NUMBER:		js_pushnumber(J, J->number);		jsonnext(J);		break; 	case '{':		js_newobject(J);		jsonnext(J);		if (jsonaccept(J, '}'))			return;		do {			if (J->lookahead != TK_STRING)				js_syntaxerror(J, "JSON: unexpected token: %s (expected string)", jsY_tokenstring(J->lookahead));			name = J->text;			jsonnext(J);			jsonexpect(J, ':');			jsonvalue(J);			js_setproperty(J, -2, name);		} while (jsonaccept(J, ','));		jsonexpect(J, '}');		break; 	case '[':		js_newarray(J);		jsonnext(J);		i = 0;		if (jsonaccept(J, ']'))			return;		do {			jsonvalue(J);			js_setindex(J, -2, i++);		} while (jsonaccept(J, ','));		jsonexpect(J, ']');		break; 	case TK_TRUE:		js_pushboolean(J, 1);		jsonnext(J);		break; 	case TK_FALSE:		js_pushboolean(J, 0);		jsonnext(J);		break; 	case TK_NULL:		js_pushnull(J);		jsonnext(J);		break; 	default:		js_syntaxerror(J, "JSON: unexpected token: %s", jsY_tokenstring(J->lookahead));	}} static void jsonrevive(js_State *J, const char *name){	const char *key;	char buf[32]; 	/* revive is in 2 */	/* holder is in -1 */ 	js_getproperty(J, -1, name); /* get value from holder */ 	if (js_isobject(J, -1)) {		if (js_isarray(J, -1)) {			int i = 0;			int n = js_getlength(J, -1);			for (i = 0; i < n; ++i) {				jsonrevive(J, js_itoa(buf, i));				if (js_isundefined(J, -1)) {					js_pop(J, 1);					js_delproperty(J, -1, buf);				} else {					js_setproperty(J, -2, buf);				}			}		} else {			js_pushiterator(J, -1, 1);			while ((key = js_nextiterator(J, -1))) {				js_rot2(J);				jsonrevive(J, key);				if (js_isundefined(J, -1)) {					js_pop(J, 1);					js_delproperty(J, -1, key);				} else {					js_setproperty(J, -2, key);				}				js_rot2(J);			}			js_pop(J, 1);		}	} 	js_copy(J, 2); /* reviver function */	js_copy(J, -3); /* holder as this */	js_pushstring(J, name); /* name */	js_copy(J, -4); /* value */	js_call(J, 2);	js_rot2pop1(J); /* pop old value, leave new value on stack */} static void JSON_parse(js_State *J){	const char *source = js_tostring(J, 1);	jsY_initlex(J, "JSON", source);	jsonnext(J); 	if (js_iscallable(J, 2)) {		js_newobject(J);		jsonvalue(J);		js_defproperty(J, -2, "", 0);		jsonrevive(J, "");	} else {		jsonvalue(J);	}} static void fmtnum(js_State *J, js_Buffer **sb, double n){	if (isnan(n)) js_puts(J, sb, "null");	else if (isinf(n)) js_puts(J, sb, "null");	else if (n == 0) js_puts(J, sb, "0");	else {		char buf[40];		js_puts(J, sb, jsV_numbertostring(J, buf, n));	}} static void fmtstr(js_State *J, js_Buffer **sb, const char *s){	static const char *HEX = "0123456789ABCDEF";	int i, n;	Rune c;	js_putc(J, sb, '"');	while (*s) {		n = chartorune(&c, s);		switch (c) {		case '"': js_puts(J, sb, "\\\""); break;		case '\\': js_puts(J, sb, "\\\\"); break;		case '\b': js_puts(J, sb, "\\b"); break;		case '\f': js_puts(J, sb, "\\f"); break;		case '\n': js_puts(J, sb, "\\n"); break;		case '\r': js_puts(J, sb, "\\r"); break;		case '\t': js_puts(J, sb, "\\t"); break;		default:			if (c < ' ') {				js_putc(J, sb, '\\');				js_putc(J, sb, 'u');				js_putc(J, sb, HEX[(c>>12)&15]);				js_putc(J, sb, HEX[(c>>8)&15]);				js_putc(J, sb, HEX[(c>>4)&15]);				js_putc(J, sb, HEX[c&15]);			} else if (c < 128) {				js_putc(J, sb, c);			} else {				for (i = 0; i < n; ++i)					js_putc(J, sb, s[i]);			}			break;		}		s += n;	}	js_putc(J, sb, '"');} static void fmtindent(js_State *J, js_Buffer **sb, const char *gap, int level){	js_putc(J, sb, '\n');	while (level--)		js_puts(J, sb, gap);} static int fmtvalue(js_State *J, js_Buffer **sb, const char *key, const char *gap, int level); static int filterprop(js_State *J, const char *key){	int i, n, found;	/* replacer/property-list is in stack slot 2 */	if (js_isarray(J, 2)) {		found = 0;		n = js_getlength(J, 2);		for (i = 0; i < n && !found; ++i) {			js_getindex(J, 2, i);			if (js_isstring(J, -1) || js_isnumber(J, -1) ||				js_isstringobject(J, -1) || js_isnumberobject(J, -1))				found = !strcmp(key, js_tostring(J, -1));			js_pop(J, 1);		}		return found;	}	return 1;} static void fmtobject(js_State *J, js_Buffer **sb, js_Object *obj, const char *gap, int level){	const char *key;	int save;	int i, n; 	n = js_gettop(J) - 1;	for (i = 4; i < n; ++i)		if (js_isobject(J, i))			if (js_toobject(J, i) == js_toobject(J, -1))				js_typeerror(J, "cyclic object value"); 	n = 0;	js_putc(J, sb, '{');	js_pushiterator(J, -1, 1);	while ((key = js_nextiterator(J, -1))) {		if (filterprop(J, key)) {			save = (*sb)->n;			if (n) js_putc(J, sb, ',');			if (gap) fmtindent(J, sb, gap, level + 1);			fmtstr(J, sb, key);			js_putc(J, sb, ':');			if (gap)				js_putc(J, sb, ' ');			js_rot2(J);			if (!fmtvalue(J, sb, key, gap, level + 1))				(*sb)->n = save;			else				++n;			js_rot2(J);		}	}	js_pop(J, 1);	if (gap && n) fmtindent(J, sb, gap, level);	js_putc(J, sb, '}');} static void fmtarray(js_State *J, js_Buffer **sb, const char *gap, int level){	int n, i;	char buf[32]; 	n = js_gettop(J) - 1;	for (i = 4; i < n; ++i)		if (js_isobject(J, i))			if (js_toobject(J, i) == js_toobject(J, -1))				js_typeerror(J, "cyclic object value"); 	js_putc(J, sb, '[');	n = js_getlength(J, -1);	for (i = 0; i < n; ++i) {		if (i) js_putc(J, sb, ',');		if (gap) fmtindent(J, sb, gap, level + 1);		if (!fmtvalue(J, sb, js_itoa(buf, i), gap, level + 1))			js_puts(J, sb, "null");	}	if (gap && n) fmtindent(J, sb, gap, level);	js_putc(J, sb, ']');} static int fmtvalue(js_State *J, js_Buffer **sb, const char *key, const char *gap, int level){	/* replacer/property-list 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_pushstring(J, key);				js_call(J, 1);				js_rot2pop1(J);			} else {				js_pop(J, 1);			}		}	} 	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);		switch (obj->type) {		case JS_CNUMBER: fmtnum(J, sb, obj->u.number); break;		case JS_CSTRING: fmtstr(J, sb, obj->u.s.string); break;		case JS_CBOOLEAN: js_puts(J, sb, obj->u.boolean ? "true" : "false"); break;		case JS_CARRAY: fmtarray(J, sb, gap, level); break;		default: fmtobject(J, sb, obj, gap, level); break;		}	}	else if (js_isboolean(J, -1))		js_puts(J, sb, js_toboolean(J, -1) ? "true" : "false");	else if (js_isnumber(J, -1))		fmtnum(J, sb, js_tonumber(J, -1));	else if (js_isstring(J, -1))		fmtstr(J, sb, js_tostring(J, -1));	else if (js_isnull(J, -1))		js_puts(J, sb, "null");	else {		js_pop(J, 1);		return 0;	} 	js_pop(J, 1);	return 1;} static void JSON_stringify(js_State *J){	js_Buffer *sb = NULL;	char buf[12];	const char *s, *gap;	int n; 	gap = NULL; 	if (js_isnumber(J, 3) || js_isnumberobject(J, 3)) {		n = js_tointeger(J, 3);		if (n < 0) n = 0;		if (n > 10) n = 10;		memset(buf, ' ', n);		buf[n] = 0;		if (n > 0) gap = buf;	} else if (js_isstring(J, 3) || js_isstringobject(J, 3)) {		s = js_tostring(J, 3);		n = strlen(s);		if (n > 10) n = 10;		memcpy(buf, s, n);		buf[n] = 0;		if (n > 0) gap = buf;	} 	if (js_try(J)) {		js_free(J, sb);		js_throw(J);	} 	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){	js_pushobject(J, jsV_newobject(J, JS_CJSON, J->Object_prototype));	{		jsB_propf(J, "JSON.parse", JSON_parse, 2);		jsB_propf(J, "JSON.stringify", JSON_stringify, 3);	}	js_defglobal(J, "JSON", JS_DONTENUM);}

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t