| Index: packages/analyzer/test/generated/scanner_test.dart
|
| diff --git a/packages/analyzer/test/generated/scanner_test.dart b/packages/analyzer/test/generated/scanner_test.dart
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..119d4aa1202328f23994342815051eb0d1ccf971
|
| --- /dev/null
|
| +++ b/packages/analyzer/test/generated/scanner_test.dart
|
| @@ -0,0 +1,1399 @@
|
| +// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
|
| +// for details. All rights reserved. Use of this source code is governed by a
|
| +// BSD-style license that can be found in the LICENSE file.
|
| +
|
| +library engine.scanner_test;
|
| +
|
| +import 'package:analyzer/src/generated/error.dart';
|
| +import 'package:analyzer/src/generated/scanner.dart';
|
| +import 'package:analyzer/src/generated/source.dart';
|
| +import 'package:unittest/unittest.dart';
|
| +
|
| +import '../reflective_tests.dart';
|
| +import '../utils.dart';
|
| +import 'test_support.dart';
|
| +
|
| +main() {
|
| + initializeTestEnvironment();
|
| + runReflectiveTests(CharSequenceReaderTest);
|
| + runReflectiveTests(KeywordStateTest);
|
| + runReflectiveTests(ScannerTest);
|
| + runReflectiveTests(TokenTypeTest);
|
| +}
|
| +
|
| +class CharacterRangeReaderTest extends EngineTestCase {
|
| + void test_advance() {
|
| + CharSequenceReader baseReader = new CharSequenceReader("xyzzy");
|
| + CharacterRangeReader reader = new CharacterRangeReader(baseReader, 1, 4);
|
| + expect(reader.advance(), 0x79);
|
| + expect(reader.advance(), 0x80);
|
| + expect(reader.advance(), 0x80);
|
| + expect(reader.advance(), -1);
|
| + expect(reader.advance(), -1);
|
| + }
|
| +
|
| + void test_creation() {
|
| + CharSequenceReader baseReader = new CharSequenceReader("xyzzy");
|
| + CharacterRangeReader reader = new CharacterRangeReader(baseReader, 1, 4);
|
| + expect(reader, isNotNull);
|
| + }
|
| +
|
| + void test_getOffset() {
|
| + CharSequenceReader baseReader = new CharSequenceReader("xyzzy");
|
| + CharacterRangeReader reader = new CharacterRangeReader(baseReader, 1, 2);
|
| + expect(reader.offset, 1);
|
| + reader.advance();
|
| + expect(reader.offset, 2);
|
| + reader.advance();
|
| + expect(reader.offset, 2);
|
| + }
|
| +
|
| + void test_getString() {
|
| + CharSequenceReader baseReader = new CharSequenceReader("__xyzzy__");
|
| + CharacterRangeReader reader = new CharacterRangeReader(baseReader, 2, 7);
|
| + reader.offset = 5;
|
| + expect(reader.getString(3, 0), "yzz");
|
| + expect(reader.getString(4, 1), "zzy");
|
| + }
|
| +
|
| + void test_peek() {
|
| + CharSequenceReader baseReader = new CharSequenceReader("xyzzy");
|
| + CharacterRangeReader reader = new CharacterRangeReader(baseReader, 1, 3);
|
| + expect(reader.peek(), 0x79);
|
| + expect(reader.peek(), 0x79);
|
| + reader.advance();
|
| + expect(reader.peek(), 0x80);
|
| + expect(reader.peek(), 0x80);
|
| + reader.advance();
|
| + expect(reader.peek(), -1);
|
| + expect(reader.peek(), -1);
|
| + }
|
| +
|
| + void test_setOffset() {
|
| + CharSequenceReader baseReader = new CharSequenceReader("xyzzy");
|
| + CharacterRangeReader reader = new CharacterRangeReader(baseReader, 1, 4);
|
| + reader.offset = 2;
|
| + expect(reader.offset, 2);
|
| + }
|
| +}
|
| +
|
| +@reflectiveTest
|
| +class CharSequenceReaderTest {
|
| + void test_advance() {
|
| + CharSequenceReader reader = new CharSequenceReader("x");
|
| + expect(reader.advance(), 0x78);
|
| + expect(reader.advance(), -1);
|
| + expect(reader.advance(), -1);
|
| + }
|
| +
|
| + void test_creation() {
|
| + expect(new CharSequenceReader("x"), isNotNull);
|
| + }
|
| +
|
| + void test_getOffset() {
|
| + CharSequenceReader reader = new CharSequenceReader("x");
|
| + expect(reader.offset, -1);
|
| + reader.advance();
|
| + expect(reader.offset, 0);
|
| + reader.advance();
|
| + expect(reader.offset, 0);
|
| + }
|
| +
|
| + void test_getString() {
|
| + CharSequenceReader reader = new CharSequenceReader("xyzzy");
|
| + reader.offset = 3;
|
| + expect(reader.getString(1, 0), "yzz");
|
| + expect(reader.getString(2, 1), "zzy");
|
| + }
|
| +
|
| + void test_peek() {
|
| + CharSequenceReader reader = new CharSequenceReader("xy");
|
| + expect(reader.peek(), 0x78);
|
| + expect(reader.peek(), 0x78);
|
| + reader.advance();
|
| + expect(reader.peek(), 0x79);
|
| + expect(reader.peek(), 0x79);
|
| + reader.advance();
|
| + expect(reader.peek(), -1);
|
| + expect(reader.peek(), -1);
|
| + }
|
| +
|
| + void test_setOffset() {
|
| + CharSequenceReader reader = new CharSequenceReader("xyz");
|
| + reader.offset = 2;
|
| + expect(reader.offset, 2);
|
| + }
|
| +}
|
| +
|
| +@reflectiveTest
|
| +class KeywordStateTest {
|
| + void test_KeywordState() {
|
| + //
|
| + // Generate the test data to be scanned.
|
| + //
|
| + List<Keyword> keywords = Keyword.values;
|
| + int keywordCount = keywords.length;
|
| + List<String> textToTest = new List<String>(keywordCount * 3);
|
| + for (int i = 0; i < keywordCount; i++) {
|
| + String syntax = keywords[i].syntax;
|
| + textToTest[i] = syntax;
|
| + textToTest[i + keywordCount] = "${syntax}x";
|
| + textToTest[i + keywordCount * 2] = syntax.substring(0, syntax.length - 1);
|
| + }
|
| + //
|
| + // Scan each of the identifiers.
|
| + //
|
| + KeywordState firstState = KeywordState.KEYWORD_STATE;
|
| + for (int i = 0; i < textToTest.length; i++) {
|
| + String text = textToTest[i];
|
| + int index = 0;
|
| + int length = text.length;
|
| + KeywordState state = firstState;
|
| + while (index < length && state != null) {
|
| + state = state.next(text.codeUnitAt(index));
|
| + index++;
|
| + }
|
| + if (i < keywordCount) {
|
| + // keyword
|
| + expect(state, isNotNull);
|
| + expect(state.keyword(), isNotNull);
|
| + expect(state.keyword(), keywords[i]);
|
| + } else if (i < keywordCount * 2) {
|
| + // keyword + "x"
|
| + expect(state, isNull);
|
| + } else {
|
| + // keyword.substring(0, keyword.length() - 1)
|
| + expect(state, isNotNull);
|
| + }
|
| + }
|
| + }
|
| +}
|
| +
|
| +@reflectiveTest
|
| +class ScannerTest {
|
| + void fail_incomplete_string_interpolation() {
|
| + // https://code.google.com/p/dart/issues/detail?id=18073
|
| + _assertErrorAndTokens(
|
| + ScannerErrorCode.UNTERMINATED_STRING_LITERAL, 9, "\"foo \${bar", [
|
| + new StringToken(TokenType.STRING, "\"foo ", 0),
|
| + new StringToken(TokenType.STRING_INTERPOLATION_EXPRESSION, "\${", 5),
|
| + new StringToken(TokenType.IDENTIFIER, "bar", 7)
|
| + ]);
|
| + }
|
| +
|
| + void test_ampersand() {
|
| + _assertToken(TokenType.AMPERSAND, "&");
|
| + }
|
| +
|
| + void test_ampersand_ampersand() {
|
| + _assertToken(TokenType.AMPERSAND_AMPERSAND, "&&");
|
| + }
|
| +
|
| + void test_ampersand_eq() {
|
| + _assertToken(TokenType.AMPERSAND_EQ, "&=");
|
| + }
|
| +
|
| + void test_at() {
|
| + _assertToken(TokenType.AT, "@");
|
| + }
|
| +
|
| + void test_backping() {
|
| + _assertToken(TokenType.BACKPING, "`");
|
| + }
|
| +
|
| + void test_backslash() {
|
| + _assertToken(TokenType.BACKSLASH, "\\");
|
| + }
|
| +
|
| + void test_bang() {
|
| + _assertToken(TokenType.BANG, "!");
|
| + }
|
| +
|
| + void test_bang_eq() {
|
| + _assertToken(TokenType.BANG_EQ, "!=");
|
| + }
|
| +
|
| + void test_bar() {
|
| + _assertToken(TokenType.BAR, "|");
|
| + }
|
| +
|
| + void test_bar_bar() {
|
| + _assertToken(TokenType.BAR_BAR, "||");
|
| + }
|
| +
|
| + void test_bar_eq() {
|
| + _assertToken(TokenType.BAR_EQ, "|=");
|
| + }
|
| +
|
| + void test_caret() {
|
| + _assertToken(TokenType.CARET, "^");
|
| + }
|
| +
|
| + void test_caret_eq() {
|
| + _assertToken(TokenType.CARET_EQ, "^=");
|
| + }
|
| +
|
| + void test_close_curly_bracket() {
|
| + _assertToken(TokenType.CLOSE_CURLY_BRACKET, "}");
|
| + }
|
| +
|
| + void test_close_paren() {
|
| + _assertToken(TokenType.CLOSE_PAREN, ")");
|
| + }
|
| +
|
| + void test_close_quare_bracket() {
|
| + _assertToken(TokenType.CLOSE_SQUARE_BRACKET, "]");
|
| + }
|
| +
|
| + void test_colon() {
|
| + _assertToken(TokenType.COLON, ":");
|
| + }
|
| +
|
| + void test_comma() {
|
| + _assertToken(TokenType.COMMA, ",");
|
| + }
|
| +
|
| + void test_comment_disabled_multi() {
|
| + Scanner scanner = new Scanner(
|
| + null,
|
| + new CharSequenceReader("/* comment */ "),
|
| + AnalysisErrorListener.NULL_LISTENER);
|
| + scanner.preserveComments = false;
|
| + Token token = scanner.tokenize();
|
| + expect(token, isNotNull);
|
| + expect(token.precedingComments, isNull);
|
| + }
|
| +
|
| + void test_comment_multi() {
|
| + _assertComment(TokenType.MULTI_LINE_COMMENT, "/* comment */");
|
| + }
|
| +
|
| + void test_comment_multi_lineEnds() {
|
| + String code = r'''
|
| +/**
|
| + * aa
|
| + * bbb
|
| + * c
|
| + */''';
|
| + GatheringErrorListener listener = new GatheringErrorListener();
|
| + Scanner scanner = new Scanner(null, new CharSequenceReader(code), listener);
|
| + scanner.tokenize();
|
| + expect(
|
| + scanner.lineStarts,
|
| + equals(<int>[
|
| + code.indexOf('/**'),
|
| + code.indexOf(' * aa'),
|
| + code.indexOf(' * bbb'),
|
| + code.indexOf(' * c'),
|
| + code.indexOf(' */')
|
| + ]));
|
| + }
|
| +
|
| + void test_comment_multi_unterminated() {
|
| + _assertError(ScannerErrorCode.UNTERMINATED_MULTI_LINE_COMMENT, 3, "/* x");
|
| + }
|
| +
|
| + void test_comment_nested() {
|
| + _assertComment(
|
| + TokenType.MULTI_LINE_COMMENT, "/* comment /* within a */ comment */");
|
| + }
|
| +
|
| + void test_comment_single() {
|
| + _assertComment(TokenType.SINGLE_LINE_COMMENT, "// comment");
|
| + }
|
| +
|
| + void test_double_both_E() {
|
| + _assertToken(TokenType.DOUBLE, "0.123E4");
|
| + }
|
| +
|
| + void test_double_both_e() {
|
| + _assertToken(TokenType.DOUBLE, "0.123e4");
|
| + }
|
| +
|
| + void test_double_fraction() {
|
| + _assertToken(TokenType.DOUBLE, ".123");
|
| + }
|
| +
|
| + void test_double_fraction_E() {
|
| + _assertToken(TokenType.DOUBLE, ".123E4");
|
| + }
|
| +
|
| + void test_double_fraction_e() {
|
| + _assertToken(TokenType.DOUBLE, ".123e4");
|
| + }
|
| +
|
| + void test_double_missingDigitInExponent() {
|
| + _assertError(ScannerErrorCode.MISSING_DIGIT, 1, "1e");
|
| + }
|
| +
|
| + void test_double_whole_E() {
|
| + _assertToken(TokenType.DOUBLE, "12E4");
|
| + }
|
| +
|
| + void test_double_whole_e() {
|
| + _assertToken(TokenType.DOUBLE, "12e4");
|
| + }
|
| +
|
| + void test_eq() {
|
| + _assertToken(TokenType.EQ, "=");
|
| + }
|
| +
|
| + void test_eq_eq() {
|
| + _assertToken(TokenType.EQ_EQ, "==");
|
| + }
|
| +
|
| + void test_gt() {
|
| + _assertToken(TokenType.GT, ">");
|
| + }
|
| +
|
| + void test_gt_eq() {
|
| + _assertToken(TokenType.GT_EQ, ">=");
|
| + }
|
| +
|
| + void test_gt_gt() {
|
| + _assertToken(TokenType.GT_GT, ">>");
|
| + }
|
| +
|
| + void test_gt_gt_eq() {
|
| + _assertToken(TokenType.GT_GT_EQ, ">>=");
|
| + }
|
| +
|
| + void test_hash() {
|
| + _assertToken(TokenType.HASH, "#");
|
| + }
|
| +
|
| + void test_hexidecimal() {
|
| + _assertToken(TokenType.HEXADECIMAL, "0x1A2B3C");
|
| + }
|
| +
|
| + void test_hexidecimal_missingDigit() {
|
| + _assertError(ScannerErrorCode.MISSING_HEX_DIGIT, 1, "0x");
|
| + }
|
| +
|
| + void test_identifier() {
|
| + _assertToken(TokenType.IDENTIFIER, "result");
|
| + }
|
| +
|
| + void test_illegalChar_cyrillicLetter_middle() {
|
| + _assertError(ScannerErrorCode.ILLEGAL_CHARACTER, 5, "Shche\u0433lov");
|
| + }
|
| +
|
| + void test_illegalChar_cyrillicLetter_start() {
|
| + _assertError(ScannerErrorCode.ILLEGAL_CHARACTER, 0, "\u0429");
|
| + }
|
| +
|
| + void test_illegalChar_nbsp() {
|
| + _assertError(ScannerErrorCode.ILLEGAL_CHARACTER, 0, "\u00A0");
|
| + }
|
| +
|
| + void test_illegalChar_notLetter() {
|
| + _assertError(ScannerErrorCode.ILLEGAL_CHARACTER, 0, "\u0312");
|
| + }
|
| +
|
| + void test_index() {
|
| + _assertToken(TokenType.INDEX, "[]");
|
| + }
|
| +
|
| + void test_index_eq() {
|
| + _assertToken(TokenType.INDEX_EQ, "[]=");
|
| + }
|
| +
|
| + void test_int() {
|
| + _assertToken(TokenType.INT, "123");
|
| + }
|
| +
|
| + void test_int_initialZero() {
|
| + _assertToken(TokenType.INT, "0123");
|
| + }
|
| +
|
| + void test_keyword_abstract() {
|
| + _assertKeywordToken("abstract");
|
| + }
|
| +
|
| + void test_keyword_as() {
|
| + _assertKeywordToken("as");
|
| + }
|
| +
|
| + void test_keyword_assert() {
|
| + _assertKeywordToken("assert");
|
| + }
|
| +
|
| + void test_keyword_break() {
|
| + _assertKeywordToken("break");
|
| + }
|
| +
|
| + void test_keyword_case() {
|
| + _assertKeywordToken("case");
|
| + }
|
| +
|
| + void test_keyword_catch() {
|
| + _assertKeywordToken("catch");
|
| + }
|
| +
|
| + void test_keyword_class() {
|
| + _assertKeywordToken("class");
|
| + }
|
| +
|
| + void test_keyword_const() {
|
| + _assertKeywordToken("const");
|
| + }
|
| +
|
| + void test_keyword_continue() {
|
| + _assertKeywordToken("continue");
|
| + }
|
| +
|
| + void test_keyword_default() {
|
| + _assertKeywordToken("default");
|
| + }
|
| +
|
| + void test_keyword_deferred() {
|
| + _assertKeywordToken("deferred");
|
| + }
|
| +
|
| + void test_keyword_do() {
|
| + _assertKeywordToken("do");
|
| + }
|
| +
|
| + void test_keyword_dynamic() {
|
| + _assertKeywordToken("dynamic");
|
| + }
|
| +
|
| + void test_keyword_else() {
|
| + _assertKeywordToken("else");
|
| + }
|
| +
|
| + void test_keyword_enum() {
|
| + _assertKeywordToken("enum");
|
| + }
|
| +
|
| + void test_keyword_export() {
|
| + _assertKeywordToken("export");
|
| + }
|
| +
|
| + void test_keyword_extends() {
|
| + _assertKeywordToken("extends");
|
| + }
|
| +
|
| + void test_keyword_factory() {
|
| + _assertKeywordToken("factory");
|
| + }
|
| +
|
| + void test_keyword_false() {
|
| + _assertKeywordToken("false");
|
| + }
|
| +
|
| + void test_keyword_final() {
|
| + _assertKeywordToken("final");
|
| + }
|
| +
|
| + void test_keyword_finally() {
|
| + _assertKeywordToken("finally");
|
| + }
|
| +
|
| + void test_keyword_for() {
|
| + _assertKeywordToken("for");
|
| + }
|
| +
|
| + void test_keyword_get() {
|
| + _assertKeywordToken("get");
|
| + }
|
| +
|
| + void test_keyword_if() {
|
| + _assertKeywordToken("if");
|
| + }
|
| +
|
| + void test_keyword_implements() {
|
| + _assertKeywordToken("implements");
|
| + }
|
| +
|
| + void test_keyword_import() {
|
| + _assertKeywordToken("import");
|
| + }
|
| +
|
| + void test_keyword_in() {
|
| + _assertKeywordToken("in");
|
| + }
|
| +
|
| + void test_keyword_is() {
|
| + _assertKeywordToken("is");
|
| + }
|
| +
|
| + void test_keyword_library() {
|
| + _assertKeywordToken("library");
|
| + }
|
| +
|
| + void test_keyword_new() {
|
| + _assertKeywordToken("new");
|
| + }
|
| +
|
| + void test_keyword_null() {
|
| + _assertKeywordToken("null");
|
| + }
|
| +
|
| + void test_keyword_operator() {
|
| + _assertKeywordToken("operator");
|
| + }
|
| +
|
| + void test_keyword_part() {
|
| + _assertKeywordToken("part");
|
| + }
|
| +
|
| + void test_keyword_rethrow() {
|
| + _assertKeywordToken("rethrow");
|
| + }
|
| +
|
| + void test_keyword_return() {
|
| + _assertKeywordToken("return");
|
| + }
|
| +
|
| + void test_keyword_set() {
|
| + _assertKeywordToken("set");
|
| + }
|
| +
|
| + void test_keyword_static() {
|
| + _assertKeywordToken("static");
|
| + }
|
| +
|
| + void test_keyword_super() {
|
| + _assertKeywordToken("super");
|
| + }
|
| +
|
| + void test_keyword_switch() {
|
| + _assertKeywordToken("switch");
|
| + }
|
| +
|
| + void test_keyword_this() {
|
| + _assertKeywordToken("this");
|
| + }
|
| +
|
| + void test_keyword_throw() {
|
| + _assertKeywordToken("throw");
|
| + }
|
| +
|
| + void test_keyword_true() {
|
| + _assertKeywordToken("true");
|
| + }
|
| +
|
| + void test_keyword_try() {
|
| + _assertKeywordToken("try");
|
| + }
|
| +
|
| + void test_keyword_typedef() {
|
| + _assertKeywordToken("typedef");
|
| + }
|
| +
|
| + void test_keyword_var() {
|
| + _assertKeywordToken("var");
|
| + }
|
| +
|
| + void test_keyword_void() {
|
| + _assertKeywordToken("void");
|
| + }
|
| +
|
| + void test_keyword_while() {
|
| + _assertKeywordToken("while");
|
| + }
|
| +
|
| + void test_keyword_with() {
|
| + _assertKeywordToken("with");
|
| + }
|
| +
|
| + void test_lineInfo_multilineComment() {
|
| + String source = "/*\r *\r */";
|
| + _assertLineInfo(source, [
|
| + new ScannerTest_ExpectedLocation(0, 1, 1),
|
| + new ScannerTest_ExpectedLocation(4, 2, 2),
|
| + new ScannerTest_ExpectedLocation(source.length - 1, 3, 3)
|
| + ]);
|
| + }
|
| +
|
| + void test_lineInfo_multilineString() {
|
| + String source = "'''a\r\nbc\r\nd'''";
|
| + _assertLineInfo(source, [
|
| + new ScannerTest_ExpectedLocation(0, 1, 1),
|
| + new ScannerTest_ExpectedLocation(7, 2, 2),
|
| + new ScannerTest_ExpectedLocation(source.length - 1, 3, 4)
|
| + ]);
|
| + }
|
| +
|
| + void test_lineInfo_multilineString_raw() {
|
| + String source = "var a = r'''\nblah\n''';\n\nfoo";
|
| + _assertLineInfo(source, [
|
| + new ScannerTest_ExpectedLocation(0, 1, 1),
|
| + new ScannerTest_ExpectedLocation(14, 2, 2),
|
| + new ScannerTest_ExpectedLocation(source.length - 2, 5, 2)
|
| + ]);
|
| + }
|
| +
|
| + void test_lineInfo_simpleClass() {
|
| + String source =
|
| + "class Test {\r\n String s = '...';\r\n int get x => s.MISSING_GETTER;\r\n}";
|
| + _assertLineInfo(source, [
|
| + new ScannerTest_ExpectedLocation(0, 1, 1),
|
| + new ScannerTest_ExpectedLocation(source.indexOf("MISSING_GETTER"), 3, 20),
|
| + new ScannerTest_ExpectedLocation(source.length - 1, 4, 1)
|
| + ]);
|
| + }
|
| +
|
| + void test_lineInfo_slashN() {
|
| + String source = "class Test {\n}";
|
| + _assertLineInfo(source, [
|
| + new ScannerTest_ExpectedLocation(0, 1, 1),
|
| + new ScannerTest_ExpectedLocation(source.indexOf("}"), 2, 1)
|
| + ]);
|
| + }
|
| +
|
| + void test_lt() {
|
| + _assertToken(TokenType.LT, "<");
|
| + }
|
| +
|
| + void test_lt_eq() {
|
| + _assertToken(TokenType.LT_EQ, "<=");
|
| + }
|
| +
|
| + void test_lt_lt() {
|
| + _assertToken(TokenType.LT_LT, "<<");
|
| + }
|
| +
|
| + void test_lt_lt_eq() {
|
| + _assertToken(TokenType.LT_LT_EQ, "<<=");
|
| + }
|
| +
|
| + void test_minus() {
|
| + _assertToken(TokenType.MINUS, "-");
|
| + }
|
| +
|
| + void test_minus_eq() {
|
| + _assertToken(TokenType.MINUS_EQ, "-=");
|
| + }
|
| +
|
| + void test_minus_minus() {
|
| + _assertToken(TokenType.MINUS_MINUS, "--");
|
| + }
|
| +
|
| + void test_open_curly_bracket() {
|
| + _assertToken(TokenType.OPEN_CURLY_BRACKET, "{");
|
| + }
|
| +
|
| + void test_open_paren() {
|
| + _assertToken(TokenType.OPEN_PAREN, "(");
|
| + }
|
| +
|
| + void test_open_square_bracket() {
|
| + _assertToken(TokenType.OPEN_SQUARE_BRACKET, "[");
|
| + }
|
| +
|
| + void test_openSquareBracket() {
|
| + _assertToken(TokenType.OPEN_SQUARE_BRACKET, "[");
|
| + }
|
| +
|
| + void test_percent() {
|
| + _assertToken(TokenType.PERCENT, "%");
|
| + }
|
| +
|
| + void test_percent_eq() {
|
| + _assertToken(TokenType.PERCENT_EQ, "%=");
|
| + }
|
| +
|
| + void test_period() {
|
| + _assertToken(TokenType.PERIOD, ".");
|
| + }
|
| +
|
| + void test_period_period() {
|
| + _assertToken(TokenType.PERIOD_PERIOD, "..");
|
| + }
|
| +
|
| + void test_period_period_period() {
|
| + _assertToken(TokenType.PERIOD_PERIOD_PERIOD, "...");
|
| + }
|
| +
|
| + void test_periodAfterNumberNotIncluded_identifier() {
|
| + _assertTokens("42.isEven()", [
|
| + new StringToken(TokenType.INT, "42", 0),
|
| + new Token(TokenType.PERIOD, 2),
|
| + new StringToken(TokenType.IDENTIFIER, "isEven", 3),
|
| + new Token(TokenType.OPEN_PAREN, 9),
|
| + new Token(TokenType.CLOSE_PAREN, 10)
|
| + ]);
|
| + }
|
| +
|
| + void test_periodAfterNumberNotIncluded_period() {
|
| + _assertTokens("42..isEven()", [
|
| + new StringToken(TokenType.INT, "42", 0),
|
| + new Token(TokenType.PERIOD_PERIOD, 2),
|
| + new StringToken(TokenType.IDENTIFIER, "isEven", 4),
|
| + new Token(TokenType.OPEN_PAREN, 10),
|
| + new Token(TokenType.CLOSE_PAREN, 11)
|
| + ]);
|
| + }
|
| +
|
| + void test_plus() {
|
| + _assertToken(TokenType.PLUS, "+");
|
| + }
|
| +
|
| + void test_plus_eq() {
|
| + _assertToken(TokenType.PLUS_EQ, "+=");
|
| + }
|
| +
|
| + void test_plus_plus() {
|
| + _assertToken(TokenType.PLUS_PLUS, "++");
|
| + }
|
| +
|
| + void test_question() {
|
| + _assertToken(TokenType.QUESTION, "?");
|
| + }
|
| +
|
| + void test_question_dot() {
|
| + _assertToken(TokenType.QUESTION_PERIOD, "?.");
|
| + }
|
| +
|
| + void test_question_question() {
|
| + _assertToken(TokenType.QUESTION_QUESTION, "??");
|
| + }
|
| +
|
| + void test_question_question_eq() {
|
| + _assertToken(TokenType.QUESTION_QUESTION_EQ, "??=");
|
| + }
|
| +
|
| + void test_scriptTag_withArgs() {
|
| + _assertToken(TokenType.SCRIPT_TAG, "#!/bin/dart -debug");
|
| + }
|
| +
|
| + void test_scriptTag_withoutSpace() {
|
| + _assertToken(TokenType.SCRIPT_TAG, "#!/bin/dart");
|
| + }
|
| +
|
| + void test_scriptTag_withSpace() {
|
| + _assertToken(TokenType.SCRIPT_TAG, "#! /bin/dart");
|
| + }
|
| +
|
| + void test_semicolon() {
|
| + _assertToken(TokenType.SEMICOLON, ";");
|
| + }
|
| +
|
| + void test_setSourceStart() {
|
| + int offsetDelta = 42;
|
| + GatheringErrorListener listener = new GatheringErrorListener();
|
| + Scanner scanner =
|
| + new Scanner(null, new SubSequenceReader("a", offsetDelta), listener);
|
| + scanner.setSourceStart(3, 9);
|
| + scanner.tokenize();
|
| + List<int> lineStarts = scanner.lineStarts;
|
| + expect(lineStarts, isNotNull);
|
| + expect(lineStarts.length, 3);
|
| + expect(lineStarts[2], 33);
|
| + }
|
| +
|
| + void test_slash() {
|
| + _assertToken(TokenType.SLASH, "/");
|
| + }
|
| +
|
| + void test_slash_eq() {
|
| + _assertToken(TokenType.SLASH_EQ, "/=");
|
| + }
|
| +
|
| + void test_star() {
|
| + _assertToken(TokenType.STAR, "*");
|
| + }
|
| +
|
| + void test_star_eq() {
|
| + _assertToken(TokenType.STAR_EQ, "*=");
|
| + }
|
| +
|
| + void test_startAndEnd() {
|
| + Token token = _scan("a");
|
| + Token previous = token.previous;
|
| + expect(previous.next, token);
|
| + expect(previous.previous, previous);
|
| + Token next = token.next;
|
| + expect(next.next, next);
|
| + expect(next.previous, token);
|
| + }
|
| +
|
| + void test_string_multi_double() {
|
| + _assertToken(TokenType.STRING, "\"\"\"line1\nline2\"\"\"");
|
| + }
|
| +
|
| + void test_string_multi_embeddedQuotes() {
|
| + _assertToken(TokenType.STRING, "\"\"\"line1\n\"\"\nline2\"\"\"");
|
| + }
|
| +
|
| + void test_string_multi_embeddedQuotes_escapedChar() {
|
| + _assertToken(TokenType.STRING, "\"\"\"a\"\"\\tb\"\"\"");
|
| + }
|
| +
|
| + void test_string_multi_interpolation_block() {
|
| + _assertTokens("\"Hello \${name}!\"", [
|
| + new StringToken(TokenType.STRING, "\"Hello ", 0),
|
| + new StringToken(TokenType.STRING_INTERPOLATION_EXPRESSION, "\${", 7),
|
| + new StringToken(TokenType.IDENTIFIER, "name", 9),
|
| + new Token(TokenType.CLOSE_CURLY_BRACKET, 13),
|
| + new StringToken(TokenType.STRING, "!\"", 14)
|
| + ]);
|
| + }
|
| +
|
| + void test_string_multi_interpolation_identifier() {
|
| + _assertTokens("\"Hello \$name!\"", [
|
| + new StringToken(TokenType.STRING, "\"Hello ", 0),
|
| + new StringToken(TokenType.STRING_INTERPOLATION_IDENTIFIER, "\$", 7),
|
| + new StringToken(TokenType.IDENTIFIER, "name", 8),
|
| + new StringToken(TokenType.STRING, "!\"", 12)
|
| + ]);
|
| + }
|
| +
|
| + void test_string_multi_single() {
|
| + _assertToken(TokenType.STRING, "'''string'''");
|
| + }
|
| +
|
| + void test_string_multi_slashEnter() {
|
| + _assertToken(TokenType.STRING, "'''\\\n'''");
|
| + }
|
| +
|
| + void test_string_multi_unterminated() {
|
| + _assertErrorAndTokens(ScannerErrorCode.UNTERMINATED_STRING_LITERAL, 8,
|
| + "'''string", [new StringToken(TokenType.STRING, "'''string", 0)]);
|
| + }
|
| +
|
| + void test_string_multi_unterminated_interpolation_block() {
|
| + _assertErrorAndTokens(
|
| + ScannerErrorCode.UNTERMINATED_STRING_LITERAL, 8, "'''\${name", [
|
| + new StringToken(TokenType.STRING, "'''", 0),
|
| + new StringToken(TokenType.STRING_INTERPOLATION_EXPRESSION, "\${", 3),
|
| + new StringToken(TokenType.IDENTIFIER, "name", 5),
|
| + new StringToken(TokenType.STRING, "", 9)
|
| + ]);
|
| + }
|
| +
|
| + void test_string_multi_unterminated_interpolation_identifier() {
|
| + _assertErrorAndTokens(
|
| + ScannerErrorCode.UNTERMINATED_STRING_LITERAL, 7, "'''\$name", [
|
| + new StringToken(TokenType.STRING, "'''", 0),
|
| + new StringToken(TokenType.STRING_INTERPOLATION_IDENTIFIER, "\$", 3),
|
| + new StringToken(TokenType.IDENTIFIER, "name", 4),
|
| + new StringToken(TokenType.STRING, "", 8)
|
| + ]);
|
| + }
|
| +
|
| + void test_string_raw_multi_double() {
|
| + _assertToken(TokenType.STRING, "r\"\"\"line1\nline2\"\"\"");
|
| + }
|
| +
|
| + void test_string_raw_multi_single() {
|
| + _assertToken(TokenType.STRING, "r'''string'''");
|
| + }
|
| +
|
| + void test_string_raw_multi_unterminated() {
|
| + String source = "r'''string";
|
| + _assertErrorAndTokens(ScannerErrorCode.UNTERMINATED_STRING_LITERAL, 9,
|
| + source, [new StringToken(TokenType.STRING, source, 0)]);
|
| + }
|
| +
|
| + void test_string_raw_simple_double() {
|
| + _assertToken(TokenType.STRING, "r\"string\"");
|
| + }
|
| +
|
| + void test_string_raw_simple_single() {
|
| + _assertToken(TokenType.STRING, "r'string'");
|
| + }
|
| +
|
| + void test_string_raw_simple_unterminated_eof() {
|
| + String source = "r'string";
|
| + _assertErrorAndTokens(ScannerErrorCode.UNTERMINATED_STRING_LITERAL, 7,
|
| + source, [new StringToken(TokenType.STRING, source, 0)]);
|
| + }
|
| +
|
| + void test_string_raw_simple_unterminated_eol() {
|
| + String source = "r'string";
|
| + _assertErrorAndTokens(ScannerErrorCode.UNTERMINATED_STRING_LITERAL, 8,
|
| + "$source\n", [new StringToken(TokenType.STRING, source, 0)]);
|
| + }
|
| +
|
| + void test_string_simple_double() {
|
| + _assertToken(TokenType.STRING, "\"string\"");
|
| + }
|
| +
|
| + void test_string_simple_escapedDollar() {
|
| + _assertToken(TokenType.STRING, "'a\\\$b'");
|
| + }
|
| +
|
| + void test_string_simple_interpolation_adjacentIdentifiers() {
|
| + _assertTokens("'\$a\$b'", [
|
| + new StringToken(TokenType.STRING, "'", 0),
|
| + new StringToken(TokenType.STRING_INTERPOLATION_IDENTIFIER, "\$", 1),
|
| + new StringToken(TokenType.IDENTIFIER, "a", 2),
|
| + new StringToken(TokenType.STRING, "", 3),
|
| + new StringToken(TokenType.STRING_INTERPOLATION_IDENTIFIER, "\$", 3),
|
| + new StringToken(TokenType.IDENTIFIER, "b", 4),
|
| + new StringToken(TokenType.STRING, "'", 5)
|
| + ]);
|
| + }
|
| +
|
| + void test_string_simple_interpolation_block() {
|
| + _assertTokens("'Hello \${name}!'", [
|
| + new StringToken(TokenType.STRING, "'Hello ", 0),
|
| + new StringToken(TokenType.STRING_INTERPOLATION_EXPRESSION, "\${", 7),
|
| + new StringToken(TokenType.IDENTIFIER, "name", 9),
|
| + new Token(TokenType.CLOSE_CURLY_BRACKET, 13),
|
| + new StringToken(TokenType.STRING, "!'", 14)
|
| + ]);
|
| + }
|
| +
|
| + void test_string_simple_interpolation_blockWithNestedMap() {
|
| + _assertTokens("'a \${f({'b' : 'c'})} d'", [
|
| + new StringToken(TokenType.STRING, "'a ", 0),
|
| + new StringToken(TokenType.STRING_INTERPOLATION_EXPRESSION, "\${", 3),
|
| + new StringToken(TokenType.IDENTIFIER, "f", 5),
|
| + new Token(TokenType.OPEN_PAREN, 6),
|
| + new Token(TokenType.OPEN_CURLY_BRACKET, 7),
|
| + new StringToken(TokenType.STRING, "'b'", 8),
|
| + new Token(TokenType.COLON, 12),
|
| + new StringToken(TokenType.STRING, "'c'", 14),
|
| + new Token(TokenType.CLOSE_CURLY_BRACKET, 17),
|
| + new Token(TokenType.CLOSE_PAREN, 18),
|
| + new Token(TokenType.CLOSE_CURLY_BRACKET, 19),
|
| + new StringToken(TokenType.STRING, " d'", 20)
|
| + ]);
|
| + }
|
| +
|
| + void test_string_simple_interpolation_firstAndLast() {
|
| + _assertTokens("'\$greeting \$name'", [
|
| + new StringToken(TokenType.STRING, "'", 0),
|
| + new StringToken(TokenType.STRING_INTERPOLATION_IDENTIFIER, "\$", 1),
|
| + new StringToken(TokenType.IDENTIFIER, "greeting", 2),
|
| + new StringToken(TokenType.STRING, " ", 10),
|
| + new StringToken(TokenType.STRING_INTERPOLATION_IDENTIFIER, "\$", 11),
|
| + new StringToken(TokenType.IDENTIFIER, "name", 12),
|
| + new StringToken(TokenType.STRING, "'", 16)
|
| + ]);
|
| + }
|
| +
|
| + void test_string_simple_interpolation_identifier() {
|
| + _assertTokens("'Hello \$name!'", [
|
| + new StringToken(TokenType.STRING, "'Hello ", 0),
|
| + new StringToken(TokenType.STRING_INTERPOLATION_IDENTIFIER, "\$", 7),
|
| + new StringToken(TokenType.IDENTIFIER, "name", 8),
|
| + new StringToken(TokenType.STRING, "!'", 12)
|
| + ]);
|
| + }
|
| +
|
| + void test_string_simple_interpolation_missingIdentifier() {
|
| + _assertTokens("'\$x\$'", [
|
| + new StringToken(TokenType.STRING, "'", 0),
|
| + new StringToken(TokenType.STRING_INTERPOLATION_IDENTIFIER, "\$", 1),
|
| + new StringToken(TokenType.IDENTIFIER, "x", 2),
|
| + new StringToken(TokenType.STRING, "", 3),
|
| + new StringToken(TokenType.STRING_INTERPOLATION_IDENTIFIER, "\$", 3),
|
| + new StringToken(TokenType.STRING, "'", 4)
|
| + ]);
|
| + }
|
| +
|
| + void test_string_simple_interpolation_nonIdentifier() {
|
| + _assertTokens("'\$1'", [
|
| + new StringToken(TokenType.STRING, "'", 0),
|
| + new StringToken(TokenType.STRING_INTERPOLATION_IDENTIFIER, "\$", 1),
|
| + new StringToken(TokenType.STRING, "1'", 2)
|
| + ]);
|
| + }
|
| +
|
| + void test_string_simple_single() {
|
| + _assertToken(TokenType.STRING, "'string'");
|
| + }
|
| +
|
| + void test_string_simple_unterminated_eof() {
|
| + String source = "'string";
|
| + _assertErrorAndTokens(ScannerErrorCode.UNTERMINATED_STRING_LITERAL, 6,
|
| + source, [new StringToken(TokenType.STRING, source, 0)]);
|
| + }
|
| +
|
| + void test_string_simple_unterminated_eol() {
|
| + String source = "'string";
|
| + _assertErrorAndTokens(ScannerErrorCode.UNTERMINATED_STRING_LITERAL, 7,
|
| + "$source\r", [new StringToken(TokenType.STRING, source, 0)]);
|
| + }
|
| +
|
| + void test_string_simple_unterminated_interpolation_block() {
|
| + _assertErrorAndTokens(
|
| + ScannerErrorCode.UNTERMINATED_STRING_LITERAL, 6, "'\${name", [
|
| + new StringToken(TokenType.STRING, "'", 0),
|
| + new StringToken(TokenType.STRING_INTERPOLATION_EXPRESSION, "\${", 1),
|
| + new StringToken(TokenType.IDENTIFIER, "name", 3),
|
| + new StringToken(TokenType.STRING, "", 7)
|
| + ]);
|
| + }
|
| +
|
| + void test_string_simple_unterminated_interpolation_identifier() {
|
| + _assertErrorAndTokens(
|
| + ScannerErrorCode.UNTERMINATED_STRING_LITERAL, 5, "'\$name", [
|
| + new StringToken(TokenType.STRING, "'", 0),
|
| + new StringToken(TokenType.STRING_INTERPOLATION_IDENTIFIER, "\$", 1),
|
| + new StringToken(TokenType.IDENTIFIER, "name", 2),
|
| + new StringToken(TokenType.STRING, "", 6)
|
| + ]);
|
| + }
|
| +
|
| + void test_tilde() {
|
| + _assertToken(TokenType.TILDE, "~");
|
| + }
|
| +
|
| + void test_tilde_slash() {
|
| + _assertToken(TokenType.TILDE_SLASH, "~/");
|
| + }
|
| +
|
| + void test_tilde_slash_eq() {
|
| + _assertToken(TokenType.TILDE_SLASH_EQ, "~/=");
|
| + }
|
| +
|
| + void test_unclosedPairInInterpolation() {
|
| + GatheringErrorListener listener = new GatheringErrorListener();
|
| + _scanWithListener("'\${(}'", listener);
|
| + }
|
| +
|
| + void _assertComment(TokenType commentType, String source) {
|
| + //
|
| + // Test without a trailing end-of-line marker
|
| + //
|
| + Token token = _scan(source);
|
| + expect(token, isNotNull);
|
| + expect(token.type, TokenType.EOF);
|
| + Token comment = token.precedingComments;
|
| + expect(comment, isNotNull);
|
| + expect(comment.type, commentType);
|
| + expect(comment.offset, 0);
|
| + expect(comment.length, source.length);
|
| + expect(comment.lexeme, source);
|
| + //
|
| + // Test with a trailing end-of-line marker
|
| + //
|
| + token = _scan("$source\n");
|
| + expect(token, isNotNull);
|
| + expect(token.type, TokenType.EOF);
|
| + comment = token.precedingComments;
|
| + expect(comment, isNotNull);
|
| + expect(comment.type, commentType);
|
| + expect(comment.offset, 0);
|
| + expect(comment.length, source.length);
|
| + expect(comment.lexeme, source);
|
| + }
|
| +
|
| + /**
|
| + * Assert that scanning the given [source] produces an error with the given
|
| + * code.
|
| + *
|
| + * [expectedError] the error that should be produced
|
| + * [expectedOffset] the string offset that should be associated with the error
|
| + * [source] the source to be scanned to produce the error
|
| + */
|
| + void _assertError(
|
| + ScannerErrorCode expectedError, int expectedOffset, String source) {
|
| + GatheringErrorListener listener = new GatheringErrorListener();
|
| + _scanWithListener(source, listener);
|
| + listener.assertErrors([
|
| + new AnalysisError(null, expectedOffset, 1, expectedError,
|
| + [source.codeUnitAt(expectedOffset)])
|
| + ]);
|
| + }
|
| +
|
| + /**
|
| + * Assert that scanning the given [source] produces an error with the given
|
| + * code, and also produces the given tokens.
|
| + *
|
| + * [expectedError] the error that should be produced
|
| + * [expectedOffset] the string offset that should be associated with the error
|
| + * [source] the source to be scanned to produce the error
|
| + * [expectedTokens] the tokens that are expected to be in the source
|
| + */
|
| + void _assertErrorAndTokens(ScannerErrorCode expectedError, int expectedOffset,
|
| + String source, List<Token> expectedTokens) {
|
| + GatheringErrorListener listener = new GatheringErrorListener();
|
| + Token token = _scanWithListener(source, listener);
|
| + listener.assertErrors([
|
| + new AnalysisError(null, expectedOffset, 1, expectedError,
|
| + [source.codeUnitAt(expectedOffset)])
|
| + ]);
|
| + _checkTokens(token, expectedTokens);
|
| + }
|
| +
|
| + /**
|
| + * Assert that when scanned the given [source] contains a single keyword token
|
| + * with the same lexeme as the original source.
|
| + */
|
| + void _assertKeywordToken(String source) {
|
| + Token token = _scan(source);
|
| + expect(token, isNotNull);
|
| + expect(token.type, TokenType.KEYWORD);
|
| + expect(token.offset, 0);
|
| + expect(token.length, source.length);
|
| + expect(token.lexeme, source);
|
| + Object value = token.value();
|
| + expect(value is Keyword, isTrue);
|
| + expect((value as Keyword).syntax, source);
|
| + token = _scan(" $source ");
|
| + expect(token, isNotNull);
|
| + expect(token.type, TokenType.KEYWORD);
|
| + expect(token.offset, 1);
|
| + expect(token.length, source.length);
|
| + expect(token.lexeme, source);
|
| + value = token.value();
|
| + expect(value is Keyword, isTrue);
|
| + expect((value as Keyword).syntax, source);
|
| + expect(token.next.type, TokenType.EOF);
|
| + }
|
| +
|
| + void _assertLineInfo(
|
| + String source, List<ScannerTest_ExpectedLocation> expectedLocations) {
|
| + GatheringErrorListener listener = new GatheringErrorListener();
|
| + _scanWithListener(source, listener);
|
| + listener.assertNoErrors();
|
| + LineInfo info = listener.getLineInfo(new TestSource());
|
| + expect(info, isNotNull);
|
| + int count = expectedLocations.length;
|
| + for (int i = 0; i < count; i++) {
|
| + ScannerTest_ExpectedLocation expectedLocation = expectedLocations[i];
|
| + LineInfo_Location location = info.getLocation(expectedLocation._offset);
|
| + expect(location.lineNumber, expectedLocation._lineNumber,
|
| + reason: 'Line number in location $i');
|
| + expect(location.columnNumber, expectedLocation._columnNumber,
|
| + reason: 'Column number in location $i');
|
| + }
|
| + }
|
| +
|
| + /**
|
| + * Assert that the token scanned from the given [source] has the
|
| + * [expectedType].
|
| + */
|
| + Token _assertToken(TokenType expectedType, String source) {
|
| + Token originalToken = _scan(source);
|
| + expect(originalToken, isNotNull);
|
| + expect(originalToken.type, expectedType);
|
| + expect(originalToken.offset, 0);
|
| + expect(originalToken.length, source.length);
|
| + expect(originalToken.lexeme, source);
|
| + if (expectedType == TokenType.SCRIPT_TAG) {
|
| + // Adding space before the script tag is not allowed, and adding text at
|
| + // the end changes nothing.
|
| + return originalToken;
|
| + } else if (expectedType == TokenType.SINGLE_LINE_COMMENT) {
|
| + // Adding space to an end-of-line comment changes the comment.
|
| + Token tokenWithSpaces = _scan(" $source");
|
| + expect(tokenWithSpaces, isNotNull);
|
| + expect(tokenWithSpaces.type, expectedType);
|
| + expect(tokenWithSpaces.offset, 1);
|
| + expect(tokenWithSpaces.length, source.length);
|
| + expect(tokenWithSpaces.lexeme, source);
|
| + return originalToken;
|
| + } else if (expectedType == TokenType.INT ||
|
| + expectedType == TokenType.DOUBLE) {
|
| + Token tokenWithLowerD = _scan("${source}d");
|
| + expect(tokenWithLowerD, isNotNull);
|
| + expect(tokenWithLowerD.type, expectedType);
|
| + expect(tokenWithLowerD.offset, 0);
|
| + expect(tokenWithLowerD.length, source.length);
|
| + expect(tokenWithLowerD.lexeme, source);
|
| + Token tokenWithUpperD = _scan("${source}D");
|
| + expect(tokenWithUpperD, isNotNull);
|
| + expect(tokenWithUpperD.type, expectedType);
|
| + expect(tokenWithUpperD.offset, 0);
|
| + expect(tokenWithUpperD.length, source.length);
|
| + expect(tokenWithUpperD.lexeme, source);
|
| + }
|
| + Token tokenWithSpaces = _scan(" $source ");
|
| + expect(tokenWithSpaces, isNotNull);
|
| + expect(tokenWithSpaces.type, expectedType);
|
| + expect(tokenWithSpaces.offset, 1);
|
| + expect(tokenWithSpaces.length, source.length);
|
| + expect(tokenWithSpaces.lexeme, source);
|
| + expect(originalToken.next.type, TokenType.EOF);
|
| + return originalToken;
|
| + }
|
| +
|
| + /**
|
| + * Assert that when scanned the given [source] contains a sequence of tokens
|
| + * identical to the given list of [expectedTokens].
|
| + */
|
| + void _assertTokens(String source, List<Token> expectedTokens) {
|
| + Token token = _scan(source);
|
| + _checkTokens(token, expectedTokens);
|
| + }
|
| +
|
| + void _checkTokens(Token firstToken, List<Token> expectedTokens) {
|
| + expect(firstToken, isNotNull);
|
| + Token token = firstToken;
|
| + for (int i = 0; i < expectedTokens.length; i++) {
|
| + Token expectedToken = expectedTokens[i];
|
| + expect(token.type, expectedToken.type, reason: "Wrong type for token $i");
|
| + expect(token.offset, expectedToken.offset,
|
| + reason: "Wrong offset for token $i");
|
| + expect(token.length, expectedToken.length,
|
| + reason: "Wrong length for token $i");
|
| + expect(token.lexeme, expectedToken.lexeme,
|
| + reason: "Wrong lexeme for token $i");
|
| + token = token.next;
|
| + expect(token, isNotNull);
|
| + }
|
| + expect(token.type, TokenType.EOF);
|
| + }
|
| +
|
| + Token _scan(String source) {
|
| + GatheringErrorListener listener = new GatheringErrorListener();
|
| + Token token = _scanWithListener(source, listener);
|
| + listener.assertNoErrors();
|
| + return token;
|
| + }
|
| +
|
| + Token _scanWithListener(String source, GatheringErrorListener listener) {
|
| + Scanner scanner =
|
| + new Scanner(null, new CharSequenceReader(source), listener);
|
| + Token result = scanner.tokenize();
|
| + listener.setLineInfo(new TestSource(), scanner.lineStarts);
|
| + return result;
|
| + }
|
| +}
|
| +
|
| +/**
|
| + * An `ExpectedLocation` encodes information about the expected location of a
|
| + * given offset in source code.
|
| + */
|
| +class ScannerTest_ExpectedLocation {
|
| + final int _offset;
|
| +
|
| + final int _lineNumber;
|
| +
|
| + final int _columnNumber;
|
| +
|
| + ScannerTest_ExpectedLocation(
|
| + this._offset, this._lineNumber, this._columnNumber);
|
| +}
|
| +
|
| +/**
|
| + * A `TokenStreamValidator` is used to validate the correct construction of a
|
| + * stream of tokens.
|
| + */
|
| +class TokenStreamValidator {
|
| + /**
|
| + * Validate that the stream of tokens that starts with the given [token] is
|
| + * correct.
|
| + */
|
| + void validate(Token token) {
|
| + StringBuffer buffer = new StringBuffer();
|
| + _validateStream(buffer, token);
|
| + if (buffer.length > 0) {
|
| + fail(buffer.toString());
|
| + }
|
| + }
|
| +
|
| + void _validateStream(StringBuffer buffer, Token token) {
|
| + if (token == null) {
|
| + return;
|
| + }
|
| + Token previousToken = null;
|
| + int previousEnd = -1;
|
| + Token currentToken = token;
|
| + while (currentToken != null && currentToken.type != TokenType.EOF) {
|
| + _validateStream(buffer, currentToken.precedingComments);
|
| + TokenType type = currentToken.type;
|
| + if (type == TokenType.OPEN_CURLY_BRACKET ||
|
| + type == TokenType.OPEN_PAREN ||
|
| + type == TokenType.OPEN_SQUARE_BRACKET ||
|
| + type == TokenType.STRING_INTERPOLATION_EXPRESSION) {
|
| + if (currentToken is! BeginToken) {
|
| + buffer.write("\r\nExpected BeginToken, found ");
|
| + buffer.write(currentToken.runtimeType.toString());
|
| + buffer.write(" ");
|
| + _writeToken(buffer, currentToken);
|
| + }
|
| + }
|
| + int currentStart = currentToken.offset;
|
| + int currentLength = currentToken.length;
|
| + int currentEnd = currentStart + currentLength - 1;
|
| + if (currentStart <= previousEnd) {
|
| + buffer.write("\r\nInvalid token sequence: ");
|
| + _writeToken(buffer, previousToken);
|
| + buffer.write(" followed by ");
|
| + _writeToken(buffer, currentToken);
|
| + }
|
| + previousEnd = currentEnd;
|
| + previousToken = currentToken;
|
| + currentToken = currentToken.next;
|
| + }
|
| + }
|
| +
|
| + void _writeToken(StringBuffer buffer, Token token) {
|
| + buffer.write("[");
|
| + buffer.write(token.type);
|
| + buffer.write(", '");
|
| + buffer.write(token.lexeme);
|
| + buffer.write("', ");
|
| + buffer.write(token.offset);
|
| + buffer.write(", ");
|
| + buffer.write(token.length);
|
| + buffer.write("]");
|
| + }
|
| +}
|
| +
|
| +@reflectiveTest
|
| +class TokenTypeTest extends EngineTestCase {
|
| + void test_isOperator() {
|
| + expect(TokenType.AMPERSAND.isOperator, isTrue);
|
| + expect(TokenType.AMPERSAND_AMPERSAND.isOperator, isTrue);
|
| + expect(TokenType.AMPERSAND_EQ.isOperator, isTrue);
|
| + expect(TokenType.BANG.isOperator, isTrue);
|
| + expect(TokenType.BANG_EQ.isOperator, isTrue);
|
| + expect(TokenType.BAR.isOperator, isTrue);
|
| + expect(TokenType.BAR_BAR.isOperator, isTrue);
|
| + expect(TokenType.BAR_EQ.isOperator, isTrue);
|
| + expect(TokenType.CARET.isOperator, isTrue);
|
| + expect(TokenType.CARET_EQ.isOperator, isTrue);
|
| + expect(TokenType.EQ.isOperator, isTrue);
|
| + expect(TokenType.EQ_EQ.isOperator, isTrue);
|
| + expect(TokenType.GT.isOperator, isTrue);
|
| + expect(TokenType.GT_EQ.isOperator, isTrue);
|
| + expect(TokenType.GT_GT.isOperator, isTrue);
|
| + expect(TokenType.GT_GT_EQ.isOperator, isTrue);
|
| + expect(TokenType.INDEX.isOperator, isTrue);
|
| + expect(TokenType.INDEX_EQ.isOperator, isTrue);
|
| + expect(TokenType.IS.isOperator, isTrue);
|
| + expect(TokenType.LT.isOperator, isTrue);
|
| + expect(TokenType.LT_EQ.isOperator, isTrue);
|
| + expect(TokenType.LT_LT.isOperator, isTrue);
|
| + expect(TokenType.LT_LT_EQ.isOperator, isTrue);
|
| + expect(TokenType.MINUS.isOperator, isTrue);
|
| + expect(TokenType.MINUS_EQ.isOperator, isTrue);
|
| + expect(TokenType.MINUS_MINUS.isOperator, isTrue);
|
| + expect(TokenType.PERCENT.isOperator, isTrue);
|
| + expect(TokenType.PERCENT_EQ.isOperator, isTrue);
|
| + expect(TokenType.PERIOD_PERIOD.isOperator, isTrue);
|
| + expect(TokenType.PLUS.isOperator, isTrue);
|
| + expect(TokenType.PLUS_EQ.isOperator, isTrue);
|
| + expect(TokenType.PLUS_PLUS.isOperator, isTrue);
|
| + expect(TokenType.QUESTION.isOperator, isTrue);
|
| + expect(TokenType.SLASH.isOperator, isTrue);
|
| + expect(TokenType.SLASH_EQ.isOperator, isTrue);
|
| + expect(TokenType.STAR.isOperator, isTrue);
|
| + expect(TokenType.STAR_EQ.isOperator, isTrue);
|
| + expect(TokenType.TILDE.isOperator, isTrue);
|
| + expect(TokenType.TILDE_SLASH.isOperator, isTrue);
|
| + expect(TokenType.TILDE_SLASH_EQ.isOperator, isTrue);
|
| + }
|
| +
|
| + void test_isUserDefinableOperator() {
|
| + expect(TokenType.AMPERSAND.isUserDefinableOperator, isTrue);
|
| + expect(TokenType.BAR.isUserDefinableOperator, isTrue);
|
| + expect(TokenType.CARET.isUserDefinableOperator, isTrue);
|
| + expect(TokenType.EQ_EQ.isUserDefinableOperator, isTrue);
|
| + expect(TokenType.GT.isUserDefinableOperator, isTrue);
|
| + expect(TokenType.GT_EQ.isUserDefinableOperator, isTrue);
|
| + expect(TokenType.GT_GT.isUserDefinableOperator, isTrue);
|
| + expect(TokenType.INDEX.isUserDefinableOperator, isTrue);
|
| + expect(TokenType.INDEX_EQ.isUserDefinableOperator, isTrue);
|
| + expect(TokenType.LT.isUserDefinableOperator, isTrue);
|
| + expect(TokenType.LT_EQ.isUserDefinableOperator, isTrue);
|
| + expect(TokenType.LT_LT.isUserDefinableOperator, isTrue);
|
| + expect(TokenType.MINUS.isUserDefinableOperator, isTrue);
|
| + expect(TokenType.PERCENT.isUserDefinableOperator, isTrue);
|
| + expect(TokenType.PLUS.isUserDefinableOperator, isTrue);
|
| + expect(TokenType.SLASH.isUserDefinableOperator, isTrue);
|
| + expect(TokenType.STAR.isUserDefinableOperator, isTrue);
|
| + expect(TokenType.TILDE.isUserDefinableOperator, isTrue);
|
| + expect(TokenType.TILDE_SLASH.isUserDefinableOperator, isTrue);
|
| + }
|
| +}
|
|
|