| 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 lax 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; |
| 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 |