| OLD | NEW |
| 1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file | 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 | 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 'package:front_end/src/base/errors.dart'; | 5 import 'package:front_end/src/base/errors.dart'; |
| 6 import 'package:front_end/src/base/jenkins_smi_hash.dart'; | 6 import 'package:front_end/src/base/jenkins_smi_hash.dart'; |
| 7 import 'package:front_end/src/scanner/errors.dart'; | 7 import 'package:front_end/src/scanner/errors.dart'; |
| 8 import 'package:front_end/src/scanner/reader.dart'; | 8 import 'package:front_end/src/scanner/reader.dart'; |
| 9 import 'package:front_end/src/scanner/scanner.dart'; | 9 import 'package:front_end/src/scanner/scanner.dart'; |
| 10 import 'package:front_end/src/scanner/token.dart'; | 10 import 'package:front_end/src/scanner/token.dart'; |
| (...skipping 417 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 428 _assertError(ScannerErrorCode.ILLEGAL_CHARACTER, 0, "\u0312", [0x312]); | 428 _assertError(ScannerErrorCode.ILLEGAL_CHARACTER, 0, "\u0312", [0x312]); |
| 429 } | 429 } |
| 430 | 430 |
| 431 void test_incomplete_string_interpolation() { | 431 void test_incomplete_string_interpolation() { |
| 432 // https://code.google.com/p/dart/issues/detail?id=18073 | 432 // https://code.google.com/p/dart/issues/detail?id=18073 |
| 433 List<Token> expectedTokens = [ | 433 List<Token> expectedTokens = [ |
| 434 new StringToken(TokenType.STRING, "\"foo ", 0), | 434 new StringToken(TokenType.STRING, "\"foo ", 0), |
| 435 new StringToken(TokenType.STRING_INTERPOLATION_EXPRESSION, "\${", 5), | 435 new StringToken(TokenType.STRING_INTERPOLATION_EXPRESSION, "\${", 5), |
| 436 new StringToken(TokenType.IDENTIFIER, "bar", 7), | 436 new StringToken(TokenType.IDENTIFIER, "bar", 7), |
| 437 ]; | 437 ]; |
| 438 var expectedErrors = [ |
| 439 new TestError(9, ScannerErrorCode.UNTERMINATED_STRING_LITERAL, null), |
| 440 ]; |
| 438 if (usingFasta) { | 441 if (usingFasta) { |
| 439 // fasta inserts synthetic closers | 442 // fasta inserts synthetic closers |
| 440 expectedTokens.addAll([ | 443 expectedTokens.addAll([ |
| 441 new SyntheticToken(TokenType.CLOSE_CURLY_BRACKET, 10), | 444 new SyntheticToken(TokenType.CLOSE_CURLY_BRACKET, 10), |
| 442 new SyntheticStringToken(TokenType.STRING, "\"", 10, 0), | 445 new SyntheticStringToken(TokenType.STRING, "\"", 10, 0), |
| 443 ]); | 446 ]); |
| 447 expectedErrors.addAll([ |
| 448 new TestError(5, ScannerErrorCode.EXPECTED_TOKEN, ['}']), |
| 449 ]); |
| 444 } else { | 450 } else { |
| 445 expectedTokens.addAll([ | 451 expectedTokens.addAll([ |
| 446 new StringToken(TokenType.STRING, "", 10), | 452 new StringToken(TokenType.STRING, "", 10), |
| 447 ]); | 453 ]); |
| 448 } | 454 } |
| 449 _assertErrorAndTokens(ScannerErrorCode.UNTERMINATED_STRING_LITERAL, 9, | 455 ErrorListener listener = new ErrorListener(); |
| 450 "\"foo \${bar", expectedTokens); | 456 Token token = scanWithListener("\"foo \${bar", listener); |
| 457 listener.assertErrors(expectedErrors); |
| 458 _checkTokens(token, expectedTokens); |
| 451 } | 459 } |
| 452 | 460 |
| 453 void test_index() { | 461 void test_index() { |
| 454 _assertToken(TokenType.INDEX, "[]"); | 462 _assertToken(TokenType.INDEX, "[]"); |
| 455 } | 463 } |
| 456 | 464 |
| 457 void test_index_eq() { | 465 void test_index_eq() { |
| 458 _assertToken(TokenType.INDEX_EQ, "[]="); | 466 _assertToken(TokenType.INDEX_EQ, "[]="); |
| 459 } | 467 } |
| 460 | 468 |
| (...skipping 251 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 712 | 720 |
| 713 void test_lt_lt() { | 721 void test_lt_lt() { |
| 714 _assertToken(TokenType.LT_LT, "<<"); | 722 _assertToken(TokenType.LT_LT, "<<"); |
| 715 } | 723 } |
| 716 | 724 |
| 717 void test_lt_lt_eq() { | 725 void test_lt_lt_eq() { |
| 718 _assertToken(TokenType.LT_LT_EQ, "<<="); | 726 _assertToken(TokenType.LT_LT_EQ, "<<="); |
| 719 } | 727 } |
| 720 | 728 |
| 721 void test_matching_braces() { | 729 void test_matching_braces() { |
| 722 var openBrace1 = _scan('{1: {2: 3}}') as BeginToken; | 730 BeginToken openBrace1 = _scan('{1: {2: 3}}'); |
| 723 var one = openBrace1.next; | 731 var one = openBrace1.next; |
| 724 var colon1 = one.next; | 732 var colon1 = one.next; |
| 725 var openBrace2 = colon1.next as BeginToken; | 733 BeginToken openBrace2 = colon1.next; |
| 726 var two = openBrace2.next; | 734 var two = openBrace2.next; |
| 727 var colon2 = two.next; | 735 var colon2 = two.next; |
| 728 var three = colon2.next; | 736 var three = colon2.next; |
| 729 var closeBrace1 = three.next; | 737 var closeBrace1 = three.next; |
| 730 var closeBrace2 = closeBrace1.next; | 738 var closeBrace2 = closeBrace1.next; |
| 731 expect(closeBrace2.next.type, TokenType.EOF); | 739 expect(closeBrace2.next.type, TokenType.EOF); |
| 732 expect(openBrace1.endToken, same(closeBrace2)); | 740 expect(openBrace1.endToken, same(closeBrace2)); |
| 733 expect(openBrace2.endToken, same(closeBrace1)); | 741 expect(openBrace2.endToken, same(closeBrace1)); |
| 734 } | 742 } |
| 735 | 743 |
| 736 void test_matching_brackets() { | 744 void test_matching_brackets() { |
| 737 var openBracket1 = _scan('[1, [2]]') as BeginToken; | 745 BeginToken openBracket1 = _scan('[1, [2]]'); |
| 738 var one = openBracket1.next; | 746 var one = openBracket1.next; |
| 739 var comma = one.next; | 747 var comma = one.next; |
| 740 var openBracket2 = comma.next as BeginToken; | 748 BeginToken openBracket2 = comma.next; |
| 741 var two = openBracket2.next; | 749 var two = openBracket2.next; |
| 742 var closeBracket1 = two.next; | 750 var closeBracket1 = two.next; |
| 743 var closeBracket2 = closeBracket1.next; | 751 var closeBracket2 = closeBracket1.next; |
| 744 expect(closeBracket2.next.type, TokenType.EOF); | 752 expect(closeBracket2.next.type, TokenType.EOF); |
| 745 expect(openBracket1.endToken, same(closeBracket2)); | 753 expect(openBracket1.endToken, same(closeBracket2)); |
| 746 expect(openBracket2.endToken, same(closeBracket1)); | 754 expect(openBracket2.endToken, same(closeBracket1)); |
| 747 } | 755 } |
| 748 | 756 |
| 749 void test_matching_parens() { | 757 void test_matching_parens() { |
| 750 var openParen1 = _scan('(f(x))') as BeginToken; | 758 BeginToken openParen1 = _scan('(f(x))'); |
| 751 var f = openParen1.next; | 759 var f = openParen1.next; |
| 752 var openParen2 = f.next as BeginToken; | 760 BeginToken openParen2 = f.next; |
| 753 var x = openParen2.next; | 761 var x = openParen2.next; |
| 754 var closeParen1 = x.next; | 762 var closeParen1 = x.next; |
| 755 var closeParen2 = closeParen1.next; | 763 var closeParen2 = closeParen1.next; |
| 756 expect(closeParen2.next.type, TokenType.EOF); | 764 expect(closeParen2.next.type, TokenType.EOF); |
| 757 expect(openParen1.endToken, same(closeParen2)); | 765 expect(openParen1.endToken, same(closeParen2)); |
| 758 expect(openParen2.endToken, same(closeParen1)); | 766 expect(openParen2.endToken, same(closeParen1)); |
| 759 } | 767 } |
| 760 | 768 |
| 761 void test_minus() { | 769 void test_minus() { |
| 762 _assertToken(TokenType.MINUS, "-"); | 770 _assertToken(TokenType.MINUS, "-"); |
| 763 } | 771 } |
| 764 | 772 |
| 765 void test_minus_eq() { | 773 void test_minus_eq() { |
| 766 _assertToken(TokenType.MINUS_EQ, "-="); | 774 _assertToken(TokenType.MINUS_EQ, "-="); |
| 767 } | 775 } |
| 768 | 776 |
| 769 void test_minus_minus() { | 777 void test_minus_minus() { |
| 770 _assertToken(TokenType.MINUS_MINUS, "--"); | 778 _assertToken(TokenType.MINUS_MINUS, "--"); |
| 771 } | 779 } |
| 772 | 780 |
| 773 void test_mismatched_closer() { | 781 void test_mismatched_closer() { |
| 774 // When openers and closers are mismatched, analyzer favors considering the | 782 // When openers and closers are mismatched, analyzer favors considering the |
| 775 // closer to be mismatched, which means that `(])` parses as a pair of | 783 // closer to be mismatched, which means that `(])` parses as a pair of |
| 776 // matched parentheses with an unmatched closing bracket between them. | 784 // matched parentheses with an unmatched closing bracket between them. |
| 777 var openParen = _scan('(])') as BeginToken; | 785 ErrorListener listener = new ErrorListener(); |
| 786 BeginToken openParen = scanWithListener('(])', listener); |
| 778 if (usingFasta) { | 787 if (usingFasta) { |
| 779 // When openers and closers are mismatched, | 788 // When openers and closers are mismatched, |
| 780 // fasta favors considering the opener to be mismatched, | 789 // fasta favors considering the opener to be mismatched, |
| 781 // and inserts synthetic closers as needed. | 790 // and inserts synthetic closers as needed. |
| 782 // `(])` is parsed as `()])` where the first `)` is synthetic | 791 // `(])` is parsed as `()])` where the first `)` is synthetic |
| 783 // and the trailing `])` are unmatched. | 792 // and the trailing `])` are unmatched. |
| 784 var closeParen = openParen.next; | 793 var closeParen = openParen.next; |
| 785 expect(closeParen.isSynthetic, isTrue); | 794 expect(closeParen.isSynthetic, isTrue); |
| 786 var closeBracket = closeParen.next; | 795 var closeBracket = closeParen.next; |
| 787 expect(closeBracket.isSynthetic, isFalse); | 796 expect(closeBracket.isSynthetic, isFalse); |
| 788 var closeParen2 = closeBracket.next; | 797 var closeParen2 = closeBracket.next; |
| 789 expect(closeParen2.isSynthetic, isFalse); | 798 expect(closeParen2.isSynthetic, isFalse); |
| 790 expect(closeParen2.next.type, TokenType.EOF); | 799 expect(closeParen2.next.type, TokenType.EOF); |
| 791 expect(openParen.endToken, same(closeParen)); | 800 expect(openParen.endToken, same(closeParen)); |
| 801 listener.assertErrors([ |
| 802 new TestError(0, ScannerErrorCode.EXPECTED_TOKEN, [')']), |
| 803 ]); |
| 792 } else { | 804 } else { |
| 793 var closeBracket = openParen.next; | 805 var closeBracket = openParen.next; |
| 794 var closeParen = closeBracket.next; | 806 var closeParen = closeBracket.next; |
| 795 expect(closeParen.next.type, TokenType.EOF); | 807 expect(closeParen.next.type, TokenType.EOF); |
| 796 expect(openParen.endToken, same(closeParen)); | 808 expect(openParen.endToken, same(closeParen)); |
| 809 listener.assertNoErrors(); |
| 797 } | 810 } |
| 798 } | 811 } |
| 799 | 812 |
| 800 void test_mismatched_opener() { | 813 void test_mismatched_opener() { |
| 801 // When openers and closers are mismatched, analyzer favors considering the | 814 // When openers and closers are mismatched, analyzer favors considering the |
| 802 // closer to be mismatched, which means that `([)` parses as three unmatched | 815 // closer to be mismatched, which means that `([)` parses as three unmatched |
| 803 // tokens. | 816 // tokens. |
| 804 var openParen = _scan('([)') as BeginToken; | 817 ErrorListener listener = new ErrorListener(); |
| 805 var openBracket = openParen.next as BeginToken; | 818 BeginToken openParen = scanWithListener('([)', listener); |
| 819 BeginToken openBracket = openParen.next; |
| 806 if (usingFasta) { | 820 if (usingFasta) { |
| 807 // When openers and closers are mismatched, | 821 // When openers and closers are mismatched, |
| 808 // fasta favors considering the opener to be mismatched | 822 // fasta favors considering the opener to be mismatched |
| 809 // and inserts synthetic closers as needed. | 823 // and inserts synthetic closers as needed. |
| 810 // `([)` is scanned as `([])` where `]` is synthetic. | 824 // `([)` is scanned as `([])` where `]` is synthetic. |
| 811 var closeBracket = openBracket.next; | 825 var closeBracket = openBracket.next; |
| 812 expect(closeBracket.isSynthetic, isTrue); | 826 expect(closeBracket.isSynthetic, isTrue); |
| 813 var closeParen = closeBracket.next; | 827 var closeParen = closeBracket.next; |
| 814 expect(closeParen.isSynthetic, isFalse); | 828 expect(closeParen.isSynthetic, isFalse); |
| 815 expect(closeParen.next.type, TokenType.EOF); | 829 expect(closeParen.next.type, TokenType.EOF); |
| 816 expect(openBracket.endToken, closeBracket); | 830 expect(openBracket.endToken, closeBracket); |
| 817 expect(openParen.endToken, closeParen); | 831 expect(openParen.endToken, closeParen); |
| 832 listener.assertErrors([ |
| 833 new TestError(1, ScannerErrorCode.EXPECTED_TOKEN, [']']), |
| 834 ]); |
| 818 } else { | 835 } else { |
| 819 var closeParen = openBracket.next; | 836 var closeParen = openBracket.next; |
| 820 expect(closeParen.next.type, TokenType.EOF); | 837 expect(closeParen.next.type, TokenType.EOF); |
| 821 expect(openParen.endToken, isNull); | 838 expect(openParen.endToken, isNull); |
| 822 expect(openBracket.endToken, isNull); | 839 expect(openBracket.endToken, isNull); |
| 840 listener.assertNoErrors(); |
| 823 } | 841 } |
| 824 } | 842 } |
| 825 | 843 |
| 826 void test_mismatched_opener_in_interpolation() { | 844 void test_mismatched_opener_in_interpolation() { |
| 827 // In an interpolation expression, analyzer considers a closing `}` to | 845 // In an interpolation expression, analyzer considers a closing `}` to |
| 828 // always match the preceding unmatched `{`, even if there are intervening | 846 // always match the preceding unmatched `{`, even if there are intervening |
| 829 // unmatched tokens, which means that `"${({(}}"` parses as though the open | 847 // unmatched tokens, which means that `"${({(}}"` parses as though the open |
| 830 // parens are unmatched but everything else is matched. | 848 // parens are unmatched but everything else is matched. |
| 831 var stringStart = _scan(r'"${({(}}"'); | 849 var stringStart = _scan(r'"${({(}}"'); |
| 832 var interpolationStart = stringStart.next as BeginToken; | 850 BeginToken interpolationStart = stringStart.next; |
| 833 var openParen1 = interpolationStart.next as BeginToken; | 851 BeginToken openParen1 = interpolationStart.next; |
| 834 var openBrace = openParen1.next as BeginToken; | 852 BeginToken openBrace = openParen1.next; |
| 835 var openParen2 = openBrace.next as BeginToken; | 853 BeginToken openParen2 = openBrace.next; |
| 836 var closeBrace = openParen2.next; | 854 var closeBrace = openParen2.next; |
| 837 var interpolationEnd = closeBrace.next; | 855 var interpolationEnd = closeBrace.next; |
| 838 var stringEnd = interpolationEnd.next; | 856 var stringEnd = interpolationEnd.next; |
| 839 expect(stringEnd.next.type, TokenType.EOF); | 857 expect(stringEnd.next.type, TokenType.EOF); |
| 840 expect(interpolationStart.endToken, same(interpolationEnd)); | 858 expect(interpolationStart.endToken, same(interpolationEnd)); |
| 841 expect(openParen1.endToken, isNull); | 859 expect(openParen1.endToken, isNull); |
| 842 expect(openBrace.endToken, same(closeBrace)); | 860 expect(openBrace.endToken, same(closeBrace)); |
| 843 expect(openParen2.endToken, isNull); | 861 expect(openParen2.endToken, isNull); |
| 844 } | 862 } |
| 845 | 863 |
| (...skipping 189 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1035 ]); | 1053 ]); |
| 1036 } | 1054 } |
| 1037 } | 1055 } |
| 1038 | 1056 |
| 1039 void test_string_multi_unterminated_interpolation_block() { | 1057 void test_string_multi_unterminated_interpolation_block() { |
| 1040 List<Token> expectedTokens = [ | 1058 List<Token> expectedTokens = [ |
| 1041 new StringToken(TokenType.STRING, "'''", 0), | 1059 new StringToken(TokenType.STRING, "'''", 0), |
| 1042 new StringToken(TokenType.STRING_INTERPOLATION_EXPRESSION, "\${", 3), | 1060 new StringToken(TokenType.STRING_INTERPOLATION_EXPRESSION, "\${", 3), |
| 1043 new StringToken(TokenType.IDENTIFIER, "name", 5), | 1061 new StringToken(TokenType.IDENTIFIER, "name", 5), |
| 1044 ]; | 1062 ]; |
| 1063 var expectedErrors = [ |
| 1064 new TestError(8, ScannerErrorCode.UNTERMINATED_STRING_LITERAL, null), |
| 1065 ]; |
| 1045 if (usingFasta) { | 1066 if (usingFasta) { |
| 1046 // fasta inserts synthetic closers | 1067 // fasta inserts synthetic closers |
| 1047 expectedTokens.addAll([ | 1068 expectedTokens.addAll([ |
| 1048 new SyntheticToken(TokenType.CLOSE_CURLY_BRACKET, 9), | 1069 new SyntheticToken(TokenType.CLOSE_CURLY_BRACKET, 9), |
| 1049 new SyntheticStringToken(TokenType.STRING, "'''", 9, 0), | 1070 new SyntheticStringToken(TokenType.STRING, "'''", 9, 0), |
| 1050 ]); | 1071 ]); |
| 1072 expectedErrors.addAll([ |
| 1073 new TestError(3, ScannerErrorCode.EXPECTED_TOKEN, ['}']), |
| 1074 ]); |
| 1051 } else { | 1075 } else { |
| 1052 expectedTokens.addAll([ | 1076 expectedTokens.addAll([ |
| 1053 new StringToken(TokenType.STRING, "", 9), | 1077 new StringToken(TokenType.STRING, "", 9), |
| 1054 ]); | 1078 ]); |
| 1055 } | 1079 } |
| 1056 _assertErrorAndTokens(ScannerErrorCode.UNTERMINATED_STRING_LITERAL, 8, | 1080 ErrorListener listener = new ErrorListener(); |
| 1057 "'''\${name", expectedTokens); | 1081 Token token = scanWithListener("'''\${name", listener); |
| 1082 listener.assertErrors(expectedErrors); |
| 1083 _checkTokens(token, expectedTokens); |
| 1058 } | 1084 } |
| 1059 | 1085 |
| 1060 void test_string_multi_unterminated_interpolation_identifier() { | 1086 void test_string_multi_unterminated_interpolation_identifier() { |
| 1061 List<Token> expectedTokens = [ | 1087 List<Token> expectedTokens = [ |
| 1062 new StringToken(TokenType.STRING, "'''", 0), | 1088 new StringToken(TokenType.STRING, "'''", 0), |
| 1063 new StringToken(TokenType.STRING_INTERPOLATION_IDENTIFIER, "\$", 3), | 1089 new StringToken(TokenType.STRING_INTERPOLATION_IDENTIFIER, "\$", 3), |
| 1064 new StringToken(TokenType.IDENTIFIER, "name", 4), | 1090 new StringToken(TokenType.IDENTIFIER, "name", 4), |
| 1065 ]; | 1091 ]; |
| 1066 if (usingFasta) { | 1092 if (usingFasta) { |
| 1067 // fasta inserts synthetic closers | 1093 // fasta inserts synthetic closers |
| (...skipping 145 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1213 } | 1239 } |
| 1214 | 1240 |
| 1215 void test_string_simple_interpolation_missingIdentifier() { | 1241 void test_string_simple_interpolation_missingIdentifier() { |
| 1216 var expectedTokens = <Token>[ | 1242 var expectedTokens = <Token>[ |
| 1217 new StringToken(TokenType.STRING, "'", 0), | 1243 new StringToken(TokenType.STRING, "'", 0), |
| 1218 new StringToken(TokenType.STRING_INTERPOLATION_IDENTIFIER, "\$", 1), | 1244 new StringToken(TokenType.STRING_INTERPOLATION_IDENTIFIER, "\$", 1), |
| 1219 new StringToken(TokenType.IDENTIFIER, "x", 2), | 1245 new StringToken(TokenType.IDENTIFIER, "x", 2), |
| 1220 new StringToken(TokenType.STRING, "", 3), | 1246 new StringToken(TokenType.STRING, "", 3), |
| 1221 new StringToken(TokenType.STRING_INTERPOLATION_IDENTIFIER, "\$", 3), | 1247 new StringToken(TokenType.STRING_INTERPOLATION_IDENTIFIER, "\$", 3), |
| 1222 ]; | 1248 ]; |
| 1249 var expectedErrors = []; |
| 1223 if (usingFasta) { | 1250 if (usingFasta) { |
| 1224 // Fasta scanner inserts a synthetic identifier | 1251 // Fasta scanner inserts a synthetic identifier |
| 1225 expectedTokens.addAll([ | 1252 expectedTokens.addAll([ |
| 1226 new SyntheticStringToken(TokenType.IDENTIFIER, "", 4, 0), | 1253 new SyntheticStringToken(TokenType.IDENTIFIER, "", 4, 0), |
| 1227 new StringToken(TokenType.STRING, "'", 4), | 1254 new StringToken(TokenType.STRING, "'", 4), |
| 1228 ]); | 1255 ]); |
| 1256 expectedErrors.addAll([ |
| 1257 new TestError(4, ScannerErrorCode.MISSING_IDENTIFIER, null), |
| 1258 ]); |
| 1229 } else { | 1259 } else { |
| 1230 expectedTokens.addAll([ | 1260 expectedTokens.addAll([ |
| 1231 new StringToken(TokenType.STRING, "'", 4), | 1261 new StringToken(TokenType.STRING, "'", 4), |
| 1232 ]); | 1262 ]); |
| 1233 } | 1263 } |
| 1234 _assertTokens("'\$x\$'", expectedTokens); | 1264 ErrorListener listener = new ErrorListener(); |
| 1265 Token token = scanWithListener("'\$x\$'", listener); |
| 1266 listener.assertErrors(expectedErrors); |
| 1267 _checkTokens(token, expectedTokens); |
| 1235 } | 1268 } |
| 1236 | 1269 |
| 1237 void test_string_simple_interpolation_nonIdentifier() { | 1270 void test_string_simple_interpolation_nonIdentifier() { |
| 1238 var expectedTokens = <Token>[ | 1271 var expectedTokens = <Token>[ |
| 1239 new StringToken(TokenType.STRING, "'", 0), | 1272 new StringToken(TokenType.STRING, "'", 0), |
| 1240 new StringToken(TokenType.STRING_INTERPOLATION_IDENTIFIER, "\$", 1), | 1273 new StringToken(TokenType.STRING_INTERPOLATION_IDENTIFIER, "\$", 1), |
| 1241 ]; | 1274 ]; |
| 1275 var expectedErrors = []; |
| 1242 if (usingFasta) { | 1276 if (usingFasta) { |
| 1243 expectedTokens.addAll([ | 1277 expectedTokens.addAll([ |
| 1244 new SyntheticStringToken(TokenType.IDENTIFIER, "", 2), | 1278 new SyntheticStringToken(TokenType.IDENTIFIER, "", 2), |
| 1245 ]); | 1279 ]); |
| 1280 expectedErrors.addAll([ |
| 1281 new TestError(2, ScannerErrorCode.MISSING_IDENTIFIER, null), |
| 1282 ]); |
| 1246 } | 1283 } |
| 1247 expectedTokens.addAll([ | 1284 expectedTokens.addAll([ |
| 1248 new StringToken(TokenType.STRING, "1'", 2), | 1285 new StringToken(TokenType.STRING, "1'", 2), |
| 1249 ]); | 1286 ]); |
| 1250 _assertTokens("'\$1'", expectedTokens); | 1287 ErrorListener listener = new ErrorListener(); |
| 1288 Token token = scanWithListener("'\$1'", listener); |
| 1289 listener.assertErrors(expectedErrors); |
| 1290 _checkTokens(token, expectedTokens); |
| 1251 } | 1291 } |
| 1252 | 1292 |
| 1253 void test_string_simple_single() { | 1293 void test_string_simple_single() { |
| 1254 _assertToken(TokenType.STRING, "'string'"); | 1294 _assertToken(TokenType.STRING, "'string'"); |
| 1255 } | 1295 } |
| 1256 | 1296 |
| 1257 void test_string_simple_unterminated_eof() { | 1297 void test_string_simple_unterminated_eof() { |
| 1258 String source = "'string"; | 1298 String source = "'string"; |
| 1259 List<Token> expectedTokens = []; | 1299 List<Token> expectedTokens = []; |
| 1260 if (usingFasta) { | 1300 if (usingFasta) { |
| (...skipping 26 matching lines...) Expand all Loading... |
| 1287 _assertErrorAndTokens(ScannerErrorCode.UNTERMINATED_STRING_LITERAL, | 1327 _assertErrorAndTokens(ScannerErrorCode.UNTERMINATED_STRING_LITERAL, |
| 1288 usingFasta ? 6 : 7, source, expectedTokens); | 1328 usingFasta ? 6 : 7, source, expectedTokens); |
| 1289 } | 1329 } |
| 1290 | 1330 |
| 1291 void test_string_simple_unterminated_interpolation_block() { | 1331 void test_string_simple_unterminated_interpolation_block() { |
| 1292 List<Token> expectedTokens = [ | 1332 List<Token> expectedTokens = [ |
| 1293 new StringToken(TokenType.STRING, "'", 0), | 1333 new StringToken(TokenType.STRING, "'", 0), |
| 1294 new StringToken(TokenType.STRING_INTERPOLATION_EXPRESSION, "\${", 1), | 1334 new StringToken(TokenType.STRING_INTERPOLATION_EXPRESSION, "\${", 1), |
| 1295 new StringToken(TokenType.IDENTIFIER, "name", 3), | 1335 new StringToken(TokenType.IDENTIFIER, "name", 3), |
| 1296 ]; | 1336 ]; |
| 1337 List<TestError> expectedErrors = [ |
| 1338 new TestError(6, ScannerErrorCode.UNTERMINATED_STRING_LITERAL, null), |
| 1339 ]; |
| 1297 if (usingFasta) { | 1340 if (usingFasta) { |
| 1298 // fasta inserts synthetic closers | 1341 // fasta inserts synthetic closers |
| 1299 expectedTokens.addAll([ | 1342 expectedTokens.addAll([ |
| 1300 new SyntheticToken(TokenType.CLOSE_CURLY_BRACKET, 7), | 1343 new SyntheticToken(TokenType.CLOSE_CURLY_BRACKET, 7), |
| 1301 new SyntheticStringToken(TokenType.STRING, "'", 7, 0), | 1344 new SyntheticStringToken(TokenType.STRING, "'", 7, 0), |
| 1302 ]); | 1345 ]); |
| 1346 expectedErrors.addAll([ |
| 1347 new TestError(1, ScannerErrorCode.EXPECTED_TOKEN, ['}']), |
| 1348 ]); |
| 1303 } else { | 1349 } else { |
| 1304 expectedTokens.addAll([ | 1350 expectedTokens.addAll([ |
| 1305 new StringToken(TokenType.STRING, "", 7), | 1351 new StringToken(TokenType.STRING, "", 7), |
| 1306 ]); | 1352 ]); |
| 1307 } | 1353 } |
| 1308 _assertErrorAndTokens(ScannerErrorCode.UNTERMINATED_STRING_LITERAL, 6, | 1354 ErrorListener listener = new ErrorListener(); |
| 1309 "'\${name", expectedTokens); | 1355 Token token = scanWithListener("'\${name", listener); |
| 1356 listener.assertErrors(expectedErrors); |
| 1357 _checkTokens(token, expectedTokens); |
| 1310 } | 1358 } |
| 1311 | 1359 |
| 1312 void test_string_simple_unterminated_interpolation_identifier() { | 1360 void test_string_simple_unterminated_interpolation_identifier() { |
| 1313 List<Token> expectedTokens = [ | 1361 List<Token> expectedTokens = [ |
| 1314 new StringToken(TokenType.STRING, "'", 0), | 1362 new StringToken(TokenType.STRING, "'", 0), |
| 1315 new StringToken(TokenType.STRING_INTERPOLATION_IDENTIFIER, "\$", 1), | 1363 new StringToken(TokenType.STRING_INTERPOLATION_IDENTIFIER, "\$", 1), |
| 1316 new StringToken(TokenType.IDENTIFIER, "name", 2), | 1364 new StringToken(TokenType.IDENTIFIER, "name", 2), |
| 1317 ]; | 1365 ]; |
| 1318 if (usingFasta) { | 1366 if (usingFasta) { |
| 1319 // fasta inserts synthetic closers | 1367 // fasta inserts synthetic closers |
| (...skipping 28 matching lines...) Expand all Loading... |
| 1348 void test_tilde_slash_eq() { | 1396 void test_tilde_slash_eq() { |
| 1349 _assertToken(TokenType.TILDE_SLASH_EQ, "~/="); | 1397 _assertToken(TokenType.TILDE_SLASH_EQ, "~/="); |
| 1350 } | 1398 } |
| 1351 | 1399 |
| 1352 void test_unclosedPairInInterpolation() { | 1400 void test_unclosedPairInInterpolation() { |
| 1353 ErrorListener listener = new ErrorListener(); | 1401 ErrorListener listener = new ErrorListener(); |
| 1354 scanWithListener("'\${(}'", listener); | 1402 scanWithListener("'\${(}'", listener); |
| 1355 } | 1403 } |
| 1356 | 1404 |
| 1357 void test_unmatched_openers() { | 1405 void test_unmatched_openers() { |
| 1358 var openBrace = _scan('{[(') as BeginToken; | 1406 BeginToken openBrace = _scan('{[('); |
| 1359 var openBracket = openBrace.next as BeginToken; | 1407 BeginToken openBracket = openBrace.next; |
| 1360 var openParen = openBracket.next as BeginToken; | 1408 BeginToken openParen = openBracket.next; |
| 1361 expect(openParen.next.type, TokenType.EOF); | 1409 expect(openParen.next.type, TokenType.EOF); |
| 1362 expect(openBrace.endToken, isNull); | 1410 expect(openBrace.endToken, isNull); |
| 1363 expect(openBracket.endToken, isNull); | 1411 expect(openBracket.endToken, isNull); |
| 1364 expect(openParen.endToken, isNull); | 1412 expect(openParen.endToken, isNull); |
| 1365 } | 1413 } |
| 1366 | 1414 |
| 1367 void _assertComment(TokenType commentType, String source, | 1415 void _assertComment(TokenType commentType, String source, |
| 1368 {bool genericMethodComments: false}) { | 1416 {bool genericMethodComments: false}) { |
| 1369 // | 1417 // |
| 1370 // Test without a trailing end-of-line marker | 1418 // Test without a trailing end-of-line marker |
| (...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1451 expect((value as Keyword).lexeme, source); | 1499 expect((value as Keyword).lexeme, source); |
| 1452 expect(token.next.type, TokenType.EOF); | 1500 expect(token.next.type, TokenType.EOF); |
| 1453 } | 1501 } |
| 1454 | 1502 |
| 1455 /** | 1503 /** |
| 1456 * Assert that the token scanned from the given [source] has the | 1504 * Assert that the token scanned from the given [source] has the |
| 1457 * [expectedType]. | 1505 * [expectedType]. |
| 1458 */ | 1506 */ |
| 1459 Token _assertToken(TokenType expectedType, String source, | 1507 Token _assertToken(TokenType expectedType, String source, |
| 1460 {bool lazyAssignmentOperators: false}) { | 1508 {bool lazyAssignmentOperators: false}) { |
| 1461 Token originalToken = | 1509 // Fasta generates errors for unmatched '{', '[', etc |
| 1462 _scan(source, lazyAssignmentOperators: lazyAssignmentOperators); | 1510 Token originalToken = _scan(source, |
| 1511 lazyAssignmentOperators: lazyAssignmentOperators, |
| 1512 ignoreErrors: usingFasta); |
| 1463 expect(originalToken, isNotNull); | 1513 expect(originalToken, isNotNull); |
| 1464 expect(originalToken.type, expectedType); | 1514 expect(originalToken.type, expectedType); |
| 1465 expect(originalToken.offset, 0); | 1515 expect(originalToken.offset, 0); |
| 1466 expect(originalToken.length, source.length); | 1516 expect(originalToken.length, source.length); |
| 1467 expect(originalToken.lexeme, source); | 1517 expect(originalToken.lexeme, source); |
| 1468 if (expectedType == TokenType.SCRIPT_TAG) { | 1518 if (expectedType == TokenType.SCRIPT_TAG) { |
| 1469 // Adding space before the script tag is not allowed, and adding text at | 1519 // Adding space before the script tag is not allowed, and adding text at |
| 1470 // the end changes nothing. | 1520 // the end changes nothing. |
| 1471 return originalToken; | 1521 return originalToken; |
| 1472 } else if (expectedType == TokenType.SINGLE_LINE_COMMENT) { | 1522 } else if (expectedType == TokenType.SINGLE_LINE_COMMENT) { |
| 1473 // Adding space to an end-of-line comment changes the comment. | 1523 // Adding space to an end-of-line comment changes the comment. |
| 1474 Token tokenWithSpaces = | 1524 Token tokenWithSpaces = _scan(" $source", |
| 1475 _scan(" $source", lazyAssignmentOperators: lazyAssignmentOperators); | 1525 lazyAssignmentOperators: lazyAssignmentOperators, |
| 1526 ignoreErrors: usingFasta); |
| 1476 expect(tokenWithSpaces, isNotNull); | 1527 expect(tokenWithSpaces, isNotNull); |
| 1477 expect(tokenWithSpaces.type, expectedType); | 1528 expect(tokenWithSpaces.type, expectedType); |
| 1478 expect(tokenWithSpaces.offset, 1); | 1529 expect(tokenWithSpaces.offset, 1); |
| 1479 expect(tokenWithSpaces.length, source.length); | 1530 expect(tokenWithSpaces.length, source.length); |
| 1480 expect(tokenWithSpaces.lexeme, source); | 1531 expect(tokenWithSpaces.lexeme, source); |
| 1481 return originalToken; | 1532 return originalToken; |
| 1482 } else if (expectedType == TokenType.INT || | 1533 } else if (expectedType == TokenType.INT || |
| 1483 expectedType == TokenType.DOUBLE) { | 1534 expectedType == TokenType.DOUBLE) { |
| 1484 Token tokenWithLowerD = | 1535 Token tokenWithLowerD = _scan("${source}d", |
| 1485 _scan("${source}d", lazyAssignmentOperators: lazyAssignmentOperators); | 1536 lazyAssignmentOperators: lazyAssignmentOperators, |
| 1537 ignoreErrors: usingFasta); |
| 1486 expect(tokenWithLowerD, isNotNull); | 1538 expect(tokenWithLowerD, isNotNull); |
| 1487 expect(tokenWithLowerD.type, expectedType); | 1539 expect(tokenWithLowerD.type, expectedType); |
| 1488 expect(tokenWithLowerD.offset, 0); | 1540 expect(tokenWithLowerD.offset, 0); |
| 1489 expect(tokenWithLowerD.length, source.length); | 1541 expect(tokenWithLowerD.length, source.length); |
| 1490 expect(tokenWithLowerD.lexeme, source); | 1542 expect(tokenWithLowerD.lexeme, source); |
| 1491 Token tokenWithUpperD = | 1543 Token tokenWithUpperD = _scan("${source}D", |
| 1492 _scan("${source}D", lazyAssignmentOperators: lazyAssignmentOperators); | 1544 lazyAssignmentOperators: lazyAssignmentOperators, |
| 1545 ignoreErrors: usingFasta); |
| 1493 expect(tokenWithUpperD, isNotNull); | 1546 expect(tokenWithUpperD, isNotNull); |
| 1494 expect(tokenWithUpperD.type, expectedType); | 1547 expect(tokenWithUpperD.type, expectedType); |
| 1495 expect(tokenWithUpperD.offset, 0); | 1548 expect(tokenWithUpperD.offset, 0); |
| 1496 expect(tokenWithUpperD.length, source.length); | 1549 expect(tokenWithUpperD.length, source.length); |
| 1497 expect(tokenWithUpperD.lexeme, source); | 1550 expect(tokenWithUpperD.lexeme, source); |
| 1498 } | 1551 } |
| 1499 Token tokenWithSpaces = | 1552 Token tokenWithSpaces = _scan(" $source ", |
| 1500 _scan(" $source ", lazyAssignmentOperators: lazyAssignmentOperators); | 1553 lazyAssignmentOperators: lazyAssignmentOperators, |
| 1554 ignoreErrors: usingFasta); |
| 1501 expect(tokenWithSpaces, isNotNull); | 1555 expect(tokenWithSpaces, isNotNull); |
| 1502 expect(tokenWithSpaces.type, expectedType); | 1556 expect(tokenWithSpaces.type, expectedType); |
| 1503 expect(tokenWithSpaces.offset, 1); | 1557 expect(tokenWithSpaces.offset, 1); |
| 1504 expect(tokenWithSpaces.length, source.length); | 1558 expect(tokenWithSpaces.length, source.length); |
| 1505 expect(tokenWithSpaces.lexeme, source); | 1559 expect(tokenWithSpaces.lexeme, source); |
| 1506 | 1560 |
| 1507 // Fasta inserts missing closers (']', '}', ')') | 1561 // Fasta inserts missing closers (']', '}', ')') |
| 1508 //expect(originalToken.next.type, TokenType.EOF); | 1562 //expect(originalToken.next.type, TokenType.EOF); |
| 1509 return originalToken; | 1563 return originalToken; |
| 1510 } | 1564 } |
| (...skipping 20 matching lines...) Expand all Loading... |
| 1531 expect(token.lexeme, expectedToken.lexeme, | 1585 expect(token.lexeme, expectedToken.lexeme, |
| 1532 reason: "Wrong lexeme for token $i"); | 1586 reason: "Wrong lexeme for token $i"); |
| 1533 token = token.next; | 1587 token = token.next; |
| 1534 expect(token, isNotNull); | 1588 expect(token, isNotNull); |
| 1535 } | 1589 } |
| 1536 expect(token.type, TokenType.EOF); | 1590 expect(token.type, TokenType.EOF); |
| 1537 } | 1591 } |
| 1538 | 1592 |
| 1539 Token _scan(String source, | 1593 Token _scan(String source, |
| 1540 {bool genericMethodComments: false, | 1594 {bool genericMethodComments: false, |
| 1541 bool lazyAssignmentOperators: false}) { | 1595 bool lazyAssignmentOperators: false, |
| 1596 bool ignoreErrors: false}) { |
| 1542 ErrorListener listener = new ErrorListener(); | 1597 ErrorListener listener = new ErrorListener(); |
| 1543 Token token = scanWithListener(source, listener, | 1598 Token token = scanWithListener(source, listener, |
| 1544 genericMethodComments: genericMethodComments, | 1599 genericMethodComments: genericMethodComments, |
| 1545 lazyAssignmentOperators: lazyAssignmentOperators); | 1600 lazyAssignmentOperators: lazyAssignmentOperators); |
| 1546 listener.assertNoErrors(); | 1601 if (!ignoreErrors) { |
| 1602 listener.assertNoErrors(); |
| 1603 } |
| 1547 return token; | 1604 return token; |
| 1548 } | 1605 } |
| 1549 } | 1606 } |
| 1550 | 1607 |
| 1551 class TestError { | 1608 class TestError { |
| 1552 final int offset; | 1609 final int offset; |
| 1553 final ErrorCode errorCode; | 1610 final ErrorCode errorCode; |
| 1554 final List<Object> arguments; | 1611 final List<Object> arguments; |
| 1555 | 1612 |
| 1556 TestError(this.offset, this.errorCode, this.arguments); | 1613 TestError(this.offset, this.errorCode, this.arguments); |
| (...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1662 _TestScanner(CharacterReader reader, [this.listener]) : super.create(reader); | 1719 _TestScanner(CharacterReader reader, [this.listener]) : super.create(reader); |
| 1663 | 1720 |
| 1664 @override | 1721 @override |
| 1665 void reportError( | 1722 void reportError( |
| 1666 ScannerErrorCode errorCode, int offset, List<Object> arguments) { | 1723 ScannerErrorCode errorCode, int offset, List<Object> arguments) { |
| 1667 if (listener != null) { | 1724 if (listener != null) { |
| 1668 listener.errors.add(new TestError(offset, errorCode, arguments)); | 1725 listener.errors.add(new TestError(offset, errorCode, arguments)); |
| 1669 } | 1726 } |
| 1670 } | 1727 } |
| 1671 } | 1728 } |
| OLD | NEW |