Mercurial Hosting > luan
changeset 720:bdd766df1c17
add json parser
author | Franklin Schmidt <fschmidt@gmail.com> |
---|---|
date | Mon, 30 May 2016 21:27:17 -0600 |
parents | 53fc65ffa65f |
children | 524ea0056573 |
files | core/src/luan/modules/Parsers.luan core/src/luan/modules/parsers/Json.java core/src/luan/modules/parsers/Theme.java |
diffstat | 3 files changed, 206 insertions(+), 4 deletions(-) [+] |
line wrap: on
line diff
--- a/core/src/luan/modules/Parsers.luan Mon May 30 19:19:38 2016 -0600 +++ b/core/src/luan/modules/Parsers.luan Mon May 30 21:27:17 2016 -0600 @@ -2,12 +2,14 @@ local BBCode = require "java:luan.modules.parsers.BBCode" local Csv = require "java:luan.modules.parsers.Csv" local Theme = require "java:luan.modules.parsers.Theme" +local Json = require "java:luan.modules.parsers.Json" local M = {} M.bbcode_to_html = BBCode.toHtml M.bbcode_to_text = BBCode.toText M.csv_to_list = Csv.toList +M.parse_json = Json.parse M.theme_to_luan = Theme.toLuan return M
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/core/src/luan/modules/parsers/Json.java Mon May 30 21:27:17 2016 -0600 @@ -0,0 +1,204 @@ +package luan.modules.parsers; + +import java.util.List; +import java.util.ArrayList; +import java.util.Map; +import java.util.LinkedHashMap; +import luan.LuanTable; + + +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(); + 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') ); + } + if( parser.anyOf("eE") ) { + parser.anyOf("+-"); + if( !parser.inCharRange('0','9') ) + return parser.failure(null); + while( parser.inCharRange('0','9') ); + } + String s = parser.textFrom(start); + return parser.success(Double.valueOf(s)); + } + + 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") ); + } +}
--- a/core/src/luan/modules/parsers/Theme.java Mon May 30 19:19:38 2016 -0600 +++ b/core/src/luan/modules/parsers/Theme.java Mon May 30 21:27:17 2016 -0600 @@ -146,10 +146,6 @@ return parser.success(rtn); } - private void InlineSpaces() { - while( parser.anyOf(" \t") ); - } - private boolean BlankLine() { parser.begin(); while( parser.anyOf(" \t") );