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

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: Fixed isDigit to take a char argument. 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)
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 int char = _char();
281 if (_isChar(CHAR_0)) { 283 if (char === MINUS) char = _nextChar();
282 position++; 284 if (char === CHAR_0) {
283 } else if (_isDigit()) { 285 char = _nextChar();
284 position++; 286 } else if (_isDigit(char)) {
285 while (_isDigit()) position++; 287 char = _nextChar();
288 while (_isDigit(char)) char = _nextChar();
286 } else { 289 } else {
287 _error("Expected digit when parsing number"); 290 _error('Expected digit when parsing number');
288 } 291 }
289 292
290 bool isInt = true; 293 bool isInt = true;
291 if (_isChar(DOT)) { 294 if (char === DOT) {
292 position++; 295 char = _nextChar();
293 if (_isDigit()) { 296 if (_isDigit(char)) {
297 char = _nextChar();
294 isInt = false; 298 isInt = false;
295 while (_isDigit()) position++; 299 while (_isDigit(char)) char = _nextChar();
296 } else { 300 } else {
297 position--; // No digit, backtrack. 301 _error('Expected digit following comma');
298 } 302 }
299 } 303 }
300 304
301 if (_isChar(CHAR_E) || _isChar(CHAR_CAPITAL_E)) { 305 if (char === CHAR_E || char === CHAR_CAPITAL_E) {
302 int backtrackTo = position; 306 char = _nextChar();
303 position++; 307 if (char === MINUS || char === PLUS) position++;
304 if (_isChar(MINUS) || _isChar(PLUS)) position++; 308 if (_isDigit(char)) {
305 if (_isDigit()) { 309 char = _nextChar();
306 position++;
307 isInt = false; 310 isInt = false;
308 while (_isDigit()) position++; 311 while (_isDigit(char)) char = _nextChar();
309 } else { 312 } else {
310 position = backtrackTo; // No digit, backtrack. 313 _error('Expected digit following \'e\' or \'E\'');
311 } 314 }
312 } 315 }
313 316
314 String number = json.substring(startPos, position); 317 String number = json.substring(startPos, position);
315 if (isInt) { 318 if (isInt) {
316 return Math.parseInt(number); 319 return Math.parseInt(number);
317 } else { 320 } else {
318 return Math.parseDouble(number); 321 return Math.parseDouble(number);
319 } 322 }
320 } 323 }
321 324
322 bool _isChar(int char) => _char() == char; 325 bool _isChar(int char) {
326 if (position >= length) return false;
327 return json.charCodeAt(position) == char;
328 }
323 329
324 bool _isDigit() { 330 bool _isDigit(int char) {
325 int char = _char();
326 return char >= CHAR_0 && char <= CHAR_9; 331 return char >= CHAR_0 && char <= CHAR_9;
327 } 332 }
328 333
329 bool _isToken(int tokenKind) => _token() == tokenKind; 334 bool _isToken(int tokenKind) => _token() == tokenKind;
330 335
331 int _char() { 336 int _char() {
332 if (position >= json.length) { 337 if (position >= length) {
333 _error("Unexpected end of JSON stream"); 338 _error('Unexpected end of JSON stream');
334 } 339 }
335 return json.charCodeAt(position); 340 return json.charCodeAt(position);
336 } 341 }
337 342
343 int _nextChar() {
344 position++;
345 if (position >= length) return 0;
346 return json.charCodeAt(position);
347 }
348
338 int _token() { 349 int _token() {
339 while (true) { 350 while (true) {
340 if (position >= json.length) return null; 351 if (position >= length) return null;
341 int char = json.charCodeAt(position); 352 int char = json.charCodeAt(position);
342 int token = tokens[char]; 353 int token = tokens[char];
343 if (token === WHITESPACE) { 354 if (token === WHITESPACE) {
344 position++; 355 position++;
345 continue; 356 continue;
346 } 357 }
347 if (token === null) _error("Invalid JSON token"); 358 if (token === null) return 0;
348 return token; 359 return token;
349 } 360 }
350 } 361 }
351 362
352 void _error(String message) { 363 void _error(String message) {
353 throw message; 364 throw message;
354 } 365 }
355 366
356 final String json; 367 final String json;
368 final int length;
357 int position = 0; 369 int position = 0;
358 static List<int> tokens; 370 static List<int> tokens;
359 } 371 }
360 372
361 // TODO: proper base class. 373 // TODO: proper base class.
362 class JsonUnsupportedObjectType { 374 class JsonUnsupportedObjectType {
363 const JsonUnsupportedObjectType(); 375 const JsonUnsupportedObjectType();
364 } 376 }
365 377
366 class JsonStringifier { 378 class JsonStringifier {
(...skipping 141 matching lines...) Expand 10 before | Expand all | Expand 10 after
508 }); 520 });
509 _sb.add('}'); 521 _sb.add('}');
510 _seen.removeLast(); 522 _seen.removeLast();
511 return; 523 return;
512 524
513 default: 525 default:
514 throw const JsonUnsupportedObjectType(); 526 throw const JsonUnsupportedObjectType();
515 } 527 }
516 } 528 }
517 } 529 }
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