shithub: libmujs

Download patch

ref: 39dd0a36bae056660c36deefdf6faccb898d98a4
parent: b8aa34d91910785c37b35e950c1c4d626ba59a1a
author: Tor Andersson <tor@ccxvii.net>
date: Mon Feb 10 07:42:12 EST 2014

JSON.parse()

--- a/jslex.c
+++ b/jslex.c
@@ -663,3 +663,40 @@
 {
 	return J->lasttoken = jsY_lexx(J);
 }
+
+int jsY_lexjson(js_State *J)
+{
+	while (1) {
+		J->lexline = J->line; /* save location of beginning of token */
+
+		while (iswhite(PEEK) || PEEK == '\n')
+			NEXT();
+
+		if (PEEK >= '0' && PEEK <= '9') {
+			return lexnumber(J);
+		}
+
+		switch (PEEK) {
+		case ',': NEXT(); return ',';
+		case ':': NEXT(); return ':';
+		case '[': NEXT(); return '[';
+		case ']': NEXT(); return ']';
+		case '{': NEXT(); return '{';
+		case '}': NEXT(); return '}';
+
+		case '\'':
+		case '"':
+			return lexstring(J);
+
+		case '.':
+			return lexnumber(J);
+
+		case 0:
+			return 0; /* EOF */
+		}
+
+		if (PEEK >= 0x20 && PEEK <= 0x7E)
+			jsY_error(J, "unexpected character: '%c'", PEEK);
+		jsY_error(J, "unexpected character: \\u%04X", PEEK);
+	}
+}
--- a/jslex.h
+++ b/jslex.h
@@ -71,5 +71,6 @@
 
 void jsY_initlex(js_State *J, const char *filename, const char *source);
 int jsY_lex(js_State *J);
+int jsY_lexjson(js_State *J);
 
 #endif
--- a/json.c
+++ b/json.c
@@ -1,10 +1,103 @@
 #include "jsi.h"
+#include "jslex.h"
 #include "jsvalue.h"
 #include "jsbuiltin.h"
 
-static int JSON_parse(js_State *J, int argc)
+static inline void jsonnext(js_State *J)
 {
+	J->lookahead = jsY_lexjson(J);
+}
+
+static inline int jsonaccept(js_State *J, int t)
+{
+	if (J->lookahead == t) {
+		jsonnext(J);
+		return 1;
+	}
 	return 0;
+}
+
+static inline 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_pushliteral(J, J->text);
+		jsonnext(J);
+		break;
+
+	case TK_NUMBER:
+		js_pushnumber(J, J->number);
+		jsonnext(J);
+		break;
+
+	case '{':
+		js_newobject(J);
+		jsonnext(J);
+		if (J->lookahead == '}')
+			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 (J->lookahead == ']')
+			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 int JSON_parse(js_State *J, int argc)
+{
+	const char *source = js_tostring(J, 1);
+	jsY_initlex(J, "JSON", source);
+	jsonnext(J);
+	jsonvalue(J);
+	// TODO: reviver Walk()
+	return 1;
 }
 
 static int JSON_stringify(js_State *J, int argc)