changeset 1112:490f77bb2ad1

add JsonParser
author Franklin Schmidt <fschmidt@gmail.com>
date Wed, 02 Aug 2017 17:37:59 -0600
parents 88b5b81cad4a
children 22652f4020fb
files src/luan/lib/json/JsonParser.java src/luan/modules/BasicLuan.java src/luan/modules/Parsers.luan src/luan/modules/RpcLuan.java src/luan/modules/parsers/Json.java
diffstat 5 files changed, 271 insertions(+), 211 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/luan/lib/json/JsonParser.java	Wed Aug 02 17:37:59 2017 -0600
@@ -0,0 +1,215 @@
+package luan.lib.json;
+
+import java.util.List;
+import java.util.ArrayList;
+import java.util.Map;
+import java.util.LinkedHashMap;
+import java.util.Collections;
+import luan.lib.parser.Parser;
+import luan.lib.parser.ParseException;
+
+
+public final class JsonParser {
+
+	public static Object parse(String text) throws ParseException {
+		return new JsonParser(text).parse();
+	}
+
+	private final Parser parser;
+
+	private JsonParser(String text) {
+		this.parser = new Parser(text);
+	}
+
+	private ParseException exception(String msg) {
+		return new ParseException(parser,msg);
+	}
+
+	private Object parse() throws ParseException {
+		spaces();
+		Object value = value();
+		spaces();
+		if( !parser.endOfInput() )
+			throw exception("unexpected text");
+		return value;
+	}
+
+	private Object value() throws ParseException {
+		if( parser.match("null") )
+			return null;
+		if( parser.match("true") )
+			return Boolean.TRUE;
+		if( parser.match("false") )
+			return Boolean.FALSE;
+		String s = string();
+		if( s != null )
+			return s;
+		Number n = number();
+		if( n != null )
+			return n;
+		List a = array();
+		if( a != null )
+			return a;
+		Map o = object();
+		if( o != null )
+			return o;
+		throw exception("invalid value");
+	}
+
+	private String string() throws ParseException {
+		parser.begin();
+		if( !parser.match('"') )
+			return parser.failure(null);
+		StringBuilder sb = new StringBuilder();
+		while( parser.anyChar() ) {
+			char c = parser.lastChar();
+			switch(c) {
+			case '"':
+				return parser.success(sb.toString());
+			case '\\':
+				if( parser.anyChar() ) {
+					c = parser.lastChar();
+					switch(c) {
+					case '"':
+					case '\\':
+					case '/':
+						sb.append(c);
+						continue;
+					case 'b':
+						sb.append('\b');
+						continue;
+					case 'f':
+						sb.append('\f');
+						continue;
+					case 'n':
+						sb.append('\n');
+						continue;
+					case 'r':
+						sb.append('\r');
+						continue;
+					case 't':
+						sb.append('\t');
+						continue;
+					case 'u':
+						int n = 0;
+						for( int i=0; i<4; i++ ) {
+							int d;
+							if( parser.inCharRange('0','9') ) {
+								d = parser.lastChar() - '0';
+							} else if( parser.inCharRange('a','f') ) {
+								d = parser.lastChar() - 'a' + 10;
+							} else if( parser.inCharRange('A','F') ) {
+								d = parser.lastChar() - 'A' + 10;
+							} else {
+								throw exception("invalid hex digit");
+							}
+							n = 16*n + d;
+						}
+						sb.append((char)n);
+						continue;
+					}
+				}
+				throw exception("invalid escape char");
+			default:
+				sb.append(c);
+			}
+		}
+		parser.failure();
+		throw exception("unclosed string");
+	}
+
+	private Number number() {
+		int start = parser.begin();
+		boolean isFloat = false;
+		parser.match('-');
+		if( !parser.match('0') ) {
+			if( !parser.inCharRange('1','9') )
+				return parser.failure(null);
+			while( parser.inCharRange('0','9') );
+		}
+		if( parser.match('.') ) {
+			if( !parser.inCharRange('0','9') )
+				return parser.failure(null);
+			while( parser.inCharRange('0','9') );
+			isFloat = true;
+		}
+		if( parser.anyOf("eE") ) {
+			parser.anyOf("+-");
+			if( !parser.inCharRange('0','9') )
+				return parser.failure(null);
+			while( parser.inCharRange('0','9') );
+			isFloat = true;
+		}
+		String s = parser.textFrom(start);
+		Number n;
+		if(isFloat)
+			n = Double.valueOf(s);
+		else
+			n = Long.valueOf(s);
+		return parser.success(n);
+	}
+
+	private List array() throws ParseException {
+		parser.begin();
+		if( !parser.match('[') )
+			return parser.failure(null);
+		spaces();
+		if( parser.match(']') )
+			return parser.success(Collections.emptyList());
+		List list = new ArrayList();
+		list.add( value() );
+		spaces();
+		while( parser.match(',') ) {
+			spaces();
+			list.add( value() );
+			spaces();
+		}
+		if( parser.match(']') )
+			return parser.success(list);
+		if( parser.endOfInput() ) {
+			parser.failure();
+			throw exception("unclosed array");
+		}
+		throw exception("unexpected text in array");
+	}
+
+	private Map object() throws ParseException {
+		parser.begin();
+		if( !parser.match('{') )
+			return parser.failure(null);
+		spaces();
+		if( parser.match('}') )
+			return parser.success(Collections.emptyMap());
+		Map map = new LinkedHashMap();
+		addEntry(map);
+		while( parser.match(',') ) {
+			spaces();
+			addEntry(map);
+		}
+		if( parser.match('}') )
+			return parser.success(map);
+		if( parser.endOfInput() ) {
+			parser.failure();
+			throw exception("unclosed object");
+		}
+		throw exception("unexpected text in object");
+	}
+
+	private void addEntry(Map map) throws ParseException {
+		String key = string();
+		if( key==null )
+			throw exception("invalid object key");
+		spaces();
+		if( !parser.match(':') )
+			throw exception("':' expected");
+		spaces();
+		Object value = value();
+		spaces();
+		map.put(key,value);
+	}
+
+	private void spaces() {
+		while( parser.anyOf(" \t\r\n") );
+	}
+
+}
--- a/src/luan/modules/BasicLuan.java	Wed Aug 02 15:19:47 2017 -0600
+++ b/src/luan/modules/BasicLuan.java	Wed Aug 02 17:37:59 2017 -0600
@@ -7,6 +7,8 @@
 import java.util.Map;
 import java.util.List;
 import java.util.ArrayList;
+import java.util.Set;
+import java.util.Arrays;
 import luan.Luan;
 import luan.LuanState;
 import luan.LuanTable;
@@ -248,4 +250,47 @@
 		}
 	}
 
+	public static Object to_luan(Object obj) throws LuanException {
+		if( !type(obj).equals("java") )
+			return obj;
+		LuanTable tbl = new LuanTable();
+		if( obj instanceof Map ) {
+			Map map = (Map)obj;
+			for( Object stupid : map.entrySet() ) {
+				Map.Entry entry = (Map.Entry)stupid;
+				Object key = entry.getKey();
+				Object value = entry.getValue();
+				if( key != null && value != null )
+					tbl.rawPut(to_luan(key),to_luan(value));
+			}
+			return tbl;
+		}
+		if( obj instanceof Set ) {
+			Set set = (Set)obj;
+			for( Object el : set ) {
+				if( el != null )
+					tbl.rawPut(to_luan(el),Boolean.TRUE);
+			}
+			return tbl;
+		}
+		List list;
+		if( obj instanceof List ) {
+			list = (List)obj;
+		} else {
+			Class cls = obj.getClass();
+			if( cls.isArray() && !cls.getComponentType().isPrimitive() ) {
+				Object[] a = (Object[])obj;
+				list = Arrays.asList(a);
+			} else
+				throw new LuanException("can't convert type "+obj.getClass().getName()+" to luan");
+		}
+		int n = list.size();
+		for( int i=0; i<n; i++ ) {
+			Object val = list.get(i);
+			if( val != null )
+				tbl.rawPut(i+1,to_luan(val));
+		}
+		return tbl;
+	}
+
 }
--- a/src/luan/modules/Parsers.luan	Wed Aug 02 15:19:47 2017 -0600
+++ b/src/luan/modules/Parsers.luan	Wed Aug 02 17:37:59 2017 -0600
@@ -4,13 +4,21 @@
 local Theme = require "java:luan.modules.parsers.Theme"
 local Json = require "java:luan.modules.parsers.Json"
 
+
 local Parsers = {}
 
 Parsers.bbcode_to_html = BBCode.toHtml
 Parsers.bbcode_to_text = BBCode.toText
 Parsers.csv_to_list = Csv.toList
-Parsers.json_parse = Json.parse  -- converts json string to luan object
 Parsers.json_string = Json.toString  -- converts luan object to json string
 Parsers.theme_to_luan = Theme.toLuan
 
+local JsonParser = require "java:luan.lib.json.JsonParser"
+local BasicLuan = require "java:luan.modules.BasicLuan"
+
+-- converts json string to luan object
+function Parsers.json_parse(obj)
+	return BasicLuan.to_luan(JsonParser.parse(obj))
+end
+
 return Parsers
--- a/src/luan/modules/RpcLuan.java	Wed Aug 02 15:19:47 2017 -0600
+++ b/src/luan/modules/RpcLuan.java	Wed Aug 02 17:37:59 2017 -0600
@@ -21,6 +21,7 @@
 import luan.LuanException;
 import luan.LuanMethod;
 import luan.modules.parsers.Json;
+import luan.lib.json.JsonParser;
 import luan.lib.parser.ParseException;
 
 
@@ -181,7 +182,7 @@
 			return fn.call(luan);
 */
 			try {
-				return Json.parse(s);
+				return BasicLuan.to_luan(JsonParser.parse(s));
 			} catch(ParseException e) {
 				throw new LuanException(e);
 			}
--- a/src/luan/modules/parsers/Json.java	Wed Aug 02 15:19:47 2017 -0600
+++ b/src/luan/modules/parsers/Json.java	Wed Aug 02 17:37:59 2017 -0600
@@ -13,215 +13,6 @@
 
 public final class Json {
 
-	public static Object parse(String text) throws ParseException {
-		return new Json(text).parse();
-	}
-
-	private final Parser parser;
-
-	private Json(String text) {
-		this.parser = new Parser(text);
-	}
-
-	private ParseException exception(String msg) {
-		return new ParseException(parser,msg);
-	}
-
-	private Object parse() throws ParseException {
-		spaces();
-		Object value = value();
-		spaces();
-		if( !parser.endOfInput() )
-			throw exception("unexpected text");
-		return value;
-	}
-
-	private Object value() throws ParseException {
-		if( parser.match("null") )
-			return null;
-		if( parser.match("true") )
-			return Boolean.TRUE;
-		if( parser.match("false") )
-			return Boolean.FALSE;
-		String s = string();
-		if( s != null )
-			return s;
-		Number n = number();
-		if( n != null )
-			return n;
-		LuanTable a = array();
-		if( a != null )
-			return a;
-		LuanTable o = object();
-		if( o != null )
-			return o;
-		throw exception("invalid value");
-	}
-
-	private String string() throws ParseException {
-		parser.begin();
-		if( !parser.match('"') )
-			return parser.failure(null);
-		StringBuilder sb = new StringBuilder();
-		while( parser.anyChar() ) {
-			char c = parser.lastChar();
-			switch(c) {
-			case '"':
-				return parser.success(sb.toString());
-			case '\\':
-				if( parser.anyChar() ) {
-					c = parser.lastChar();
-					switch(c) {
-					case '"':
-					case '\\':
-					case '/':
-						sb.append(c);
-						continue;
-					case 'b':
-						sb.append('\b');
-						continue;
-					case 'f':
-						sb.append('\f');
-						continue;
-					case 'n':
-						sb.append('\n');
-						continue;
-					case 'r':
-						sb.append('\r');
-						continue;
-					case 't':
-						sb.append('\t');
-						continue;
-					case 'u':
-						int n = 0;
-						for( int i=0; i<4; i++ ) {
-							int d;
-							if( parser.inCharRange('0','9') ) {
-								d = parser.lastChar() - '0';
-							} else if( parser.inCharRange('a','f') ) {
-								d = parser.lastChar() - 'a' + 10;
-							} else if( parser.inCharRange('A','F') ) {
-								d = parser.lastChar() - 'A' + 10;
-							} else {
-								throw exception("invalid hex digit");
-							}
-							n = 16*n + d;
-						}
-						sb.append((char)n);
-						continue;
-					}
-				}
-				throw exception("invalid escape char");
-			default:
-				sb.append(c);
-			}
-		}
-		parser.failure();
-		throw exception("unclosed string");
-	}
-
-	private Number number() {
-		int start = parser.begin();
-		boolean isFloat = false;
-		parser.match('-');
-		if( !parser.match('0') ) {
-			if( !parser.inCharRange('1','9') )
-				return parser.failure(null);
-			while( parser.inCharRange('0','9') );
-		}
-		if( parser.match('.') ) {
-			if( !parser.inCharRange('0','9') )
-				return parser.failure(null);
-			while( parser.inCharRange('0','9') );
-			isFloat = true;
-		}
-		if( parser.anyOf("eE") ) {
-			parser.anyOf("+-");
-			if( !parser.inCharRange('0','9') )
-				return parser.failure(null);
-			while( parser.inCharRange('0','9') );
-			isFloat = true;
-		}
-		String s = parser.textFrom(start);
-		Number n;
-		if(isFloat)
-			n = Double.valueOf(s);
-		else
-			n = Long.valueOf(s);
-		return parser.success(n);
-	}
-
-	private LuanTable array() throws ParseException {
-		parser.begin();
-		if( !parser.match('[') )
-			return parser.failure(null);
-		spaces();
-		if( parser.match(']') )
-			return parser.success(new LuanTable());
-		List list = new ArrayList();
-		list.add( value() );
-		spaces();
-		while( parser.match(',') ) {
-			spaces();
-			list.add( value() );
-			spaces();
-		}
-		if( parser.match(']') )
-			return parser.success(new LuanTable(list));
-		if( parser.endOfInput() ) {
-			parser.failure();
-			throw exception("unclosed array");
-		}
-		throw exception("unexpected text in array");
-	}
-
-	private LuanTable object() throws ParseException {
-		parser.begin();
-		if( !parser.match('{') )
-			return parser.failure(null);
-		spaces();
-		if( parser.match('}') )
-			return parser.success(new LuanTable());
-		Map map = new LinkedHashMap();
-		addEntry(map);
-		while( parser.match(',') ) {
-			spaces();
-			addEntry(map);
-		}
-		if( parser.match('}') )
-			return parser.success(new LuanTable(map));
-		if( parser.endOfInput() ) {
-			parser.failure();
-			throw exception("unclosed object");
-		}
-		throw exception("unexpected text in object");
-	}
-
-	private void addEntry(Map map) throws ParseException {
-		String key = string();
-		if( key==null )
-			throw exception("invalid object key");
-		spaces();
-		if( !parser.match(':') )
-			throw exception("':' expected");
-		spaces();
-		Object value = value();
-		spaces();
-		map.put(key,value);
-	}
-
-	private void spaces() {
-		while( parser.anyOf(" \t\r\n") );
-	}
-
-
-
-
-
-
-
-
-
 	public static String toString(Object obj) throws LuanException {
 		StringBuilder sb = new StringBuilder();
 		toString(obj,sb);