Mercurial Hosting > luan
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
diff -r 88b5b81cad4a -r 490f77bb2ad1 src/luan/lib/json/JsonParser.java --- /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") ); + } + +}
diff -r 88b5b81cad4a -r 490f77bb2ad1 src/luan/modules/BasicLuan.java --- 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; + } + }
diff -r 88b5b81cad4a -r 490f77bb2ad1 src/luan/modules/Parsers.luan --- 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
diff -r 88b5b81cad4a -r 490f77bb2ad1 src/luan/modules/RpcLuan.java --- 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); }
diff -r 88b5b81cad4a -r 490f77bb2ad1 src/luan/modules/parsers/Json.java --- 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);