| OLD | NEW |
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, 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 import "dart:typed_data"; | 5 import "dart:typed_data"; |
| 6 | 6 |
| 7 // JSON conversion. | 7 // JSON conversion. |
| 8 | 8 |
| 9 patch _parseJson(String json, reviver(var key, var value)) { | 9 patch _parseJson(String json, reviver(var key, var value)) { |
| 10 _BuildJsonListener listener; | 10 _BuildJsonListener listener; |
| (...skipping 353 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 364 if (source.codeUnitAt(position + 1) != CHAR_a || | 364 if (source.codeUnitAt(position + 1) != CHAR_a || |
| 365 source.codeUnitAt(position + 2) != CHAR_l || | 365 source.codeUnitAt(position + 2) != CHAR_l || |
| 366 source.codeUnitAt(position + 3) != CHAR_s || | 366 source.codeUnitAt(position + 3) != CHAR_s || |
| 367 source.codeUnitAt(position + 4) != CHAR_e) { | 367 source.codeUnitAt(position + 4) != CHAR_e) { |
| 368 fail(position); | 368 fail(position); |
| 369 } | 369 } |
| 370 listener.handleBool(false); | 370 listener.handleBool(false); |
| 371 return position + 5; | 371 return position + 5; |
| 372 } | 372 } |
| 373 | 373 |
| 374 /** Parses a "null" literal starting at [position]. | 374 /** |
| 375 * Parses a "null" literal starting at [position]. |
| 375 * | 376 * |
| 376 * [:source[position]:] must be "n". | 377 * [:source[position]:] must be "n". |
| 377 */ | 378 */ |
| 378 int parseNull(int position) { | 379 int parseNull(int position) { |
| 379 assert(source.codeUnitAt(position) == CHAR_n); | 380 assert(source.codeUnitAt(position) == CHAR_n); |
| 380 if (source.length < position + 4) fail(position, "Unexpected identifier"); | 381 if (source.length < position + 4) fail(position, "Unexpected identifier"); |
| 381 if (source.codeUnitAt(position + 1) != CHAR_u || | 382 if (source.codeUnitAt(position + 1) != CHAR_u || |
| 382 source.codeUnitAt(position + 2) != CHAR_l || | 383 source.codeUnitAt(position + 2) != CHAR_l || |
| 383 source.codeUnitAt(position + 3) != CHAR_l) { | 384 source.codeUnitAt(position + 3) != CHAR_l) { |
| 384 fail(position); | 385 fail(position); |
| 385 } | 386 } |
| 386 listener.handleNull(); | 387 listener.handleNull(); |
| 387 return position + 4; | 388 return position + 4; |
| 388 } | 389 } |
| 389 | 390 |
| 391 /** |
| 392 * Parses a string value. |
| 393 * |
| 394 * Initial [position] is right after the initial quote. |
| 395 * Returned position right after the final quote. |
| 396 */ |
| 390 int parseString(int position) { | 397 int parseString(int position) { |
| 391 // Format: '"'([^\x00-\x1f\\\"]|'\\'[bfnrt/\\"])*'"' | 398 // Format: '"'([^\x00-\x1f\\\"]|'\\'[bfnrt/\\"])*'"' |
| 392 // Initial position is right after first '"'. | 399 // Initial position is right after first '"'. |
| 393 int start = position; | 400 int start = position; |
| 394 int char; | 401 while (position < source.length) { |
| 395 do { | 402 int char = source.codeUnitAt(position++); |
| 396 if (position == source.length) { | 403 // BACKSLASH is larger than QUOTE and SPACE. |
| 397 fail(start - 1, "Unterminated string"); | 404 if (char > BACKSLASH) { |
| 405 continue; |
| 398 } | 406 } |
| 399 char = source.codeUnitAt(position); | 407 if (char == BACKSLASH) { |
| 408 return parseStringWithEscapes(start, position - 1); |
| 409 } |
| 400 if (char == QUOTE) { | 410 if (char == QUOTE) { |
| 401 listener.handleString(source.substring(start, position)); | 411 listener.handleString(source.substring(start, position - 1)); |
| 402 return position + 1; | 412 return position; |
| 403 } | 413 } |
| 404 if (char < SPACE) { | 414 if (char < SPACE) { |
| 405 fail(position, "Control character in string"); | 415 fail(position - 1, "Control character in string"); |
| 406 } | 416 } |
| 407 position++; | 417 } |
| 408 } while (char != BACKSLASH); | 418 fail(start - 1, "Unterminated string"); |
| 419 } |
| 420 |
| 421 int parseStringWithEscapes(start, position) { |
| 409 // Backslash escape detected. Collect character codes for rest of string. | 422 // Backslash escape detected. Collect character codes for rest of string. |
| 410 int firstEscape = position - 1; | 423 int firstEscape = position; |
| 411 List<int> chars = <int>[]; | 424 List<int> chars = <int>[]; |
| 425 for (int i = start; i < firstEscape; i++) { |
| 426 chars.add(source.codeUnitAt(i)); |
| 427 } |
| 428 position++; |
| 412 while (true) { | 429 while (true) { |
| 413 if (position == source.length) { | 430 if (position == source.length) { |
| 414 fail(start - 1, "Unterminated string"); | 431 fail(start - 1, "Unterminated string"); |
| 415 } | 432 } |
| 416 char = source.codeUnitAt(position); | 433 int char = source.codeUnitAt(position); |
| 417 switch (char) { | 434 switch (char) { |
| 418 case CHAR_b: char = BACKSPACE; break; | 435 case CHAR_b: char = BACKSPACE; break; |
| 419 case CHAR_f: char = FORM_FEED; break; | 436 case CHAR_f: char = FORM_FEED; break; |
| 420 case CHAR_n: char = NEWLINE; break; | 437 case CHAR_n: char = NEWLINE; break; |
| 421 case CHAR_r: char = CARRIAGE_RETURN; break; | 438 case CHAR_r: char = CARRIAGE_RETURN; break; |
| 422 case CHAR_t: char = TAB; break; | 439 case CHAR_t: char = TAB; break; |
| 423 case SLASH: | 440 case SLASH: |
| 424 case BACKSLASH: | 441 case BACKSLASH: |
| 425 case QUOTE: | 442 case QUOTE: |
| 426 break; | 443 break; |
| (...skipping 24 matching lines...) Expand all Loading... |
| 451 if (char < SPACE) fail(position, "Control character in string"); | 468 if (char < SPACE) fail(position, "Control character in string"); |
| 452 fail(position, "Unrecognized string escape"); | 469 fail(position, "Unrecognized string escape"); |
| 453 } | 470 } |
| 454 do { | 471 do { |
| 455 chars.add(char); | 472 chars.add(char); |
| 456 position++; | 473 position++; |
| 457 if (position == source.length) fail(start - 1, "Unterminated string"); | 474 if (position == source.length) fail(start - 1, "Unterminated string"); |
| 458 char = source.codeUnitAt(position); | 475 char = source.codeUnitAt(position); |
| 459 if (char == QUOTE) { | 476 if (char == QUOTE) { |
| 460 String result = new String.fromCharCodes(chars); | 477 String result = new String.fromCharCodes(chars); |
| 461 if (start < firstEscape) { | |
| 462 result = "${source.substring(start, firstEscape)}$result"; | |
| 463 } | |
| 464 listener.handleString(result); | 478 listener.handleString(result); |
| 465 return position + 1; | 479 return position + 1; |
| 466 } | 480 } |
| 467 if (char < SPACE) { | 481 if (char < SPACE) { |
| 468 fail(position, "Control character in string"); | 482 fail(position, "Control character in string"); |
| 469 } | 483 } |
| 470 } while (char != BACKSLASH); | 484 } while (char != BACKSLASH); |
| 471 position++; | 485 position++; |
| 472 } | 486 } |
| 473 } | 487 } |
| 474 | 488 |
| 475 int _handleLiteral(start, position, isDouble) { | |
| 476 String literal = source.substring(start, position); | |
| 477 // This correctly creates -0 for doubles. | |
| 478 num value = (isDouble ? double.parse(literal) : int.parse(literal)); | |
| 479 listener.handleNumber(value); | |
| 480 return position; | |
| 481 } | |
| 482 | |
| 483 int parseNumber(int char, int position) { | 489 int parseNumber(int char, int position) { |
| 484 // Format: | 490 // Format: |
| 485 // '-'?('0'|[1-9][0-9]*)('.'[0-9]+)?([eE][+-]?[0-9]+)? | 491 // '-'?('0'|[1-9][0-9]*)('.'[0-9]+)?([eE][+-]?[0-9]+)? |
| 486 int start = position; | 492 int start = position; |
| 487 int length = source.length; | 493 int length = source.length; |
| 494 int intValue = 0; // Collect int value while parsing. |
| 495 int intSign = 1; |
| 488 bool isDouble = false; | 496 bool isDouble = false; |
| 489 if (char == MINUS) { | 497 // Break this block when the end of the number literal is reached. |
| 490 position++; | 498 // At that time, position points to the next character, and isDouble |
| 491 if (position == length) fail(position, "Missing expected digit"); | 499 // is set if the literal contains a decimal point or an exponential. |
| 492 char = source.codeUnitAt(position); | 500 parsing: { |
| 493 } | 501 if (char == MINUS) { |
| 494 if (char < CHAR_0 || char > CHAR_9) { | 502 intSign = -1; |
| 495 fail(position, "Missing expected digit"); | |
| 496 } | |
| 497 if (char == CHAR_0) { | |
| 498 position++; | |
| 499 if (position == length) return _handleLiteral(start, position, false); | |
| 500 char = source.codeUnitAt(position); | |
| 501 if (CHAR_0 <= char && char <= CHAR_9) { | |
| 502 fail(position); | |
| 503 } | |
| 504 } else { | |
| 505 do { | |
| 506 position++; | |
| 507 if (position == length) return _handleLiteral(start, position, false); | |
| 508 char = source.codeUnitAt(position); | |
| 509 } while (CHAR_0 <= char && char <= CHAR_9); | |
| 510 } | |
| 511 if (char == DECIMALPOINT) { | |
| 512 isDouble = true; | |
| 513 position++; | |
| 514 if (position == length) fail(position, "Missing expected digit"); | |
| 515 char = source.codeUnitAt(position); | |
| 516 if (char < CHAR_0 || char > CHAR_9) fail(position); | |
| 517 do { | |
| 518 position++; | |
| 519 if (position == length) return _handleLiteral(start, position, true); | |
| 520 char = source.codeUnitAt(position); | |
| 521 } while (CHAR_0 <= char && char <= CHAR_9); | |
| 522 } | |
| 523 if (char == CHAR_e || char == CHAR_E) { | |
| 524 isDouble = true; | |
| 525 position++; | |
| 526 if (position == length) fail(position, "Missing expected digit"); | |
| 527 char = source.codeUnitAt(position); | |
| 528 if (char == PLUS || char == MINUS) { | |
| 529 position++; | 503 position++; |
| 530 if (position == length) fail(position, "Missing expected digit"); | 504 if (position == length) fail(position, "Missing expected digit"); |
| 531 char = source.codeUnitAt(position); | 505 char = source.codeUnitAt(position); |
| 532 } | 506 } |
| 533 if (char < CHAR_0 || char > CHAR_9) { | 507 if (char < CHAR_0 || char > CHAR_9) { |
| 534 fail(position, "Missing expected digit"); | 508 fail(position, "Missing expected digit"); |
| 535 } | 509 } |
| 536 do { | 510 if (char == CHAR_0) { |
| 537 position++; | 511 position++; |
| 538 if (position == length) return _handleLiteral(start, position, true); | 512 if (position == length) break parsing; |
| 539 char = source.codeUnitAt(position); | 513 char = source.codeUnitAt(position); |
| 540 } while (CHAR_0 <= char && char <= CHAR_9); | 514 if (CHAR_0 <= char && char <= CHAR_9) { |
| 515 fail(position); |
| 516 } |
| 517 } else { |
| 518 do { |
| 519 intValue = intValue * 10 + (char - CHAR_0); |
| 520 position++; |
| 521 if (position == length) break parsing; |
| 522 char = source.codeUnitAt(position); |
| 523 } while (CHAR_0 <= char && char <= CHAR_9); |
| 524 } |
| 525 if (char == DECIMALPOINT) { |
| 526 isDouble = true; |
| 527 position++; |
| 528 if (position == length) fail(position, "Missing expected digit"); |
| 529 char = source.codeUnitAt(position); |
| 530 if (char < CHAR_0 || char > CHAR_9) fail(position); |
| 531 do { |
| 532 position++; |
| 533 if (position == length) break parsing; |
| 534 char = source.codeUnitAt(position); |
| 535 } while (CHAR_0 <= char && char <= CHAR_9); |
| 536 } |
| 537 if (char == CHAR_e || char == CHAR_E) { |
| 538 isDouble = true; |
| 539 position++; |
| 540 if (position == length) fail(position, "Missing expected digit"); |
| 541 char = source.codeUnitAt(position); |
| 542 if (char == PLUS || char == MINUS) { |
| 543 position++; |
| 544 if (position == length) fail(position, "Missing expected digit"); |
| 545 char = source.codeUnitAt(position); |
| 546 } |
| 547 if (char < CHAR_0 || char > CHAR_9) { |
| 548 fail(position, "Missing expected digit"); |
| 549 } |
| 550 do { |
| 551 position++; |
| 552 if (position == length) break parsing; |
| 553 char = source.codeUnitAt(position); |
| 554 } while (CHAR_0 <= char && char <= CHAR_9); |
| 555 } |
| 541 } | 556 } |
| 542 return _handleLiteral(start, position, isDouble); | 557 if (!isDouble) { |
| 558 listener.handleNumber(intSign * intValue); |
| 559 return position; |
| 560 } |
| 561 // Consider whether we can have an int/double.parse that works on part of |
| 562 // a string, to avoid creating the substring. |
| 563 String literal = source.substring(start, position); |
| 564 // This correctly creates -0.0 for doubles. |
| 565 listener.handleNumber(double.parse(literal)); |
| 566 return position; |
| 543 } | 567 } |
| 544 | 568 |
| 545 void fail(int position, [String message]) { | 569 void fail(int position, [String message]) { |
| 546 if (message == null) message = "Unexpected character"; | 570 if (message == null) message = "Unexpected character"; |
| 547 listener.fail(source, position, message); | 571 listener.fail(source, position, message); |
| 548 // If the listener didn't throw, do it here. | 572 // If the listener didn't throw, do it here. |
| 549 String slice; | 573 String slice; |
| 550 int sliceEnd = position + 20; | 574 int sliceEnd = position + 20; |
| 551 if (sliceEnd > source.length) { | 575 if (sliceEnd > source.length) { |
| 552 slice = "'${source.substring(position)}'"; | 576 slice = "'${source.substring(position)}'"; |
| 553 } else { | 577 } else { |
| 554 slice = "'${source.substring(position, sliceEnd)}...'"; | 578 slice = "'${source.substring(position, sliceEnd)}...'"; |
| 555 } | 579 } |
| 556 throw new FormatException("Unexpected character at $position: $slice"); | 580 throw new FormatException("Unexpected character at $position: $slice"); |
| 557 } | 581 } |
| 558 } | 582 } |
| 559 | 583 |
| 560 // UTF-8 conversion. | 584 // UTF-8 conversion. |
| 561 | 585 |
| 562 patch class _Utf8Encoder { | 586 patch class _Utf8Encoder { |
| 563 /* patch */ static List<int> _createBuffer(int size) => new Uint8List(size); | 587 /* patch */ static List<int> _createBuffer(int size) => new Uint8List(size); |
| 564 } | 588 } |
| OLD | NEW |