comparison src/luan/lib/json/JsonParser.java @ 1112:490f77bb2ad1

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