| OLD | NEW |
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, 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 part of scanner; | 5 part of scanner; |
| 6 | 6 |
| 7 abstract class Scanner { | 7 abstract class Scanner { |
| 8 Token tokenize(); | 8 Token tokenize(); |
| 9 | 9 |
| 10 factory Scanner(SourceFile file, {bool includeComments: false}) { | 10 factory Scanner(SourceFile file, {bool includeComments: false}) { |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 42 */ | 42 */ |
| 43 Token tail; | 43 Token tail; |
| 44 | 44 |
| 45 /** | 45 /** |
| 46 * The source file that is being scanned. This field can be [:null:]. | 46 * The source file that is being scanned. This field can be [:null:]. |
| 47 * If the source file is available, the scanner assigns its [:lineStarts:] and | 47 * If the source file is available, the scanner assigns its [:lineStarts:] and |
| 48 * [:length:] fields at the end of [tokenize]. | 48 * [:length:] fields at the end of [tokenize]. |
| 49 */ | 49 */ |
| 50 final SourceFile file; | 50 final SourceFile file; |
| 51 | 51 |
| 52 final List<int> lineStarts = [0]; | 52 final List<int> lineStarts = <int>[0]; |
| 53 | 53 |
| 54 AbstractScanner(this.file, this.includeComments) { | 54 AbstractScanner(this.file, this.includeComments) { |
| 55 this.tail = this.tokens; | 55 this.tail = this.tokens; |
| 56 } | 56 } |
| 57 | 57 |
| 58 | |
| 59 /** | 58 /** |
| 60 * Advances and returns the next character. | 59 * Advances and returns the next character. |
| 61 * | 60 * |
| 62 * If the next character is non-ASCII, then the returned value depends on the | 61 * If the next character is non-ASCII, then the returned value depends on the |
| 63 * scanner implementation. The [Utf8BytesScanner] returns a UTF-8 byte, while | 62 * scanner implementation. The [Utf8BytesScanner] returns a UTF-8 byte, while |
| 64 * the [StringScanner] returns a UTF-16 code unit. | 63 * the [StringScanner] returns a UTF-16 code unit. |
| 65 * | 64 * |
| 66 * The scanner ensures that [advance] is not invoked after it returned [$EOF]. | 65 * The scanner ensures that [advance] is not invoked after it returned [$EOF]. |
| 67 * This allows implementations to omit bound checks if the data structure ends | 66 * This allows implementations to omit bound checks if the data structure ends |
| 68 * with '0'. | 67 * with '0'. |
| 69 */ | 68 */ |
| 70 int advance(); | 69 int advance(); |
| 71 | 70 |
| 72 /** | 71 /** |
| 73 * Returns the current unicode character. | 72 * Returns the current unicode character. |
| 74 * | 73 * |
| 75 * If the current character is ASCII, then it is returned unchanged. | 74 * If the current character is ASCII, then it is returned unchanged. |
| 76 * | 75 * |
| 77 * The [Utf8BytesScanner] decodes the next unicode code point starting at the | 76 * The [Utf8BytesScanner] decodes the next unicode code point starting at the |
| 78 * current position. Note that every unicode character is returned as a single | 77 * current position. Note that every unicode character is returned as a single |
| 79 * code point, i.e., for '\u{1d11e}' it returns 119070, and the following | 78 * code point, that is, for '\u{1d11e}' it returns 119070, and the following |
| 80 * [advance] returns the next character. | 79 * [advance] returns the next character. |
| 81 * | 80 * |
| 82 * The [StringScanner] returns the current character unchanged, which might | 81 * The [StringScanner] returns the current character unchanged, which might |
| 83 * be a surrogate character. In the case of '\u{1d11e}', it returns the first | 82 * be a surrogate character. In the case of '\u{1d11e}', it returns the first |
| 84 * code unit 55348, and the following [advance] returns the second code unit | 83 * code unit 55348, and the following [advance] returns the second code unit |
| 85 * 56606. | 84 * 56606. |
| 86 * | 85 * |
| 87 * Invoking [currentAsUnicode] multiple times is safe, i.e., | 86 * Invoking [currentAsUnicode] multiple times is safe, i.e., |
| 88 * [:currentAsUnicode(next) == currentAsUnicode(currentAsUnicode(next)):]. | 87 * [:currentAsUnicode(next) == currentAsUnicode(currentAsUnicode(next)):]. |
| 89 */ | 88 */ |
| (...skipping 758 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 848 } | 847 } |
| 849 } | 848 } |
| 850 if (raw) { | 849 if (raw) { |
| 851 return tokenizeSingleLineRawString(next, quoteChar, start); | 850 return tokenizeSingleLineRawString(next, quoteChar, start); |
| 852 } else { | 851 } else { |
| 853 return tokenizeSingleLineString(next, quoteChar, start); | 852 return tokenizeSingleLineString(next, quoteChar, start); |
| 854 } | 853 } |
| 855 } | 854 } |
| 856 | 855 |
| 857 /** | 856 /** |
| 858 * [next] is the first character after the qoute. | 857 * [next] is the first character after the quote. |
| 859 * [start] is the scanOffset of the quote. | 858 * [start] is the scanOffset of the quote. |
| 860 * | 859 * |
| 861 * The token contains a substring of the source file, including the | 860 * The token contains a substring of the source file, including the |
| 862 * string quotes, backslashes for escaping. For interpolated strings, | 861 * string quotes, backslashes for escaping. For interpolated strings, |
| 863 * the parts before and after are separate tokens. | 862 * the parts before and after are separate tokens. |
| 864 * | 863 * |
| 865 * "a $b c" | 864 * "a $b c" |
| 866 * | 865 * |
| 867 * gives StringToken("a $), StringToken(b) and StringToken( c"). | 866 * gives StringToken("a $), StringToken(b) and StringToken( c"). |
| 868 */ | 867 */ |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 922 int tokenizeInterpolatedIdentifier(int next) { | 921 int tokenizeInterpolatedIdentifier(int next) { |
| 923 appendPrecedenceToken(STRING_INTERPOLATION_IDENTIFIER_INFO); | 922 appendPrecedenceToken(STRING_INTERPOLATION_IDENTIFIER_INFO); |
| 924 beginToken(); // The identifier starts here. | 923 beginToken(); // The identifier starts here. |
| 925 next = tokenizeKeywordOrIdentifier(next, false); | 924 next = tokenizeKeywordOrIdentifier(next, false); |
| 926 beginToken(); // The string interpolation suffix starts here. | 925 beginToken(); // The string interpolation suffix starts here. |
| 927 return next; | 926 return next; |
| 928 } | 927 } |
| 929 | 928 |
| 930 int tokenizeSingleLineRawString(int next, int quoteChar, int start) { | 929 int tokenizeSingleLineRawString(int next, int quoteChar, int start) { |
| 931 bool asciiOnly = true; | 930 bool asciiOnly = true; |
| 932 next = advance(); // Advance past the quote | 931 next = advance(); // Advance past the quote. |
| 933 while (next != $EOF) { | 932 while (next != $EOF) { |
| 934 if (identical(next, quoteChar)) { | 933 if (identical(next, quoteChar)) { |
| 935 if (!asciiOnly) handleUnicode(start); | 934 if (!asciiOnly) handleUnicode(start); |
| 936 next = advance(); | 935 next = advance(); |
| 937 appendSubstringToken(STRING_INFO, start, asciiOnly); | 936 appendSubstringToken(STRING_INFO, start, asciiOnly); |
| 938 return next; | 937 return next; |
| 939 } else if (identical(next, $LF) || identical(next, $CR)) { | 938 } else if (identical(next, $LF) || identical(next, $CR)) { |
| 940 if (!asciiOnly) handleUnicode(start); | 939 if (!asciiOnly) handleUnicode(start); |
| 941 return error("unterminated string literal"); | 940 return error("unterminated string literal"); |
| 942 } else if (next > 127) { | 941 } else if (next > 127) { |
| 943 asciiOnly = false; | 942 asciiOnly = false; |
| 944 } | 943 } |
| 945 next = advance(); | 944 next = advance(); |
| 946 } | 945 } |
| 947 if (!asciiOnly) handleUnicode(start); | 946 if (!asciiOnly) handleUnicode(start); |
| 948 return error("unterminated string literal"); | 947 return error("unterminated string literal"); |
| 949 } | 948 } |
| 950 | 949 |
| 951 int tokenizeMultiLineRawString(int quoteChar, int start) { | 950 int tokenizeMultiLineRawString(int quoteChar, int start) { |
| 952 bool asciiOnlyString = true; | 951 bool asciiOnlyString = true; |
| 953 bool asciiOnlyLine = true; | 952 bool asciiOnlyLine = true; |
| 954 int unicodeStart = start; | 953 int unicodeStart = start; |
| 955 int next = advance(); // Advance past the (last) quote (of three) | 954 int next = advance(); // Advance past the (last) quote (of three). |
| 956 outer: while (!identical(next, $EOF)) { | 955 outer: while (!identical(next, $EOF)) { |
| 957 while (!identical(next, quoteChar)) { | 956 while (!identical(next, quoteChar)) { |
| 958 if (identical(next, $LF)) { | 957 if (identical(next, $LF)) { |
| 959 if (!asciiOnlyLine) { | 958 if (!asciiOnlyLine) { |
| 960 // Synchronize the string offset in the utf8 scanner. | 959 // Synchronize the string offset in the utf8 scanner. |
| 961 handleUnicode(unicodeStart); | 960 handleUnicode(unicodeStart); |
| 962 asciiOnlyLine = true; | 961 asciiOnlyLine = true; |
| 963 unicodeStart = scanOffset; | 962 unicodeStart = scanOffset; |
| 964 } | 963 } |
| 965 lineFeedInMultiline(); | 964 lineFeedInMultiline(); |
| (...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1038 | 1037 |
| 1039 int error(String message) { | 1038 int error(String message) { |
| 1040 appendStringToken(BAD_INPUT_INFO, message); | 1039 appendStringToken(BAD_INPUT_INFO, message); |
| 1041 return advance(); // Ensure progress. | 1040 return advance(); // Ensure progress. |
| 1042 } | 1041 } |
| 1043 | 1042 |
| 1044 void unmatchedBeginGroup(BeginGroupToken begin) { | 1043 void unmatchedBeginGroup(BeginGroupToken begin) { |
| 1045 String error = 'unmatched "${begin.stringValue}"'; | 1044 String error = 'unmatched "${begin.stringValue}"'; |
| 1046 Token close = | 1045 Token close = |
| 1047 new StringToken.fromString( | 1046 new StringToken.fromString( |
| 1048 BAD_INPUT_INFO, error, begin.charOffset, true); | 1047 BAD_INPUT_INFO, error, begin.charOffset, canonicalize: true); |
| 1049 | 1048 |
| 1050 // We want to ensure that unmatched BeginGroupTokens are reported | 1049 // We want to ensure that unmatched BeginGroupTokens are reported |
| 1051 // as errors. However, the rest of the parser assume the groups | 1050 // as errors. However, the rest of the parser assumes the groups |
| 1052 // are well-balanced and will never look at the endGroup | 1051 // are well-balanced and will never look at the endGroup |
| 1053 // token. This is a nice property that allows us to skip quickly | 1052 // token. This is a nice property that allows us to skip quickly |
| 1054 // over correct code. By inserting an additional error token in | 1053 // over correct code. By inserting an additional error token in |
| 1055 // the stream, we can keep ignoring endGroup tokens. | 1054 // the stream, we can keep ignoring endGroup tokens. |
| 1056 // | 1055 // |
| 1057 // [begin] --next--> [tail] | 1056 // [begin] --next--> [tail] |
| 1058 // [begin] --endG--> [close] --next--> [next] --next--> [tail] | 1057 // [begin] --endG--> [close] --next--> [next] --next--> [tail] |
| 1059 // | 1058 // |
| 1060 // This allows the parser to skip from [begin] via endGroup to [close] and | 1059 // This allows the parser to skip from [begin] via endGroup to [close] and |
| 1061 // ignore the [close] token (assuming it's correct), then the error will be | 1060 // ignore the [close] token (assuming it's correct), then the error will be |
| 1062 // reported when parsing the [next] token. | 1061 // reported when parsing the [next] token. |
| 1063 | 1062 |
| 1064 Token next = new StringToken.fromString( | 1063 Token next = new StringToken.fromString( |
| 1065 BAD_INPUT_INFO, error, begin.charOffset, true); | 1064 BAD_INPUT_INFO, error, begin.charOffset, canonicalize: true); |
| 1066 begin.endGroup = close; | 1065 begin.endGroup = close; |
| 1067 close.next = next; | 1066 close.next = next; |
| 1068 next.next = begin.next; | 1067 next.next = begin.next; |
| 1069 } | 1068 } |
| 1070 } | 1069 } |
| OLD | NEW |