comparison src/luan/modules/parsers/Json.java @ 1112:490f77bb2ad1

add JsonParser
author Franklin Schmidt <fschmidt@gmail.com>
date Wed, 02 Aug 2017 17:37:59 -0600
parents 88b5b81cad4a
children
comparison
equal deleted inserted replaced
1111:88b5b81cad4a 1112:490f77bb2ad1
10 import luan.lib.parser.Parser; 10 import luan.lib.parser.Parser;
11 import luan.lib.parser.ParseException; 11 import luan.lib.parser.ParseException;
12 12
13 13
14 public final class Json { 14 public final class Json {
15
16 public static Object parse(String text) throws ParseException {
17 return new Json(text).parse();
18 }
19
20 private final Parser parser;
21
22 private Json(String text) {
23 this.parser = new Parser(text);
24 }
25
26 private ParseException exception(String msg) {
27 return new ParseException(parser,msg);
28 }
29
30 private Object parse() throws ParseException {
31 spaces();
32 Object value = value();
33 spaces();
34 if( !parser.endOfInput() )
35 throw exception("unexpected text");
36 return value;
37 }
38
39 private Object value() throws ParseException {
40 if( parser.match("null") )
41 return null;
42 if( parser.match("true") )
43 return Boolean.TRUE;
44 if( parser.match("false") )
45 return Boolean.FALSE;
46 String s = string();
47 if( s != null )
48 return s;
49 Number n = number();
50 if( n != null )
51 return n;
52 LuanTable a = array();
53 if( a != null )
54 return a;
55 LuanTable o = object();
56 if( o != null )
57 return o;
58 throw exception("invalid value");
59 }
60
61 private String string() throws ParseException {
62 parser.begin();
63 if( !parser.match('"') )
64 return parser.failure(null);
65 StringBuilder sb = new StringBuilder();
66 while( parser.anyChar() ) {
67 char c = parser.lastChar();
68 switch(c) {
69 case '"':
70 return parser.success(sb.toString());
71 case '\\':
72 if( parser.anyChar() ) {
73 c = parser.lastChar();
74 switch(c) {
75 case '"':
76 case '\\':
77 case '/':
78 sb.append(c);
79 continue;
80 case 'b':
81 sb.append('\b');
82 continue;
83 case 'f':
84 sb.append('\f');
85 continue;
86 case 'n':
87 sb.append('\n');
88 continue;
89 case 'r':
90 sb.append('\r');
91 continue;
92 case 't':
93 sb.append('\t');
94 continue;
95 case 'u':
96 int n = 0;
97 for( int i=0; i<4; i++ ) {
98 int d;
99 if( parser.inCharRange('0','9') ) {
100 d = parser.lastChar() - '0';
101 } else if( parser.inCharRange('a','f') ) {
102 d = parser.lastChar() - 'a' + 10;
103 } else if( parser.inCharRange('A','F') ) {
104 d = parser.lastChar() - 'A' + 10;
105 } else {
106 throw exception("invalid hex digit");
107 }
108 n = 16*n + d;
109 }
110 sb.append((char)n);
111 continue;
112 }
113 }
114 throw exception("invalid escape char");
115 default:
116 sb.append(c);
117 }
118 }
119 parser.failure();
120 throw exception("unclosed string");
121 }
122
123 private Number number() {
124 int start = parser.begin();
125 boolean isFloat = false;
126 parser.match('-');
127 if( !parser.match('0') ) {
128 if( !parser.inCharRange('1','9') )
129 return parser.failure(null);
130 while( parser.inCharRange('0','9') );
131 }
132 if( parser.match('.') ) {
133 if( !parser.inCharRange('0','9') )
134 return parser.failure(null);
135 while( parser.inCharRange('0','9') );
136 isFloat = true;
137 }
138 if( parser.anyOf("eE") ) {
139 parser.anyOf("+-");
140 if( !parser.inCharRange('0','9') )
141 return parser.failure(null);
142 while( parser.inCharRange('0','9') );
143 isFloat = true;
144 }
145 String s = parser.textFrom(start);
146 Number n;
147 if(isFloat)
148 n = Double.valueOf(s);
149 else
150 n = Long.valueOf(s);
151 return parser.success(n);
152 }
153
154 private LuanTable array() throws ParseException {
155 parser.begin();
156 if( !parser.match('[') )
157 return parser.failure(null);
158 spaces();
159 if( parser.match(']') )
160 return parser.success(new LuanTable());
161 List list = new ArrayList();
162 list.add( value() );
163 spaces();
164 while( parser.match(',') ) {
165 spaces();
166 list.add( value() );
167 spaces();
168 }
169 if( parser.match(']') )
170 return parser.success(new LuanTable(list));
171 if( parser.endOfInput() ) {
172 parser.failure();
173 throw exception("unclosed array");
174 }
175 throw exception("unexpected text in array");
176 }
177
178 private LuanTable object() throws ParseException {
179 parser.begin();
180 if( !parser.match('{') )
181 return parser.failure(null);
182 spaces();
183 if( parser.match('}') )
184 return parser.success(new LuanTable());
185 Map map = new LinkedHashMap();
186 addEntry(map);
187 while( parser.match(',') ) {
188 spaces();
189 addEntry(map);
190 }
191 if( parser.match('}') )
192 return parser.success(new LuanTable(map));
193 if( parser.endOfInput() ) {
194 parser.failure();
195 throw exception("unclosed object");
196 }
197 throw exception("unexpected text in object");
198 }
199
200 private void addEntry(Map map) throws ParseException {
201 String key = string();
202 if( key==null )
203 throw exception("invalid object key");
204 spaces();
205 if( !parser.match(':') )
206 throw exception("':' expected");
207 spaces();
208 Object value = value();
209 spaces();
210 map.put(key,value);
211 }
212
213 private void spaces() {
214 while( parser.anyOf(" \t\r\n") );
215 }
216
217
218
219
220
221
222
223
224 15
225 public static String toString(Object obj) throws LuanException { 16 public static String toString(Object obj) throws LuanException {
226 StringBuilder sb = new StringBuilder(); 17 StringBuilder sb = new StringBuilder();
227 toString(obj,sb); 18 toString(obj,sb);
228 return sb.toString(); 19 return sb.toString();