Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(157)

Side by Side Diff: lib/json/json.dart

Issue 10254029: Fix errors in the JSON parser. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Further optimize length. Created 8 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 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. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 #library("json"); 5 #library("json");
6 6
7 // Pure Dart implementation of JSON protocol. 7 // Pure Dart implementation of JSON protocol.
8 8
9 /** 9 /**
10 * Utility class to parse JSON and serialize objects to JSON. 10 * Utility class to parse JSON and serialize objects to JSON.
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after
89 89
90 static final String NULL_STRING = "null"; 90 static final String NULL_STRING = "null";
91 static final String TRUE_STRING = "true"; 91 static final String TRUE_STRING = "true";
92 static final String FALSE_STRING = "false"; 92 static final String FALSE_STRING = "false";
93 93
94 94
95 static parse(String json) { 95 static parse(String json) {
96 return new _JsonParser._internal(json)._parseToplevel(); 96 return new _JsonParser._internal(json)._parseToplevel();
97 } 97 }
98 98
99 _JsonParser._internal(String json) : this.json = '${json} ' { 99 _JsonParser._internal(String json)
Anton Muhin 2012/04/28 09:09:24 nit: ._internal(this.json) ?
Anders Johnsen 2012/04/28 09:28:26 Not possible when extracting length in initializer
100 : json = json,
101 length = json.length {
100 if (tokens !== null) return; 102 if (tokens !== null) return;
101 103
102 // Use a list as jump-table, faster then switch and if. 104 // Use a list as jump-table, faster then switch and if.
103 tokens = new List<int>(LAST_ASCII + 1); 105 tokens = new List<int>(LAST_ASCII + 1);
104 tokens[TAB] = WHITESPACE; 106 tokens[TAB] = WHITESPACE;
105 tokens[NEW_LINE] = WHITESPACE; 107 tokens[NEW_LINE] = WHITESPACE;
106 tokens[CARRIAGE_RETURN] = WHITESPACE; 108 tokens[CARRIAGE_RETURN] = WHITESPACE;
107 tokens[SPACE] = WHITESPACE; 109 tokens[SPACE] = WHITESPACE;
108 tokens[CHAR_0] = NUMBER_LITERAL; 110 tokens[CHAR_0] = NUMBER_LITERAL;
109 tokens[CHAR_1] = NUMBER_LITERAL; 111 tokens[CHAR_1] = NUMBER_LITERAL;
(...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after
214 216
215 List<int> charCodes = new List<int>(); 217 List<int> charCodes = new List<int>();
216 while (true) { 218 while (true) {
217 int c = _char(); 219 int c = _char();
218 if (c == QUOTE) { 220 if (c == QUOTE) {
219 position++; 221 position++;
220 break; 222 break;
221 } 223 }
222 if (c == BACKSLASH) { 224 if (c == BACKSLASH) {
223 position++; 225 position++;
224 if (position == json.length) { 226 if (position == length) {
225 _error('\\ at the end of input'); 227 _error('\\ at the end of input');
226 } 228 }
227 229
228 switch (_char()) { 230 switch (_char()) {
229 case QUOTE: 231 case QUOTE:
230 c = QUOTE; 232 c = QUOTE;
231 break; 233 break;
232 case BACKSLASH: 234 case BACKSLASH:
233 c = BACKSLASH; 235 c = BACKSLASH;
234 break; 236 break;
235 case SLASH: 237 case SLASH:
236 c = SLASH; 238 c = SLASH;
237 break; 239 break;
238 case CHAR_B: 240 case CHAR_B:
239 c = BACKSPACE; 241 c = BACKSPACE;
240 break; 242 break;
241 case CHAR_N: 243 case CHAR_N:
242 c = NEW_LINE; 244 c = NEW_LINE;
243 break; 245 break;
244 case CHAR_R: 246 case CHAR_R:
245 c = CARRIAGE_RETURN; 247 c = CARRIAGE_RETURN;
246 break; 248 break;
247 case CHAR_F: 249 case CHAR_F:
248 c = FORM_FEED; 250 c = FORM_FEED;
249 break; 251 break;
250 case CHAR_T: 252 case CHAR_T:
251 c = TAB; 253 c = TAB;
252 break; 254 break;
253 case CHAR_U: 255 case CHAR_U:
254 if (position + 5 > json.length) { 256 if (position + 5 > length) {
255 _error('Invalid unicode esacape sequence'); 257 _error('Invalid unicode esacape sequence');
256 } 258 }
257 final codeString = json.substring(position + 1, position + 5); 259 final codeString = json.substring(position + 1, position + 5);
258 try { 260 try {
259 c = Math.parseInt('0x${codeString}'); 261 c = Math.parseInt('0x${codeString}');
260 } catch (var e) { 262 } catch (var e) {
261 _error('Invalid unicode esacape sequence'); 263 _error('Invalid unicode esacape sequence');
262 } 264 }
263 position += 4; 265 position += 4;
264 break; 266 break;
265 default: 267 default:
266 _error('Invalid esacape sequence in string literal'); 268 _error('Invalid esacape sequence in string literal');
267 } 269 }
268 } 270 }
269 charCodes.add(c); 271 charCodes.add(c);
270 position++; 272 position++;
271 } 273 }
272 274
273 return new String.fromCharCodes(charCodes); 275 return new String.fromCharCodes(charCodes);
274 } 276 }
275 277
276 num _parseNumber() { 278 num _parseNumber() {
277 if (!_isToken(NUMBER_LITERAL)) _error("Expected number literal"); 279 if (!_isToken(NUMBER_LITERAL)) _error("Expected number literal");
278 280
279 final int startPos = position; 281 final int startPos = position;
280 if (_isChar(MINUS)) position++; 282 if (_isChar(MINUS)) position++;
Anton Muhin 2012/04/28 09:09:24 just an idea: maybe fetch char once with _char() a
Anders Johnsen 2012/04/28 09:28:26 Done.
281 if (_isChar(CHAR_0)) { 283 if (_isChar(CHAR_0)) {
282 position++; 284 position++;
283 } else if (_isDigit()) { 285 } else if (_isDigit()) {
284 position++; 286 position++;
285 while (_isDigit()) position++; 287 while (_isDigit()) position++;
286 } else { 288 } else {
287 _error("Expected digit when parsing number"); 289 _error("Expected digit when parsing number");
288 } 290 }
289 291
290 bool isInt = true; 292 bool isInt = true;
291 if (_isChar(DOT)) { 293 if (_isChar(DOT)) {
292 position++; 294 position++;
293 if (_isDigit()) { 295 if (_isDigit()) {
296 position++;
294 isInt = false; 297 isInt = false;
295 while (_isDigit()) position++; 298 while (_isDigit()) position++;
296 } else { 299 } else {
297 position--; // No digit, backtrack. 300 _error("Expected digit following comma");
Anton Muhin 2012/04/28 09:09:24 nit: single quotes
Anton Muhin 2012/04/28 09:09:24 is it a correct thing, may we double check with JS
Anders Johnsen 2012/04/28 09:28:26 Done.
Anders Johnsen 2012/04/28 09:28:26 There is not token in JSON that can follow a numbe
298 } 301 }
299 } 302 }
300 303
301 if (_isChar(CHAR_E) || _isChar(CHAR_CAPITAL_E)) { 304 if (_isChar(CHAR_E) || _isChar(CHAR_CAPITAL_E)) {
Anton Muhin 2012/04/28 09:09:24 ditto here: fetch char once and then do both check
Anders Johnsen 2012/04/28 09:28:26 Done.
302 int backtrackTo = position;
303 position++; 305 position++;
304 if (_isChar(MINUS) || _isChar(PLUS)) position++; 306 if (_isChar(MINUS) || _isChar(PLUS)) position++;
Anton Muhin 2012/04/28 09:09:24 ditto
Anders Johnsen 2012/04/28 09:28:26 Done.
305 if (_isDigit()) { 307 if (_isDigit()) {
306 position++; 308 position++;
307 isInt = false; 309 isInt = false;
308 while (_isDigit()) position++; 310 while (_isDigit()) position++;
309 } else { 311 } else {
310 position = backtrackTo; // No digit, backtrack. 312 _error("Expected digit following 'e' or 'E'");
Anton Muhin 2012/04/28 09:09:24 ditto nit for ''
Anders Johnsen 2012/04/28 09:28:26 Done.
311 } 313 }
312 } 314 }
313 315
314 String number = json.substring(startPos, position); 316 String number = json.substring(startPos, position);
315 if (isInt) { 317 if (isInt) {
316 return Math.parseInt(number); 318 return Math.parseInt(number);
317 } else { 319 } else {
318 return Math.parseDouble(number); 320 return Math.parseDouble(number);
319 } 321 }
320 } 322 }
321 323
322 bool _isChar(int char) => _char() == char; 324 bool _isChar(int char) {
325 if (position >= length) return false;
326 return json.charCodeAt(position) == char;
327 }
323 328
324 bool _isDigit() { 329 bool _isDigit() {
325 int char = _char(); 330 if (position >= length) return false;
331 int char = json.charCodeAt(position);
326 return char >= CHAR_0 && char <= CHAR_9; 332 return char >= CHAR_0 && char <= CHAR_9;
327 } 333 }
328 334
329 bool _isToken(int tokenKind) => _token() == tokenKind; 335 bool _isToken(int tokenKind) => _token() == tokenKind;
330 336
331 int _char() { 337 int _char() {
332 if (position >= json.length) { 338 if (position >= length) {
333 _error("Unexpected end of JSON stream"); 339 _error("Unexpected end of JSON stream");
334 } 340 }
335 return json.charCodeAt(position); 341 return json.charCodeAt(position);
336 } 342 }
337 343
338 int _token() { 344 int _token() {
339 while (true) { 345 while (true) {
340 if (position >= json.length) return null; 346 if (position >= length) return null;
341 int char = json.charCodeAt(position); 347 int char = json.charCodeAt(position);
342 int token = tokens[char]; 348 int token = tokens[char];
343 if (token === WHITESPACE) { 349 if (token === WHITESPACE) {
344 position++; 350 position++;
345 continue; 351 continue;
346 } 352 }
347 if (token === null) _error("Invalid JSON token"); 353 if (token === null) return 0;
348 return token; 354 return token;
349 } 355 }
350 } 356 }
351 357
352 void _error(String message) { 358 void _error(String message) {
353 throw message; 359 throw message;
354 } 360 }
355 361
356 final String json; 362 final String json;
363 final int length;
357 int position = 0; 364 int position = 0;
358 static List<int> tokens; 365 static List<int> tokens;
359 } 366 }
360 367
361 // TODO: proper base class. 368 // TODO: proper base class.
362 class JsonUnsupportedObjectType { 369 class JsonUnsupportedObjectType {
363 const JsonUnsupportedObjectType(); 370 const JsonUnsupportedObjectType();
364 } 371 }
365 372
366 class JsonStringifier { 373 class JsonStringifier {
(...skipping 141 matching lines...) Expand 10 before | Expand all | Expand 10 after
508 }); 515 });
509 _sb.add('}'); 516 _sb.add('}');
510 _seen.removeLast(); 517 _seen.removeLast();
511 return; 518 return;
512 519
513 default: 520 default:
514 throw const JsonUnsupportedObjectType(); 521 throw const JsonUnsupportedObjectType();
515 } 522 }
516 } 523 }
517 } 524 }
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698