Chromium Code Reviews| Index: pkg/front_end/test/scanner_test.dart |
| diff --git a/pkg/front_end/test/scanner_test.dart b/pkg/front_end/test/scanner_test.dart |
| index 69e802d3008e3b898096106cdaafabf806b56901..10c2ad11350fe9350ef35bce7663c4bbfecfb45e 100644 |
| --- a/pkg/front_end/test/scanner_test.dart |
| +++ b/pkg/front_end/test/scanner_test.dart |
| @@ -4,6 +4,11 @@ |
| import 'package:front_end/src/base/errors.dart'; |
| import 'package:front_end/src/base/jenkins_smi_hash.dart'; |
| +import 'package:front_end/src/fasta/scanner/error_token.dart' as fasta; |
| +import 'package:front_end/src/fasta/scanner/keyword.dart' as fasta; |
| +import 'package:front_end/src/fasta/scanner/string_scanner.dart' as fasta; |
| +import 'package:front_end/src/fasta/scanner/token.dart' as fasta; |
| +import 'package:front_end/src/fasta/scanner/token_constants.dart' as fasta; |
| import 'package:front_end/src/scanner/errors.dart'; |
| import 'package:front_end/src/scanner/reader.dart'; |
| import 'package:front_end/src/scanner/scanner.dart'; |
| @@ -16,6 +21,7 @@ main() { |
| defineReflectiveTests(CharSequenceReaderTest); |
| defineReflectiveTests(KeywordStateTest); |
| defineReflectiveTests(ScannerTest); |
|
Paul Berry
2017/02/03 23:10:36
Note that this test file now tests both the analyz
|
| + defineReflectiveTests(ScannerTest_Fasta); |
| defineReflectiveTests(TokenTypeTest); |
| }); |
| } |
| @@ -113,7 +119,556 @@ class KeywordStateTest { |
| } |
| @reflectiveTest |
| -class ScannerTest { |
| +class ScannerTest extends ScannerTestBase { |
| + @override |
| + Token _scanWithListener(String source, _ErrorListener listener, |
| + {bool genericMethodComments: false, |
| + bool lazyAssignmentOperators: false}) { |
| + Scanner scanner = |
| + new _TestScanner(new CharSequenceReader(source), listener); |
| + scanner.scanGenericMethodComments = genericMethodComments; |
| + scanner.scanLazyAssignmentOperators = lazyAssignmentOperators; |
| + return scanner.tokenize(); |
| + } |
| +} |
| + |
| +@reflectiveTest |
| +class ScannerTest_Fasta extends ScannerTestBase { |
| + final _keywordMap = { |
| + "assert": Keyword.ASSERT, |
| + "break": Keyword.BREAK, |
| + "case": Keyword.CASE, |
| + "catch": Keyword.CATCH, |
| + "class": Keyword.CLASS, |
| + "const": Keyword.CONST, |
| + "continue": Keyword.CONTINUE, |
| + "default": Keyword.DEFAULT, |
| + "do": Keyword.DO, |
| + "else": Keyword.ELSE, |
| + "enum": Keyword.ENUM, |
| + "extends": Keyword.EXTENDS, |
| + "false": Keyword.FALSE, |
| + "final": Keyword.FINAL, |
| + "finally": Keyword.FINALLY, |
| + "for": Keyword.FOR, |
| + "if": Keyword.IF, |
| + "in": Keyword.IN, |
| + "new": Keyword.NEW, |
| + "null": Keyword.NULL, |
| + "rethrow": Keyword.RETHROW, |
| + "return": Keyword.RETURN, |
| + "super": Keyword.SUPER, |
| + "switch": Keyword.SWITCH, |
| + "this": Keyword.THIS, |
| + "throw": Keyword.THROW, |
| + "true": Keyword.TRUE, |
| + "try": Keyword.TRY, |
| + "var": Keyword.VAR, |
| + "void": Keyword.VOID, |
| + "while": Keyword.WHILE, |
| + "with": Keyword.WITH, |
| + "is": Keyword.IS, |
| + "abstract": Keyword.ABSTRACT, |
| + "as": Keyword.AS, |
| + "covariant": Keyword.COVARIANT, |
| + "dynamic": Keyword.DYNAMIC, |
| + "export": Keyword.EXPORT, |
| + "external": Keyword.EXTERNAL, |
| + "factory": Keyword.FACTORY, |
| + "get": Keyword.GET, |
| + "implements": Keyword.IMPLEMENTS, |
| + "import": Keyword.IMPORT, |
| + "library": Keyword.LIBRARY, |
| + "operator": Keyword.OPERATOR, |
| + "part": Keyword.PART, |
| + "set": Keyword.SET, |
| + "static": Keyword.STATIC, |
| + "typedef": Keyword.TYPEDEF, |
| + "deferred": Keyword.DEFERRED, |
| + }; |
| + |
| + @override |
| + @failingTest |
|
Paul Berry
2017/02/03 23:10:36
Note: these overrides indicate to the test_reflect
|
| + void test_ampersand_ampersand_eq() { |
| + // TODO(paulberry,ahe): Fasta doesn't support `&&=` yet |
| + super.test_ampersand_ampersand_eq(); |
| + } |
| + |
| + @override |
| + @failingTest |
| + void test_bar_bar_eq() { |
| + // TODO(paulberry,ahe): Fasta doesn't support `||=` yet |
| + super.test_bar_bar_eq(); |
| + } |
| + |
| + @override |
| + @failingTest |
| + void test_comment_generic_method_type_assign() { |
| + // TODO(paulberry,ahe): Fasta doesn't support generic method comment syntax. |
|
ahe
2017/02/06 11:01:20
Do you think that would be necessary to support in
Paul Berry
2017/02/06 13:46:54
It's not clear at this point. I asked Dan Grove a
|
| + super.test_comment_generic_method_type_assign(); |
| + } |
| + |
| + @override |
| + @failingTest |
| + void test_comment_generic_method_type_list() { |
| + // TODO(paulberry,ahe): Fasta doesn't support generic method comment syntax. |
| + super.test_comment_generic_method_type_list(); |
| + } |
| + |
| + @override |
| + @failingTest |
| + void test_comment_multi_unterminated() { |
| + // TODO(paulberry,ahe): see UnimplementedError("distinguish unterminated errors") |
|
ahe
2017/02/06 11:01:20
Long line here and a few below.
Paul Berry
2017/02/06 13:46:54
Done.
|
| + super.test_comment_multi_unterminated(); |
| + } |
| + |
| + @override |
| + @failingTest |
| + void test_comment_single() { |
| + // TODO(paulberry,ahe): See TODO comment below in _translateTokenInfoKind(). |
| + super.test_comment_single(); |
| + } |
| + |
| + @override |
| + @failingTest |
| + void test_double_missingDigitInExponent() { |
| + // TODO(paulberry,ahe): see UnimplementedError("distinguish unterminated errors") |
| + super.test_double_missingDigitInExponent(); |
| + } |
| + |
| + @override |
| + @failingTest |
| + void test_hexidecimal_missingDigit() { |
| + // TODO(paulberry,ahe): see UnimplementedError("distinguish unterminated errors") |
| + super.test_hexidecimal_missingDigit(); |
| + } |
| + |
| + @override |
| + @failingTest |
| + void test_index() { |
| + // TODO(paulberry,ahe): "[]" should be parsed as a single token. |
|
ahe
2017/02/04 09:48:19
Note: [] and []= are tokenized as a single token o
Paul Berry
2017/02/04 14:57:55
Interesting. The behavior of the analyzer scanner
ahe
2017/02/06 11:01:20
I agree. A corner case with the dart2js/fasta appr
Paul Berry
2017/02/06 13:46:54
SGTM.
Siggi Cherem (dart-lang)
2017/02/06 23:51:29
A small question: could we annotate somehow these
Paul Berry
2017/02/07 13:56:11
I've filed an issue: https://github.com/dart-lang/
|
| + super.test_index(); |
| + } |
| + |
| + @override |
| + @failingTest |
| + void test_index_eq() { |
| + // TODO(paulberry,ahe): "[]=" should be parsed as a single token. |
| + super.test_index_eq(); |
| + } |
| + |
| + @override |
| + @failingTest |
| + void test_scriptTag_withArgs() { |
| + // TODO(paulberry,ahe): script tags are needed by analyzer. |
| + super.test_scriptTag_withArgs(); |
| + } |
| + |
| + @override |
| + @failingTest |
| + void test_scriptTag_withoutSpace() { |
| + // TODO(paulberry,ahe): script tags are needed by analyzer. |
| + super.test_scriptTag_withoutSpace(); |
| + } |
| + |
| + @override |
| + @failingTest |
| + void test_scriptTag_withSpace() { |
| + // TODO(paulberry,ahe): script tags are needed by analyzer. |
| + super.test_scriptTag_withSpace(); |
| + } |
| + |
| + @override |
| + @failingTest |
| + void test_string_multi_unterminated() { |
| + // TODO(paulberry,ahe): bad error recovery. |
| + super.test_string_multi_unterminated(); |
| + } |
| + |
| + @override |
| + @failingTest |
| + void test_string_multi_unterminated_interpolation_block() { |
| + // TODO(paulberry,ahe): bad error recovery. |
| + super.test_string_multi_unterminated_interpolation_block(); |
| + } |
| + |
| + @override |
| + @failingTest |
| + void test_string_multi_unterminated_interpolation_identifier() { |
| + // TODO(paulberry,ahe): bad error recovery. |
| + super.test_string_multi_unterminated_interpolation_identifier(); |
| + } |
| + |
| + @override |
| + @failingTest |
| + void test_string_raw_multi_unterminated() { |
| + // TODO(paulberry,ahe): bad error recovery. |
| + super.test_string_raw_multi_unterminated(); |
| + } |
| + |
| + @override |
| + @failingTest |
| + void test_string_raw_simple_unterminated_eof() { |
| + // TODO(paulberry,ahe): bad error recovery. |
| + super.test_string_raw_simple_unterminated_eof(); |
| + } |
| + |
| + @override |
| + @failingTest |
| + void test_string_raw_simple_unterminated_eol() { |
| + // TODO(paulberry,ahe): bad error recovery. |
| + super.test_string_raw_simple_unterminated_eol(); |
| + } |
| + |
| + @override |
| + @failingTest |
| + void test_string_simple_interpolation_missingIdentifier() { |
| + // TODO(paulberry,ahe): bad error recovery. |
| + super.test_string_simple_interpolation_missingIdentifier(); |
| + } |
| + |
| + @override |
| + @failingTest |
| + void test_string_simple_interpolation_nonIdentifier() { |
| + // TODO(paulberry,ahe): bad error recovery. |
| + super.test_string_simple_interpolation_nonIdentifier(); |
| + } |
| + |
| + @override |
| + @failingTest |
| + void test_string_simple_unterminated_eof() { |
| + // TODO(paulberry,ahe): bad error recovery. |
| + super.test_string_simple_unterminated_eof(); |
| + } |
| + |
| + @override |
| + @failingTest |
| + void test_string_simple_unterminated_eol() { |
| + // TODO(paulberry,ahe): bad error recovery. |
| + super.test_string_simple_unterminated_eol(); |
| + } |
| + |
| + @override |
| + @failingTest |
| + void test_string_simple_unterminated_interpolation_block() { |
| + // TODO(paulberry,ahe): bad error recovery. |
| + super.test_string_simple_unterminated_interpolation_block(); |
| + } |
| + |
| + @override |
| + @failingTest |
| + void test_string_simple_unterminated_interpolation_identifier() { |
| + // TODO(paulberry,ahe): bad error recovery. |
| + super.test_string_simple_unterminated_interpolation_identifier(); |
| + } |
| + |
| + @override |
| + Token _scanWithListener(String source, _ErrorListener listener, |
| + {bool genericMethodComments: false, |
| + bool lazyAssignmentOperators: false}) { |
| + if (genericMethodComments) { |
| + // Fasta doesn't support generic method comments. |
| + // TODO(paulberry): once the analyzer toolchain no longer needs generic |
| + // method comments, remove tests that exercise them. |
| + fail('No generic method comment support in Fasta'); |
| + } |
| + // Note: Fasta always supports lazy assignment operators (`&&=` and `||=`), |
| + // so we can ignore the `lazyAssignmentOperators` flag. |
| + // TODO(paulberry): once lazyAssignmentOperators are fully supported by |
| + // Dart, remove this flag. |
| + var scanner = new fasta.StringScanner(source, includeComments: true); |
| + var token = scanner.tokenize(); |
| + var analyzerTokenHead = new Token(null, 0); |
| + analyzerTokenHead.previous = analyzerTokenHead; |
| + var analyzerTokenTail = analyzerTokenHead; |
| + // TODO(paulberry,ahe): Fasta includes comments directly in the token |
| + // stream, rather than pointing to them via a "precedingComment" pointer, as |
| + // analyzer does. This seems like it will complicate parsing and other |
| + // operations. |
| + CommentToken currentCommentHead; |
| + CommentToken currentCommentTail; |
| + while (true) { |
| + if (token is fasta.ErrorToken) { |
| + var error = _translateErrorToken(token, source.length); |
| + if (error != null) { |
| + listener.errors.add(error); |
| + } |
| + } else if (token is fasta.StringToken && |
| + token.info.kind == fasta.COMMENT_TOKEN) { |
| + var translatedToken = _translateToken(token, null) as CommentToken; |
| + if (currentCommentHead == null) { |
| + currentCommentHead = currentCommentTail = translatedToken; |
| + } else { |
| + currentCommentTail.setNext(translatedToken); |
| + currentCommentTail = translatedToken; |
| + } |
| + } else { |
| + var translatedToken = _translateToken(token, currentCommentHead); |
| + translatedToken.setNext(translatedToken); |
| + currentCommentHead = currentCommentTail = null; |
| + analyzerTokenTail.setNext(translatedToken); |
| + translatedToken.previous = analyzerTokenTail; |
| + analyzerTokenTail = translatedToken; |
| + } |
| + if (token.isEof) { |
| + return analyzerTokenHead.next; |
| + } |
| + token = token.next; |
| + } |
| + } |
| + |
| + _TestError _translateErrorToken(fasta.ErrorToken token, int inputLength) { |
| + int charOffset = token.charOffset; |
| + // TODO(paulberry,ahe): why is endOffset sometimes null? |
| + int endOffset = token.endOffset ?? charOffset; |
| + _TestError _makeError(ScannerErrorCode errorCode, List<Object> arguments) { |
| + int errorLength = endOffset - charOffset; |
| + if (charOffset == inputLength) { |
| + // Analyzer never generates an error message past the end of the input, |
| + // since such an error would not be visible in an editor. |
| + // TODO(paulberry,ahe): would it make sense to replicate this behavior |
| + // in fasta, or move it elsewhere in analyzer? |
| + charOffset--; |
| + } |
| + if (errorLength == 0) { |
| + // Analyzer never generates an error message of length zero, |
| + // since such an error would not be visible in an editor. |
| + // TODO(paulberry,ahe): would it make sense to replicate this behavior |
| + // in fasta, or move it elsewhere in analyzer? |
| + errorLength = 1; |
| + } |
| + return new _TestError(charOffset, errorLength, errorCode, arguments); |
| + } |
| + |
| + if (token is fasta.UnterminatedToken) { |
| + // TODO(paulberry,ahe): How to tell what kind of error to |
| + // report? It could be ScannerErrorCode.UNTERMINATED_STRING_LITERAL, |
| + // ScannerErrorCode.MISSING_HEX_DIGIT, or |
| + // ScannerErrorCode.UNTERMINATED_MULTI_LINE_COMMENT |
|
ahe
2017/02/04 09:48:19
Absolutely. Just this week, I was thinking about c
Paul Berry
2017/02/04 14:57:55
Aha, thank you. I failed to notice the presence o
ahe
2017/02/06 11:01:20
We should be careful about polymorphism, but in th
Paul Berry
2017/02/06 13:46:54
Aha, nice. When I do my rework of this code (whic
|
| + return _makeError( |
| + throw new UnimplementedError("distinguish unterminated errors"), |
| + null); |
| + } else if (token is fasta.UnmatchedToken) { |
| + return null; |
| + } else if (token is fasta.NonAsciiIdentifierToken) { |
| + return _makeError(ScannerErrorCode.ILLEGAL_CHARACTER, [token.character]); |
| + } else if (token is fasta.NonAsciiWhitespaceToken) { |
| + return _makeError(ScannerErrorCode.ILLEGAL_CHARACTER, [token.character]); |
| + } |
| + throw new UnimplementedError('${token.runtimeType}'); |
| + } |
| + |
| + Keyword _translateKeyword(String syntax) => |
| + _keywordMap[syntax] ?? (throw new UnimplementedError('$syntax')); |
| + |
| + Token _translateToken(fasta.Token token, CommentToken comment) { |
| + var type = _translateTokenInfoKind(token.info.kind); |
| + int offset = token.charOffset; |
| + Token makeStringToken(String value) { |
| + if (comment == null) { |
| + return new StringToken(type, value, offset); |
| + } else { |
| + return new StringTokenWithComment(type, value, offset, comment); |
| + } |
| + } |
| + |
| + Token makeKeywordToken(Keyword keyword) { |
| + if (comment == null) { |
| + return new KeywordToken(keyword, offset); |
| + } else { |
| + return new KeywordTokenWithComment(keyword, offset, comment); |
| + } |
| + } |
| + |
| + Token makeBeginToken() { |
| + if (comment == null) { |
| + return new BeginToken(type, offset); |
| + } else { |
| + return new BeginTokenWithComment(type, offset, comment); |
| + } |
| + } |
| + |
| + Token makeCommentToken() { |
| + return new CommentToken(type, token.value, offset); |
| + } |
| + |
| + if (token is fasta.StringToken) { |
| + if (token.info.kind == fasta.COMMENT_TOKEN) { |
| + return makeCommentToken(); |
| + } else { |
| + return makeStringToken(token.value); |
| + } |
| + } else if (token is fasta.KeywordToken) { |
| + return makeKeywordToken(_translateKeyword(token.keyword.syntax)); |
| + } else if (token is fasta.SymbolToken) { |
| + if (token is fasta.BeginGroupToken) { |
| + if (type == TokenType.LT) { |
| + return makeStringToken(token.value); |
| + } else { |
| + return makeBeginToken(); |
| + } |
| + } else { |
| + return makeStringToken(token.value); |
| + } |
| + } |
| + throw new UnimplementedError('${token.runtimeType}'); |
| + } |
| + |
| + TokenType _translateTokenInfoKind(int kind) { |
| + switch (kind) { |
| + case fasta.EOF_TOKEN: |
| + return TokenType.EOF; |
| + case fasta.KEYWORD_TOKEN: |
| + return TokenType.KEYWORD; |
| + case fasta.IDENTIFIER_TOKEN: |
| + return TokenType.IDENTIFIER; |
| + case fasta.BAD_INPUT_TOKEN: |
| + return TokenType.STRING; |
| + case fasta.DOUBLE_TOKEN: |
| + return TokenType.DOUBLE; |
| + case fasta.INT_TOKEN: |
| + return TokenType.INT; |
| + case fasta.HEXADECIMAL_TOKEN: |
| + return TokenType.HEXADECIMAL; |
| + case fasta.STRING_TOKEN: |
| + return TokenType.STRING; |
| + case fasta.AMPERSAND_TOKEN: |
| + return TokenType.AMPERSAND; |
| + case fasta.BACKPING_TOKEN: |
| + return TokenType.BACKPING; |
| + case fasta.BACKSLASH_TOKEN: |
| + return TokenType.BACKSLASH; |
| + case fasta.BANG_TOKEN: |
| + return TokenType.BANG; |
| + case fasta.BAR_TOKEN: |
| + return TokenType.BAR; |
| + case fasta.COLON_TOKEN: |
| + return TokenType.COLON; |
| + case fasta.COMMA_TOKEN: |
| + return TokenType.COMMA; |
| + case fasta.EQ_TOKEN: |
| + return TokenType.EQ; |
| + case fasta.GT_TOKEN: |
| + return TokenType.GT; |
| + case fasta.HASH_TOKEN: |
| + return TokenType.HASH; |
| + case fasta.OPEN_CURLY_BRACKET_TOKEN: |
| + return TokenType.OPEN_CURLY_BRACKET; |
| + case fasta.OPEN_SQUARE_BRACKET_TOKEN: |
| + return TokenType.OPEN_SQUARE_BRACKET; |
| + case fasta.OPEN_PAREN_TOKEN: |
| + return TokenType.OPEN_PAREN; |
| + case fasta.LT_TOKEN: |
| + return TokenType.LT; |
| + case fasta.MINUS_TOKEN: |
| + return TokenType.MINUS; |
| + case fasta.PERIOD_TOKEN: |
| + return TokenType.PERIOD; |
| + case fasta.PLUS_TOKEN: |
| + return TokenType.PLUS; |
| + case fasta.QUESTION_TOKEN: |
| + return TokenType.QUESTION; |
| + case fasta.AT_TOKEN: |
| + return TokenType.AT; |
| + case fasta.CLOSE_CURLY_BRACKET_TOKEN: |
| + return TokenType.CLOSE_CURLY_BRACKET; |
| + case fasta.CLOSE_SQUARE_BRACKET_TOKEN: |
| + return TokenType.CLOSE_SQUARE_BRACKET; |
| + case fasta.CLOSE_PAREN_TOKEN: |
| + return TokenType.CLOSE_PAREN; |
| + case fasta.SEMICOLON_TOKEN: |
| + return TokenType.SEMICOLON; |
| + case fasta.SLASH_TOKEN: |
| + return TokenType.SLASH; |
| + case fasta.TILDE_TOKEN: |
| + return TokenType.TILDE; |
| + case fasta.STAR_TOKEN: |
| + return TokenType.STAR; |
| + case fasta.PERCENT_TOKEN: |
| + return TokenType.PERCENT; |
| + case fasta.CARET_TOKEN: |
| + return TokenType.CARET; |
| + case fasta.STRING_INTERPOLATION_TOKEN: |
| + return TokenType.STRING_INTERPOLATION_EXPRESSION; |
| + case fasta.LT_EQ_TOKEN: |
| + return TokenType.LT_EQ; |
| + case fasta.FUNCTION_TOKEN: |
| + return TokenType.FUNCTION; |
| + case fasta.SLASH_EQ_TOKEN: |
| + return TokenType.SLASH_EQ; |
| + case fasta.PERIOD_PERIOD_PERIOD_TOKEN: |
| + return TokenType.PERIOD_PERIOD_PERIOD; |
| + case fasta.PERIOD_PERIOD_TOKEN: |
| + return TokenType.PERIOD_PERIOD; |
| + case fasta.EQ_EQ_EQ_TOKEN: |
| + // TODO(paulberry,ahe): what is this? |
| + throw new UnimplementedError(); |
| + case fasta.EQ_EQ_TOKEN: |
| + return TokenType.EQ_EQ; |
| + case fasta.LT_LT_EQ_TOKEN: |
| + return TokenType.LT_LT_EQ; |
| + case fasta.LT_LT_TOKEN: |
| + return TokenType.LT_LT; |
| + case fasta.GT_EQ_TOKEN: |
| + return TokenType.GT_EQ; |
| + case fasta.GT_GT_EQ_TOKEN: |
| + return TokenType.GT_GT_EQ; |
| + case fasta.INDEX_EQ_TOKEN: |
| + return TokenType.INDEX_EQ; |
| + case fasta.INDEX_TOKEN: |
| + return TokenType.INDEX; |
| + case fasta.BANG_EQ_EQ_TOKEN: |
| + // TODO(paulberry,ahe): what is this? |
| + throw new UnimplementedError(); |
| + case fasta.BANG_EQ_TOKEN: |
| + return TokenType.BANG_EQ; |
| + case fasta.AMPERSAND_AMPERSAND_TOKEN: |
| + return TokenType.AMPERSAND_AMPERSAND; |
| + case fasta.AMPERSAND_EQ_TOKEN: |
| + return TokenType.AMPERSAND_EQ; |
| + case fasta.BAR_BAR_TOKEN: |
| + return TokenType.BAR_BAR; |
| + case fasta.BAR_EQ_TOKEN: |
| + return TokenType.BAR_EQ; |
| + case fasta.STAR_EQ_TOKEN: |
| + return TokenType.STAR_EQ; |
| + case fasta.PLUS_PLUS_TOKEN: |
| + return TokenType.PLUS_PLUS; |
| + case fasta.PLUS_EQ_TOKEN: |
| + return TokenType.PLUS_EQ; |
| + case fasta.MINUS_MINUS_TOKEN: |
| + return TokenType.MINUS_MINUS; |
| + case fasta.MINUS_EQ_TOKEN: |
| + return TokenType.MINUS_EQ; |
| + case fasta.TILDE_SLASH_EQ_TOKEN: |
| + return TokenType.TILDE_SLASH_EQ; |
| + case fasta.TILDE_SLASH_TOKEN: |
| + return TokenType.TILDE_SLASH; |
| + case fasta.PERCENT_EQ_TOKEN: |
| + return TokenType.PERCENT_EQ; |
| + case fasta.GT_GT_TOKEN: |
| + return TokenType.GT_GT; |
| + case fasta.CARET_EQ_TOKEN: |
| + return TokenType.CARET_EQ; |
| + case fasta.COMMENT_TOKEN: |
| + // TODO(paulberry,ahe): how to distinguish multi-line from |
| + // single-line comments? Causes a failure in test_comment_single(). |
|
ahe
2017/02/06 11:01:20
I'd just look at the first two characters of the c
Paul Berry
2017/02/06 13:46:54
Ok. I'll make a follow-up CL that adjusts this co
|
| + return TokenType.MULTI_LINE_COMMENT; |
| + case fasta.STRING_INTERPOLATION_IDENTIFIER_TOKEN: |
| + return TokenType.STRING_INTERPOLATION_IDENTIFIER; |
| + case fasta.QUESTION_PERIOD_TOKEN: |
| + return TokenType.QUESTION_PERIOD; |
| + case fasta.QUESTION_QUESTION_TOKEN: |
| + return TokenType.QUESTION_QUESTION; |
| + case fasta.QUESTION_QUESTION_EQ_TOKEN: |
| + return TokenType.QUESTION_QUESTION_EQ; |
| + default: |
| + throw new UnimplementedError('$kind'); |
| + } |
| + } |
| +} |
| + |
| +abstract class ScannerTestBase { |
| void fail_incomplete_string_interpolation() { |
| // https://code.google.com/p/dart/issues/detail?id=18073 |
| _assertErrorAndTokens( |
| @@ -230,6 +785,36 @@ class ScannerTest { |
| _assertComment(TokenType.MULTI_LINE_COMMENT, "/* comment */"); |
| } |
| + void test_comment_multi_consecutive_2() { |
|
Paul Berry
2017/02/03 23:10:36
Note: during this process I discovered that consec
|
| + Token token = _scan("/* x */ /* y */ z"); |
| + expect(token.type, TokenType.IDENTIFIER); |
| + expect(token.precedingComments, isNotNull); |
| + expect(token.precedingComments.value(), "/* x */"); |
| + expect(token.precedingComments.previous, isNull); |
| + expect(token.precedingComments.next, isNotNull); |
| + expect(token.precedingComments.next.value(), "/* y */"); |
| + expect( |
| + token.precedingComments.next.previous, same(token.precedingComments)); |
| + expect(token.precedingComments.next.next, isNull); |
| + } |
| + |
| + void test_comment_multi_consecutive_3() { |
| + Token token = _scan("/* x */ /* y */ /* z */ a"); |
| + expect(token.type, TokenType.IDENTIFIER); |
| + expect(token.precedingComments, isNotNull); |
| + expect(token.precedingComments.value(), "/* x */"); |
| + expect(token.precedingComments.previous, isNull); |
| + expect(token.precedingComments.next, isNotNull); |
| + expect(token.precedingComments.next.value(), "/* y */"); |
| + expect( |
| + token.precedingComments.next.previous, same(token.precedingComments)); |
| + expect(token.precedingComments.next.next, isNotNull); |
| + expect(token.precedingComments.next.next.value(), "/* z */"); |
| + expect(token.precedingComments.next.next.previous, |
| + same(token.precedingComments.next)); |
| + expect(token.precedingComments.next.next.next, isNull); |
| + } |
| + |
| void test_comment_multi_lineEnds() { |
| String code = r''' |
| /** |
| @@ -1149,14 +1734,7 @@ class ScannerTest { |
| } |
| Token _scanWithListener(String source, _ErrorListener listener, |
| - {bool genericMethodComments: false, |
| - bool lazyAssignmentOperators: false}) { |
| - Scanner scanner = |
| - new _TestScanner(new CharSequenceReader(source), listener); |
| - scanner.scanGenericMethodComments = genericMethodComments; |
| - scanner.scanLazyAssignmentOperators = lazyAssignmentOperators; |
| - return scanner.tokenize(); |
| - } |
| + {bool genericMethodComments: false, bool lazyAssignmentOperators: false}); |
| } |
| @reflectiveTest |