Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file | |
| 2 // for details. All rights reserved. Use of this source code is governed by a | |
| 3 // BSD-style license that can be found in the LICENSE file. | |
| 4 | |
| 5 /// Decode a lazy JSON encoded text, that is, JSON with Dart-like comments and | |
| 6 /// trailing commas. | |
| 7 /// | |
| 8 /// This is used together with `load.dart` and `save.dart` to allow for an easy | |
| 9 /// editing of a human-readable source-map file. | |
| 10 | |
| 11 library lazon; | |
|
Siggi Cherem (dart-lang)
2016/10/27 13:25:19
funny name, but it might help to rename this libra
Johnni Winther
2016/11/02 14:34:30
How about lax_json (or laxon), it also supports tr
| |
| 12 | |
| 13 decode(String text) { | |
| 14 return new _Decoder(text)._decode(); | |
| 15 } | |
| 16 | |
| 17 class _Decoder { | |
| 18 static final int LF = '\n'.codeUnits.single; | |
| 19 static final int CR = '\r'.codeUnits.single; | |
| 20 static final int BACKSPACE = '\b'.codeUnits.single; | |
| 21 static final int FORMFEED = '\f'.codeUnits.single; | |
| 22 static final int TAB = '\t'.codeUnits.single; | |
| 23 static final int SPACE = ' '.codeUnits.single; | |
| 24 static final int SLASH = '/'.codeUnits.single; | |
| 25 static final int STAR = '*'.codeUnits.single; | |
| 26 static final int QUOTE = '"'.codeUnits.single; | |
| 27 static final int BACKSLASH = '\\'.codeUnits.single; | |
| 28 static final int COMMA = ','.codeUnits.single; | |
| 29 static final int COLON = ':'.codeUnits.single; | |
| 30 static final int LEFT_BRACE = '{'.codeUnits.single; | |
| 31 static final int RIGHT_BRACE = '}'.codeUnits.single; | |
| 32 static final int LEFT_BRACKET = '['.codeUnits.single; | |
| 33 static final int RIGHT_BRACKET = ']'.codeUnits.single; | |
| 34 static final int T = 't'.codeUnits.single; | |
| 35 static final List<int> TRUE = 'true'.codeUnits; | |
| 36 static final int F = 'f'.codeUnits.single; | |
| 37 static final List<int> FALSE = 'false'.codeUnits; | |
| 38 static final int N = 'n'.codeUnits.single; | |
| 39 static final List<int> NULL = 'null'.codeUnits; | |
| 40 static final int _0 = '0'.codeUnits.single; | |
| 41 static final int _9 = '9'.codeUnits.single; | |
| 42 static final int B = 'b'.codeUnits.single; | |
| 43 static final int R = 'r'.codeUnits.single; | |
| 44 static final int U = 'u'.codeUnits.single; | |
| 45 | |
| 46 final List<int> codeUnits; | |
| 47 final int length; | |
| 48 int position = 0; | |
| 49 | |
| 50 _Decoder(String text) | |
| 51 : codeUnits = text.codeUnits, | |
| 52 length = text.length; | |
| 53 | |
| 54 _decode() { | |
| 55 var result = _decodeValue(); | |
| 56 _trimWhitespace(); | |
| 57 if (position != codeUnits.length) { | |
| 58 throw new ArgumentError("Unexpected trailing text: " | |
| 59 "'${new String.fromCharCodes(codeUnits, position)}'."); | |
| 60 } | |
| 61 return result; | |
| 62 } | |
| 63 | |
| 64 _decodeValue() { | |
| 65 var result; | |
| 66 _trimWhitespace(); | |
| 67 if (position < codeUnits.length) { | |
| 68 int codeUnit = codeUnits[position]; | |
| 69 if (codeUnit == QUOTE) { | |
| 70 result = _decodeString(); | |
| 71 } else if (codeUnit == LEFT_BRACE) { | |
| 72 result = _decodeMap(); | |
| 73 } else if (codeUnit == LEFT_BRACKET) { | |
| 74 result = _decodeList(); | |
| 75 } else if (codeUnit == T) { | |
| 76 result = _decodeTrue(); | |
| 77 } else if (codeUnit == F) { | |
| 78 result = _decodeFalse(); | |
| 79 } else if (codeUnit == N) { | |
| 80 result = _decodeNull(); | |
| 81 } else { | |
| 82 result = _decodeNumber(); | |
| 83 } | |
| 84 } else { | |
| 85 throw new ArgumentError("No value found in text: " | |
| 86 "'${new String.fromCharCodes(codeUnits, 0)}'."); | |
| 87 } | |
| 88 return result; | |
| 89 } | |
| 90 | |
| 91 void _trimWhitespace() { | |
| 92 OUTER: | |
| 93 while (position < codeUnits.length) { | |
| 94 int codeUnit = codeUnits[position]; | |
| 95 if (codeUnit == SLASH) { | |
| 96 if (position + 1 < codeUnits.length) { | |
| 97 int nextCodeUnit = codeUnits[position + 1]; | |
| 98 if (nextCodeUnit == SLASH) { | |
| 99 position += 2; | |
| 100 while (position < codeUnits.length) { | |
| 101 codeUnit = codeUnits[position]; | |
| 102 if (codeUnit == LF || codeUnit == CR) { | |
| 103 continue OUTER; | |
| 104 } | |
| 105 position++; | |
| 106 } | |
| 107 } else if (nextCodeUnit == STAR) { | |
| 108 position += 2; | |
| 109 while (position < codeUnits.length) { | |
| 110 codeUnit = codeUnits[position]; | |
| 111 if (codeUnit == STAR && | |
| 112 position + 1 < codeUnits.length && | |
| 113 codeUnits[position + 1] == SLASH) { | |
| 114 position += 2; | |
| 115 continue OUTER; | |
| 116 } | |
| 117 position++; | |
| 118 } | |
| 119 } | |
| 120 } | |
| 121 break; | |
| 122 } else if (codeUnit == LF || | |
| 123 codeUnit == CR || | |
| 124 codeUnit == TAB || | |
| 125 codeUnit == SPACE) { | |
| 126 position++; | |
| 127 } else { | |
| 128 break; | |
| 129 } | |
| 130 } | |
| 131 } | |
| 132 | |
| 133 String _decodeString() { | |
| 134 int codeUnit = codeUnits[position]; | |
| 135 if (codeUnit != QUOTE) { | |
| 136 _fail(); | |
| 137 } | |
| 138 position++; | |
| 139 List<int> charCodes = <int>[]; | |
| 140 while (position < length) { | |
| 141 codeUnit = codeUnits[position]; | |
| 142 if (codeUnit == QUOTE) { | |
| 143 break; | |
| 144 } else if (codeUnit == BACKSLASH) { | |
| 145 if (position + 1 >= length) { | |
| 146 _fail(); | |
| 147 } | |
| 148 codeUnit = codeUnits[++position]; | |
| 149 if (codeUnit == B) { | |
| 150 codeUnit = BACKSPACE; | |
| 151 } else if (codeUnit == F) { | |
| 152 codeUnit = FORMFEED; | |
| 153 } else if (codeUnit == N) { | |
| 154 codeUnit = LF; | |
| 155 } else if (codeUnit == R) { | |
| 156 codeUnit = CR; | |
| 157 } else if (codeUnit == T) { | |
| 158 codeUnit = TAB; | |
| 159 } else if (codeUnit == U) { | |
| 160 throw new UnsupportedError('unicode escapes'); | |
| 161 } else if (codeUnit == QUOTE || | |
| 162 codeUnit == SLASH || | |
| 163 codeUnit == BACKSLASH) { | |
| 164 // Ok. | |
| 165 } else { | |
| 166 _fail(); | |
| 167 } | |
| 168 } | |
| 169 charCodes.add(codeUnit); | |
| 170 position++; | |
| 171 } | |
| 172 if (codeUnit != QUOTE) { | |
| 173 _fail(); | |
| 174 } | |
| 175 position++; | |
| 176 return new String.fromCharCodes(charCodes); | |
| 177 } | |
| 178 | |
| 179 Map _decodeMap() { | |
| 180 int codeUnit = codeUnits[position]; | |
| 181 if (codeUnit != LEFT_BRACE) { | |
| 182 _fail(); | |
| 183 } | |
| 184 position++; | |
| 185 _trimWhitespace(); | |
| 186 Map result = {}; | |
| 187 while (position < length) { | |
| 188 codeUnit = codeUnits[position]; | |
| 189 if (codeUnit == RIGHT_BRACE) { | |
| 190 break; | |
| 191 } | |
| 192 String key = _decodeString(); | |
| 193 _trimWhitespace(); | |
| 194 if (position < length) { | |
| 195 codeUnit = codeUnits[position]; | |
| 196 if (codeUnit == COLON) { | |
| 197 position++; | |
| 198 _trimWhitespace(); | |
| 199 } else { | |
| 200 _fail(); | |
| 201 } | |
| 202 } else { | |
| 203 _fail(); | |
| 204 } | |
| 205 var value = _decodeValue(); | |
| 206 result[key] = value; | |
| 207 _trimWhitespace(); | |
| 208 if (position < length) { | |
| 209 codeUnit = codeUnits[position]; | |
| 210 if (codeUnit == COMMA) { | |
| 211 position++; | |
| 212 _trimWhitespace(); | |
| 213 continue; | |
| 214 } else { | |
| 215 break; | |
| 216 } | |
| 217 } | |
| 218 } | |
| 219 | |
| 220 if (codeUnit != RIGHT_BRACE) { | |
| 221 _fail(); | |
| 222 } | |
| 223 position++; | |
| 224 return result; | |
| 225 } | |
| 226 | |
| 227 List _decodeList() { | |
| 228 int codeUnit = codeUnits[position]; | |
| 229 if (codeUnit != LEFT_BRACKET) { | |
| 230 _fail(); | |
| 231 } | |
| 232 position++; | |
| 233 _trimWhitespace(); | |
| 234 List result = []; | |
| 235 while (position < length) { | |
| 236 codeUnit = codeUnits[position]; | |
| 237 if (codeUnit == RIGHT_BRACKET) { | |
| 238 break; | |
| 239 } | |
| 240 result.add(_decodeValue()); | |
| 241 _trimWhitespace(); | |
| 242 if (position < length) { | |
| 243 codeUnit = codeUnits[position]; | |
| 244 if (codeUnit == COMMA) { | |
| 245 position++; | |
| 246 _trimWhitespace(); | |
| 247 continue; | |
| 248 } else { | |
| 249 break; | |
| 250 } | |
| 251 } | |
| 252 } | |
| 253 | |
| 254 if (codeUnit != RIGHT_BRACKET) { | |
| 255 _fail(); | |
| 256 } | |
| 257 position++; | |
| 258 return result; | |
| 259 } | |
| 260 | |
| 261 bool _decodeTrue() { | |
| 262 match(TRUE); | |
| 263 return true; | |
| 264 } | |
| 265 | |
| 266 bool _decodeFalse() { | |
| 267 match(FALSE); | |
| 268 return false; | |
| 269 } | |
| 270 | |
| 271 Null _decodeNull() { | |
| 272 match(NULL); | |
| 273 return null; | |
| 274 } | |
| 275 | |
| 276 void match(List<int> codes) { | |
| 277 if (position + codes.length > length) { | |
| 278 _fail(); | |
| 279 } | |
| 280 for (int i = 0; i < codes.length; i++) { | |
| 281 if (codes[i] != codeUnits[position + i]) { | |
| 282 _fail(); | |
| 283 } | |
| 284 } | |
| 285 position += codes.length; | |
| 286 } | |
| 287 | |
| 288 num _decodeNumber() { | |
| 289 throw new UnsupportedError('_decodeNumber'); | |
| 290 } | |
| 291 | |
| 292 void _fail() { | |
| 293 throw new ArgumentError("Unexpected value: " | |
| 294 "'${new String.fromCharCodes(codeUnits, position)}'."); | |
| 295 } | |
| 296 } | |
| OLD | NEW |