| OLD | NEW |
| 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 interface Scanner { | 5 interface Scanner { |
| 6 Token tokenize(); | 6 Token tokenize(); |
| 7 } | 7 } |
| 8 | 8 |
| 9 /** | 9 /** |
| 10 * Common base class for a Dart scanner. | 10 * Common base class for a Dart scanner. |
| 11 */ | 11 */ |
| 12 class AbstractScanner<T> implements Scanner { | 12 class AbstractScanner<T> implements Scanner { |
| 13 // TODO(ahe): following makes frog happy. | 13 // TODO(ahe): following makes frog happy. |
| 14 abstract int advance(); | 14 abstract int advance(); |
| 15 abstract int nextByte(); | 15 abstract int nextByte(); |
| 16 abstract int peek(); | 16 abstract int peek(); |
| 17 abstract int select(int choice, String yes, String no); | 17 abstract int select(int choice, String yes, String no); |
| 18 abstract void appendStringToken(int kind, String value); | 18 abstract void appendStringToken(int kind, String value); |
| 19 abstract void appendByteStringToken(int kind, T value); | 19 abstract void appendByteStringToken(int kind, T value); |
| 20 abstract void appendKeywordToken(Keyword keyword); | 20 abstract void appendKeywordToken(Keyword keyword); |
| 21 abstract void appendWhiteSpace(int next); | 21 abstract void appendWhiteSpace(int next); |
| 22 abstract void appendEofToken(); | 22 abstract void appendEofToken(); |
| 23 abstract T asciiString(int start); | 23 abstract T asciiString(int start, int offset); |
| 24 abstract T utf8String(int start, int offset); | 24 abstract T utf8String(int start, int offset); |
| 25 abstract Token firstToken(); | 25 abstract Token firstToken(); |
| 26 abstract void beginToken(); | 26 abstract void beginToken(); |
| 27 abstract void addToCharOffset(int offset); | 27 abstract void addToCharOffset(int offset); |
| 28 abstract int get charOffset(); | 28 abstract int get charOffset(); |
| 29 abstract int get byteOffset(); | 29 abstract int get byteOffset(); |
| 30 abstract void appendBeginGroup(int kind, String value); | 30 abstract void appendBeginGroup(int kind, String value); |
| 31 abstract void appendEndGroup(int kind, String value, int openKind); | 31 abstract int appendEndGroup(int kind, String value, int openKind); |
| 32 abstract void appendGtGt(int kind, String value); | 32 abstract void appendGtGt(int kind, String value); |
| 33 abstract void appendGtGtGt(int kind, String value); | 33 abstract void appendGtGtGt(int kind, String value); |
| 34 abstract void discardOpenLt(); |
| 34 | 35 |
| 35 // TODO(ahe): Move this class to implementation. | 36 // TODO(ahe): Move this class to implementation. |
| 36 | 37 |
| 37 Token tokenize() { | 38 Token tokenize() { |
| 38 int next = advance(); | 39 int next = advance(); |
| 39 while (next != $EOF) { | 40 while (next !== $EOF) { |
| 40 next = bigSwitch(next); | 41 next = bigSwitch(next); |
| 41 } | 42 } |
| 42 appendEofToken(); | 43 appendEofToken(); |
| 43 return firstToken(); | 44 return firstToken(); |
| 44 } | 45 } |
| 45 | 46 |
| 46 int bigSwitch(int next) { | 47 int bigSwitch(int next) { |
| 47 beginToken(); | 48 beginToken(); |
| 48 if (next === $TAB || next === $LF || next === $CR || next === $SPACE) { | 49 if (next === $TAB || next === $LF || next === $CR || next === $SPACE) { |
| 49 appendWhiteSpace(next); | 50 appendWhiteSpace(next); |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 118 if (next === $HASH) { | 119 if (next === $HASH) { |
| 119 return tokenizeTag(next); | 120 return tokenizeTag(next); |
| 120 } | 121 } |
| 121 | 122 |
| 122 if (next === $LPAREN) { | 123 if (next === $LPAREN) { |
| 123 appendBeginGroup(LPAREN_TOKEN, "("); | 124 appendBeginGroup(LPAREN_TOKEN, "("); |
| 124 return advance(); | 125 return advance(); |
| 125 } | 126 } |
| 126 | 127 |
| 127 if (next === $RPAREN) { | 128 if (next === $RPAREN) { |
| 128 appendEndGroup(RPAREN_TOKEN, ")", LPAREN_TOKEN); | 129 return appendEndGroup(RPAREN_TOKEN, ")", LPAREN_TOKEN); |
| 129 return advance(); | |
| 130 } | 130 } |
| 131 | 131 |
| 132 if (next === $COMMA) { | 132 if (next === $COMMA) { |
| 133 appendStringToken(COMMA_TOKEN, ","); | 133 appendStringToken(COMMA_TOKEN, ","); |
| 134 return advance(); | 134 return advance(); |
| 135 } | 135 } |
| 136 | 136 |
| 137 if (next === $COLON) { | 137 if (next === $COLON) { |
| 138 appendStringToken(COLON_TOKEN, ":"); | 138 appendStringToken(COLON_TOKEN, ":"); |
| 139 return advance(); | 139 return advance(); |
| 140 } | 140 } |
| 141 | 141 |
| 142 if (next === $SEMICOLON) { | 142 if (next === $SEMICOLON) { |
| 143 appendStringToken(SEMICOLON_TOKEN, ";"); | 143 appendStringToken(SEMICOLON_TOKEN, ";"); |
| 144 discardOpenLt(); |
| 144 return advance(); | 145 return advance(); |
| 145 } | 146 } |
| 146 | 147 |
| 147 if (next === $QUESTION) { | 148 if (next === $QUESTION) { |
| 148 appendStringToken(QUESTION_TOKEN, "?"); | 149 appendStringToken(QUESTION_TOKEN, "?"); |
| 149 return advance(); | 150 return advance(); |
| 150 } | 151 } |
| 151 | 152 |
| 152 if (next === $CLOSE_SQUARE_BRACKET) { | 153 if (next === $CLOSE_SQUARE_BRACKET) { |
| 153 appendEndGroup(CLOSE_SQUARE_BRACKET_TOKEN, "]", | 154 return appendEndGroup(CLOSE_SQUARE_BRACKET_TOKEN, "]", |
| 154 OPEN_SQUARE_BRACKET_TOKEN); | 155 OPEN_SQUARE_BRACKET_TOKEN); |
| 155 return advance(); | |
| 156 } | 156 } |
| 157 | 157 |
| 158 if (next === $BACKPING) { | 158 if (next === $BACKPING) { |
| 159 appendStringToken(BACKPING_TOKEN, "`"); | 159 appendStringToken(BACKPING_TOKEN, "`"); |
| 160 return advance(); | 160 return advance(); |
| 161 } | 161 } |
| 162 | 162 |
| 163 if (next === $OPEN_CURLY_BRACKET) { | 163 if (next === $OPEN_CURLY_BRACKET) { |
| 164 appendBeginGroup(OPEN_CURLY_BRACKET_TOKEN, "{"); | 164 appendBeginGroup(OPEN_CURLY_BRACKET_TOKEN, "{"); |
| 165 return advance(); | 165 return advance(); |
| 166 } | 166 } |
| 167 | 167 |
| 168 if (next === $CLOSE_CURLY_BRACKET) { | 168 if (next === $CLOSE_CURLY_BRACKET) { |
| 169 appendEndGroup(CLOSE_CURLY_BRACKET_TOKEN, "}", OPEN_CURLY_BRACKET_TOKEN); | 169 return appendEndGroup(CLOSE_CURLY_BRACKET_TOKEN, "}", |
| 170 return advance(); | 170 OPEN_CURLY_BRACKET_TOKEN); |
| 171 } | 171 } |
| 172 | 172 |
| 173 if (next === $SLASH) { | 173 if (next === $SLASH) { |
| 174 return tokenizeSlashOrComment(next); | 174 return tokenizeSlashOrComment(next); |
| 175 } | 175 } |
| 176 | 176 |
| 177 if (next === $AT) { | 177 if (next === $AT) { |
| 178 return tokenizeRawString(next); | 178 return tokenizeRawString(next); |
| 179 } | 179 } |
| 180 | 180 |
| (...skipping 178 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 359 return advance(); | 359 return advance(); |
| 360 } else { | 360 } else { |
| 361 appendGtGtGt(GT_TOKEN, ">>>"); | 361 appendGtGtGt(GT_TOKEN, ">>>"); |
| 362 return next; | 362 return next; |
| 363 } | 363 } |
| 364 } else { | 364 } else { |
| 365 appendGtGt(GT_TOKEN, ">>"); | 365 appendGtGt(GT_TOKEN, ">>"); |
| 366 return next; | 366 return next; |
| 367 } | 367 } |
| 368 } else { | 368 } else { |
| 369 appendEndGroup(GT_TOKEN, ">", LT_TOKEN); | 369 appendGt(GT_TOKEN, ">"); |
| 370 return next; | 370 return next; |
| 371 } | 371 } |
| 372 } | 372 } |
| 373 | 373 |
| 374 int tokenizeLessThan(int next) { | 374 int tokenizeLessThan(int next) { |
| 375 // < <= << <<= | 375 // < <= << <<= |
| 376 next = advance(); | 376 next = advance(); |
| 377 if ($EQ === next) { | 377 if ($EQ === next) { |
| 378 appendStringToken(LT_EQ_TOKEN, "<="); | 378 appendStringToken(LT_EQ_TOKEN, "<="); |
| 379 return advance(); | 379 return advance(); |
| 380 } else if ($LT === next) { | 380 } else if ($LT === next) { |
| 381 return select($EQ, "<<=", "<<"); | 381 return select($EQ, "<<=", "<<"); |
| 382 } else { | 382 } else { |
| 383 appendBeginGroup(LT_TOKEN, "<"); | 383 appendBeginGroup(LT_TOKEN, "<"); |
| 384 return next; | 384 return next; |
| 385 } | 385 } |
| 386 } | 386 } |
| 387 | 387 |
| 388 int tokenizeNumber(int next) { | 388 int tokenizeNumber(int next) { |
| 389 int start = byteOffset; | 389 int start = byteOffset; |
| 390 while (true) { | 390 while (true) { |
| 391 next = advance(); | 391 next = advance(); |
| 392 if ($0 <= next && next <= $9) { | 392 if ($0 <= next && next <= $9) { |
| 393 continue; | 393 continue; |
| 394 } else if (next === $PERIOD) { | 394 } else if (next === $PERIOD) { |
| 395 return tokenizeFractionPart(advance(), start); | 395 return tokenizeFractionPart(advance(), start); |
| 396 } else if (next === $e || next === $E || next === $d || next === $D) { | 396 } else if (next === $e || next === $E || next === $d || next === $D) { |
| 397 return tokenizeFractionPart(next, start); | 397 return tokenizeFractionPart(next, start); |
| 398 } else { | 398 } else { |
| 399 appendByteStringToken(INT_TOKEN, asciiString(start)); | 399 appendByteStringToken(INT_TOKEN, asciiString(start, 0)); |
| 400 return next; | 400 return next; |
| 401 } | 401 } |
| 402 } | 402 } |
| 403 } | 403 } |
| 404 | 404 |
| 405 int tokenizeHexOrNumber(int next) { | 405 int tokenizeHexOrNumber(int next) { |
| 406 int x = peek(); | 406 int x = peek(); |
| 407 if (x === $x || x === $X) { | 407 if (x === $x || x === $X) { |
| 408 advance(); | 408 advance(); |
| 409 return tokenizeHex(x); | 409 return tokenizeHex(x); |
| 410 } | 410 } |
| 411 return tokenizeNumber(next); | 411 return tokenizeNumber(next); |
| 412 } | 412 } |
| 413 | 413 |
| 414 int tokenizeHex(int next) { | 414 int tokenizeHex(int next) { |
| 415 int start = byteOffset; | 415 int start = byteOffset - 1; |
| 416 bool hasDigits = false; | 416 bool hasDigits = false; |
| 417 while (true) { | 417 while (true) { |
| 418 next = advance(); | 418 next = advance(); |
| 419 if (($0 <= next && next <= $9) | 419 if (($0 <= next && next <= $9) |
| 420 || ($A <= next && next <= $F) | 420 || ($A <= next && next <= $F) |
| 421 || ($a <= next && next <= $f)) { | 421 || ($a <= next && next <= $f)) { |
| 422 hasDigits = true; | 422 hasDigits = true; |
| 423 } else { | 423 } else { |
| 424 if (!hasDigits) { | 424 if (!hasDigits) { |
| 425 throw new MalformedInputException(charOffset); | 425 throw new MalformedInputException(charOffset); |
| 426 } | 426 } |
| 427 appendByteStringToken(HEXADECIMAL_TOKEN, asciiString(start)); | 427 appendByteStringToken(HEXADECIMAL_TOKEN, asciiString(start, 0)); |
| 428 return next; | 428 return next; |
| 429 } | 429 } |
| 430 } | 430 } |
| 431 } | 431 } |
| 432 | 432 |
| 433 int tokenizeDotOrNumber(int next) { | 433 int tokenizeDotOrNumber(int next) { |
| 434 int start = byteOffset; | 434 int start = byteOffset; |
| 435 next = advance(); | 435 next = advance(); |
| 436 if (($0 <= next && next <= $9)) { | 436 if (($0 <= next && next <= $9)) { |
| 437 return tokenizeFractionPart(next, start); | 437 return tokenizeFractionPart(next, start); |
| 438 } else if ($PERIOD === next) { | 438 } else if ($PERIOD === next) { |
| 439 return select($PERIOD, "...", ".."); | 439 return select($PERIOD, "...", ".."); |
| 440 } else { | 440 } else { |
| 441 appendStringToken(PERIOD_TOKEN, "."); | 441 appendStringToken(PERIOD_TOKEN, "."); |
| 442 return next; | 442 return next; |
| 443 } | 443 } |
| 444 } | 444 } |
| 445 | 445 |
| 446 int tokenizeFractionPart(int next, int start) { | 446 int tokenizeFractionPart(int next, int start) { |
| 447 bool done = false; | 447 bool done = false; |
| 448 bool hasDigit = false; |
| 448 LOOP: while (!done) { | 449 LOOP: while (!done) { |
| 449 if ($0 <= next && next <= $9) { | 450 if ($0 <= next && next <= $9) { |
| 451 hasDigit = true; |
| 450 } else if ($e === next || $E === next) { | 452 } else if ($e === next || $E === next) { |
| 453 hasDigit = true; |
| 451 next = tokenizeExponent(advance()); | 454 next = tokenizeExponent(advance()); |
| 452 done = true; | 455 done = true; |
| 453 continue LOOP; | 456 continue LOOP; |
| 454 } else { | 457 } else { |
| 455 done = true; | 458 done = true; |
| 456 continue LOOP; | 459 continue LOOP; |
| 457 } | 460 } |
| 458 next = advance(); | 461 next = advance(); |
| 459 } | 462 } |
| 463 if (!hasDigit) { |
| 464 appendByteStringToken(INT_TOKEN, asciiString(start, -2)); |
| 465 // TODO(ahe): Wrong offset for the period. |
| 466 appendStringToken(PERIOD_TOKEN, "."); |
| 467 return bigSwitch(next); |
| 468 } |
| 460 if (next === $d || next === $D) { | 469 if (next === $d || next === $D) { |
| 461 next = advance(); | 470 next = advance(); |
| 462 } | 471 } |
| 463 appendByteStringToken(DOUBLE_TOKEN, asciiString(start)); | 472 appendByteStringToken(DOUBLE_TOKEN, asciiString(start, 0)); |
| 464 return next; | 473 return next; |
| 465 } | 474 } |
| 466 | 475 |
| 467 int tokenizeExponent(int next) { | 476 int tokenizeExponent(int next) { |
| 468 if (next === $PLUS || next === $MINUS) { | 477 if (next === $PLUS || next === $MINUS) { |
| 469 next = advance(); | 478 next = advance(); |
| 470 } | 479 } |
| 471 bool hasDigits = false; | 480 bool hasDigits = false; |
| 472 while (true) { | 481 while (true) { |
| 473 if ($0 <= next && next <= $9) { | 482 if ($0 <= next && next <= $9) { |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 524 } | 533 } |
| 525 } | 534 } |
| 526 | 535 |
| 527 int tokenizeKeywordOrIdentifier(int next) { | 536 int tokenizeKeywordOrIdentifier(int next) { |
| 528 KeywordState state = KeywordState.KEYWORD_STATE; | 537 KeywordState state = KeywordState.KEYWORD_STATE; |
| 529 int start = byteOffset; | 538 int start = byteOffset; |
| 530 while (state !== null && $a <= next && next <= $z) { | 539 while (state !== null && $a <= next && next <= $z) { |
| 531 state = state.next(next); | 540 state = state.next(next); |
| 532 next = advance(); | 541 next = advance(); |
| 533 } | 542 } |
| 534 if (state === null || !state.isLeaf()) { | 543 if (state === null || state.keyword === null) { |
| 535 return tokenizeIdentifier(next, start); | 544 return tokenizeIdentifier(next, start); |
| 536 } | 545 } |
| 537 if (($A <= next && next <= $Z) || | 546 if (($A <= next && next <= $Z) || |
| 538 ($0 <= next && next <= $9) || | 547 ($0 <= next && next <= $9) || |
| 539 next === $_ || | 548 next === $_ || |
| 540 next === $$) { | 549 next === $$) { |
| 541 return tokenizeIdentifier(next, start); | 550 return tokenizeIdentifier(next, start); |
| 542 } else if (next < 128) { | 551 } else if (next < 128) { |
| 543 appendKeywordToken(state.keyword); | 552 appendKeywordToken(state.keyword); |
| 544 return next; | 553 return next; |
| 545 } else { | 554 } else { |
| 546 return tokenizeIdentifier(next, start); | 555 return tokenizeIdentifier(next, start); |
| 547 } | 556 } |
| 548 } | 557 } |
| 549 | 558 |
| 550 int tokenizeIdentifier(int next, int start) { | 559 int tokenizeIdentifier(int next, int start) { |
| 551 bool isAscii = true; | 560 bool isAscii = true; |
| 552 while (true) { | 561 while (true) { |
| 553 if (($a <= next && next <= $z) || | 562 if (($a <= next && next <= $z) || |
| 554 ($A <= next && next <= $Z) || | 563 ($A <= next && next <= $Z) || |
| 555 ($0 <= next && next <= $9) || | 564 ($0 <= next && next <= $9) || |
| 556 next === $_ || | 565 next === $_ || |
| 557 next === $$) { | 566 next === $$) { |
| 558 next = advance(); | 567 next = advance(); |
| 559 } else if (next < 128) { | 568 } else if (next < 128) { |
| 560 if (isAscii) { | 569 if (isAscii) { |
| 561 appendByteStringToken(IDENTIFIER_TOKEN, asciiString(start)); | 570 appendByteStringToken(IDENTIFIER_TOKEN, asciiString(start, 0)); |
| 562 } else { | 571 } else { |
| 563 appendByteStringToken(IDENTIFIER_TOKEN, utf8String(start, -1)); | 572 appendByteStringToken(IDENTIFIER_TOKEN, utf8String(start, -1)); |
| 564 } | 573 } |
| 565 return next; | 574 return next; |
| 566 } else { | 575 } else { |
| 567 int nonAsciiStart = byteOffset; | 576 int nonAsciiStart = byteOffset; |
| 568 do { | 577 do { |
| 569 next = nextByte(); | 578 next = nextByte(); |
| 570 } while (next > 127); | 579 } while (next > 127); |
| 571 String string = utf8String(nonAsciiStart, -1).toString(); | 580 String string = utf8String(nonAsciiStart, -1).toString(); |
| (...skipping 29 matching lines...) Expand all Loading... |
| 601 } | 610 } |
| 602 } | 611 } |
| 603 if (raw) { | 612 if (raw) { |
| 604 return tokenizeSingleLineRawString(next, q, start); | 613 return tokenizeSingleLineRawString(next, q, start); |
| 605 } else { | 614 } else { |
| 606 return tokenizeSingleLineString(next, q, start); | 615 return tokenizeSingleLineString(next, q, start); |
| 607 } | 616 } |
| 608 } | 617 } |
| 609 | 618 |
| 610 int tokenizeSingleLineString(int next, int q1, int start) { | 619 int tokenizeSingleLineString(int next, int q1, int start) { |
| 611 while (next != $EOF) { | 620 while (next !== $EOF) { |
| 612 if (next === q1) { | 621 if (next === q1) { |
| 613 appendByteStringToken(STRING_TOKEN, utf8String(start, 0)); | 622 appendByteStringToken(STRING_TOKEN, utf8String(start, 0)); |
| 614 return advance(); | 623 return advance(); |
| 615 } else if (next === $BACKSLASH) { | 624 } else if (next === $BACKSLASH) { |
| 616 next = advance(); | 625 next = advance(); |
| 617 if (next === $EOF) { | 626 if (next === $EOF) { |
| 618 throw new MalformedInputException(charOffset); | 627 throw new MalformedInputException(charOffset); |
| 619 } | 628 } |
| 629 } else if (next === $$) { |
| 630 beginToken(); |
| 631 next = advance(); |
| 632 if (next === $OPEN_CURLY_BRACKET) { |
| 633 next = tokenizeInterpolatedExpression(next, q1, start); |
| 634 } |
| 635 continue; |
| 620 } else if (next === $LF || next === $CR) { | 636 } else if (next === $LF || next === $CR) { |
| 621 throw new MalformedInputException(charOffset); | 637 throw new MalformedInputException(charOffset); |
| 622 } | 638 } |
| 623 next = advance(); | 639 next = advance(); |
| 624 } | 640 } |
| 625 throw new MalformedInputException(charOffset); | 641 throw new MalformedInputException(charOffset); |
| 626 } | 642 } |
| 627 | 643 |
| 644 int tokenizeInterpolatedExpression(int next, int q, int start) { |
| 645 appendByteStringToken(STRING_TOKEN, utf8String(start, 0)); |
| 646 appendBeginGroup(STRING_INTERPOLATION_TOKEN, "\${"); |
| 647 next = advance(); |
| 648 while (next !== $EOF && next !== $STX) { |
| 649 next = bigSwitch(next); |
| 650 } |
| 651 if (next === $EOF) return next; |
| 652 return advance(); |
| 653 } |
| 654 |
| 628 int tokenizeSingleLineRawString(int next, int q1, int start) { | 655 int tokenizeSingleLineRawString(int next, int q1, int start) { |
| 629 next = advance(); | 656 next = advance(); |
| 630 while (next != $EOF) { | 657 while (next != $EOF) { |
| 631 if (next === q1) { | 658 if (next === q1) { |
| 632 appendByteStringToken(STRING_TOKEN, utf8String(start, 0)); | 659 appendByteStringToken(STRING_TOKEN, utf8String(start, 0)); |
| 633 return advance(); | 660 return advance(); |
| 634 } else if (next === $LF || next === $CR) { | 661 } else if (next === $LF || next === $CR) { |
| 635 throw new MalformedInputException(charOffset); | 662 throw new MalformedInputException(charOffset); |
| 636 } | 663 } |
| 637 next = advance(); | 664 next = advance(); |
| (...skipping 19 matching lines...) Expand all Loading... |
| 657 } | 684 } |
| 658 return next; | 685 return next; |
| 659 } | 686 } |
| 660 } | 687 } |
| 661 | 688 |
| 662 class MalformedInputException { | 689 class MalformedInputException { |
| 663 final message; | 690 final message; |
| 664 MalformedInputException(this.message); | 691 MalformedInputException(this.message); |
| 665 toString() => message.toString(); | 692 toString() => message.toString(); |
| 666 } | 693 } |
| OLD | NEW |