Mercurial Hosting > luan
annotate src/goodjava/json/JsonParser.java @ 2021:b8e5d53c4fc9
admin monitors scheduler
| author | Franklin Schmidt <fschmidt@gmail.com> |
|---|---|
| date | Mon, 20 Oct 2025 14:45:27 -0600 |
| parents | 27efb1fcbcb5 |
| children |
| rev | line source |
|---|---|
|
1402
27efb1fcbcb5
move luan.lib to goodjava
Franklin Schmidt <fschmidt@gmail.com>
parents:
1307
diff
changeset
|
1 package goodjava.json; |
| 720 | 2 |
| 3 import java.util.List; | |
| 4 import java.util.ArrayList; | |
| 5 import java.util.Map; | |
| 6 import java.util.LinkedHashMap; | |
| 1112 | 7 import java.util.Collections; |
|
1402
27efb1fcbcb5
move luan.lib to goodjava
Franklin Schmidt <fschmidt@gmail.com>
parents:
1307
diff
changeset
|
8 import goodjava.parser.Parser; |
|
27efb1fcbcb5
move luan.lib to goodjava
Franklin Schmidt <fschmidt@gmail.com>
parents:
1307
diff
changeset
|
9 import goodjava.parser.ParseException; |
| 720 | 10 |
| 11 | |
| 1112 | 12 public final class JsonParser { |
| 720 | 13 |
| 14 public static Object parse(String text) throws ParseException { | |
| 1112 | 15 return new JsonParser(text).parse(); |
| 720 | 16 } |
| 17 | |
| 18 private final Parser parser; | |
| 19 | |
| 1112 | 20 private JsonParser(String text) { |
| 720 | 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; | |
| 1112 | 50 List a = array(); |
| 720 | 51 if( a != null ) |
| 52 return a; | |
| 1112 | 53 Map o = object(); |
| 720 | 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 '"': | |
| 1307 | 74 case '\'': // not in spec |
| 720 | 75 case '\\': |
| 76 case '/': | |
| 77 sb.append(c); | |
| 78 continue; | |
| 79 case 'b': | |
| 80 sb.append('\b'); | |
| 81 continue; | |
| 82 case 'f': | |
| 83 sb.append('\f'); | |
| 84 continue; | |
| 85 case 'n': | |
| 86 sb.append('\n'); | |
| 87 continue; | |
| 88 case 'r': | |
| 89 sb.append('\r'); | |
| 90 continue; | |
| 91 case 't': | |
| 92 sb.append('\t'); | |
| 93 continue; | |
| 94 case 'u': | |
| 95 int n = 0; | |
| 96 for( int i=0; i<4; i++ ) { | |
| 97 int d; | |
| 98 if( parser.inCharRange('0','9') ) { | |
| 99 d = parser.lastChar() - '0'; | |
| 100 } else if( parser.inCharRange('a','f') ) { | |
| 101 d = parser.lastChar() - 'a' + 10; | |
| 102 } else if( parser.inCharRange('A','F') ) { | |
| 103 d = parser.lastChar() - 'A' + 10; | |
| 104 } else { | |
| 105 throw exception("invalid hex digit"); | |
| 106 } | |
| 107 n = 16*n + d; | |
| 108 } | |
| 109 sb.append((char)n); | |
| 110 continue; | |
| 111 } | |
| 112 } | |
| 113 throw exception("invalid escape char"); | |
| 114 default: | |
| 115 sb.append(c); | |
| 116 } | |
| 117 } | |
| 118 parser.failure(); | |
| 119 throw exception("unclosed string"); | |
| 120 } | |
| 121 | |
| 122 private Number number() { | |
| 123 int start = parser.begin(); | |
|
759
ae612dfc57cb
better handling of longs in rpc and json
Franklin Schmidt <fschmidt@gmail.com>
parents:
758
diff
changeset
|
124 boolean isFloat = false; |
| 720 | 125 parser.match('-'); |
| 126 if( !parser.match('0') ) { | |
| 127 if( !parser.inCharRange('1','9') ) | |
| 128 return parser.failure(null); | |
| 129 while( parser.inCharRange('0','9') ); | |
| 130 } | |
| 131 if( parser.match('.') ) { | |
| 132 if( !parser.inCharRange('0','9') ) | |
| 133 return parser.failure(null); | |
| 134 while( parser.inCharRange('0','9') ); | |
|
759
ae612dfc57cb
better handling of longs in rpc and json
Franklin Schmidt <fschmidt@gmail.com>
parents:
758
diff
changeset
|
135 isFloat = true; |
| 720 | 136 } |
| 137 if( parser.anyOf("eE") ) { | |
| 138 parser.anyOf("+-"); | |
| 139 if( !parser.inCharRange('0','9') ) | |
| 140 return parser.failure(null); | |
| 141 while( parser.inCharRange('0','9') ); | |
|
759
ae612dfc57cb
better handling of longs in rpc and json
Franklin Schmidt <fschmidt@gmail.com>
parents:
758
diff
changeset
|
142 isFloat = true; |
| 720 | 143 } |
| 144 String s = parser.textFrom(start); | |
|
759
ae612dfc57cb
better handling of longs in rpc and json
Franklin Schmidt <fschmidt@gmail.com>
parents:
758
diff
changeset
|
145 Number n; |
|
ae612dfc57cb
better handling of longs in rpc and json
Franklin Schmidt <fschmidt@gmail.com>
parents:
758
diff
changeset
|
146 if(isFloat) |
|
ae612dfc57cb
better handling of longs in rpc and json
Franklin Schmidt <fschmidt@gmail.com>
parents:
758
diff
changeset
|
147 n = Double.valueOf(s); |
|
ae612dfc57cb
better handling of longs in rpc and json
Franklin Schmidt <fschmidt@gmail.com>
parents:
758
diff
changeset
|
148 else |
|
ae612dfc57cb
better handling of longs in rpc and json
Franklin Schmidt <fschmidt@gmail.com>
parents:
758
diff
changeset
|
149 n = Long.valueOf(s); |
|
ae612dfc57cb
better handling of longs in rpc and json
Franklin Schmidt <fschmidt@gmail.com>
parents:
758
diff
changeset
|
150 return parser.success(n); |
| 720 | 151 } |
| 152 | |
| 1112 | 153 private List array() throws ParseException { |
| 720 | 154 parser.begin(); |
| 155 if( !parser.match('[') ) | |
| 156 return parser.failure(null); | |
| 157 spaces(); | |
| 158 if( parser.match(']') ) | |
| 1112 | 159 return parser.success(Collections.emptyList()); |
| 720 | 160 List list = new ArrayList(); |
| 161 list.add( value() ); | |
| 162 spaces(); | |
| 163 while( parser.match(',') ) { | |
| 164 spaces(); | |
| 165 list.add( value() ); | |
| 166 spaces(); | |
| 167 } | |
| 168 if( parser.match(']') ) | |
| 1112 | 169 return parser.success(list); |
| 720 | 170 if( parser.endOfInput() ) { |
| 171 parser.failure(); | |
| 172 throw exception("unclosed array"); | |
| 173 } | |
| 174 throw exception("unexpected text in array"); | |
| 175 } | |
| 176 | |
| 1112 | 177 private Map object() throws ParseException { |
| 720 | 178 parser.begin(); |
| 179 if( !parser.match('{') ) | |
| 180 return parser.failure(null); | |
| 181 spaces(); | |
| 182 if( parser.match('}') ) | |
| 1112 | 183 return parser.success(Collections.emptyMap()); |
| 720 | 184 Map map = new LinkedHashMap(); |
| 185 addEntry(map); | |
| 186 while( parser.match(',') ) { | |
| 187 spaces(); | |
| 188 addEntry(map); | |
| 189 } | |
| 190 if( parser.match('}') ) | |
| 1112 | 191 return parser.success(map); |
| 720 | 192 if( parser.endOfInput() ) { |
| 193 parser.failure(); | |
| 194 throw exception("unclosed object"); | |
| 195 } | |
| 196 throw exception("unexpected text in object"); | |
| 197 } | |
| 198 | |
| 199 private void addEntry(Map map) throws ParseException { | |
| 200 String key = string(); | |
| 201 if( key==null ) | |
| 202 throw exception("invalid object key"); | |
| 203 spaces(); | |
| 204 if( !parser.match(':') ) | |
| 205 throw exception("':' expected"); | |
| 206 spaces(); | |
| 207 Object value = value(); | |
| 208 spaces(); | |
| 209 map.put(key,value); | |
| 210 } | |
| 211 | |
| 212 private void spaces() { | |
| 213 while( parser.anyOf(" \t\r\n") ); | |
| 214 } | |
|
758
c29d11d675fd
added Json.toString() and rpc now sends tables as json
Franklin Schmidt <fschmidt@gmail.com>
parents:
720
diff
changeset
|
215 |
| 720 | 216 } |
