Version 2.12.0-145.0.dev
Merge commit 'b16c212776da8dd65921f8cd858b9997cc385fbe' into 'dev'
diff --git a/benchmarks/BigIntParsePrint/dart/BigIntParsePrint.dart b/benchmarks/BigIntParsePrint/dart/BigIntParsePrint.dart
index f9e05e7..5cade7b 100644
--- a/benchmarks/BigIntParsePrint/dart/BigIntParsePrint.dart
+++ b/benchmarks/BigIntParsePrint/dart/BigIntParsePrint.dart
@@ -4,6 +4,8 @@
// ignore_for_file: avoid_function_literals_in_foreach_calls
+import 'dart:math' show pow;
+
import 'package:benchmark_harness/benchmark_harness.dart';
import 'package:fixnum/fixnum.dart';
@@ -103,6 +105,41 @@
}
}
+class ParseIntBenchmark extends BenchmarkBase {
+ final int bits;
+ final int seed;
+ final List<String> strings = [];
+
+ ParseIntBenchmark(String name, this.bits)
+ : seed = (pow(2, bits) as int) - 1,
+ super(name);
+
+ @override
+ void setup() {
+ var b = seed;
+ var totalLength = 0;
+ while (totalLength < requiredDigits) {
+ if (b.bitLength < bits) {
+ b = seed;
+ }
+ final string = b.toString();
+ strings.add(string);
+ totalLength += string.length;
+ b = b - b ~/ 256;
+ }
+ }
+
+ @override
+ void run() {
+ for (final s in strings) {
+ final b = int.parse(s);
+ sink1 = s;
+ sink2 = b;
+ }
+ check(sink2.isEven);
+ }
+}
+
class ParseJsBigIntBenchmark extends BenchmarkBase {
final int bits;
final Object seed;
@@ -181,6 +218,45 @@
}
}
+class FormatIntBenchmark extends BenchmarkBase {
+ final int bits;
+ final int seed;
+ final List<int> values = [];
+
+ FormatIntBenchmark(String name, this.bits)
+ : seed = (pow(2, bits) as int) - 1,
+ super(name);
+
+ @override
+ void setup() {
+ var b = seed;
+ var totalLength = 0;
+ int kk = b ~/ 100000;
+ while (totalLength < requiredDigits) {
+ if (b.bitLength < bits) {
+ b = seed - ++kk;
+ }
+ final string = b.toString();
+ values.add(b - 4096); // We add 'one' back later.
+ totalLength += string.length;
+ b = b - (b ~/ 256);
+ }
+ }
+
+ @override
+ void run() {
+ for (final b0 in values) {
+ // Instances might cache `toString()`, so use arithmetic to create a new
+ // instance to try to protect against measuring a cached string.
+ final b = b0 + 4096;
+ final s = b.toString();
+ sink1 = s;
+ sink2 = b;
+ }
+ check(sink2.isEven);
+ }
+}
+
class FormatInt64Benchmark extends BenchmarkBase {
final int bits;
final Int64 seed;
@@ -293,6 +369,9 @@
void main() {
final benchmarks = [
+ () => ParseIntBenchmark('Int.parse.0009.bits', 9),
+ () => ParseIntBenchmark('Int.parse.0032.bits', 32),
+ () => ParseIntBenchmark('Int.parse.0064.bits', 63),
() => ParseInt64Benchmark('Int64.parse.0009.bits', 9),
() => ParseInt64Benchmark('Int64.parse.0032.bits', 32),
() => ParseInt64Benchmark('Int64.parse.0064.bits', 64),
@@ -308,6 +387,9 @@
selectParseNativeBigIntBenchmark('JsBigInt.parse.0256.bits', 256),
selectParseNativeBigIntBenchmark('JsBigInt.parse.1024.bits', 1024),
selectParseNativeBigIntBenchmark('JsBigInt.parse.4096.bits', 4096),
+ () => FormatIntBenchmark('Int.toString.0009.bits', 9),
+ () => FormatIntBenchmark('Int.toString.0032.bits', 32),
+ () => FormatIntBenchmark('Int.toString.0064.bits', 63),
() => FormatInt64Benchmark('Int64.toString.0009.bits', 9),
() => FormatInt64Benchmark('Int64.toString.0032.bits', 32),
() => FormatInt64Benchmark('Int64.toString.0064.bits', 64),
diff --git a/pkg/analysis_server/lib/src/services/correction/dart/convert_quotes.dart b/pkg/analysis_server/lib/src/services/correction/dart/convert_quotes.dart
index 3ddef42..00bed8c 100644
--- a/pkg/analysis_server/lib/src/services/correction/dart/convert_quotes.dart
+++ b/pkg/analysis_server/lib/src/services/correction/dart/convert_quotes.dart
@@ -27,8 +27,8 @@
? (_fromDouble ? "'''" : '"""')
: (_fromDouble ? "'" : '"');
var quoteLength = literal.isMultiline ? 3 : 1;
- var lexeme = literal.literal.lexeme;
- if (!lexeme.contains(newQuote)) {
+ var token = literal.literal;
+ if (!token.isSynthetic && !token.lexeme.contains(newQuote)) {
await builder.addDartFileEdit(file, (builder) {
builder.addSimpleReplacement(
SourceRange(
@@ -53,8 +53,8 @@
for (var i = 0; i < elements.length; i++) {
var element = elements[i];
if (element is InterpolationString) {
- var lexeme = element.contents.lexeme;
- if (lexeme.contains(newQuote)) {
+ var token = element.contents;
+ if (token.isSynthetic || token.lexeme.contains(newQuote)) {
return null;
}
}
diff --git a/pkg/analysis_server/lib/src/services/correction/dart/convert_to_multiline_string.dart b/pkg/analysis_server/lib/src/services/correction/dart/convert_to_multiline_string.dart
index 15a289f..e394659 100644
--- a/pkg/analysis_server/lib/src/services/correction/dart/convert_to_multiline_string.dart
+++ b/pkg/analysis_server/lib/src/services/correction/dart/convert_to_multiline_string.dart
@@ -21,7 +21,7 @@
}
if (node is SingleStringLiteral) {
var literal = node;
- if (!literal.isMultiline) {
+ if (!literal.isSynthetic && !literal.isMultiline) {
await builder.addDartFileEdit(file, (builder) {
var newQuote = literal.isSingleQuoted ? "'''" : '"""';
builder.addReplacement(
diff --git a/pkg/analysis_server/lib/src/services/correction/dart/remove_comparison.dart b/pkg/analysis_server/lib/src/services/correction/dart/remove_comparison.dart
index 080bc4f9..8802226 100644
--- a/pkg/analysis_server/lib/src/services/correction/dart/remove_comparison.dart
+++ b/pkg/analysis_server/lib/src/services/correction/dart/remove_comparison.dart
@@ -60,27 +60,36 @@
}
} else if (parent is IfStatement) {
if (parent.elseStatement == null && _conditionIsTrue) {
- var body = _extractBody(parent);
- body = utils.indentSourceLeftRight(body);
- await builder.addDartFileEdit(file, (builder) {
- builder.addSimpleReplacement(
- range.startOffsetEndOffset(
- parent.offset, utils.getLineContentEnd(parent.end)),
- body);
- });
+ await _ifStatement(parent, builder);
}
}
}
- String _extractBody(IfStatement statement) {
- var body = statement.thenStatement;
- if (body is Block) {
- var statements = body.statements;
- return utils.getRangeText(range.startOffsetEndOffset(
- statements.first.offset,
- utils.getLineContentEnd(statements.last.end)));
- }
- return utils.getNodeText(body);
+ Future<void> _ifStatement(IfStatement node, ChangeBuilder builder) async {
+ await builder.addDartFileEdit(file, (builder) {
+ var nodeRange = utils.getLinesRangeStatements([node]);
+
+ String bodyCode;
+ var body = node.thenStatement;
+ if (body is Block) {
+ var statements = body.statements;
+ if (statements.isEmpty) {
+ builder.addDeletion(nodeRange);
+ return;
+ } else {
+ bodyCode = utils.getRangeText(
+ utils.getLinesRangeStatements(statements),
+ );
+ }
+ } else {
+ bodyCode = utils.getRangeText(
+ utils.getLinesRangeStatements([body]),
+ );
+ }
+
+ bodyCode = utils.indentSourceLeftRight(bodyCode);
+ builder.addSimpleReplacement(nodeRange, bodyCode);
+ });
}
/// Use the [builder] to add an edit to delete the operator and given
diff --git a/pkg/analysis_server/test/services/completion/dart/completion_contributor_util.dart b/pkg/analysis_server/test/services/completion/dart/completion_contributor_util.dart
index 63573c1..89353f4 100644
--- a/pkg/analysis_server/test/services/completion/dart/completion_contributor_util.dart
+++ b/pkg/analysis_server/test/services/completion/dart/completion_contributor_util.dart
@@ -13,7 +13,6 @@
import 'package:analysis_server/src/services/completion/dart/utilities.dart';
import 'package:analyzer/dart/analysis/results.dart';
import 'package:analyzer/src/dartdoc/dartdoc_directive_info.dart';
-import 'package:analyzer/src/generated/parser.dart' as analyzer;
import 'package:analyzer_plugin/protocol/protocol_common.dart';
import 'package:meta/meta.dart';
import 'package:test/test.dart';
@@ -96,7 +95,7 @@
/// where there is no `new` or `const` keyword.
bool get suggestConstructorsWithoutNew => true;
- bool get usingFastaParser => analyzer.Parser.useFasta;
+ bool get usingFastaParser => true;
void addTestSource(String content) {
expect(completionOffset, isNull, reason: 'Call addTestUnit exactly once');
diff --git a/pkg/analysis_server/test/src/services/correction/assist/assist_processor.dart b/pkg/analysis_server/test/src/services/correction/assist/assist_processor.dart
index 2235fe2..510843f 100644
--- a/pkg/analysis_server/test/src/services/correction/assist/assist_processor.dart
+++ b/pkg/analysis_server/test/src/services/correction/assist/assist_processor.dart
@@ -6,6 +6,7 @@
import 'package:analysis_server/src/services/correction/assist.dart';
import 'package:analysis_server/src/services/correction/assist_internal.dart';
import 'package:analysis_server/src/services/correction/change_workspace.dart';
+import 'package:analyzer/exception/exception.dart';
import 'package:analyzer/instrumentation/service.dart';
import 'package:analyzer/src/test_utilities/platform.dart';
import 'package:analyzer_plugin/protocol/protocol_common.dart'
@@ -193,7 +194,7 @@
Future<List<Assist>> _computeAssists() async {
var context = DartAssistContextImpl(
- InstrumentationService.NULL_SERVICE,
+ _TestInstrumentationService(),
workspace,
testAnalysisResult,
_offset,
@@ -212,3 +213,19 @@
return positions;
}
}
+
+class _TestInstrumentationService implements InstrumentationService {
+ @override
+ void logException(
+ exception, [
+ StackTrace stackTrace,
+ List<InstrumentationServiceAttachment> attachments,
+ ]) {
+ throw CaughtException(exception, stackTrace);
+ }
+
+ @override
+ dynamic noSuchMethod(Invocation invocation) {
+ return super.noSuchMethod(invocation);
+ }
+}
diff --git a/pkg/analysis_server/test/src/services/correction/assist/convert_to_double_quoted_string_test.dart b/pkg/analysis_server/test/src/services/correction/assist/convert_to_double_quoted_string_test.dart
index 6f8f3d2..813e4bc 100644
--- a/pkg/analysis_server/test/src/services/correction/assist/convert_to_double_quoted_string_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/assist/convert_to_double_quoted_string_test.dart
@@ -54,6 +54,16 @@
''');
}
+ Future<void> test_one_interpolation_unterminated() async {
+ verifyNoTestUnitErrors = false;
+ await resolveTestCode(r'''
+void f(int a) {
+ '$a
+}
+''');
+ await assertNoAssistAt("'");
+ }
+
Future<void> test_one_raw() async {
await resolveTestCode('''
main() {
@@ -80,6 +90,16 @@
''');
}
+ Future<void> test_one_simple_unterminated_empty() async {
+ verifyNoTestUnitErrors = false;
+ await resolveTestCode('''
+void f() {
+ '
+}
+''');
+ await assertNoAssistAt("'");
+ }
+
Future<void> test_three_embeddedTarget() async {
await resolveTestCode("""
main() {
diff --git a/pkg/analysis_server/test/src/services/correction/assist/convert_to_multiline_string_test.dart b/pkg/analysis_server/test/src/services/correction/assist/convert_to_multiline_string_test.dart
index 316515d..c7f2b1e 100644
--- a/pkg/analysis_server/test/src/services/correction/assist/convert_to_multiline_string_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/assist/convert_to_multiline_string_test.dart
@@ -103,6 +103,16 @@
''');
}
+ Future<void> test_doubleQuoted_unterminated() async {
+ verifyNoTestUnitErrors = false;
+ await resolveTestCode('''
+void f() {
+ "
+}
+''');
+ await assertNoAssistAt('"');
+ }
+
Future<void> test_singleQuoted() async {
await resolveTestCode('''
main() {
@@ -177,4 +187,14 @@
}
""");
}
+
+ Future<void> test_singleQuoted_unterminated() async {
+ verifyNoTestUnitErrors = false;
+ await resolveTestCode('''
+void f() {
+ '
+}
+''');
+ await assertNoAssistAt("'");
+ }
}
diff --git a/pkg/analysis_server/test/src/services/correction/assist/convert_to_single_quoted_string_test.dart b/pkg/analysis_server/test/src/services/correction/assist/convert_to_single_quoted_string_test.dart
index 9e925c0..4214de8 100644
--- a/pkg/analysis_server/test/src/services/correction/assist/convert_to_single_quoted_string_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/assist/convert_to_single_quoted_string_test.dart
@@ -55,6 +55,16 @@
''');
}
+ Future<void> test_one_interpolation_unterminated() async {
+ verifyNoTestUnitErrors = false;
+ await resolveTestCode(r'''
+void f(int a) {
+ "$a
+}
+''');
+ await assertNoAssistAt('"');
+ }
+
Future<void> test_one_raw() async {
await resolveTestCode('''
main() {
@@ -92,6 +102,16 @@
await assertNoAssist();
}
+ Future<void> test_one_simple_unterminated_empty() async {
+ verifyNoTestUnitErrors = false;
+ await resolveTestCode('''
+void f() {
+ "
+}
+''');
+ await assertNoAssistAt('"');
+ }
+
Future<void> test_three_embeddedTarget() async {
await resolveTestCode('''
main() {
diff --git a/pkg/analysis_server/test/src/services/correction/fix/remove_comparison_test.dart b/pkg/analysis_server/test/src/services/correction/fix/remove_comparison_test.dart
index 356d591..5494406 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/remove_comparison_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/remove_comparison_test.dart
@@ -146,7 +146,7 @@
''');
}
- Future<void> test_ifStatement() async {
+ Future<void> test_ifStatement_thenBlock() async {
await resolveTestCode('''
void f(String s) {
if (s != null) {
@@ -160,4 +160,31 @@
}
''');
}
+
+ Future<void> test_ifStatement_thenBlock_empty() async {
+ await resolveTestCode('''
+void f(String s) {
+ if (s != null) {
+ }
+}
+''');
+ await assertHasFix('''
+void f(String s) {
+}
+''');
+ }
+
+ Future<void> test_ifStatement_thenStatement() async {
+ await resolveTestCode('''
+void f(String s) {
+ if (s != null)
+ print(s);
+}
+''');
+ await assertHasFix('''
+void f(String s) {
+ print(s);
+}
+''');
+ }
}
diff --git a/pkg/analysis_server/test/utils/test_support.dart b/pkg/analysis_server/test/utils/test_support.dart
index 959be9b..2d176d5 100644
--- a/pkg/analysis_server/test/utils/test_support.dart
+++ b/pkg/analysis_server/test/utils/test_support.dart
@@ -9,7 +9,6 @@
import 'package:analyzer/error/error.dart';
import 'package:analyzer/error/listener.dart';
import 'package:analyzer/src/generated/engine.dart';
-import 'package:analyzer/src/generated/parser.dart';
import 'package:analyzer/src/generated/source.dart';
import 'package:test/test.dart';
@@ -119,7 +118,7 @@
final Map<Source, LineInfo> _lineInfoMap = <Source, LineInfo>{};
/// Initialize a newly created error listener to collect errors.
- GatheringErrorListener({this.checkRanges = Parser.useFasta});
+ GatheringErrorListener({this.checkRanges = true});
/// Return the errors that were collected.
List<AnalysisError> get errors => _errors;
diff --git a/pkg/analyzer/lib/src/dart/analysis/file_state.dart b/pkg/analyzer/lib/src/dart/analysis/file_state.dart
index a37f6a7..942e449 100644
--- a/pkg/analyzer/lib/src/dart/analysis/file_state.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/file_state.dart
@@ -592,7 +592,6 @@
}
CompilationUnit _parse(AnalysisErrorListener errorListener) {
- AnalysisOptionsImpl analysisOptions = _fsState._analysisOptions;
if (source == null) {
return _createEmptyCompilationUnit();
}
@@ -608,12 +607,10 @@
Token token = scanner.tokenize(reportScannerErrors: false);
LineInfo lineInfo = LineInfo(scanner.lineStarts);
- bool useFasta = analysisOptions.useFastaParser;
Parser parser = Parser(
source,
errorListener,
featureSet: scanner.featureSet,
- useFasta: useFasta,
);
parser.enableOptionalNewAndConst = true;
@@ -755,7 +752,6 @@
final FileContentOverlay _contentOverlay;
final SourceFactory _sourceFactory;
final Workspace _workspace;
- final AnalysisOptions _analysisOptions;
final DeclaredVariables _declaredVariables;
final Uint32List _saltForUnlinked;
final Uint32List _saltForElements;
@@ -820,7 +816,8 @@
this.contextName,
this._sourceFactory,
this._workspace,
- this._analysisOptions,
+ @Deprecated('No longer used; will be removed')
+ AnalysisOptions analysisOptions,
this._declaredVariables,
this._saltForUnlinked,
this._saltForElements,
diff --git a/pkg/analyzer/lib/src/dart/micro/library_graph.dart b/pkg/analyzer/lib/src/dart/micro/library_graph.dart
index 26887ce..971bc79 100644
--- a/pkg/analyzer/lib/src/dart/micro/library_graph.dart
+++ b/pkg/analyzer/lib/src/dart/micro/library_graph.dart
@@ -177,8 +177,6 @@
}
CompilationUnit parse(AnalysisErrorListener errorListener, String content) {
- AnalysisOptionsImpl analysisOptions = _fsState._analysisOptions;
-
CharSequenceReader reader = CharSequenceReader(content);
Scanner scanner = Scanner(source, reader, errorListener)
..configureFeatures(
@@ -190,7 +188,6 @@
Token token = scanner.tokenize(reportScannerErrors: false);
LineInfo lineInfo = LineInfo(scanner.lineStarts);
- bool useFasta = analysisOptions.useFastaParser;
// Pass the feature set from the scanner to the parser
// because the scanner may have detected a language version comment
// and downgraded the feature set it holds.
@@ -198,7 +195,6 @@
source,
errorListener,
featureSet: scanner.featureSet,
- useFasta: useFasta,
);
parser.enableOptionalNewAndConst = true;
CompilationUnit unit = parser.parseCompilationUnit(token);
@@ -460,7 +456,6 @@
final CiderByteStore _byteStore;
final SourceFactory _sourceFactory;
final Workspace _workspace;
- final AnalysisOptions _analysisOptions;
final Uint32List _linkedSalt;
/// A function that returns the digest for a file as a String. The function
@@ -486,7 +481,8 @@
this._byteStore,
this._sourceFactory,
this._workspace,
- this._analysisOptions,
+ @Deprecated('No longer used; will be removed')
+ AnalysisOptions analysisOptions,
this._linkedSalt,
this.featureSetProvider,
this.getFileDigest,
diff --git a/pkg/analyzer/lib/src/generated/parser.dart b/pkg/analyzer/lib/src/generated/parser.dart
index 89c2ca2..a76eef9 100644
--- a/pkg/analyzer/lib/src/generated/parser.dart
+++ b/pkg/analyzer/lib/src/generated/parser.dart
@@ -4,40 +4,25 @@
library analyzer.parser;
-import 'dart:collection';
-import "dart:math" as math;
-
import 'package:_fe_analyzer_shared/src/parser/identifier_context.dart'
as fasta;
import 'package:_fe_analyzer_shared/src/parser/member_kind.dart' as fasta;
import 'package:_fe_analyzer_shared/src/parser/parser.dart' as fasta;
import 'package:_fe_analyzer_shared/src/parser/type_info.dart' as fasta;
-import 'package:_fe_analyzer_shared/src/scanner/scanner.dart' as fasta;
import 'package:analyzer/dart/analysis/features.dart';
import 'package:analyzer/dart/ast/ast.dart';
-import 'package:analyzer/dart/ast/standard_ast_factory.dart';
import 'package:analyzer/dart/ast/token.dart';
-import 'package:analyzer/error/error.dart';
import 'package:analyzer/error/listener.dart';
-import 'package:analyzer/src/dart/ast/ast.dart';
import 'package:analyzer/src/dart/ast/token.dart';
import 'package:analyzer/src/dart/error/syntactic_errors.dart';
-import 'package:analyzer/src/dart/scanner/reader.dart';
import 'package:analyzer/src/dart/scanner/scanner.dart';
-import 'package:analyzer/src/error/codes.dart';
import 'package:analyzer/src/fasta/ast_builder.dart';
-import 'package:analyzer/src/generated/engine.dart' show AnalysisEngine;
-import 'package:analyzer/src/generated/java_core.dart';
-import 'package:analyzer/src/generated/java_engine.dart';
import 'package:analyzer/src/generated/source.dart';
-import 'package:analyzer/src/generated/utilities_dart.dart';
import 'package:meta/meta.dart';
export 'package:analyzer/src/dart/ast/utilities.dart' show ResolutionCopier;
export 'package:analyzer/src/dart/error/syntactic_errors.dart';
-part 'parser_fasta.dart';
-
/// A simple data-holder for a method that needs to return multiple values.
class CommentAndMetadata {
/// The documentation comment that was parsed, or `null` if none was given.
@@ -129,7873 +114,261 @@
/// A parser used to parse tokens into an AST structure.
class Parser {
- static String ASYNC = Keyword.ASYNC.lexeme;
+ Token currentToken;
- static final String _AWAIT = Keyword.AWAIT.lexeme;
+ /// The fasta parser being wrapped.
+ final fasta.Parser fastaParser;
- static final String _HIDE = Keyword.HIDE.lexeme;
+ /// The builder which creates the analyzer AST data structures
+ /// based on the Fasta parser.
+ final AstBuilder astBuilder;
- static final String _SHOW = Keyword.SHOW.lexeme;
-
- static final String SYNC = Keyword.SYNC.lexeme;
-
- static final String _YIELD = Keyword.YIELD.lexeme;
-
- static const int _MAX_TREE_DEPTH = 300;
-
- /// A flag indicating whether the analyzer [Parser] factory method
- /// will return a fasta based parser or an analyzer based parser.
- static const bool useFasta = true;
-
- /// The source being parsed.
- final Source _source;
-
- /// The error listener that will be informed of any errors that are found
- /// during the parse.
- final AnalysisErrorListener _errorListener;
-
- /// An [_errorListener] lock, if more than `0`, then errors are not reported.
- int _errorListenerLock = 0;
-
- /// A flag indicating whether the parser should parse instance creation
- /// expressions that lack either the `new` or `const` keyword.
- bool _enableOptionalNewAndConst = true;
-
- /// A flag indicating whether parser is to parse function bodies.
- bool _parseFunctionBodies = true;
-
- /// The next token to be parsed.
- Token _currentToken;
-
- /// The depth of the current AST. When this depth is too high, so we're at the
- /// risk of overflowing the stack, we stop parsing and report an error.
- int _treeDepth = 0;
-
- /// A flag indicating whether the parser is currently in a function body
- /// marked as being 'async'.
- bool _inAsync = false;
-
- /// A flag indicating whether the parser is currently in a function body
- /// marked(by a star) as being a generator.
- bool _inGenerator = false;
-
- /// A flag indicating whether the parser is currently in the body of a loop.
- bool _inLoop = false;
-
- /// A flag indicating whether the parser is currently in a switch statement.
- bool _inSwitch = false;
-
- /// A flag indicating whether the parser is currently in a constructor field
- /// initializer, with no intervening parentheses, braces, or brackets.
- bool _inInitializer = false;
-
- /// A flag indicating whether the parser is to parse generic method syntax.
- @deprecated
- bool parseGenericMethods = false;
-
- bool allowNativeClause;
-
- FeatureSet _featureSet;
-
- /// Initialize a newly created parser to parse tokens in the given [_source]
- /// and to report any errors that are found to the given [_errorListener].
- factory Parser(Source source, AnalysisErrorListener errorListener,
- {bool useFasta, @required FeatureSet featureSet}) {
- featureSet ??= FeatureSet.latestLanguageVersion();
- if (useFasta ?? Parser.useFasta) {
- return _Parser2(source, errorListener, featureSet,
- allowNativeClause: true);
- } else {
- return Parser.withoutFasta(source, errorListener, featureSet: featureSet);
- }
+ Parser(Source source, AnalysisErrorListener errorListener,
+ {@required FeatureSet featureSet, bool allowNativeClause = true})
+ : fastaParser = fasta.Parser(null),
+ astBuilder = AstBuilder(
+ ErrorReporter(
+ errorListener,
+ source,
+ isNonNullableByDefault:
+ featureSet.isEnabled(Feature.non_nullable),
+ ),
+ source.uri,
+ true,
+ featureSet) {
+ fastaParser.listener = astBuilder;
+ astBuilder.parser = fastaParser;
+ astBuilder.allowNativeClause = allowNativeClause;
}
- /// Creates a parser using the old (legacy) analyzer parsing logic.
- ///
- /// In a future major version release of the analyzer, the [featureSet]
- /// argument will be required.
- Parser.withoutFasta(this._source, this._errorListener,
- {FeatureSet featureSet}) {
- if (featureSet != null) {
- _configureFeatures(featureSet);
- }
+ set allowNativeClause(bool value) {
+ astBuilder.allowNativeClause = value;
}
- /// Return the current token.
- Token get currentToken => _currentToken;
+ bool get enableOptionalNewAndConst => false;
- /// Set the token with which the parse is to begin to the given [token].
- set currentToken(Token token) {
- _currentToken = token;
- }
+ set enableOptionalNewAndConst(bool enable) {}
- /// Return `true` if the parser is to parse asserts in the initializer list of
- /// a constructor.
- @deprecated
- bool get enableAssertInitializer => true;
-
- /// Set whether the parser is to parse asserts in the initializer list of a
- /// constructor to match the given [enable] flag.
- @deprecated
- set enableAssertInitializer(bool enable) {}
-
- /// Return `true` if the parser should parse instance creation expressions
- /// that lack either the `new` or `const` keyword.
- bool get enableOptionalNewAndConst => _enableOptionalNewAndConst;
-
- /// Set whether the parser should parse instance creation expressions that
- /// lack either the `new` or `const` keyword.
- set enableOptionalNewAndConst(bool enable) {
- _enableOptionalNewAndConst = enable;
- }
-
- /// Enables or disables parsing of set literals.
set enableSetLiterals(bool value) {
// TODO(danrubel): Remove this method once the reference to this flag
// has been removed from dartfmt.
}
- /// Return `true` if the parser is to allow URI's in part-of directives.
- @deprecated
- bool get enableUriInPartOf => true;
-
- /// Set whether the parser is to allow URI's in part-of directives to the
- /// given [enable] flag.
- @deprecated
- set enableUriInPartOf(bool enable) {}
-
- /// Return `true` if the current token is the first token of a return type
- /// that is followed by an identifier, possibly followed by a list of type
- /// parameters, followed by a left-parenthesis. This is used by
- /// [parseTypeAlias] to determine whether or not to parse a return type.
- bool get hasReturnTypeInTypeAlias {
- // TODO(brianwilkerson) This is too expensive as implemented and needs to be
- // re-implemented or removed.
- Token next = skipTypeAnnotation(_currentToken);
- if (next == null) {
- return false;
- }
- return _tokenMatchesIdentifier(next);
- }
-
- /// Set whether the parser is to parse the async support.
- ///
- /// Support for removing the 'async' library has been removed.
- @deprecated
- set parseAsync(bool parseAsync) {}
-
- @deprecated
- bool get parseConditionalDirectives => true;
-
- @deprecated
- set parseConditionalDirectives(bool value) {}
-
- /// Set whether parser is to parse function bodies.
set parseFunctionBodies(bool parseFunctionBodies) {
- _parseFunctionBodies = parseFunctionBodies;
+ astBuilder.parseFunctionBodies = parseFunctionBodies;
}
- /// Return the content of a string with the given literal representation. The
- /// [lexeme] is the literal representation of the string. The flag [isFirst]
- /// is `true` if this is the first token in a string literal. The flag
- /// [isLast] is `true` if this is the last token in a string literal.
- String computeStringValue(String lexeme, bool isFirst, bool isLast) {
- StringLexemeHelper helper = StringLexemeHelper(lexeme, isFirst, isLast);
- int start = helper.start;
- int end = helper.end;
- bool stringEndsAfterStart = end >= start;
- assert(stringEndsAfterStart);
- if (!stringEndsAfterStart) {
- AnalysisEngine.instance.instrumentationService.logError(
- "Internal error: computeStringValue($lexeme, $isFirst, $isLast)");
- return "";
+ /// Append the given token to the end of the token stream,
+ /// and update the token's offset.
+ void appendToken(Token token, Token newToken) {
+ while (!token.next.isEof) {
+ token = token.next;
}
- if (helper.isRaw) {
- return lexeme.substring(start, end);
- }
- StringBuffer buffer = StringBuffer();
- int index = start;
- while (index < end) {
- index = _translateCharacter(buffer, lexeme, index);
- }
- return buffer.toString();
+ newToken
+ ..offset = token.end
+ ..setNext(token.next);
+ token.setNext(newToken);
}
- /// Return a synthetic identifier.
- SimpleIdentifier createSyntheticIdentifier({bool isDeclaration = false}) {
- Token syntheticToken;
- if (_currentToken.type.isKeyword) {
- // Consider current keyword token as an identifier.
- // It is not always true, e.g. "^is T" where "^" is place the place for
- // synthetic identifier. By creating SyntheticStringToken we can
- // distinguish a real identifier from synthetic. In the code completion
- // behavior will depend on a cursor position - before or on "is".
- syntheticToken = _injectToken(SyntheticStringToken(
- TokenType.IDENTIFIER, _currentToken.lexeme, _currentToken.offset));
- } else {
- syntheticToken = _createSyntheticToken(TokenType.IDENTIFIER);
- }
- return astFactory.simpleIdentifier(syntheticToken,
- isDeclaration: isDeclaration);
- }
+ Expression parseAdditiveExpression() => parseExpression2();
- /// Return a synthetic string literal.
- SimpleStringLiteral createSyntheticStringLiteral() => astFactory
- .simpleStringLiteral(_createSyntheticToken(TokenType.STRING), "");
-
- /// Advance to the next token in the token stream, making it the new current
- /// token and return the token that was current before this method was
- /// invoked.
- Token getAndAdvance() {
- Token token = _currentToken;
- _currentToken = _currentToken.next;
- return token;
- }
-
- /// Return `true` if the current token appears to be the beginning of a
- /// function declaration.
- bool isFunctionDeclaration() {
- Keyword keyword = _currentToken.keyword;
- Token afterReturnType = skipTypeWithoutFunction(_currentToken);
- if (afterReturnType != null &&
- _tokenMatchesKeyword(afterReturnType, Keyword.FUNCTION)) {
- afterReturnType = skipGenericFunctionTypeAfterReturnType(afterReturnType);
- }
- // If there was no return type, because it was optional, go back
- // to where we started.
- afterReturnType ??= _currentToken;
- Token afterIdentifier = skipSimpleIdentifier(afterReturnType);
-
- // It's possible that we parsed the function name as if it were a type
- // name, so see whether it makes sense if we assume that there is no type.
- afterIdentifier ??= skipSimpleIdentifier(_currentToken);
- if (afterIdentifier == null) {
- return false;
- }
- if (isFunctionExpression(afterIdentifier)) {
- return true;
- }
- // It's possible that we have found a getter. While this isn't valid at this
- // point we test for it in order to recover better.
- if (keyword == Keyword.GET) {
- Token afterName = skipSimpleIdentifier(_currentToken.next);
- if (afterName == null) {
- return false;
- }
- TokenType type = afterName.type;
- return type == TokenType.FUNCTION || type == TokenType.OPEN_CURLY_BRACKET;
- } else if (_tokenMatchesKeyword(afterReturnType, Keyword.GET)) {
- Token afterName = skipSimpleIdentifier(afterReturnType.next);
- if (afterName == null) {
- return false;
- }
- TokenType type = afterName.type;
- return type == TokenType.FUNCTION || type == TokenType.OPEN_CURLY_BRACKET;
- }
- return false;
- }
-
- /// Return `true` if the given [token] appears to be the beginning of a
- /// function expression.
- bool isFunctionExpression(Token token) {
- // Function expressions aren't allowed in initializer lists.
- if (_inInitializer) {
- return false;
- }
- Token afterTypeParameters = _skipTypeParameterList(token);
- afterTypeParameters ??= token;
- Token afterParameters = _skipFormalParameterList(afterTypeParameters);
- if (afterParameters == null) {
- return false;
- }
- if (afterParameters.matchesAny(
- const <TokenType>[TokenType.OPEN_CURLY_BRACKET, TokenType.FUNCTION])) {
- return true;
- }
- String lexeme = afterParameters.lexeme;
- return lexeme == ASYNC || lexeme == SYNC;
- }
-
- /// Return `true` if the current token is the first token in an initialized
- /// variable declaration rather than an expression. This method assumes that
- /// we have already skipped past any metadata that might be associated with
- /// the declaration.
- ///
- /// initializedVariableDeclaration ::=
- /// declaredIdentifier ('=' expression)? (',' initializedIdentifier)*
- ///
- /// declaredIdentifier ::=
- /// metadata finalConstVarOrType identifier
- ///
- /// finalConstVarOrType ::=
- /// 'final' type?
- /// | 'const' type?
- /// | 'var'
- /// | type
- ///
- /// type ::=
- /// qualified typeArguments?
- ///
- /// initializedIdentifier ::=
- /// identifier ('=' expression)?
- bool isInitializedVariableDeclaration() {
- Keyword keyword = _currentToken.keyword;
- if (keyword == Keyword.FINAL ||
- keyword == Keyword.VAR ||
- keyword == Keyword.VOID) {
- // An expression cannot start with a keyword other than 'const',
- // 'rethrow', or 'throw'.
- return true;
- }
- if (keyword == Keyword.CONST) {
- // Look to see whether we might be at the start of a list or map literal,
- // otherwise this should be the start of a variable declaration.
- return !_peek().matchesAny(const <TokenType>[
- TokenType.LT,
- TokenType.OPEN_CURLY_BRACKET,
- TokenType.OPEN_SQUARE_BRACKET,
- TokenType.INDEX
- ]);
- }
- bool allowAdditionalTokens = true;
- // We know that we have an identifier, and need to see whether it might be
- // a type name.
- if (_currentToken.type != TokenType.IDENTIFIER) {
- allowAdditionalTokens = false;
- }
- Token token = skipTypeName(_currentToken);
- if (token == null) {
- // There was no type name, so this can't be a declaration.
- return false;
- }
- while (_atGenericFunctionTypeAfterReturnType(token)) {
- token = skipGenericFunctionTypeAfterReturnType(token);
- if (token == null) {
- // There was no type name, so this can't be a declaration.
- return false;
- }
- }
- if (token.type != TokenType.IDENTIFIER) {
- allowAdditionalTokens = false;
- }
- token = skipSimpleIdentifier(token);
- if (token == null) {
- return false;
- }
- TokenType type = token.type;
- // Usual cases in valid code:
- // String v = '';
- // String v, v2;
- // String v;
- // for (String item in items) {}
- if (type == TokenType.EQ ||
- type == TokenType.COMMA ||
- type == TokenType.SEMICOLON ||
- token.keyword == Keyword.IN) {
- return true;
- }
- // It is OK to parse as a variable declaration in these cases:
- // String v }
- // String v if (true) print('OK');
- // String v { print(42); }
- // ...but not in these cases:
- // get getterName {
- // String get getterName
- if (allowAdditionalTokens) {
- if (type == TokenType.CLOSE_CURLY_BRACKET ||
- type.isKeyword ||
- type == TokenType.IDENTIFIER ||
- type == TokenType.OPEN_CURLY_BRACKET) {
- return true;
- }
- }
- return false;
- }
-
- /// Return `true` if the current token appears to be the beginning of a switch
- /// member.
- bool isSwitchMember() {
- Token token = _currentToken;
- while (_tokenMatches(token, TokenType.IDENTIFIER) &&
- _tokenMatches(token.next, TokenType.COLON)) {
- token = token.next.next;
- }
- Keyword keyword = token.keyword;
- return keyword == Keyword.CASE || keyword == Keyword.DEFAULT;
- }
-
- /// Parse an additive expression. Return the additive expression that was
- /// parsed.
- ///
- /// additiveExpression ::=
- /// multiplicativeExpression (additiveOperator multiplicativeExpression)*
- /// | 'super' (additiveOperator multiplicativeExpression)+
- Expression parseAdditiveExpression() {
- Expression expression;
- if (_currentToken.keyword == Keyword.SUPER &&
- _currentToken.next.type.isAdditiveOperator) {
- expression = astFactory.superExpression(getAndAdvance());
- } else {
- expression = parseMultiplicativeExpression();
- }
- while (_currentToken.type.isAdditiveOperator) {
- expression = astFactory.binaryExpression(
- expression, getAndAdvance(), parseMultiplicativeExpression());
- }
- return expression;
- }
-
- /// Parse an annotation. Return the annotation that was parsed.
- ///
- /// This method assumes that the current token matches [TokenType.AT].
- ///
- /// annotation ::=
- /// '@' qualified ('.' identifier)? arguments?
- Annotation parseAnnotation() {
- Token atSign = getAndAdvance();
- Identifier name = parsePrefixedIdentifier();
- Token period;
- SimpleIdentifier constructorName;
- if (_matches(TokenType.PERIOD)) {
- period = getAndAdvance();
- constructorName = parseSimpleIdentifier();
- }
- ArgumentList arguments;
- if (_matches(TokenType.OPEN_PAREN)) {
- arguments = parseArgumentList();
- }
- return astFactory.annotation(
- atSign, name, period, constructorName, arguments);
- }
-
- /// Parse an argument. Return the argument that was parsed.
- ///
- /// argument ::=
- /// namedArgument
- /// | expression
- ///
- /// namedArgument ::=
- /// label expression
Expression parseArgument() {
- // TODO(brianwilkerson) Consider returning a wrapper indicating whether the
- // expression is a named expression in order to remove the 'is' check in
- // 'parseArgumentList'.
- //
- // Both namedArgument and expression can start with an identifier, but only
- // namedArgument can have an identifier followed by a colon.
- //
- if (_matchesIdentifier() && _tokenMatches(_peek(), TokenType.COLON)) {
- return astFactory.namedExpression(parseLabel(), parseExpression2());
- } else {
- return parseExpression2();
- }
+ currentToken = SimpleToken(TokenType.OPEN_PAREN, 0)..setNext(currentToken);
+ appendToken(currentToken, SimpleToken(TokenType.CLOSE_PAREN, 0));
+ currentToken = fastaParser
+ .parseArguments(fastaParser.syntheticPreviousToken(currentToken))
+ .next;
+ var invocation = astBuilder.pop() as MethodInvocation;
+ return invocation.argumentList.arguments[0];
}
- /// Parse a list of arguments. Return the argument list that was parsed.
- ///
- /// This method assumes that the current token matches [TokenType.OPEN_PAREN].
- ///
- /// arguments ::=
- /// '(' argumentList? ')'
- ///
- /// argumentList ::=
- /// namedArgument (',' namedArgument)*
- /// | expressionList (',' namedArgument)*
- ArgumentList parseArgumentList() {
- Token leftParenthesis = getAndAdvance();
- if (_matches(TokenType.CLOSE_PAREN)) {
- return astFactory.argumentList(leftParenthesis, null, getAndAdvance());
- }
+ Expression parseAssignableExpression(bool primaryAllowed) =>
+ parseExpression2();
- /// Return `true` if the parser appears to be at the beginning of an
- /// argument even though there was no comma. This is a special case of the
- /// more general recovery technique described below.
- bool isLikelyMissingComma() {
- if (_matchesIdentifier() &&
- _tokenMatches(_currentToken.next, TokenType.COLON) &&
- leftParenthesis is BeginToken &&
- leftParenthesis.endToken != null) {
- _reportErrorForToken(
- ParserErrorCode.EXPECTED_TOKEN, _currentToken.previous, [',']);
- return true;
- }
- return false;
- }
+ Expression parseBitwiseAndExpression() => parseExpression2();
- //
- // Even though unnamed arguments must all appear before any named arguments,
- // we allow them to appear in any order so that we can recover faster.
- //
- bool wasInInitializer = _inInitializer;
- _inInitializer = false;
- try {
- Token previousStartOfArgument = _currentToken;
- Expression argument = parseArgument();
- List<Expression> arguments = <Expression>[argument];
- bool foundNamedArgument = argument is NamedExpression;
- bool generatedError = false;
- while (_optional(TokenType.COMMA) ||
- (isLikelyMissingComma() &&
- previousStartOfArgument != _currentToken)) {
- if (_matches(TokenType.CLOSE_PAREN)) {
- break;
- }
- previousStartOfArgument = _currentToken;
- argument = parseArgument();
- arguments.add(argument);
- if (argument is NamedExpression) {
- foundNamedArgument = true;
- } else if (foundNamedArgument) {
- if (!generatedError) {
- if (!argument.isSynthetic) {
- // Report the error, once, but allow the arguments to be in any
- // order in the AST.
- _reportErrorForCurrentToken(
- ParserErrorCode.POSITIONAL_AFTER_NAMED_ARGUMENT);
- generatedError = true;
- }
- }
- }
- }
- // Recovery: If the next token is not a right parenthesis, look at the
- // left parenthesis to see whether there is a matching right parenthesis.
- // If there is, then we're more likely missing a comma and should go back
- // to parsing arguments.
- Token rightParenthesis = _expect(TokenType.CLOSE_PAREN);
- return astFactory.argumentList(
- leftParenthesis, arguments, rightParenthesis);
- } finally {
- _inInitializer = wasInInitializer;
- }
- }
+ Expression parseBitwiseOrExpression() => parseExpression2();
- /// Parse an assert statement. Return the assert statement.
- ///
- /// This method assumes that the current token matches `Keyword.ASSERT`.
- ///
- /// assertStatement ::=
- /// 'assert' '(' expression [',' expression] ')' ';'
- AssertStatement parseAssertStatement() {
- Token keyword = getAndAdvance();
- Token leftParen = _expect(TokenType.OPEN_PAREN);
- Expression expression = parseExpression2();
- Token comma;
- Expression message;
- if (_matches(TokenType.COMMA)) {
- comma = getAndAdvance();
- if (_matches(TokenType.CLOSE_PAREN)) {
- comma;
- } else {
- message = parseExpression2();
- if (_matches(TokenType.COMMA)) {
- getAndAdvance();
- }
- }
- }
- Token rightParen = _expect(TokenType.CLOSE_PAREN);
- Token semicolon = _expect(TokenType.SEMICOLON);
- // TODO(brianwilkerson) We should capture the trailing comma in the AST, but
- // that would be a breaking change, so we drop it for now.
- return astFactory.assertStatement(
- keyword, leftParen, expression, comma, message, rightParen, semicolon);
- }
+ Expression parseBitwiseXorExpression() => parseExpression2();
- /// Parse an assignable expression. The [primaryAllowed] is `true` if the
- /// expression is allowed to be a primary without any assignable selector.
- /// Return the assignable expression that was parsed.
- ///
- /// assignableExpression ::=
- /// primary (arguments* assignableSelector)+
- /// | 'super' unconditionalAssignableSelector
- /// | identifier
- Expression parseAssignableExpression(bool primaryAllowed) {
- //
- // A primary expression can start with an identifier. We resolve the
- // ambiguity by determining whether the primary consists of anything other
- // than an identifier and/or is followed by an assignableSelector.
- //
- Expression expression = parsePrimaryExpression();
- bool isOptional =
- primaryAllowed || _isValidAssignableExpression(expression);
- while (true) {
- while (_isLikelyArgumentList()) {
- TypeArgumentList typeArguments = _parseOptionalTypeArguments();
- ArgumentList argumentList = parseArgumentList();
- Expression currentExpression = expression;
- if (currentExpression is SimpleIdentifier) {
- expression = astFactory.methodInvocation(
- null, null, currentExpression, typeArguments, argumentList);
- } else if (currentExpression is PrefixedIdentifier) {
- expression = astFactory.methodInvocation(
- currentExpression.prefix,
- currentExpression.period,
- currentExpression.identifier,
- typeArguments,
- argumentList);
- } else if (currentExpression is PropertyAccess) {
- expression = astFactory.methodInvocation(
- currentExpression.target,
- currentExpression.operator,
- currentExpression.propertyName,
- typeArguments,
- argumentList);
- } else {
- expression = astFactory.functionExpressionInvocation(
- expression, typeArguments, argumentList);
- }
- if (!primaryAllowed) {
- isOptional = false;
- }
- }
- Expression selectorExpression = parseAssignableSelector(
- expression, isOptional || (expression is PrefixedIdentifier));
- if (identical(selectorExpression, expression)) {
- return expression;
- }
- expression = selectorExpression;
- isOptional = true;
- }
- }
-
- /// Parse an assignable selector. The [prefix] is the expression preceding the
- /// selector. The [optional] is `true` if the selector is optional. Return the
- /// assignable selector that was parsed, or the original prefix if there was
- /// no assignable selector. If [allowConditional] is false, then the '?.'
- /// operator will still be parsed, but a parse error will be generated.
- ///
- /// unconditionalAssignableSelector ::=
- /// '[' expression ']'
- /// | '.' identifier
- ///
- /// assignableSelector ::=
- /// unconditionalAssignableSelector
- /// | '?.' identifier
- Expression parseAssignableSelector(Expression prefix, bool optional,
- {bool allowConditional = true}) {
- TokenType type = _currentToken.type;
- if (type == TokenType.OPEN_SQUARE_BRACKET) {
- Token leftBracket = getAndAdvance();
- bool wasInInitializer = _inInitializer;
- _inInitializer = false;
- try {
- Expression index = parseExpression2();
- Token rightBracket = _expect(TokenType.CLOSE_SQUARE_BRACKET);
- return astFactory.indexExpressionForTarget2(
- target: prefix,
- leftBracket: leftBracket,
- index: index,
- rightBracket: rightBracket);
- } finally {
- _inInitializer = wasInInitializer;
- }
- } else {
- bool isQuestionPeriod = type == TokenType.QUESTION_PERIOD;
- if (type == TokenType.PERIOD || isQuestionPeriod) {
- if (isQuestionPeriod && !allowConditional) {
- _reportErrorForCurrentToken(
- ParserErrorCode.INVALID_OPERATOR_FOR_SUPER,
- [_currentToken.lexeme]);
- }
- Token operator = getAndAdvance();
- return astFactory.propertyAccess(
- prefix, operator, parseSimpleIdentifier());
- } else if (type == TokenType.INDEX) {
- _splitIndex();
- Token leftBracket = getAndAdvance();
- Expression index = parseSimpleIdentifier();
- Token rightBracket = getAndAdvance();
- return astFactory.indexExpressionForTarget2(
- target: prefix,
- leftBracket: leftBracket,
- index: index,
- rightBracket: rightBracket);
- } else {
- if (!optional) {
- // Report the missing selector.
- _reportErrorForCurrentToken(
- ParserErrorCode.MISSING_ASSIGNABLE_SELECTOR);
- }
- return prefix;
- }
- }
- }
-
- /// Parse a await expression. Return the await expression that was parsed.
- ///
- /// This method assumes that the current token matches `_AWAIT`.
- ///
- /// awaitExpression ::=
- /// 'await' unaryExpression
- AwaitExpression parseAwaitExpression() {
- Token awaitToken = getAndAdvance();
- Expression expression = parseUnaryExpression();
- return astFactory.awaitExpression(awaitToken, expression);
- }
-
- /// Parse a bitwise and expression. Return the bitwise and expression that was
- /// parsed.
- ///
- /// bitwiseAndExpression ::=
- /// shiftExpression ('&' shiftExpression)*
- /// | 'super' ('&' shiftExpression)+
- Expression parseBitwiseAndExpression() {
- Expression expression;
- if (_currentToken.keyword == Keyword.SUPER &&
- _currentToken.next.type == TokenType.AMPERSAND) {
- expression = astFactory.superExpression(getAndAdvance());
- } else {
- expression = parseShiftExpression();
- }
- while (_currentToken.type == TokenType.AMPERSAND) {
- expression = astFactory.binaryExpression(
- expression, getAndAdvance(), parseShiftExpression());
- }
- return expression;
- }
-
- /// Parse a bitwise or expression. Return the bitwise or expression that was
- /// parsed.
- ///
- /// bitwiseOrExpression ::=
- /// bitwiseXorExpression ('|' bitwiseXorExpression)*
- /// | 'super' ('|' bitwiseXorExpression)+
- Expression parseBitwiseOrExpression() {
- Expression expression;
- if (_currentToken.keyword == Keyword.SUPER &&
- _currentToken.next.type == TokenType.BAR) {
- expression = astFactory.superExpression(getAndAdvance());
- } else {
- expression = parseBitwiseXorExpression();
- }
- while (_currentToken.type == TokenType.BAR) {
- expression = astFactory.binaryExpression(
- expression, getAndAdvance(), parseBitwiseXorExpression());
- }
- return expression;
- }
-
- /// Parse a bitwise exclusive-or expression. Return the bitwise exclusive-or
- /// expression that was parsed.
- ///
- /// bitwiseXorExpression ::=
- /// bitwiseAndExpression ('^' bitwiseAndExpression)*
- /// | 'super' ('^' bitwiseAndExpression)+
- Expression parseBitwiseXorExpression() {
- Expression expression;
- if (_currentToken.keyword == Keyword.SUPER &&
- _currentToken.next.type == TokenType.CARET) {
- expression = astFactory.superExpression(getAndAdvance());
- } else {
- expression = parseBitwiseAndExpression();
- }
- while (_currentToken.type == TokenType.CARET) {
- expression = astFactory.binaryExpression(
- expression, getAndAdvance(), parseBitwiseAndExpression());
- }
- return expression;
- }
-
- /// Parse a block. Return the block that was parsed.
- ///
- /// This method assumes that the current token matches
- /// [TokenType.OPEN_CURLY_BRACKET].
- ///
- /// block ::=
- /// '{' statements '}'
- Block parseBlock() {
- bool isEndOfBlock() {
- TokenType type = _currentToken.type;
- return type == TokenType.EOF || type == TokenType.CLOSE_CURLY_BRACKET;
- }
-
- Token leftBracket = getAndAdvance();
- List<Statement> statements = <Statement>[];
- Token statementStart = _currentToken;
- while (!isEndOfBlock()) {
- Statement statement = parseStatement2();
- if (identical(_currentToken, statementStart)) {
- // Ensure that we are making progress and report an error if we're not.
- _reportErrorForToken(ParserErrorCode.UNEXPECTED_TOKEN, _currentToken,
- [_currentToken.lexeme]);
- _advance();
- } else if (statement != null) {
- statements.add(statement);
- }
- statementStart = _currentToken;
- }
- // Recovery: If the next token is not a right curly bracket, look at the
- // left curly bracket to see whether there is a matching right bracket. If
- // there is, then we're more likely missing a semi-colon and should go back
- // to parsing statements.
- Token rightBracket = _expect(TokenType.CLOSE_CURLY_BRACKET);
- return astFactory.block(leftBracket, statements, rightBracket);
- }
-
- /// Parse a break statement. Return the break statement that was parsed.
- ///
- /// This method assumes that the current token matches `Keyword.BREAK`.
- ///
- /// breakStatement ::=
- /// 'break' identifier? ';'
- Statement parseBreakStatement() {
- Token breakKeyword = getAndAdvance();
- SimpleIdentifier label;
- if (_matchesIdentifier()) {
- label = _parseSimpleIdentifierUnchecked();
- }
- if (!_inLoop && !_inSwitch && label == null) {
- _reportErrorForToken(ParserErrorCode.BREAK_OUTSIDE_OF_LOOP, breakKeyword);
- }
- Token semicolon = _expect(TokenType.SEMICOLON);
- return astFactory.breakStatement(breakKeyword, label, semicolon);
- }
-
- /// Parse a cascade section. Return the expression representing the cascaded
- /// method invocation.
- ///
- /// This method assumes that the current token matches
- /// `TokenType.PERIOD_PERIOD`.
- ///
- /// cascadeSection ::=
- /// '..' (cascadeSelector typeArguments? arguments*)
- /// (assignableSelector typeArguments? arguments*)* cascadeAssignment?
- ///
- /// cascadeSelector ::=
- /// '[' expression ']'
- /// | identifier
- ///
- /// cascadeAssignment ::=
- /// assignmentOperator expressionWithoutCascade
- Expression parseCascadeSection() {
- Token period = getAndAdvance();
- Expression expression;
- SimpleIdentifier functionName;
- if (_matchesIdentifier()) {
- functionName = _parseSimpleIdentifierUnchecked();
- } else if (_currentToken.type == TokenType.OPEN_SQUARE_BRACKET) {
- Token leftBracket = getAndAdvance();
- bool wasInInitializer = _inInitializer;
- _inInitializer = false;
- try {
- Expression index = parseExpression2();
- Token rightBracket = _expect(TokenType.CLOSE_SQUARE_BRACKET);
- expression = astFactory.indexExpressionForCascade2(
- period: period,
- leftBracket: leftBracket,
- index: index,
- rightBracket: rightBracket);
- period;
- } finally {
- _inInitializer = wasInInitializer;
- }
- } else {
- _reportErrorForToken(ParserErrorCode.MISSING_IDENTIFIER, _currentToken,
- [_currentToken.lexeme]);
- functionName = createSyntheticIdentifier();
- }
- assert((expression == null && functionName != null) ||
- (expression != null && functionName == null));
- if (_isLikelyArgumentList()) {
- do {
- TypeArgumentList typeArguments = _parseOptionalTypeArguments();
- if (functionName != null) {
- expression = astFactory.methodInvocation(expression, period,
- functionName, typeArguments, parseArgumentList());
- period;
- functionName;
- } else if (expression == null) {
- // It should not be possible to get here.
- expression = astFactory.methodInvocation(expression, period,
- createSyntheticIdentifier(), typeArguments, parseArgumentList());
- } else {
- expression = astFactory.functionExpressionInvocation(
- expression, typeArguments, parseArgumentList());
- }
- } while (_isLikelyArgumentList());
- } else if (functionName != null) {
- expression = astFactory.propertyAccess(expression, period, functionName);
- period;
- }
- assert(expression != null);
- bool progress = true;
- while (progress) {
- progress = false;
- Expression selector = parseAssignableSelector(expression, true);
- if (!identical(selector, expression)) {
- expression = selector;
- progress = true;
- while (_isLikelyArgumentList()) {
- TypeArgumentList typeArguments = _parseOptionalTypeArguments();
- Expression currentExpression = expression;
- if (currentExpression is PropertyAccess) {
- expression = astFactory.methodInvocation(
- currentExpression.target,
- currentExpression.operator,
- currentExpression.propertyName,
- typeArguments,
- parseArgumentList());
- } else {
- expression = astFactory.functionExpressionInvocation(
- expression, typeArguments, parseArgumentList());
- }
- }
- }
- }
- if (_currentToken.type.isAssignmentOperator) {
- Token operator = getAndAdvance();
- _ensureAssignable(expression);
- expression = astFactory.assignmentExpression(
- expression, operator, parseExpressionWithoutCascade());
- }
- return expression;
- }
-
- /// Parse a class declaration. The [commentAndMetadata] is the metadata to be
- /// associated with the member. The [abstractKeyword] is the token for the
- /// keyword 'abstract', or `null` if the keyword was not given. Return the
- /// class declaration that was parsed.
- ///
- /// This method assumes that the current token matches `Keyword.CLASS`.
- ///
- /// classDeclaration ::=
- /// metadata 'abstract'? 'class' name typeParameterList? (extendsClause withClause?)? implementsClause? '{' classMembers '}' |
- /// metadata 'abstract'? 'class' mixinApplicationClass
- CompilationUnitMember parseClassDeclaration(
- CommentAndMetadata commentAndMetadata, Token abstractKeyword) {
- //
- // Parse the name and type parameters.
- //
- Token keyword = getAndAdvance();
- SimpleIdentifier name = parseSimpleIdentifier(isDeclaration: true);
- String className = name.name;
- TypeParameterList typeParameters;
- TokenType type = _currentToken.type;
- if (type == TokenType.LT) {
- typeParameters = parseTypeParameterList();
- type = _currentToken.type;
- }
- //
- // Check to see whether this might be a class type alias rather than a class
- // declaration.
- //
- if (type == TokenType.EQ) {
- return _parseClassTypeAliasAfterName(
- commentAndMetadata, abstractKeyword, keyword, name, typeParameters);
- }
- //
- // Parse the clauses. The parser accepts clauses in any order, but will
- // generate errors if they are not in the order required by the
- // specification.
- //
- ExtendsClause extendsClause;
- WithClause withClause;
- ImplementsClause implementsClause;
- bool foundClause = true;
- while (foundClause) {
- Keyword keyword = _currentToken.keyword;
- if (keyword == Keyword.EXTENDS) {
- if (extendsClause == null) {
- extendsClause = parseExtendsClause();
- if (withClause != null) {
- _reportErrorForToken(
- ParserErrorCode.WITH_BEFORE_EXTENDS, withClause.withKeyword);
- } else if (implementsClause != null) {
- _reportErrorForToken(ParserErrorCode.IMPLEMENTS_BEFORE_EXTENDS,
- implementsClause.implementsKeyword);
- }
- } else {
- _reportErrorForToken(ParserErrorCode.MULTIPLE_EXTENDS_CLAUSES,
- extendsClause.extendsKeyword);
- parseExtendsClause();
- }
- } else if (keyword == Keyword.WITH) {
- if (withClause == null) {
- withClause = parseWithClause();
- if (implementsClause != null) {
- _reportErrorForToken(ParserErrorCode.IMPLEMENTS_BEFORE_WITH,
- implementsClause.implementsKeyword);
- }
- } else {
- _reportErrorForToken(
- ParserErrorCode.MULTIPLE_WITH_CLAUSES, withClause.withKeyword);
- parseWithClause();
- // TODO(brianwilkerson) Should we merge the list of applied mixins
- // into a single list?
- }
- } else if (keyword == Keyword.IMPLEMENTS) {
- if (implementsClause == null) {
- implementsClause = parseImplementsClause();
- } else {
- _reportErrorForToken(ParserErrorCode.MULTIPLE_IMPLEMENTS_CLAUSES,
- implementsClause.implementsKeyword);
- parseImplementsClause();
- // TODO(brianwilkerson) Should we merge the list of implemented
- // classes into a single list?
- }
- } else {
- foundClause = false;
- }
- }
- //
- // Look for and skip over the extra-lingual 'native' specification.
- //
- NativeClause nativeClause;
- if (_matchesKeyword(Keyword.NATIVE) &&
- _tokenMatches(_peek(), TokenType.STRING)) {
- nativeClause = _parseNativeClause();
- }
- //
- // Parse the body of the class.
- //
- Token leftBracket;
- List<ClassMember> members;
- Token rightBracket;
- if (_matches(TokenType.OPEN_CURLY_BRACKET)) {
- leftBracket = getAndAdvance();
- members = _parseClassMembers(className, _getEndToken(leftBracket));
- rightBracket = _expect(TokenType.CLOSE_CURLY_BRACKET);
- } else {
- // Recovery: Check for an unmatched closing curly bracket and parse
- // members until it is reached.
- leftBracket = _createSyntheticToken(TokenType.OPEN_CURLY_BRACKET);
- rightBracket = _createSyntheticToken(TokenType.CLOSE_CURLY_BRACKET);
- _reportErrorForCurrentToken(ParserErrorCode.EXPECTED_BODY);
- }
- ClassDeclaration classDeclaration = astFactory.classDeclaration(
- commentAndMetadata.comment,
- commentAndMetadata.metadata,
- abstractKeyword,
- keyword,
- name,
- typeParameters,
- extendsClause,
- withClause,
- implementsClause,
- leftBracket,
- members,
- rightBracket);
- classDeclaration.nativeClause = nativeClause;
- return classDeclaration;
- }
-
- /// Parse a class member. The [className] is the name of the class containing
- /// the member being parsed. Return the class member that was parsed, or
- /// `null` if what was found was not a valid class member.
- ///
- /// classMemberDefinition ::=
- /// declaration ';'
- /// | methodSignature functionBody
- ClassMember parseClassMember(String className) {
- CommentAndMetadata commentAndMetadata = parseCommentAndMetadata();
- Modifiers modifiers = parseModifiers();
- Keyword keyword = _currentToken.keyword;
- if (keyword == Keyword.VOID ||
- _atGenericFunctionTypeAfterReturnType(_currentToken)) {
- TypeAnnotation returnType;
- if (keyword == Keyword.VOID) {
- if (_atGenericFunctionTypeAfterReturnType(_peek())) {
- returnType = parseTypeAnnotation(false);
- } else {
- returnType = astFactory.typeName(
- astFactory.simpleIdentifier(getAndAdvance()), null);
- }
- } else {
- returnType = parseTypeAnnotation(false);
- }
- keyword = _currentToken.keyword;
- Token next = _peek();
- bool isFollowedByIdentifier = _tokenMatchesIdentifier(next);
- if (keyword == Keyword.GET && isFollowedByIdentifier) {
- _validateModifiersForGetterOrSetterOrMethod(modifiers);
- return parseGetter(commentAndMetadata, modifiers.externalKeyword,
- modifiers.staticKeyword, returnType);
- } else if (keyword == Keyword.SET && isFollowedByIdentifier) {
- _validateModifiersForGetterOrSetterOrMethod(modifiers);
- return parseSetter(commentAndMetadata, modifiers.externalKeyword,
- modifiers.staticKeyword, returnType);
- } else if (keyword == Keyword.OPERATOR &&
- (_isOperator(next) || next.type == TokenType.EQ_EQ_EQ)) {
- _validateModifiersForOperator(modifiers);
- return _parseOperatorAfterKeyword(commentAndMetadata,
- modifiers.externalKeyword, returnType, getAndAdvance());
- } else if (_matchesIdentifier() &&
- _peek().matchesAny(const <TokenType>[
- TokenType.OPEN_PAREN,
- TokenType.OPEN_CURLY_BRACKET,
- TokenType.FUNCTION,
- TokenType.LT
- ])) {
- _validateModifiersForGetterOrSetterOrMethod(modifiers);
- return _parseMethodDeclarationAfterReturnType(commentAndMetadata,
- modifiers.externalKeyword, modifiers.staticKeyword, returnType);
- } else if (_matchesIdentifier() &&
- _peek().matchesAny(const <TokenType>[
- TokenType.EQ,
- TokenType.COMMA,
- TokenType.SEMICOLON
- ])) {
- return parseInitializedIdentifierList(
- commentAndMetadata,
- modifiers.staticKeyword,
- modifiers.covariantKeyword,
- _validateModifiersForField(modifiers),
- returnType);
- } else {
- //
- // We have found an error of some kind. Try to recover.
- //
- if (_isOperator(_currentToken)) {
- //
- // We appear to have found an operator declaration without the
- // 'operator' keyword.
- //
- _validateModifiersForOperator(modifiers);
- return parseOperator(
- commentAndMetadata, modifiers.externalKeyword, returnType);
- }
- _reportErrorForToken(
- ParserErrorCode.EXPECTED_EXECUTABLE, _currentToken);
- return null;
- }
- }
- Token next = _peek();
- bool isFollowedByIdentifier = _tokenMatchesIdentifier(next);
- if (keyword == Keyword.GET && isFollowedByIdentifier) {
- _validateModifiersForGetterOrSetterOrMethod(modifiers);
- return parseGetter(commentAndMetadata, modifiers.externalKeyword,
- modifiers.staticKeyword, null);
- } else if (keyword == Keyword.SET && isFollowedByIdentifier) {
- _validateModifiersForGetterOrSetterOrMethod(modifiers);
- return parseSetter(commentAndMetadata, modifiers.externalKeyword,
- modifiers.staticKeyword, null);
- } else if (keyword == Keyword.OPERATOR && _isOperator(next)) {
- _validateModifiersForOperator(modifiers);
- return _parseOperatorAfterKeyword(
- commentAndMetadata, modifiers.externalKeyword, null, getAndAdvance());
- } else if (!_matchesIdentifier()) {
- //
- // Recover from an error.
- //
- if (_matchesKeyword(Keyword.CLASS)) {
- _reportErrorForCurrentToken(ParserErrorCode.CLASS_IN_CLASS);
- // TODO(brianwilkerson) We don't currently have any way to capture the
- // class that was parsed.
- parseClassDeclaration(commentAndMetadata, null);
- return null;
- } else if (_matchesKeyword(Keyword.ABSTRACT) &&
- _tokenMatchesKeyword(_peek(), Keyword.CLASS)) {
- _reportErrorForToken(ParserErrorCode.CLASS_IN_CLASS, _peek());
- // TODO(brianwilkerson) We don't currently have any way to capture the
- // class that was parsed.
- parseClassDeclaration(commentAndMetadata, getAndAdvance());
- return null;
- } else if (_matchesKeyword(Keyword.ENUM)) {
- _reportErrorForToken(ParserErrorCode.ENUM_IN_CLASS, _peek());
- // TODO(brianwilkerson) We don't currently have any way to capture the
- // enum that was parsed.
- parseEnumDeclaration(commentAndMetadata);
- return null;
- } else if (_isOperator(_currentToken)) {
- //
- // We appear to have found an operator declaration without the
- // 'operator' keyword.
- //
- _validateModifiersForOperator(modifiers);
- return parseOperator(
- commentAndMetadata, modifiers.externalKeyword, null);
- }
- Token keyword = modifiers.varKeyword ??
- modifiers.finalKeyword ??
- modifiers.constKeyword;
- if (keyword != null) {
- //
- // We appear to have found an incomplete field declaration.
- //
- _reportErrorForCurrentToken(ParserErrorCode.MISSING_IDENTIFIER);
- VariableDeclaration variable = astFactory.variableDeclaration(
- createSyntheticIdentifier(), null, null);
- List<VariableDeclaration> variables = <VariableDeclaration>[variable];
- return astFactory.fieldDeclaration2(
- comment: commentAndMetadata.comment,
- metadata: commentAndMetadata.metadata,
- covariantKeyword: modifiers.covariantKeyword,
- fieldList: astFactory.variableDeclarationList(
- null, null, keyword, null, variables),
- semicolon: _expect(TokenType.SEMICOLON));
- }
- _reportErrorForToken(
- ParserErrorCode.EXPECTED_CLASS_MEMBER, _currentToken);
- if (commentAndMetadata.comment != null ||
- commentAndMetadata.hasMetadata) {
- //
- // We appear to have found an incomplete declaration at the end of the
- // class. At this point it consists of a metadata, which we don't want
- // to loose, so we'll treat it as a method declaration with a missing
- // name, parameters and empty body.
- //
- return astFactory.methodDeclaration(
- commentAndMetadata.comment,
- commentAndMetadata.metadata,
- null,
- null,
- null,
- null,
- null,
- createSyntheticIdentifier(isDeclaration: true),
- null,
- astFactory.formalParameterList(
- _createSyntheticToken(TokenType.OPEN_PAREN),
- <FormalParameter>[],
- null,
- null,
- _createSyntheticToken(TokenType.CLOSE_PAREN)),
- astFactory
- .emptyFunctionBody(_createSyntheticToken(TokenType.SEMICOLON)));
- }
- return null;
- } else if (_tokenMatches(next, TokenType.PERIOD) &&
- _tokenMatchesIdentifierOrKeyword(_peekAt(2)) &&
- _tokenMatches(_peekAt(3), TokenType.OPEN_PAREN)) {
- if (!_tokenMatchesIdentifier(_peekAt(2))) {
- _reportErrorForToken(ParserErrorCode.INVALID_CONSTRUCTOR_NAME,
- _peekAt(2), [_peekAt(2).lexeme]);
- }
- return _parseConstructor(
- commentAndMetadata,
- modifiers.externalKeyword,
- _validateModifiersForConstructor(modifiers),
- modifiers.factoryKeyword,
- parseSimpleIdentifier(),
- getAndAdvance(),
- parseSimpleIdentifier(allowKeyword: true, isDeclaration: true),
- parseFormalParameterList());
- } else if (_tokenMatches(next, TokenType.OPEN_PAREN)) {
- TypeName returnType;
- SimpleIdentifier methodName = parseSimpleIdentifier(isDeclaration: true);
- TypeParameterList typeParameters;
- FormalParameterList parameters = parseFormalParameterList();
- if (_matches(TokenType.COLON) ||
- modifiers.factoryKeyword != null ||
- methodName.name == className) {
- return _parseConstructor(
- commentAndMetadata,
- modifiers.externalKeyword,
- _validateModifiersForConstructor(modifiers),
- modifiers.factoryKeyword,
- astFactory.simpleIdentifier(methodName.token, isDeclaration: false),
- null,
- null,
- parameters);
- }
- _validateModifiersForGetterOrSetterOrMethod(modifiers);
- _validateFormalParameterList(parameters);
- return _parseMethodDeclarationAfterParameters(
- commentAndMetadata,
- modifiers.externalKeyword,
- modifiers.staticKeyword,
- returnType,
- methodName,
- typeParameters,
- parameters);
- } else if (next.matchesAny(const <TokenType>[
- TokenType.EQ,
- TokenType.COMMA,
- TokenType.SEMICOLON
- ])) {
- if (modifiers.constKeyword == null &&
- modifiers.finalKeyword == null &&
- modifiers.varKeyword == null) {
- _reportErrorForCurrentToken(
- ParserErrorCode.MISSING_CONST_FINAL_VAR_OR_TYPE);
- }
- return parseInitializedIdentifierList(
- commentAndMetadata,
- modifiers.staticKeyword,
- modifiers.covariantKeyword,
- _validateModifiersForField(modifiers),
- null);
- } else if (keyword == Keyword.TYPEDEF) {
- _reportErrorForCurrentToken(ParserErrorCode.TYPEDEF_IN_CLASS);
- // TODO(brianwilkerson) We don't currently have any way to capture the
- // function type alias that was parsed.
- _parseFunctionTypeAlias(commentAndMetadata, getAndAdvance());
- return null;
- } else {
- Token token = _skipTypeParameterList(_peek());
- if (token != null && _tokenMatches(token, TokenType.OPEN_PAREN)) {
- return _parseMethodDeclarationAfterReturnType(commentAndMetadata,
- modifiers.externalKeyword, modifiers.staticKeyword, null);
- }
- }
- TypeAnnotation type = _parseTypeAnnotationAfterIdentifier();
- keyword = _currentToken.keyword;
- next = _peek();
- isFollowedByIdentifier = _tokenMatchesIdentifier(next);
- if (keyword == Keyword.GET && isFollowedByIdentifier) {
- _validateModifiersForGetterOrSetterOrMethod(modifiers);
- return parseGetter(commentAndMetadata, modifiers.externalKeyword,
- modifiers.staticKeyword, type);
- } else if (keyword == Keyword.SET && isFollowedByIdentifier) {
- _validateModifiersForGetterOrSetterOrMethod(modifiers);
- return parseSetter(commentAndMetadata, modifiers.externalKeyword,
- modifiers.staticKeyword, type);
- } else if (keyword == Keyword.OPERATOR && _isOperator(next)) {
- _validateModifiersForOperator(modifiers);
- return _parseOperatorAfterKeyword(
- commentAndMetadata, modifiers.externalKeyword, type, getAndAdvance());
- } else if (!_matchesIdentifier()) {
- if (_matches(TokenType.CLOSE_CURLY_BRACKET)) {
- //
- // We appear to have found an incomplete declaration at the end of the
- // class. At this point it consists of a type name, so we'll treat it as
- // a field declaration with a missing field name and semicolon.
- //
- return parseInitializedIdentifierList(
- commentAndMetadata,
- modifiers.staticKeyword,
- modifiers.covariantKeyword,
- _validateModifiersForField(modifiers),
- type);
- }
- if (_isOperator(_currentToken)) {
- //
- // We appear to have found an operator declaration without the
- // 'operator' keyword.
- //
- _validateModifiersForOperator(modifiers);
- return parseOperator(
- commentAndMetadata, modifiers.externalKeyword, type);
- }
- //
- // We appear to have found an incomplete declaration before another
- // declaration. At this point it consists of a type name, so we'll treat
- // it as a field declaration with a missing field name and semicolon.
- //
- _reportErrorForToken(
- ParserErrorCode.EXPECTED_CLASS_MEMBER, _currentToken);
- try {
- _lockErrorListener();
- return parseInitializedIdentifierList(
- commentAndMetadata,
- modifiers.staticKeyword,
- modifiers.covariantKeyword,
- _validateModifiersForField(modifiers),
- type);
- } finally {
- _unlockErrorListener();
- }
- } else if (_tokenMatches(next, TokenType.OPEN_PAREN)) {
- SimpleIdentifier methodName =
- _parseSimpleIdentifierUnchecked(isDeclaration: true);
- TypeParameterList typeParameters;
- FormalParameterList parameters = parseFormalParameterList();
- if (methodName.name == className) {
- _reportErrorForNode(ParserErrorCode.CONSTRUCTOR_WITH_RETURN_TYPE, type);
- return _parseConstructor(
- commentAndMetadata,
- modifiers.externalKeyword,
- _validateModifiersForConstructor(modifiers),
- modifiers.factoryKeyword,
- astFactory.simpleIdentifier(methodName.token, isDeclaration: true),
- null,
- null,
- parameters);
- }
- _validateModifiersForGetterOrSetterOrMethod(modifiers);
- _validateFormalParameterList(parameters);
- return _parseMethodDeclarationAfterParameters(
- commentAndMetadata,
- modifiers.externalKeyword,
- modifiers.staticKeyword,
- type,
- methodName,
- typeParameters,
- parameters);
- } else if (_tokenMatches(next, TokenType.LT)) {
- return _parseMethodDeclarationAfterReturnType(commentAndMetadata,
- modifiers.externalKeyword, modifiers.staticKeyword, type);
- } else if (_tokenMatches(next, TokenType.OPEN_CURLY_BRACKET)) {
- // We have found "TypeName identifier {", and are guessing that this is a
- // getter without the keyword 'get'.
- _validateModifiersForGetterOrSetterOrMethod(modifiers);
- _reportErrorForCurrentToken(ParserErrorCode.MISSING_GET);
- _currentToken = _injectToken(
- SyntheticKeywordToken(Keyword.GET, _currentToken.offset));
- return parseGetter(commentAndMetadata, modifiers.externalKeyword,
- modifiers.staticKeyword, type);
- }
- return parseInitializedIdentifierList(
- commentAndMetadata,
- modifiers.staticKeyword,
- modifiers.covariantKeyword,
- _validateModifiersForField(modifiers),
- type);
- }
-
- /// Parse a single combinator. Return the combinator that was parsed, or
- /// `null` if no combinator is found.
- ///
- /// combinator ::=
- /// 'show' identifier (',' identifier)*
- /// | 'hide' identifier (',' identifier)*
- Combinator parseCombinator() {
- if (_matchesKeyword(Keyword.SHOW)) {
- return astFactory.showCombinator(getAndAdvance(), parseIdentifierList());
- } else if (_matchesKeyword(Keyword.HIDE)) {
- return astFactory.hideCombinator(getAndAdvance(), parseIdentifierList());
- }
- return null;
- }
-
- /// Parse a list of combinators in a directive. Return the combinators that
- /// were parsed, or `null` if there are no combinators.
- ///
- /// combinator ::=
- /// 'show' identifier (',' identifier)*
- /// | 'hide' identifier (',' identifier)*
- List<Combinator> parseCombinators() {
- List<Combinator> combinators;
- while (true) {
- Combinator combinator = parseCombinator();
- if (combinator == null) {
- break;
- }
- combinators ??= <Combinator>[];
- combinators.add(combinator);
- }
- return combinators;
- }
-
- /// Parse the documentation comment and metadata preceding a declaration. This
- /// method allows any number of documentation comments to occur before, after
- /// or between the metadata, but only returns the last (right-most)
- /// documentation comment that is found. Return the documentation comment and
- /// metadata that were parsed.
- ///
- /// metadata ::=
- /// annotation*
- CommentAndMetadata parseCommentAndMetadata() {
- // TODO(brianwilkerson) Consider making the creation of documentation
- // comments be lazy.
- List<DocumentationCommentToken> tokens = parseDocumentationCommentTokens();
- List<Annotation> metadata;
- while (_matches(TokenType.AT)) {
- metadata ??= <Annotation>[];
- metadata.add(parseAnnotation());
- List<DocumentationCommentToken> optionalTokens =
- parseDocumentationCommentTokens();
- if (optionalTokens != null) {
- tokens = optionalTokens;
- }
- }
- return CommentAndMetadata(parseDocumentationComment(tokens), metadata);
- }
-
- /// Parse a comment reference from the source between square brackets. The
- /// [referenceSource] is the source occurring between the square brackets
- /// within a documentation comment. The [sourceOffset] is the offset of the
- /// first character of the reference source. Return the comment reference that
- /// was parsed, or `null` if no reference could be found.
- ///
- /// commentReference ::=
- /// 'new'? prefixedIdentifier
- CommentReference parseCommentReference(
- String referenceSource, int sourceOffset) {
- // TODO(brianwilkerson) The errors are not getting the right offset/length
- // and are being duplicated.
- try {
- BooleanErrorListener listener = BooleanErrorListener();
- Scanner scanner = Scanner(
- null, SubSequenceReader(referenceSource, sourceOffset), listener)
- ..configureFeatures(
- featureSetForOverriding: _featureSet,
- featureSet: _featureSet,
- );
- scanner.setSourceStart(1, 1);
- Token firstToken = scanner.tokenize();
- if (listener.errorReported) {
- return null;
- }
- if (firstToken.type == TokenType.EOF) {
- Token syntheticToken =
- SyntheticStringToken(TokenType.IDENTIFIER, "", sourceOffset);
- syntheticToken.setNext(firstToken);
- return astFactory.commentReference(
- null, astFactory.simpleIdentifier(syntheticToken));
- }
- Token newKeyword;
- if (_tokenMatchesKeyword(firstToken, Keyword.NEW)) {
- newKeyword = firstToken;
- firstToken = firstToken.next;
- }
- if (firstToken.isUserDefinableOperator) {
- if (firstToken.next.type != TokenType.EOF) {
- return null;
- }
- Identifier identifier = astFactory.simpleIdentifier(firstToken);
- return astFactory.commentReference(null, identifier);
- } else if (_tokenMatchesKeyword(firstToken, Keyword.OPERATOR)) {
- Token secondToken = firstToken.next;
- if (secondToken.isUserDefinableOperator) {
- if (secondToken.next.type != TokenType.EOF) {
- return null;
- }
- Identifier identifier = astFactory.simpleIdentifier(secondToken);
- return astFactory.commentReference(null, identifier);
- }
- return null;
- } else if (_tokenMatchesIdentifier(firstToken)) {
- Token secondToken = firstToken.next;
- Token thirdToken = secondToken.next;
- Token nextToken;
- Identifier identifier;
- if (_tokenMatches(secondToken, TokenType.PERIOD)) {
- if (thirdToken.isUserDefinableOperator) {
- identifier = astFactory.prefixedIdentifier(
- astFactory.simpleIdentifier(firstToken),
- secondToken,
- astFactory.simpleIdentifier(thirdToken));
- nextToken = thirdToken.next;
- } else if (_tokenMatchesKeyword(thirdToken, Keyword.OPERATOR)) {
- Token fourthToken = thirdToken.next;
- if (fourthToken.isUserDefinableOperator) {
- identifier = astFactory.prefixedIdentifier(
- astFactory.simpleIdentifier(firstToken),
- secondToken,
- astFactory.simpleIdentifier(fourthToken));
- nextToken = fourthToken.next;
- } else {
- return null;
- }
- } else if (_tokenMatchesIdentifier(thirdToken)) {
- identifier = astFactory.prefixedIdentifier(
- astFactory.simpleIdentifier(firstToken),
- secondToken,
- astFactory.simpleIdentifier(thirdToken));
- nextToken = thirdToken.next;
- }
- } else {
- identifier = astFactory.simpleIdentifier(firstToken);
- nextToken = firstToken.next;
- }
- if (nextToken.type != TokenType.EOF) {
- return null;
- }
- return astFactory.commentReference(newKeyword, identifier);
- } else {
- Keyword keyword = firstToken.keyword;
- if (keyword == Keyword.THIS ||
- keyword == Keyword.NULL ||
- keyword == Keyword.TRUE ||
- keyword == Keyword.FALSE) {
- // TODO(brianwilkerson) If we want to support this we will need to
- // extend the definition of CommentReference to take an expression
- // rather than an identifier. For now we just ignore it to reduce the
- // number of errors produced, but that's probably not a valid long term
- // approach.
- return null;
- }
- }
- } catch (exception) {
- // Ignored because we assume that it wasn't a real comment reference.
- }
- return null;
- }
-
- /// Parse all of the comment references occurring in the given array of
- /// documentation comments. The [tokens] are the comment tokens representing
- /// the documentation comments to be parsed. Return the comment references
- /// that were parsed.
- ///
- /// commentReference ::=
- /// '[' 'new'? qualified ']' libraryReference?
- ///
- /// libraryReference ::=
- /// '(' stringLiteral ')'
- List<CommentReference> parseCommentReferences(
- List<DocumentationCommentToken> tokens) {
- List<CommentReference> references = <CommentReference>[];
- bool isInGitHubCodeBlock = false;
- for (DocumentationCommentToken token in tokens) {
- String comment = token.lexeme;
- // Skip GitHub code blocks.
- // https://help.github.com/articles/creating-and-highlighting-code-blocks/
- if (tokens.length != 1) {
- if (comment.contains('```')) {
- isInGitHubCodeBlock = !isInGitHubCodeBlock;
- }
- if (isInGitHubCodeBlock) {
- continue;
- }
- }
- // Remove GitHub include code.
- comment = _removeGitHubInlineCode(comment);
- // Find references.
- int length = comment.length;
- List<List<int>> codeBlockRanges = _getCodeBlockRanges(comment);
- int leftIndex = comment.indexOf('[');
- while (leftIndex >= 0 && leftIndex + 1 < length) {
- List<int> range = _findRange(codeBlockRanges, leftIndex);
- if (range == null) {
- int nameOffset = token.offset + leftIndex + 1;
- int rightIndex = comment.indexOf(']', leftIndex);
- if (rightIndex >= 0) {
- int firstChar = comment.codeUnitAt(leftIndex + 1);
- if (firstChar != 0x27 && firstChar != 0x22) {
- if (_isLinkText(comment, rightIndex)) {
- // TODO(brianwilkerson) Handle the case where there's a library
- // URI in the link text.
- } else {
- CommentReference reference = parseCommentReference(
- comment.substring(leftIndex + 1, rightIndex), nameOffset);
- if (reference != null) {
- references.add(reference);
- }
- }
- }
- } else {
- // terminating ']' is not typed yet
- int charAfterLeft = comment.codeUnitAt(leftIndex + 1);
- Token nameToken;
- if (Character.isLetterOrDigit(charAfterLeft)) {
- int nameEnd = StringUtilities.indexOfFirstNotLetterDigit(
- comment, leftIndex + 1);
- String name = comment.substring(leftIndex + 1, nameEnd);
- nameToken = StringToken(TokenType.IDENTIFIER, name, nameOffset);
- } else {
- nameToken =
- SyntheticStringToken(TokenType.IDENTIFIER, '', nameOffset);
- }
- nameToken.setNext(Token.eof(nameToken.end));
- references.add(astFactory.commentReference(
- null, astFactory.simpleIdentifier(nameToken)));
- // next character
- rightIndex = leftIndex + 1;
- }
- leftIndex = comment.indexOf('[', rightIndex);
- } else {
- leftIndex = comment.indexOf('[', range[1]);
- }
- }
- }
- return references;
- }
-
- /// Parse a compilation unit, starting with the given [token]. Return the
- /// compilation unit that was parsed.
CompilationUnit parseCompilationUnit(Token token) {
- _currentToken = token;
+ currentToken = token;
return parseCompilationUnit2();
}
- /// Parse a compilation unit. Return the compilation unit that was parsed.
- ///
- /// Specified:
- ///
- /// compilationUnit ::=
- /// scriptTag? directive* topLevelDeclaration*
- ///
- /// Actual:
- ///
- /// compilationUnit ::=
- /// scriptTag? topLevelElement*
- ///
- /// topLevelElement ::=
- /// directive
- /// | topLevelDeclaration
CompilationUnit parseCompilationUnit2() {
- Token firstToken = _currentToken;
- ScriptTag scriptTag;
- if (_matches(TokenType.SCRIPT_TAG)) {
- scriptTag = astFactory.scriptTag(getAndAdvance());
- }
- //
- // Even though all directives must appear before declarations and must occur
- // in a given order, we allow directives and declarations to occur in any
- // order so that we can recover better.
- //
- bool libraryDirectiveFound = false;
- bool partOfDirectiveFound = false;
- bool partDirectiveFound = false;
- bool directiveFoundAfterDeclaration = false;
- List<Directive> directives = <Directive>[];
- List<CompilationUnitMember> declarations = <CompilationUnitMember>[];
- Token memberStart = _currentToken;
- TokenType type = _currentToken.type;
- while (type != TokenType.EOF) {
- CommentAndMetadata commentAndMetadata = parseCommentAndMetadata();
- Keyword keyword = _currentToken.keyword;
- TokenType nextType = _currentToken.next.type;
- if ((keyword == Keyword.IMPORT ||
- keyword == Keyword.EXPORT ||
- keyword == Keyword.LIBRARY ||
- keyword == Keyword.PART) &&
- nextType != TokenType.PERIOD &&
- nextType != TokenType.LT &&
- nextType != TokenType.OPEN_PAREN) {
- Directive parseDirective() {
- if (keyword == Keyword.IMPORT) {
- if (partDirectiveFound) {
- _reportErrorForCurrentToken(
- ParserErrorCode.IMPORT_DIRECTIVE_AFTER_PART_DIRECTIVE);
- }
- return parseImportDirective(commentAndMetadata);
- } else if (keyword == Keyword.EXPORT) {
- if (partDirectiveFound) {
- _reportErrorForCurrentToken(
- ParserErrorCode.EXPORT_DIRECTIVE_AFTER_PART_DIRECTIVE);
- }
- return parseExportDirective(commentAndMetadata);
- } else if (keyword == Keyword.LIBRARY) {
- if (libraryDirectiveFound) {
- _reportErrorForCurrentToken(
- ParserErrorCode.MULTIPLE_LIBRARY_DIRECTIVES);
- } else {
- if (directives.isNotEmpty) {
- _reportErrorForCurrentToken(
- ParserErrorCode.LIBRARY_DIRECTIVE_NOT_FIRST);
- }
- libraryDirectiveFound = true;
- }
- return parseLibraryDirective(commentAndMetadata);
- } else if (keyword == Keyword.PART) {
- if (_tokenMatchesKeyword(_peek(), Keyword.OF)) {
- partOfDirectiveFound = true;
- return _parsePartOfDirective(commentAndMetadata);
- } else {
- partDirectiveFound = true;
- return _parsePartDirective(commentAndMetadata);
- }
- } else {
- // Internal error: this method should not have been invoked if the
- // current token was something other than one of the above.
- throw StateError(
- "parseDirective invoked in an invalid state (currentToken = $_currentToken)");
- }
- }
-
- Directive directive = parseDirective();
- if (declarations.isNotEmpty && !directiveFoundAfterDeclaration) {
- _reportErrorForToken(ParserErrorCode.DIRECTIVE_AFTER_DECLARATION,
- directive.beginToken);
- directiveFoundAfterDeclaration = true;
- }
- directives.add(directive);
- } else if (type == TokenType.SEMICOLON) {
- // TODO(brianwilkerson) Consider moving this error detection into
- // _parseCompilationUnitMember (in the places where EXPECTED_EXECUTABLE
- // is being generated).
- _reportErrorForToken(ParserErrorCode.UNEXPECTED_TOKEN, _currentToken,
- [_currentToken.lexeme]);
- _advance();
- } else {
- CompilationUnitMember member;
- try {
- member = parseCompilationUnitMember(commentAndMetadata);
- } on _TooDeepTreeError {
- _reportErrorForToken(ParserErrorCode.STACK_OVERFLOW, _currentToken);
- Token eof = Token.eof(0);
- return astFactory.compilationUnit(
- beginToken: eof,
- endToken: eof,
- featureSet: _featureSet,
- );
- }
- if (member != null) {
- declarations.add(member);
- }
- }
- if (identical(_currentToken, memberStart)) {
- _reportErrorForToken(ParserErrorCode.UNEXPECTED_TOKEN, _currentToken,
- [_currentToken.lexeme]);
- _advance();
- while (!_matches(TokenType.EOF) &&
- !_couldBeStartOfCompilationUnitMember()) {
- _advance();
- }
- }
- memberStart = _currentToken;
- type = _currentToken.type;
- }
- if (partOfDirectiveFound && directives.length > 1) {
- // TODO(brianwilkerson) Improve error reporting when both a library and
- // part-of directive are found.
-// if (libraryDirectiveFound) {
-// int directiveCount = directives.length;
-// for (int i = 0; i < directiveCount; i++) {
-// Directive directive = directives[i];
-// if (directive is PartOfDirective) {
-// _reportErrorForToken(
-// ParserErrorCode.PART_OF_IN_LIBRARY, directive.partKeyword);
-// }
-// }
-// } else {
- bool firstPartOf = true;
- int directiveCount = directives.length;
- for (int i = 0; i < directiveCount; i++) {
- Directive directive = directives[i];
- if (directive is PartOfDirective) {
- if (firstPartOf) {
- firstPartOf = false;
- } else {
- _reportErrorForToken(ParserErrorCode.MULTIPLE_PART_OF_DIRECTIVES,
- directive.partKeyword);
- }
- } else {
- _reportErrorForToken(ParserErrorCode.NON_PART_OF_DIRECTIVE_IN_PART,
- directives[i].keyword);
- }
-// }
- }
- }
- return astFactory.compilationUnit(
- beginToken: firstToken,
- scriptTag: scriptTag,
- directives: directives,
- declarations: declarations,
- endToken: _currentToken,
- featureSet: _featureSet,
- );
+ currentToken = fastaParser.parseUnit(currentToken);
+ return astBuilder.pop() as CompilationUnit;
}
- /// Parse a compilation unit member. The [commentAndMetadata] is the metadata
- /// to be associated with the member. Return the compilation unit member that
- /// was parsed, or `null` if what was parsed could not be represented as a
- /// compilation unit member.
- ///
- /// compilationUnitMember ::=
- /// classDefinition
- /// | functionTypeAlias
- /// | external functionSignature
- /// | external getterSignature
- /// | external setterSignature
- /// | functionSignature functionBody
- /// | returnType? getOrSet identifier formalParameterList functionBody
- /// | (final | const) type? staticFinalDeclarationList ';'
- /// | variableDeclaration ';'
- CompilationUnitMember parseCompilationUnitMember(
- CommentAndMetadata commentAndMetadata) {
- Modifiers modifiers = parseModifiers();
- Keyword keyword = _currentToken.keyword;
- if (keyword == Keyword.CLASS) {
- return parseClassDeclaration(
- commentAndMetadata, _validateModifiersForClass(modifiers));
- }
- Token next = _peek();
- TokenType nextType = next.type;
- if (keyword == Keyword.TYPEDEF &&
- nextType != TokenType.PERIOD &&
- nextType != TokenType.LT &&
- nextType != TokenType.OPEN_PAREN) {
- _validateModifiersForTypedef(modifiers);
- return parseTypeAlias(commentAndMetadata);
- } else if (keyword == Keyword.ENUM) {
- _validateModifiersForEnum(modifiers);
- return parseEnumDeclaration(commentAndMetadata);
- } else if (keyword == Keyword.VOID ||
- _atGenericFunctionTypeAfterReturnType(_currentToken)) {
- TypeAnnotation returnType;
- if (keyword == Keyword.VOID) {
- if (_atGenericFunctionTypeAfterReturnType(next)) {
- returnType = parseTypeAnnotation(false);
- } else {
- returnType = astFactory.typeName(
- astFactory.simpleIdentifier(getAndAdvance()), null);
- }
- } else {
- returnType = parseTypeAnnotation(false);
- }
- keyword = _currentToken.keyword;
- next = _peek();
- if ((keyword == Keyword.GET || keyword == Keyword.SET) &&
- _tokenMatchesIdentifier(next)) {
- _validateModifiersForTopLevelFunction(modifiers);
- return parseFunctionDeclaration(
- commentAndMetadata, modifiers.externalKeyword, returnType);
- } else if (keyword == Keyword.OPERATOR && _isOperator(next)) {
- _reportErrorForToken(ParserErrorCode.TOP_LEVEL_OPERATOR, _currentToken);
- return _convertToFunctionDeclaration(_parseOperatorAfterKeyword(
- commentAndMetadata,
- modifiers.externalKeyword,
- returnType,
- getAndAdvance()));
- } else if (_matchesIdentifier() &&
- next.matchesAny(const <TokenType>[
- TokenType.OPEN_PAREN,
- TokenType.OPEN_CURLY_BRACKET,
- TokenType.FUNCTION,
- TokenType.LT
- ])) {
- _validateModifiersForTopLevelFunction(modifiers);
- return parseFunctionDeclaration(
- commentAndMetadata, modifiers.externalKeyword, returnType);
- } else if (_matchesIdentifier() &&
- next.matchesAny(const <TokenType>[
- TokenType.EQ,
- TokenType.COMMA,
- TokenType.SEMICOLON
- ])) {
- return astFactory.topLevelVariableDeclaration(
- commentAndMetadata.comment,
- commentAndMetadata.metadata,
- parseVariableDeclarationListAfterType(null,
- _validateModifiersForTopLevelVariable(modifiers), returnType),
- _expect(TokenType.SEMICOLON));
- } else {
- //
- // We have found an error of some kind. Try to recover.
- //
- _reportErrorForToken(
- ParserErrorCode.EXPECTED_EXECUTABLE, _currentToken);
- return null;
- }
- } else if ((keyword == Keyword.GET || keyword == Keyword.SET) &&
- _tokenMatchesIdentifier(next)) {
- _validateModifiersForTopLevelFunction(modifiers);
- return parseFunctionDeclaration(
- commentAndMetadata, modifiers.externalKeyword, null);
- } else if (keyword == Keyword.OPERATOR && _isOperator(next)) {
- _reportErrorForToken(ParserErrorCode.TOP_LEVEL_OPERATOR, _currentToken);
- return _convertToFunctionDeclaration(_parseOperatorAfterKeyword(
- commentAndMetadata,
- modifiers.externalKeyword,
- null,
- getAndAdvance()));
- } else if (!_matchesIdentifier()) {
- Token keyword = modifiers.varKeyword;
- keyword ??= modifiers.finalKeyword;
- keyword ??= modifiers.constKeyword;
- if (keyword != null) {
- //
- // We appear to have found an incomplete top-level variable declaration.
- //
- _reportErrorForCurrentToken(ParserErrorCode.MISSING_IDENTIFIER);
- VariableDeclaration variable = astFactory.variableDeclaration(
- createSyntheticIdentifier(), null, null);
- List<VariableDeclaration> variables = <VariableDeclaration>[variable];
- return astFactory.topLevelVariableDeclaration(
- commentAndMetadata.comment,
- commentAndMetadata.metadata,
- astFactory.variableDeclarationList(
- null, null, keyword, null, variables),
- _expect(TokenType.SEMICOLON));
- }
- _reportErrorForToken(ParserErrorCode.EXPECTED_EXECUTABLE, _currentToken);
- return null;
- } else if (_isPeekGenericTypeParametersAndOpenParen()) {
- return parseFunctionDeclaration(
- commentAndMetadata, modifiers.externalKeyword, null);
- } else if (_tokenMatches(next, TokenType.OPEN_PAREN)) {
- TypeName returnType;
- _validateModifiersForTopLevelFunction(modifiers);
- return parseFunctionDeclaration(
- commentAndMetadata, modifiers.externalKeyword, returnType);
- } else if (next.matchesAny(const <TokenType>[
- TokenType.EQ,
- TokenType.COMMA,
- TokenType.SEMICOLON
- ])) {
- if (modifiers.constKeyword == null &&
- modifiers.finalKeyword == null &&
- modifiers.varKeyword == null) {
- _reportErrorForCurrentToken(
- ParserErrorCode.MISSING_CONST_FINAL_VAR_OR_TYPE);
- }
- return astFactory.topLevelVariableDeclaration(
- commentAndMetadata.comment,
- commentAndMetadata.metadata,
- parseVariableDeclarationListAfterType(
- null, _validateModifiersForTopLevelVariable(modifiers), null),
- _expect(TokenType.SEMICOLON));
- }
- TypeAnnotation returnType = parseTypeAnnotation(false);
- keyword = _currentToken.keyword;
- next = _peek();
- if ((keyword == Keyword.GET || keyword == Keyword.SET) &&
- _tokenMatchesIdentifier(next)) {
- _validateModifiersForTopLevelFunction(modifiers);
- return parseFunctionDeclaration(
- commentAndMetadata, modifiers.externalKeyword, returnType);
- } else if (keyword == Keyword.OPERATOR && _isOperator(next)) {
- _reportErrorForToken(ParserErrorCode.TOP_LEVEL_OPERATOR, _currentToken);
- return _convertToFunctionDeclaration(_parseOperatorAfterKeyword(
- commentAndMetadata,
- modifiers.externalKeyword,
- returnType,
- getAndAdvance()));
- } else if (_matches(TokenType.AT)) {
- return astFactory.topLevelVariableDeclaration(
- commentAndMetadata.comment,
- commentAndMetadata.metadata,
- parseVariableDeclarationListAfterType(null,
- _validateModifiersForTopLevelVariable(modifiers), returnType),
- _expect(TokenType.SEMICOLON));
- } else if (!_matchesIdentifier()) {
- // TODO(brianwilkerson) Generalize this error. We could also be parsing a
- // top-level variable at this point.
- _reportErrorForToken(ParserErrorCode.EXPECTED_EXECUTABLE, _currentToken);
- Token semicolon;
- if (_matches(TokenType.SEMICOLON)) {
- semicolon = getAndAdvance();
- } else {
- semicolon = _createSyntheticToken(TokenType.SEMICOLON);
- }
- VariableDeclaration variable = astFactory.variableDeclaration(
- createSyntheticIdentifier(), null, null);
- List<VariableDeclaration> variables = <VariableDeclaration>[variable];
- return astFactory.topLevelVariableDeclaration(
- commentAndMetadata.comment,
- commentAndMetadata.metadata,
- astFactory.variableDeclarationList(
- null, null, null, returnType, variables),
- semicolon);
- } else if (next.matchesAny(const <TokenType>[
- TokenType.OPEN_PAREN,
- TokenType.FUNCTION,
- TokenType.OPEN_CURLY_BRACKET,
- TokenType.LT
- ])) {
- _validateModifiersForTopLevelFunction(modifiers);
- return parseFunctionDeclaration(
- commentAndMetadata, modifiers.externalKeyword, returnType);
- }
- return astFactory.topLevelVariableDeclaration(
- commentAndMetadata.comment,
- commentAndMetadata.metadata,
- parseVariableDeclarationListAfterType(
- null, _validateModifiersForTopLevelVariable(modifiers), returnType),
- _expect(TokenType.SEMICOLON));
- }
+ Expression parseConditionalExpression() => parseExpression2();
- /// Parse a conditional expression. Return the conditional expression that was
- /// parsed.
- ///
- /// conditionalExpression ::=
- /// ifNullExpression ('?' expressionWithoutCascade ':' expressionWithoutCascade)?
- Expression parseConditionalExpression() {
- Expression condition = parseIfNullExpression();
- if (_currentToken.type != TokenType.QUESTION) {
- return condition;
- }
- Token question = getAndAdvance();
- Expression thenExpression = parseExpressionWithoutCascade();
- Token colon = _expect(TokenType.COLON);
- Expression elseExpression = parseExpressionWithoutCascade();
- return astFactory.conditionalExpression(
- condition, question, thenExpression, colon, elseExpression);
- }
-
- /// Parse a configuration in either an import or export directive.
- ///
- /// This method assumes that the current token matches `Keyword.IF`.
- ///
- /// configuration ::=
- /// 'if' '(' test ')' uri
- ///
- /// test ::=
- /// dottedName ('==' stringLiteral)?
- ///
- /// dottedName ::=
- /// identifier ('.' identifier)*
Configuration parseConfiguration() {
- Token ifKeyword = getAndAdvance();
- Token leftParenthesis = _expect(TokenType.OPEN_PAREN);
- DottedName name = parseDottedName();
- Token equalToken;
- StringLiteral value;
- if (_matches(TokenType.EQ_EQ)) {
- equalToken = getAndAdvance();
- value = parseStringLiteral();
- if (value is StringInterpolation) {
- _reportErrorForNode(
- ParserErrorCode.INVALID_LITERAL_IN_CONFIGURATION, value);
- }
- }
- Token rightParenthesis = _expect(TokenType.CLOSE_PAREN);
- StringLiteral libraryUri = _parseUri();
- return astFactory.configuration(ifKeyword, leftParenthesis, name,
- equalToken, value, rightParenthesis, libraryUri);
+ currentToken = fastaParser
+ .parseConditionalUri(fastaParser.syntheticPreviousToken(currentToken))
+ .next;
+ return astBuilder.pop() as Configuration;
}
- /// Parse a const expression. Return the const expression that was parsed.
- ///
- /// This method assumes that the current token matches `Keyword.CONST`.
- ///
- /// constExpression ::=
- /// instanceCreationExpression
- /// | listLiteral
- /// | mapLiteral
- Expression parseConstExpression() {
- Token keyword = getAndAdvance();
- TokenType type = _currentToken.type;
- if (type == TokenType.LT) {
- return parseListOrMapLiteral(keyword);
- } else if (type == TokenType.OPEN_SQUARE_BRACKET ||
- type == TokenType.INDEX) {
- return parseListLiteral(keyword, null);
- } else if (type == TokenType.OPEN_CURLY_BRACKET) {
- return parseMapLiteral(keyword, null);
- }
- return parseInstanceCreationExpression(keyword);
- }
+ Expression parseConstExpression() => parseExpression2();
- /// Parse a field initializer within a constructor. The flag [hasThis] should
- /// be true if the current token is `this`. Return the field initializer that
- /// was parsed.
- ///
- /// fieldInitializer:
- /// ('this' '.')? identifier '=' conditionalExpression cascadeSection*
- ConstructorFieldInitializer parseConstructorFieldInitializer(bool hasThis) {
- Token keywordToken;
- Token period;
- if (hasThis) {
- keywordToken = getAndAdvance();
- period = _expect(TokenType.PERIOD);
- }
- SimpleIdentifier fieldName = parseSimpleIdentifier();
- Token equals;
- TokenType type = _currentToken.type;
- if (type == TokenType.EQ) {
- equals = getAndAdvance();
- } else {
- _reportErrorForCurrentToken(
- ParserErrorCode.MISSING_ASSIGNMENT_IN_INITIALIZER);
- Keyword keyword = _currentToken.keyword;
- if (keyword != Keyword.THIS &&
- keyword != Keyword.SUPER &&
- type != TokenType.OPEN_CURLY_BRACKET &&
- type != TokenType.FUNCTION) {
- equals = _createSyntheticToken(TokenType.EQ);
- } else {
- return astFactory.constructorFieldInitializer(
- keywordToken,
- period,
- fieldName,
- _createSyntheticToken(TokenType.EQ),
- createSyntheticIdentifier());
- }
- }
- bool wasInInitializer = _inInitializer;
- _inInitializer = true;
- try {
- Expression expression = parseConditionalExpression();
- if (_matches(TokenType.PERIOD_PERIOD)) {
- List<Expression> cascadeSections = <Expression>[];
- do {
- Expression section = parseCascadeSection();
- if (section != null) {
- cascadeSections.add(section);
- }
- } while (_matches(TokenType.PERIOD_PERIOD));
- expression = astFactory.cascadeExpression(expression, cascadeSections);
- }
- return astFactory.constructorFieldInitializer(
- keywordToken, period, fieldName, equals, expression);
- } finally {
- _inInitializer = wasInInitializer;
- }
- }
-
- /// Parse the name of a constructor. Return the constructor name that was
- /// parsed.
- ///
- /// constructorName:
- /// type ('.' identifier)?
- ConstructorName parseConstructorName() {
- TypeName type = parseTypeName(false);
- Token period;
- SimpleIdentifier name;
- if (_matches(TokenType.PERIOD)) {
- period = getAndAdvance();
- name = parseSimpleIdentifier();
- }
- return astFactory.constructorName(type, period, name);
- }
-
- /// Parse a continue statement. Return the continue statement that was parsed.
- ///
- /// This method assumes that the current token matches `Keyword.CONTINUE`.
- ///
- /// continueStatement ::=
- /// 'continue' identifier? ';'
- Statement parseContinueStatement() {
- Token continueKeyword = getAndAdvance();
- if (!_inLoop && !_inSwitch) {
- _reportErrorForToken(
- ParserErrorCode.CONTINUE_OUTSIDE_OF_LOOP, continueKeyword);
- }
- SimpleIdentifier label;
- if (_matchesIdentifier()) {
- label = _parseSimpleIdentifierUnchecked();
- }
- if (_inSwitch && !_inLoop && label == null) {
- _reportErrorForToken(
- ParserErrorCode.CONTINUE_WITHOUT_LABEL_IN_CASE, continueKeyword);
- }
- Token semicolon = _expect(TokenType.SEMICOLON);
- return astFactory.continueStatement(continueKeyword, label, semicolon);
- }
-
- /// Parse a directive. The [commentAndMetadata] is the metadata to be
- /// associated with the directive. Return the directive that was parsed.
- ///
- /// directive ::=
- /// exportDirective
- /// | libraryDirective
- /// | importDirective
- /// | partDirective
- Directive parseDirective(CommentAndMetadata commentAndMetadata) {
- if (_matchesKeyword(Keyword.IMPORT)) {
- return parseImportDirective(commentAndMetadata);
- } else if (_matchesKeyword(Keyword.EXPORT)) {
- return parseExportDirective(commentAndMetadata);
- } else if (_matchesKeyword(Keyword.LIBRARY)) {
- return parseLibraryDirective(commentAndMetadata);
- } else if (_matchesKeyword(Keyword.PART)) {
- return parsePartOrPartOfDirective(commentAndMetadata);
- } else {
- // Internal error: this method should not have been invoked if the current
- // token was something other than one of the above.
- throw StateError(
- "parseDirective invoked in an invalid state; currentToken = $_currentToken");
- }
- }
-
- /// Parse the script tag and directives in a compilation unit, starting with
- /// the given [token], until the first non-directive is encountered. The
- /// remainder of the compilation unit will not be parsed. Specifically, if
- /// there are directives later in the file, they will not be parsed. Return
- /// the compilation unit that was parsed.
CompilationUnit parseDirectives(Token token) {
- _currentToken = token;
+ currentToken = token;
return parseDirectives2();
}
- /// Parse the script tag and directives in a compilation unit until the first
- /// non-directive is encountered. Return the compilation unit that was parsed.
- ///
- /// compilationUnit ::=
- /// scriptTag? directive*
CompilationUnit parseDirectives2() {
- Token firstToken = _currentToken;
- ScriptTag scriptTag;
- if (_matches(TokenType.SCRIPT_TAG)) {
- scriptTag = astFactory.scriptTag(getAndAdvance());
- }
- List<Directive> directives = <Directive>[];
- while (!_matches(TokenType.EOF)) {
- CommentAndMetadata commentAndMetadata = parseCommentAndMetadata();
- Keyword keyword = _currentToken.keyword;
- TokenType type = _peek().type;
- if ((keyword == Keyword.IMPORT ||
- keyword == Keyword.EXPORT ||
- keyword == Keyword.LIBRARY ||
- keyword == Keyword.PART) &&
- type != TokenType.PERIOD &&
- type != TokenType.LT &&
- type != TokenType.OPEN_PAREN) {
- directives.add(parseDirective(commentAndMetadata));
- } else if (_matches(TokenType.SEMICOLON)) {
- _advance();
- } else {
- while (!_matches(TokenType.EOF)) {
- _advance();
- }
- return astFactory.compilationUnit(
- beginToken: firstToken,
- scriptTag: scriptTag,
- directives: directives,
- endToken: _currentToken,
- featureSet: _featureSet,
- );
- }
- }
- return astFactory.compilationUnit(
- beginToken: firstToken,
- scriptTag: scriptTag,
- directives: directives,
- endToken: _currentToken,
- featureSet: _featureSet,
- );
+ currentToken = fastaParser.parseDirectives(currentToken);
+ return astBuilder.pop() as CompilationUnit;
}
- /// Parse a documentation comment based on the given list of documentation
- /// comment tokens. Return the documentation comment that was parsed, or
- /// `null` if there was no comment.
- ///
- /// documentationComment ::=
- /// multiLineComment?
- /// | singleLineComment*
- Comment parseDocumentationComment(List<DocumentationCommentToken> tokens) {
- if (tokens == null) {
- return null;
- }
- List<CommentReference> references = parseCommentReferences(tokens);
- return astFactory.documentationComment(tokens, references);
- }
-
- /// Parse a documentation comment. Return the documentation comment that was
- /// parsed, or `null` if there was no comment.
- ///
- /// documentationComment ::=
- /// multiLineComment?
- /// | singleLineComment*
- List<DocumentationCommentToken> parseDocumentationCommentTokens() {
- List<DocumentationCommentToken> tokens = <DocumentationCommentToken>[];
- CommentToken commentToken = _currentToken.precedingComments;
- while (commentToken != null) {
- if (commentToken is DocumentationCommentToken) {
- if (tokens.isNotEmpty) {
- if (commentToken.type == TokenType.SINGLE_LINE_COMMENT) {
- if (tokens[0].type != TokenType.SINGLE_LINE_COMMENT) {
- tokens.clear();
- }
- } else {
- tokens.clear();
- }
- }
- tokens.add(commentToken);
- }
- commentToken = commentToken.next;
- }
- return tokens.isEmpty ? null : tokens;
- }
-
- /// Parse a do statement. Return the do statement that was parsed.
- ///
- /// This method assumes that the current token matches `Keyword.DO`.
- ///
- /// doStatement ::=
- /// 'do' statement 'while' '(' expression ')' ';'
- Statement parseDoStatement() {
- bool wasInLoop = _inLoop;
- _inLoop = true;
- try {
- Token doKeyword = getAndAdvance();
- Statement body = parseStatement2();
- Token whileKeyword = _expectKeyword(Keyword.WHILE);
- Token leftParenthesis = _expect(TokenType.OPEN_PAREN);
- Expression condition = parseExpression2();
- Token rightParenthesis = _expect(TokenType.CLOSE_PAREN);
- Token semicolon = _expect(TokenType.SEMICOLON);
- return astFactory.doStatement(doKeyword, body, whileKeyword,
- leftParenthesis, condition, rightParenthesis, semicolon);
- } finally {
- _inLoop = wasInLoop;
- }
- }
-
- /// Parse a dotted name. Return the dotted name that was parsed.
- ///
- /// dottedName ::=
- /// identifier ('.' identifier)*
DottedName parseDottedName() {
- List<SimpleIdentifier> components = <SimpleIdentifier>[
- parseSimpleIdentifier()
- ];
- while (_optional(TokenType.PERIOD)) {
- components.add(parseSimpleIdentifier());
- }
- return astFactory.dottedName(components);
+ currentToken = fastaParser
+ .parseDottedName(fastaParser.syntheticPreviousToken(currentToken))
+ .next;
+ return astBuilder.pop() as DottedName;
}
- /// Parse an empty statement. Return the empty statement that was parsed.
- ///
- /// This method assumes that the current token matches `TokenType.SEMICOLON`.
- ///
- /// emptyStatement ::=
- /// ';'
- Statement parseEmptyStatement() => astFactory.emptyStatement(getAndAdvance());
+ Expression parseEqualityExpression() => parseExpression2();
- /// Parse an enum declaration. The [commentAndMetadata] is the metadata to be
- /// associated with the member. Return the enum declaration that was parsed.
- ///
- /// This method assumes that the current token matches `Keyword.ENUM`.
- ///
- /// enumType ::=
- /// metadata 'enum' id '{' id (',' id)* (',')? '}'
- EnumDeclaration parseEnumDeclaration(CommentAndMetadata commentAndMetadata) {
- Token keyword = getAndAdvance();
- SimpleIdentifier name = parseSimpleIdentifier(isDeclaration: true);
- Token leftBracket;
- List<EnumConstantDeclaration> constants = <EnumConstantDeclaration>[];
- Token rightBracket;
- if (_matches(TokenType.OPEN_CURLY_BRACKET)) {
- leftBracket = getAndAdvance();
- if (_matchesIdentifier() || _matches(TokenType.AT)) {
- constants.add(_parseEnumConstantDeclaration());
- } else if (_matches(TokenType.COMMA) &&
- _tokenMatchesIdentifier(_peek())) {
- constants.add(_parseEnumConstantDeclaration());
- _reportErrorForCurrentToken(ParserErrorCode.MISSING_IDENTIFIER);
- } else {
- constants.add(_parseEnumConstantDeclaration());
- _reportErrorForCurrentToken(ParserErrorCode.EMPTY_ENUM_BODY);
- }
- while (_optional(TokenType.COMMA)) {
- if (_matches(TokenType.CLOSE_CURLY_BRACKET)) {
- break;
- }
- constants.add(_parseEnumConstantDeclaration());
- }
- rightBracket = _expect(TokenType.CLOSE_CURLY_BRACKET);
- } else {
- leftBracket = _createSyntheticToken(TokenType.OPEN_CURLY_BRACKET);
- rightBracket = _createSyntheticToken(TokenType.CLOSE_CURLY_BRACKET);
- _reportErrorForCurrentToken(ParserErrorCode.MISSING_ENUM_BODY);
- }
- return astFactory.enumDeclaration(
- commentAndMetadata.comment,
- commentAndMetadata.metadata,
- keyword,
- name,
- leftBracket,
- constants,
- rightBracket);
- }
-
- /// Parse an equality expression. Return the equality expression that was
- /// parsed.
- ///
- /// equalityExpression ::=
- /// relationalExpression (equalityOperator relationalExpression)?
- /// | 'super' equalityOperator relationalExpression
- Expression parseEqualityExpression() {
- Expression expression;
- if (_currentToken.keyword == Keyword.SUPER &&
- _currentToken.next.type.isEqualityOperator) {
- expression = astFactory.superExpression(getAndAdvance());
- } else {
- expression = parseRelationalExpression();
- }
- bool leftEqualityExpression = false;
- while (_currentToken.type.isEqualityOperator) {
- if (leftEqualityExpression) {
- _reportErrorForNode(
- ParserErrorCode.EQUALITY_CANNOT_BE_EQUALITY_OPERAND, expression);
- }
- expression = astFactory.binaryExpression(
- expression, getAndAdvance(), parseRelationalExpression());
- leftEqualityExpression = true;
- }
- return expression;
- }
-
- /// Parse an export directive. The [commentAndMetadata] is the metadata to be
- /// associated with the directive. Return the export directive that was
- /// parsed.
- ///
- /// This method assumes that the current token matches `Keyword.EXPORT`.
- ///
- /// exportDirective ::=
- /// metadata 'export' stringLiteral configuration* combinator*';'
- ExportDirective parseExportDirective(CommentAndMetadata commentAndMetadata) {
- Token exportKeyword = getAndAdvance();
- StringLiteral libraryUri = _parseUri();
- List<Configuration> configurations = _parseConfigurations();
- List<Combinator> combinators = parseCombinators();
- Token semicolon = _expect(TokenType.SEMICOLON);
- return astFactory.exportDirective(
- commentAndMetadata.comment,
- commentAndMetadata.metadata,
- exportKeyword,
- libraryUri,
- configurations,
- combinators,
- semicolon);
- }
-
- /// Parse an expression, starting with the given [token]. Return the
- /// expression that was parsed, or `null` if the tokens do not represent a
- /// recognizable expression.
Expression parseExpression(Token token) {
- _currentToken = token;
+ currentToken = token;
return parseExpression2();
}
- /// Parse an expression that might contain a cascade. Return the expression
- /// that was parsed.
- ///
- /// expression ::=
- /// assignableExpression assignmentOperator expression
- /// | conditionalExpression cascadeSection*
- /// | throwExpression
Expression parseExpression2() {
- if (_treeDepth > _MAX_TREE_DEPTH) {
- throw _TooDeepTreeError();
- }
- _treeDepth++;
- try {
- Keyword keyword = _currentToken.keyword;
- if (keyword == Keyword.THROW) {
- return parseThrowExpression();
- } else if (keyword == Keyword.RETHROW) {
- // TODO(brianwilkerson) Rethrow is a statement again.
- return parseRethrowExpression();
- }
- //
- // assignableExpression is a subset of conditionalExpression, so we can
- // parse a conditional expression and then determine whether it is followed
- // by an assignmentOperator, checking for conformance to the restricted
- // grammar after making that determination.
- //
- Expression expression = parseConditionalExpression();
- TokenType type = _currentToken.type;
- if (type == TokenType.PERIOD_PERIOD) {
- List<Expression> cascadeSections = <Expression>[];
- do {
- Expression section = parseCascadeSection();
- if (section != null) {
- cascadeSections.add(section);
- }
- } while (_currentToken.type == TokenType.PERIOD_PERIOD);
- return astFactory.cascadeExpression(expression, cascadeSections);
- } else if (type.isAssignmentOperator) {
- Token operator = getAndAdvance();
- _ensureAssignable(expression);
- return astFactory.assignmentExpression(
- expression, operator, parseExpression2());
- }
- return expression;
- } finally {
- _treeDepth--;
- }
+ currentToken = fastaParser
+ .parseExpression(fastaParser.syntheticPreviousToken(currentToken))
+ .next;
+ return astBuilder.pop() as Expression;
}
- /// Parse a list of expressions. Return the expression that was parsed.
- ///
- /// expressionList ::=
- /// expression (',' expression)*
- List<Expression> parseExpressionList() {
- List<Expression> expressions = <Expression>[parseExpression2()];
- while (_optional(TokenType.COMMA)) {
- expressions.add(parseExpression2());
- }
- return expressions;
- }
+ Expression parseExpressionWithoutCascade() => parseExpression2();
- /// Parse an expression that does not contain any cascades. Return the
- /// expression that was parsed.
- ///
- /// expressionWithoutCascade ::=
- /// assignableExpression assignmentOperator expressionWithoutCascade
- /// | conditionalExpression
- /// | throwExpressionWithoutCascade
- Expression parseExpressionWithoutCascade() {
- if (_matchesKeyword(Keyword.THROW)) {
- return parseThrowExpressionWithoutCascade();
- } else if (_matchesKeyword(Keyword.RETHROW)) {
- return parseRethrowExpression();
- }
- //
- // assignableExpression is a subset of conditionalExpression, so we can
- // parse a conditional expression and then determine whether it is followed
- // by an assignmentOperator, checking for conformance to the restricted
- // grammar after making that determination.
- //
- Expression expression = parseConditionalExpression();
- if (_currentToken.type.isAssignmentOperator) {
- Token operator = getAndAdvance();
- _ensureAssignable(expression);
- expression = astFactory.assignmentExpression(
- expression, operator, parseExpressionWithoutCascade());
- }
- return expression;
- }
-
- /// Parse a class extends clause. Return the class extends clause that was
- /// parsed.
- ///
- /// This method assumes that the current token matches `Keyword.EXTENDS`.
- ///
- /// classExtendsClause ::=
- /// 'extends' type
- ExtendsClause parseExtendsClause() {
- Token keyword = getAndAdvance();
- TypeName superclass = parseTypeName(false);
- return astFactory.extendsClause(keyword, superclass);
- }
-
- /// Parse the 'final', 'const', 'var' or type preceding a variable
- /// declaration. The [optional] is `true` if the keyword and type are
- /// optional. Return the 'final', 'const', 'var' or type that was parsed.
- ///
- /// finalConstVarOrType ::=
- /// 'final' type?
- /// | 'const' type?
- /// | 'var'
- /// | type
- FinalConstVarOrType parseFinalConstVarOrType(bool optional,
- {bool inFunctionType = false}) {
- Token keywordToken;
- TypeAnnotation type;
- Keyword keyword = _currentToken.keyword;
- if (keyword == Keyword.FINAL || keyword == Keyword.CONST) {
- keywordToken = getAndAdvance();
- if (_isTypedIdentifier(_currentToken)) {
- type = parseTypeAnnotation(false);
- }
- } else if (keyword == Keyword.VAR) {
- keywordToken = getAndAdvance();
- } else if (_isTypedIdentifier(_currentToken)) {
- type = parseTypeAnnotation(false);
- } else if (inFunctionType && _matchesIdentifier()) {
- type = parseTypeAnnotation(false);
- } else if (!optional) {
- // If there is a valid type immediately following an unexpected token,
- // then report and skip the unexpected token.
- Token next = _peek();
- Keyword nextKeyword = next.keyword;
- if (nextKeyword == Keyword.FINAL ||
- nextKeyword == Keyword.CONST ||
- nextKeyword == Keyword.VAR ||
- _isTypedIdentifier(next) ||
- inFunctionType && _tokenMatchesIdentifier(next)) {
- _reportErrorForCurrentToken(
- ParserErrorCode.UNEXPECTED_TOKEN, [_currentToken.lexeme]);
- _advance();
- return parseFinalConstVarOrType(optional,
- inFunctionType: inFunctionType);
- }
- _reportErrorForCurrentToken(
- ParserErrorCode.MISSING_CONST_FINAL_VAR_OR_TYPE);
- } else {
- // Support parameters such as `(/*=K*/ key, /*=V*/ value)`
- // This is not supported if the type is required.
- type;
- }
- return FinalConstVarOrType(keywordToken, type);
- }
-
- /// Parse a formal parameter. At most one of `isOptional` and `isNamed` can be
- /// `true`. The [kind] is the kind of parameter being expected based on the
- /// presence or absence of group delimiters. Return the formal parameter that
- /// was parsed.
- ///
- /// defaultFormalParameter ::=
- /// normalFormalParameter ('=' expression)?
- ///
- /// defaultNamedParameter ::=
- /// normalFormalParameter ('=' expression)?
- /// normalFormalParameter (':' expression)?
- FormalParameter parseFormalParameter(ParameterKind kind,
- {bool inFunctionType = false}) {
- NormalFormalParameter parameter =
- parseNormalFormalParameter(inFunctionType: inFunctionType);
- TokenType type = _currentToken.type;
- if (type == TokenType.EQ) {
- if (inFunctionType) {
- _reportErrorForCurrentToken(
- ParserErrorCode.DEFAULT_VALUE_IN_FUNCTION_TYPE);
- }
- Token separator = getAndAdvance();
- Expression defaultValue = parseExpression2();
- if (kind == ParameterKind.REQUIRED) {
- _reportErrorForNode(
- ParserErrorCode.POSITIONAL_PARAMETER_OUTSIDE_GROUP, parameter);
- kind = ParameterKind.POSITIONAL;
- } else if (kind == ParameterKind.NAMED &&
- inFunctionType &&
- parameter.identifier == null) {
- _reportErrorForCurrentToken(
- ParserErrorCode.MISSING_NAME_FOR_NAMED_PARAMETER);
- parameter.identifier = createSyntheticIdentifier(isDeclaration: true);
- }
- return astFactory.defaultFormalParameter(
- parameter, kind, separator, defaultValue);
- } else if (type == TokenType.COLON) {
- if (inFunctionType) {
- _reportErrorForCurrentToken(
- ParserErrorCode.DEFAULT_VALUE_IN_FUNCTION_TYPE);
- }
- Token separator = getAndAdvance();
- Expression defaultValue = parseExpression2();
- if (kind == ParameterKind.REQUIRED) {
- _reportErrorForNode(
- ParserErrorCode.NAMED_PARAMETER_OUTSIDE_GROUP, parameter);
- kind = ParameterKind.NAMED;
- } else if (kind == ParameterKind.POSITIONAL) {
- _reportErrorForToken(
- ParserErrorCode.WRONG_SEPARATOR_FOR_POSITIONAL_PARAMETER,
- separator);
- } else if (kind == ParameterKind.NAMED &&
- inFunctionType &&
- parameter.identifier == null) {
- _reportErrorForCurrentToken(
- ParserErrorCode.MISSING_NAME_FOR_NAMED_PARAMETER);
- parameter.identifier = createSyntheticIdentifier(isDeclaration: true);
- }
- return astFactory.defaultFormalParameter(
- parameter, kind, separator, defaultValue);
- } else if (kind != ParameterKind.REQUIRED) {
- if (kind == ParameterKind.NAMED &&
- inFunctionType &&
- parameter.identifier == null) {
- _reportErrorForCurrentToken(
- ParserErrorCode.MISSING_NAME_FOR_NAMED_PARAMETER);
- parameter.identifier = createSyntheticIdentifier(isDeclaration: true);
- }
- return astFactory.defaultFormalParameter(parameter, kind, null, null);
- }
- return parameter;
- }
-
- /// Parse a list of formal parameters. Return the formal parameters that were
- /// parsed.
- ///
- /// formalParameterList ::=
- /// '(' ')'
- /// | '(' normalFormalParameters (',' optionalFormalParameters)? ')'
- /// | '(' optionalFormalParameters ')'
- ///
- /// normalFormalParameters ::=
- /// normalFormalParameter (',' normalFormalParameter)*
- ///
- /// optionalFormalParameters ::=
- /// optionalPositionalFormalParameters
- /// | namedFormalParameters
- ///
- /// optionalPositionalFormalParameters ::=
- /// '[' defaultFormalParameter (',' defaultFormalParameter)* ']'
- ///
- /// namedFormalParameters ::=
- /// '{' defaultNamedParameter (',' defaultNamedParameter)* '}'
FormalParameterList parseFormalParameterList({bool inFunctionType = false}) {
- if (_matches(TokenType.OPEN_PAREN)) {
- return _parseFormalParameterListUnchecked(inFunctionType: inFunctionType);
- }
- // TODO(brianwilkerson) Improve the error message.
- _reportErrorForCurrentToken(
- ParserErrorCode.EXPECTED_TOKEN, [TokenType.OPEN_PAREN.lexeme]);
- // Recovery: Check for an unmatched closing paren and parse parameters until
- // it is reached.
- return _parseFormalParameterListAfterParen(
- _createSyntheticToken(TokenType.OPEN_PAREN));
+ currentToken = fastaParser
+ .parseFormalParametersRequiredOpt(
+ fastaParser.syntheticPreviousToken(currentToken),
+ inFunctionType
+ ? fasta.MemberKind.GeneralizedFunctionType
+ : fasta.MemberKind.NonStaticMethod)
+ .next;
+ return astBuilder.pop() as FormalParameterList;
}
- /// Parse a for statement. Return the for statement that was parsed.
- ///
- /// forStatement ::=
- /// 'for' '(' forLoopParts ')' statement
- ///
- /// forLoopParts ::=
- /// forInitializerStatement expression? ';' expressionList?
- /// | declaredIdentifier 'in' expression
- /// | identifier 'in' expression
- ///
- /// forInitializerStatement ::=
- /// localVariableDeclaration ';'
- /// | expression? ';'
- Statement parseForStatement() {
- bool wasInLoop = _inLoop;
- _inLoop = true;
- try {
- Token awaitKeyword;
- if (_matchesKeyword(Keyword.AWAIT)) {
- awaitKeyword = getAndAdvance();
- }
- Token forKeyword = _expectKeyword(Keyword.FOR);
- Token leftParenthesis = _expect(TokenType.OPEN_PAREN);
- VariableDeclarationList variableList;
- Expression initialization;
- if (!_matches(TokenType.SEMICOLON)) {
- CommentAndMetadata commentAndMetadata = parseCommentAndMetadata();
- if (_matchesIdentifier() &&
- (_tokenMatchesKeyword(_peek(), Keyword.IN) ||
- _tokenMatches(_peek(), TokenType.COLON))) {
- SimpleIdentifier variableName = _parseSimpleIdentifierUnchecked();
- variableList = astFactory.variableDeclarationList(
- commentAndMetadata.comment,
- commentAndMetadata.metadata,
- null,
- null, <VariableDeclaration>[
- astFactory.variableDeclaration(variableName, null, null)
- ]);
- } else if (isInitializedVariableDeclaration()) {
- variableList =
- parseVariableDeclarationListAfterMetadata(commentAndMetadata);
- } else {
- initialization = parseExpression2();
- }
- TokenType type = _currentToken.type;
- if (_matchesKeyword(Keyword.IN) || type == TokenType.COLON) {
- if (type == TokenType.COLON) {
- _reportErrorForCurrentToken(ParserErrorCode.COLON_IN_PLACE_OF_IN);
- }
- DeclaredIdentifier loopVariable;
- SimpleIdentifier identifier;
- if (variableList == null) {
- // We found: <expression> 'in'
- _reportErrorForCurrentToken(
- ParserErrorCode.MISSING_VARIABLE_IN_FOR_EACH);
- } else {
- NodeList<VariableDeclaration> variables = variableList.variables;
- if (variables.length > 1) {
- _reportErrorForCurrentToken(
- ParserErrorCode.MULTIPLE_VARIABLES_IN_FOR_EACH,
- [variables.length.toString()]);
- }
- VariableDeclaration variable = variables[0];
- if (variable.initializer != null) {
- _reportErrorForCurrentToken(
- ParserErrorCode.INITIALIZED_VARIABLE_IN_FOR_EACH);
- }
- Token keyword = variableList.keyword;
- TypeAnnotation type = variableList.type;
- if (keyword != null || type != null) {
- loopVariable = astFactory.declaredIdentifier(
- commentAndMetadata.comment,
- commentAndMetadata.metadata,
- keyword,
- type,
- astFactory.simpleIdentifier(variable.name.token,
- isDeclaration: true));
- } else {
- if (commentAndMetadata.hasMetadata) {
- // TODO(jwren) metadata isn't allowed before the identifier in
- // "identifier in expression", add warning if commentAndMetadata
- // has content
- }
- identifier = variable.name;
- }
- }
- Token inKeyword = getAndAdvance();
- Expression iterator = parseExpression2();
- Token rightParenthesis = _expect(TokenType.CLOSE_PAREN);
- Statement body = parseStatement2();
- ForLoopParts forLoopParts;
- if (loopVariable == null) {
- forLoopParts = astFactory.forEachPartsWithIdentifier(
- identifier: identifier,
- inKeyword: inKeyword,
- iterable: iterator);
- } else {
- forLoopParts = astFactory.forEachPartsWithDeclaration(
- loopVariable: loopVariable,
- inKeyword: inKeyword,
- iterable: iterator);
- }
- return astFactory.forStatement(
- forKeyword: forKeyword,
- leftParenthesis: leftParenthesis,
- forLoopParts: forLoopParts,
- rightParenthesis: rightParenthesis,
- body: body);
- }
- }
- if (awaitKeyword != null) {
- _reportErrorForToken(
- ParserErrorCode.INVALID_AWAIT_IN_FOR, awaitKeyword);
- }
- Token leftSeparator = _expect(TokenType.SEMICOLON);
- Expression condition;
- if (!_matches(TokenType.SEMICOLON)) {
- condition = parseExpression2();
- }
- Token rightSeparator = _expect(TokenType.SEMICOLON);
- List<Expression> updaters;
- if (!_matches(TokenType.CLOSE_PAREN)) {
- updaters = parseExpressionList();
- }
- ForLoopParts forLoopParts;
- if (variableList != null) {
- forLoopParts = astFactory.forPartsWithDeclarations(
- variables: variableList,
- leftSeparator: leftSeparator,
- condition: condition,
- rightSeparator: rightSeparator,
- updaters: updaters);
- } else {
- forLoopParts = astFactory.forPartsWithExpression(
- initialization: initialization,
- leftSeparator: leftSeparator,
- condition: condition,
- rightSeparator: rightSeparator,
- updaters: updaters);
- }
- Token rightParenthesis = _expect(TokenType.CLOSE_PAREN);
- Statement body = parseStatement2();
- return astFactory.forStatement(
- forKeyword: forKeyword,
- leftParenthesis: leftParenthesis,
- forLoopParts: forLoopParts,
- rightParenthesis: rightParenthesis,
- body: body);
- } finally {
- _inLoop = wasInLoop;
- }
- }
-
- /// Parse a function body. The [mayBeEmpty] is `true` if the function body is
- /// allowed to be empty. The [emptyErrorCode] is the error code to report if
- /// function body expected, but not found. The [inExpression] is `true` if the
- /// function body is being parsed as part of an expression and therefore does
- /// not have a terminating semicolon. Return the function body that was
- /// parsed.
- ///
- /// functionBody ::=
- /// '=>' expression ';'
- /// | block
- ///
- /// functionExpressionBody ::=
- /// '=>' expression
- /// | block
FunctionBody parseFunctionBody(
bool mayBeEmpty, ParserErrorCode emptyErrorCode, bool inExpression) {
- bool wasInAsync = _inAsync;
- bool wasInGenerator = _inGenerator;
- bool wasInLoop = _inLoop;
- bool wasInSwitch = _inSwitch;
- _inAsync = false;
- _inGenerator = false;
- _inLoop = false;
- _inSwitch = false;
- try {
- TokenType type = _currentToken.type;
- if (type == TokenType.SEMICOLON) {
- if (!mayBeEmpty) {
- _reportErrorForCurrentToken(emptyErrorCode);
- }
- return astFactory.emptyFunctionBody(getAndAdvance());
- }
- Token keyword;
- Token star;
- bool foundAsync = false;
- bool foundSync = false;
- if (type.isKeyword) {
- String lexeme = _currentToken.lexeme;
- if (lexeme == ASYNC) {
- foundAsync = true;
- keyword = getAndAdvance();
- if (_matches(TokenType.STAR)) {
- star = getAndAdvance();
- _inGenerator = true;
- }
- type = _currentToken.type;
- _inAsync = true;
- } else if (lexeme == SYNC) {
- foundSync = true;
- keyword = getAndAdvance();
- if (_matches(TokenType.STAR)) {
- star = getAndAdvance();
- _inGenerator = true;
- }
- type = _currentToken.type;
- }
- }
- if (type == TokenType.FUNCTION) {
- if (keyword != null) {
- if (!foundAsync) {
- _reportErrorForToken(ParserErrorCode.INVALID_SYNC, keyword);
- keyword;
- } else if (star != null) {
- _reportErrorForToken(
- ParserErrorCode.INVALID_STAR_AFTER_ASYNC, star);
- }
- }
- Token functionDefinition = getAndAdvance();
- if (_matchesKeyword(Keyword.RETURN)) {
- _reportErrorForToken(ParserErrorCode.UNEXPECTED_TOKEN, _currentToken,
- [_currentToken.lexeme]);
- _advance();
- }
- Expression expression = parseExpression2();
- Token semicolon;
- if (!inExpression) {
- semicolon = _expect(TokenType.SEMICOLON);
- }
- if (!_parseFunctionBodies) {
- return astFactory
- .emptyFunctionBody(_createSyntheticToken(TokenType.SEMICOLON));
- }
- return astFactory.expressionFunctionBody(
- keyword, functionDefinition, expression, semicolon);
- } else if (type == TokenType.OPEN_CURLY_BRACKET) {
- if (keyword != null) {
- if (foundSync && star == null) {
- _reportErrorForToken(
- ParserErrorCode.MISSING_STAR_AFTER_SYNC, keyword);
- }
- }
- if (!_parseFunctionBodies) {
- _skipBlock();
- return astFactory
- .emptyFunctionBody(_createSyntheticToken(TokenType.SEMICOLON));
- }
- return astFactory.blockFunctionBody(keyword, star, parseBlock());
- } else if (_matchesKeyword(Keyword.NATIVE)) {
- Token nativeToken = getAndAdvance();
- StringLiteral stringLiteral;
- if (_matches(TokenType.STRING)) {
- stringLiteral = _parseStringLiteralUnchecked();
- }
- return astFactory.nativeFunctionBody(
- nativeToken, stringLiteral, _expect(TokenType.SEMICOLON));
- } else {
- // Invalid function body
- _reportErrorForCurrentToken(emptyErrorCode);
- return astFactory
- .emptyFunctionBody(_createSyntheticToken(TokenType.SEMICOLON));
- }
- } finally {
- _inAsync = wasInAsync;
- _inGenerator = wasInGenerator;
- _inLoop = wasInLoop;
- _inSwitch = wasInSwitch;
- }
+ currentToken = fastaParser.parseAsyncModifierOpt(
+ fastaParser.syntheticPreviousToken(currentToken));
+ currentToken =
+ fastaParser.parseFunctionBody(currentToken, inExpression, mayBeEmpty);
+ return astBuilder.pop() as FunctionBody;
}
- /// Parse a function declaration. The [commentAndMetadata] is the
- /// documentation comment and metadata to be associated with the declaration.
- /// The [externalKeyword] is the 'external' keyword, or `null` if the
- /// function is not external. The [returnType] is the return type, or `null`
- /// if there is no return type. The [isStatement] is `true` if the function
- /// declaration is being parsed as a statement. Return the function
- /// declaration that was parsed.
- ///
- /// functionDeclaration ::=
- /// functionSignature functionBody
- /// | returnType? getOrSet identifier formalParameterList functionBody
- FunctionDeclaration parseFunctionDeclaration(
- CommentAndMetadata commentAndMetadata,
- Token externalKeyword,
- TypeAnnotation returnType) {
- Token keywordToken;
- bool isGetter = false;
- Keyword keyword = _currentToken.keyword;
- SimpleIdentifier name;
- if (keyword == Keyword.GET) {
- keywordToken = getAndAdvance();
- isGetter = true;
- } else if (keyword == Keyword.SET) {
- keywordToken = getAndAdvance();
- }
- if (keywordToken != null && _matches(TokenType.OPEN_PAREN)) {
- name = astFactory.simpleIdentifier(keywordToken, isDeclaration: true);
- keywordToken;
- isGetter = false;
- } else {
- name = parseSimpleIdentifier(isDeclaration: true);
- }
- TypeParameterList typeParameters = _parseGenericMethodTypeParameters();
- FormalParameterList parameters;
- if (!isGetter) {
- if (_matches(TokenType.OPEN_PAREN)) {
- parameters = _parseFormalParameterListUnchecked();
- _validateFormalParameterList(parameters);
- } else {
- _reportErrorForCurrentToken(
- ParserErrorCode.MISSING_FUNCTION_PARAMETERS);
- parameters = astFactory.formalParameterList(
- _createSyntheticToken(TokenType.OPEN_PAREN),
- null,
- null,
- null,
- _createSyntheticToken(TokenType.CLOSE_PAREN));
- }
- } else if (_matches(TokenType.OPEN_PAREN)) {
- _reportErrorForCurrentToken(ParserErrorCode.GETTER_WITH_PARAMETERS);
- _parseFormalParameterListUnchecked();
- }
- FunctionBody body;
- if (externalKeyword == null) {
- body = parseFunctionBody(
- false, ParserErrorCode.MISSING_FUNCTION_BODY, false);
- } else {
- body = astFactory.emptyFunctionBody(_expect(TokenType.SEMICOLON));
- }
-// if (!isStatement && matches(TokenType.SEMICOLON)) {
-// // TODO(brianwilkerson) Improve this error message.
-// reportError(ParserErrorCode.UNEXPECTED_TOKEN, currentToken.getLexeme());
-// advance();
-// }
- return astFactory.functionDeclaration(
- commentAndMetadata.comment,
- commentAndMetadata.metadata,
- externalKeyword,
- returnType,
- keywordToken,
- name,
- astFactory.functionExpression(typeParameters, parameters, body));
- }
+ FunctionExpression parseFunctionExpression() =>
+ parseExpression2() as FunctionExpression;
- /// Parse a function declaration statement. Return the function declaration
- /// statement that was parsed.
- ///
- /// functionDeclarationStatement ::=
- /// functionSignature functionBody
- Statement parseFunctionDeclarationStatement() {
- Modifiers modifiers = parseModifiers();
- _validateModifiersForFunctionDeclarationStatement(modifiers);
- return _parseFunctionDeclarationStatementAfterReturnType(
- parseCommentAndMetadata(), _parseOptionalReturnType());
- }
+ Expression parseLogicalAndExpression() => parseExpression2();
- /// Parse a function expression. Return the function expression that was
- /// parsed.
- ///
- /// functionExpression ::=
- /// typeParameters? formalParameterList functionExpressionBody
- FunctionExpression parseFunctionExpression() {
- TypeParameterList typeParameters = _parseGenericMethodTypeParameters();
- FormalParameterList parameters = parseFormalParameterList();
- _validateFormalParameterList(parameters);
- FunctionBody body =
- parseFunctionBody(false, ParserErrorCode.MISSING_FUNCTION_BODY, true);
- return astFactory.functionExpression(typeParameters, parameters, body);
- }
+ Expression parseLogicalOrExpression() => parseExpression2();
- /// Parse the portion of a generic function type following the [returnType].
- ///
- /// functionType ::=
- /// returnType? 'Function' typeParameters? parameterTypeList
- /// parameterTypeList ::=
- /// '(' ')' |
- /// | '(' normalParameterTypes ','? ')' |
- /// | '(' normalParameterTypes ',' optionalParameterTypes ')' |
- /// | '(' optionalParameterTypes ')'
- /// normalParameterTypes ::=
- /// normalParameterType (',' normalParameterType)*
- /// normalParameterType ::=
- /// type | typedIdentifier
- /// optionalParameterTypes ::=
- /// optionalPositionalParameterTypes | namedParameterTypes
- /// optionalPositionalParameterTypes ::=
- /// '[' normalParameterTypes ','? ']'
- /// namedParameterTypes ::=
- /// '{' typedIdentifier (',' typedIdentifier)* ','? '}'
- /// typedIdentifier ::=
- /// type identifier
- GenericFunctionType parseGenericFunctionTypeAfterReturnType(
- TypeAnnotation returnType) {
- Token functionKeyword;
- if (_matchesKeyword(Keyword.FUNCTION)) {
- functionKeyword = getAndAdvance();
- } else if (_matchesIdentifier()) {
- _reportErrorForCurrentToken(ParserErrorCode.NAMED_FUNCTION_TYPE);
- } else {
- _reportErrorForCurrentToken(ParserErrorCode.MISSING_FUNCTION_KEYWORD);
- }
- TypeParameterList typeParameters;
- if (_matches(TokenType.LT)) {
- typeParameters = parseTypeParameterList();
- }
- FormalParameterList parameters =
- parseFormalParameterList(inFunctionType: true);
- return astFactory.genericFunctionType(
- returnType, functionKeyword, typeParameters, parameters);
- }
+ Expression parseMultiplicativeExpression() => parseExpression2();
- /// Parse a generic function type alias.
- ///
- /// This method assumes that the current token is an identifier.
- ///
- /// genericTypeAlias ::=
- /// 'typedef' identifier typeParameterList? '=' functionType ';'
- GenericTypeAlias parseGenericTypeAlias(
- CommentAndMetadata commentAndMetadata, Token keyword) {
- Identifier name = _parseSimpleIdentifierUnchecked(isDeclaration: true);
- TypeParameterList typeParameters;
- if (_matches(TokenType.LT)) {
- typeParameters = parseTypeParameterList();
- }
- Token equals = _expect(TokenType.EQ);
- TypeAnnotation functionType = parseTypeAnnotation(false);
- Token semicolon = _expect(TokenType.SEMICOLON);
- if (functionType is! GenericFunctionType) {
- // TODO(brianwilkerson) Generate a better error.
- _reportErrorForToken(
- ParserErrorCode.INVALID_GENERIC_FUNCTION_TYPE, semicolon);
- // TODO(brianwilkerson) Recover better than this.
- return astFactory.genericTypeAlias(
- commentAndMetadata.comment,
- commentAndMetadata.metadata,
- keyword,
- name,
- typeParameters,
- equals,
- null,
- semicolon);
- }
- return astFactory.genericTypeAlias(
- commentAndMetadata.comment,
- commentAndMetadata.metadata,
- keyword,
- name,
- typeParameters,
- equals,
- functionType,
- semicolon);
- }
-
- /// Parse a getter. The [commentAndMetadata] is the documentation comment and
- /// metadata to be associated with the declaration. The externalKeyword] is
- /// the 'external' token. The staticKeyword] is the static keyword, or `null`
- /// if the getter is not static. The [returnType] the return type that has
- /// already been parsed, or `null` if there was no return type. Return the
- /// getter that was parsed.
- ///
- /// This method assumes that the current token matches `Keyword.GET`.
- ///
- /// getter ::=
- /// getterSignature functionBody?
- ///
- /// getterSignature ::=
- /// 'external'? 'static'? returnType? 'get' identifier
- MethodDeclaration parseGetter(CommentAndMetadata commentAndMetadata,
- Token externalKeyword, Token staticKeyword, TypeAnnotation returnType) {
- Token propertyKeyword = getAndAdvance();
- SimpleIdentifier name = parseSimpleIdentifier(isDeclaration: true);
- if (_matches(TokenType.OPEN_PAREN) &&
- _tokenMatches(_peek(), TokenType.CLOSE_PAREN)) {
- _reportErrorForCurrentToken(ParserErrorCode.GETTER_WITH_PARAMETERS);
- _advance();
- _advance();
- }
- FunctionBody body = parseFunctionBody(
- externalKeyword != null || staticKeyword == null,
- ParserErrorCode.STATIC_GETTER_WITHOUT_BODY,
- false);
- if (externalKeyword != null && body is! EmptyFunctionBody) {
- _reportErrorForCurrentToken(ParserErrorCode.EXTERNAL_GETTER_WITH_BODY);
- }
- return astFactory.methodDeclaration(
- commentAndMetadata.comment,
- commentAndMetadata.metadata,
- externalKeyword,
- staticKeyword,
- returnType,
- propertyKeyword,
- null,
- name,
- null,
- null,
- body);
- }
-
- /// Parse a list of identifiers. Return the list of identifiers that were
- /// parsed.
- ///
- /// identifierList ::=
- /// identifier (',' identifier)*
- List<SimpleIdentifier> parseIdentifierList() {
- List<SimpleIdentifier> identifiers = <SimpleIdentifier>[
- parseSimpleIdentifier()
- ];
- while (_optional(TokenType.COMMA)) {
- identifiers.add(parseSimpleIdentifier());
- }
- return identifiers;
- }
-
- /// Parse an if-null expression. Return the if-null expression that was
- /// parsed.
- ///
- /// ifNullExpression ::= logicalOrExpression ('??' logicalOrExpression)*
- Expression parseIfNullExpression() {
- Expression expression = parseLogicalOrExpression();
- while (_currentToken.type == TokenType.QUESTION_QUESTION) {
- expression = astFactory.binaryExpression(
- expression, getAndAdvance(), parseLogicalOrExpression());
- }
- return expression;
- }
-
- /// Parse an if statement. Return the if statement that was parsed.
- ///
- /// This method assumes that the current token matches `Keyword.IF`.
- ///
- /// ifStatement ::=
- /// 'if' '(' expression ')' statement ('else' statement)?
- Statement parseIfStatement() {
- Token ifKeyword = getAndAdvance();
- Token leftParenthesis = _expect(TokenType.OPEN_PAREN);
- Expression condition = parseExpression2();
- Token rightParenthesis = _expect(TokenType.CLOSE_PAREN);
- Statement thenStatement = parseStatement2();
- Token elseKeyword;
- Statement elseStatement;
- if (_matchesKeyword(Keyword.ELSE)) {
- elseKeyword = getAndAdvance();
- elseStatement = parseStatement2();
- }
- return astFactory.ifStatement(ifKeyword, leftParenthesis, condition,
- rightParenthesis, thenStatement, elseKeyword, elseStatement);
- }
-
- /// Parse an implements clause. Return the implements clause that was parsed.
- ///
- /// This method assumes that the current token matches `Keyword.IMPLEMENTS`.
- ///
- /// implementsClause ::=
- /// 'implements' type (',' type)*
- ImplementsClause parseImplementsClause() {
- Token keyword = getAndAdvance();
- List<TypeName> interfaces = <TypeName>[];
- do {
- TypeName typeName = parseTypeName(false);
- interfaces.add(typeName);
- } while (_optional(TokenType.COMMA));
- return astFactory.implementsClause(keyword, interfaces);
- }
-
- /// Parse an import directive. The [commentAndMetadata] is the metadata to be
- /// associated with the directive. Return the import directive that was
- /// parsed.
- ///
- /// This method assumes that the current token matches `Keyword.IMPORT`.
- ///
- /// importDirective ::=
- /// metadata 'import' stringLiteral configuration* (deferred)? ('as' identifier)? combinator*';'
- ImportDirective parseImportDirective(CommentAndMetadata commentAndMetadata) {
- Token importKeyword = getAndAdvance();
- StringLiteral libraryUri = _parseUri();
- List<Configuration> configurations = _parseConfigurations();
- Token deferredToken;
- Token asToken;
- SimpleIdentifier prefix;
- if (_matchesKeyword(Keyword.DEFERRED)) {
- deferredToken = getAndAdvance();
- }
- if (_matchesKeyword(Keyword.AS)) {
- asToken = getAndAdvance();
- prefix = parseSimpleIdentifier(isDeclaration: true);
- } else if (deferredToken != null) {
- _reportErrorForCurrentToken(
- ParserErrorCode.MISSING_PREFIX_IN_DEFERRED_IMPORT);
- } else if (!_matches(TokenType.SEMICOLON) &&
- !_matchesKeyword(Keyword.SHOW) &&
- !_matchesKeyword(Keyword.HIDE)) {
- Token nextToken = _peek();
- if (_tokenMatchesKeyword(nextToken, Keyword.AS) ||
- _tokenMatchesKeyword(nextToken, Keyword.SHOW) ||
- _tokenMatchesKeyword(nextToken, Keyword.HIDE)) {
- _reportErrorForCurrentToken(
- ParserErrorCode.UNEXPECTED_TOKEN, [_currentToken]);
- _advance();
- if (_matchesKeyword(Keyword.AS)) {
- asToken = getAndAdvance();
- prefix = parseSimpleIdentifier(isDeclaration: true);
- }
- }
- }
- List<Combinator> combinators = parseCombinators();
- Token semicolon = _expect(TokenType.SEMICOLON);
- return astFactory.importDirective(
- commentAndMetadata.comment,
- commentAndMetadata.metadata,
- importKeyword,
- libraryUri,
- configurations,
- deferredToken,
- asToken,
- prefix,
- combinators,
- semicolon);
- }
-
- /// Parse a list of initialized identifiers. The [commentAndMetadata] is the
- /// documentation comment and metadata to be associated with the declaration.
- /// The [staticKeyword] is the static keyword, or `null` if the getter is not
- /// static. The [keyword] is the token representing the 'final', 'const' or
- /// 'var' keyword, or `null` if there is no keyword. The [type] is the type
- /// that has already been parsed, or `null` if 'var' was provided. Return the
- /// getter that was parsed.
- ///
- /// declaration ::=
- /// ('static' | 'covariant')? ('var' | type) initializedIdentifierList ';'
- /// | 'final' type? initializedIdentifierList ';'
- ///
- /// initializedIdentifierList ::=
- /// initializedIdentifier (',' initializedIdentifier)*
- ///
- /// initializedIdentifier ::=
- /// identifier ('=' expression)?
- FieldDeclaration parseInitializedIdentifierList(
- CommentAndMetadata commentAndMetadata,
- Token staticKeyword,
- Token covariantKeyword,
- Token keyword,
- TypeAnnotation type) {
- VariableDeclarationList fieldList =
- parseVariableDeclarationListAfterType(null, keyword, type);
- return astFactory.fieldDeclaration2(
- comment: commentAndMetadata.comment,
- metadata: commentAndMetadata.metadata,
- covariantKeyword: covariantKeyword,
- staticKeyword: staticKeyword,
- fieldList: fieldList,
- semicolon: _expect(TokenType.SEMICOLON));
- }
-
- /// Parse an instance creation expression. The [keyword] is the 'new' or
- /// 'const' keyword that introduces the expression. Return the instance
- /// creation expression that was parsed.
- ///
- /// instanceCreationExpression ::=
- /// ('new' | 'const') type ('.' identifier)? argumentList
- InstanceCreationExpression parseInstanceCreationExpression(Token keyword) {
- ConstructorName constructorName = parseConstructorName();
- ArgumentList argumentList = _parseArgumentListChecked();
- return astFactory.instanceCreationExpression(
- keyword, constructorName, argumentList);
- }
-
- /// Parse a label. Return the label that was parsed.
- ///
- /// This method assumes that the current token matches an identifier and that
- /// the following token matches `TokenType.COLON`.
- ///
- /// label ::=
- /// identifier ':'
- Label parseLabel({bool isDeclaration = false}) {
- SimpleIdentifier label =
- _parseSimpleIdentifierUnchecked(isDeclaration: isDeclaration);
- Token colon = getAndAdvance();
- return astFactory.label(label, colon);
- }
-
- /// Parse a library directive. The [commentAndMetadata] is the metadata to be
- /// associated with the directive. Return the library directive that was
- /// parsed.
- ///
- /// This method assumes that the current token matches `Keyword.LIBRARY`.
- ///
- /// libraryDirective ::=
- /// metadata 'library' identifier ';'
- LibraryDirective parseLibraryDirective(
- CommentAndMetadata commentAndMetadata) {
- Token keyword = getAndAdvance();
- LibraryIdentifier libraryName = _parseLibraryName(
- ParserErrorCode.MISSING_NAME_IN_LIBRARY_DIRECTIVE, keyword);
- Token semicolon = _expect(TokenType.SEMICOLON);
- return astFactory.libraryDirective(commentAndMetadata.comment,
- commentAndMetadata.metadata, keyword, libraryName, semicolon);
- }
-
- /// Parse a library identifier. Return the library identifier that was parsed.
- ///
- /// libraryIdentifier ::=
- /// identifier ('.' identifier)*
- LibraryIdentifier parseLibraryIdentifier() {
- List<SimpleIdentifier> components = <SimpleIdentifier>[];
- components.add(parseSimpleIdentifier());
- while (_optional(TokenType.PERIOD)) {
- components.add(parseSimpleIdentifier());
- }
- return astFactory.libraryIdentifier(components);
- }
-
- /// Parse a list literal. The [modifier] is the 'const' modifier appearing
- /// before the literal, or `null` if there is no modifier. The [typeArguments]
- /// is the type arguments appearing before the literal, or `null` if there are
- /// no type arguments. Return the list literal that was parsed.
- ///
- /// This method assumes that the current token matches either
- /// `TokenType.OPEN_SQUARE_BRACKET` or `TokenType.INDEX`.
- ///
- /// listLiteral ::=
- /// 'const'? typeArguments? '[' (expressionList ','?)? ']'
- ListLiteral parseListLiteral(Token modifier, TypeArgumentList typeArguments) {
- if (_matches(TokenType.INDEX)) {
- _splitIndex();
- return astFactory.listLiteral(
- modifier, typeArguments, getAndAdvance(), null, getAndAdvance());
- }
- Token leftBracket = getAndAdvance();
- if (_matches(TokenType.CLOSE_SQUARE_BRACKET)) {
- return astFactory.listLiteral(
- modifier, typeArguments, leftBracket, null, getAndAdvance());
- }
- bool wasInInitializer = _inInitializer;
- _inInitializer = false;
- try {
- List<Expression> elements = <Expression>[parseExpression2()];
- while (_optional(TokenType.COMMA)) {
- if (_matches(TokenType.CLOSE_SQUARE_BRACKET)) {
- return astFactory.listLiteral(
- modifier, typeArguments, leftBracket, elements, getAndAdvance());
- }
- elements.add(parseExpression2());
- }
- Token rightBracket = _expect(TokenType.CLOSE_SQUARE_BRACKET);
- return astFactory.listLiteral(
- modifier, typeArguments, leftBracket, elements, rightBracket);
- } finally {
- _inInitializer = wasInInitializer;
- }
- }
-
- /// Parse a list or map literal. The [modifier] is the 'const' modifier
- /// appearing before the literal, or `null` if there is no modifier. Return
- /// the list or map literal that was parsed.
- ///
- /// listOrMapLiteral ::=
- /// listLiteral
- /// | mapLiteral
- TypedLiteral parseListOrMapLiteral(Token modifier) {
- TypeArgumentList typeArguments = _parseOptionalTypeArguments();
- if (_matches(TokenType.OPEN_CURLY_BRACKET)) {
- return parseMapLiteral(modifier, typeArguments);
- } else if (_matches(TokenType.OPEN_SQUARE_BRACKET) ||
- _matches(TokenType.INDEX)) {
- return parseListLiteral(modifier, typeArguments);
- }
- _reportErrorForCurrentToken(ParserErrorCode.EXPECTED_LIST_OR_MAP_LITERAL);
- return astFactory.listLiteral(
- modifier,
- typeArguments,
- _createSyntheticToken(TokenType.OPEN_SQUARE_BRACKET),
- null,
- _createSyntheticToken(TokenType.CLOSE_SQUARE_BRACKET));
- }
-
- /// Parse a logical and expression. Return the logical and expression that was
- /// parsed.
- ///
- /// logicalAndExpression ::=
- /// equalityExpression ('&&' equalityExpression)*
- Expression parseLogicalAndExpression() {
- Expression expression = parseEqualityExpression();
- while (_currentToken.type == TokenType.AMPERSAND_AMPERSAND) {
- expression = astFactory.binaryExpression(
- expression, getAndAdvance(), parseEqualityExpression());
- }
- return expression;
- }
-
- /// Parse a logical or expression. Return the logical or expression that was
- /// parsed.
- ///
- /// logicalOrExpression ::=
- /// logicalAndExpression ('||' logicalAndExpression)*
- Expression parseLogicalOrExpression() {
- Expression expression = parseLogicalAndExpression();
- while (_currentToken.type == TokenType.BAR_BAR) {
- expression = astFactory.binaryExpression(
- expression, getAndAdvance(), parseLogicalAndExpression());
- }
- return expression;
- }
-
- /// Parse a map literal. The [modifier] is the 'const' modifier appearing
- /// before the literal, or `null` if there is no modifier. The [typeArguments]
- /// is the type arguments that were declared, or `null` if there are no type
- /// arguments. Return the map literal that was parsed.
- ///
- /// This method assumes that the current token matches
- /// `TokenType.OPEN_CURLY_BRACKET`.
- ///
- /// mapLiteral ::=
- /// 'const'? typeArguments? '{' (mapLiteralEntry (',' mapLiteralEntry)* ','?)? '}'
- SetOrMapLiteral parseMapLiteral(
- Token modifier, TypeArgumentList typeArguments) {
- Token leftBracket = getAndAdvance();
- if (_matches(TokenType.CLOSE_CURLY_BRACKET)) {
- return astFactory.setOrMapLiteral(
- constKeyword: modifier,
- typeArguments: typeArguments,
- leftBracket: leftBracket,
- rightBracket: getAndAdvance());
- }
- bool wasInInitializer = _inInitializer;
- _inInitializer = false;
- try {
- List<MapLiteralEntry> entries = <MapLiteralEntry>[parseMapLiteralEntry()];
- while (_optional(TokenType.COMMA)) {
- if (_matches(TokenType.CLOSE_CURLY_BRACKET)) {
- return astFactory.setOrMapLiteral(
- constKeyword: modifier,
- typeArguments: typeArguments,
- leftBracket: leftBracket,
- elements: entries,
- rightBracket: getAndAdvance());
- }
- entries.add(parseMapLiteralEntry());
- }
- Token rightBracket = _expect(TokenType.CLOSE_CURLY_BRACKET);
- return astFactory.setOrMapLiteral(
- constKeyword: modifier,
- typeArguments: typeArguments,
- leftBracket: leftBracket,
- elements: entries,
- rightBracket: rightBracket);
- } finally {
- _inInitializer = wasInInitializer;
- }
- }
-
- /// Parse a map literal entry. Return the map literal entry that was parsed.
- ///
- /// mapLiteralEntry ::=
- /// expression ':' expression
- MapLiteralEntry parseMapLiteralEntry() {
- Expression key = parseExpression2();
- Token separator = _expect(TokenType.COLON);
- Expression value = parseExpression2();
- return astFactory.mapLiteralEntry(key, separator, value);
- }
-
- /// Parse the modifiers preceding a declaration. This method allows the
- /// modifiers to appear in any order but does generate errors for duplicated
- /// modifiers. Checks for other problems, such as having the modifiers appear
- /// in the wrong order or specifying both 'const' and 'final', are reported in
- /// one of the methods whose name is prefixed with `validateModifiersFor`.
- /// Return the modifiers that were parsed.
- ///
- /// modifiers ::=
- /// ('abstract' | 'const' | 'external' | 'factory' | 'final' | 'static' | 'var')*
- Modifiers parseModifiers() {
- Modifiers modifiers = Modifiers();
- bool progress = true;
- while (progress) {
- TokenType nextType = _peek().type;
- if (nextType == TokenType.PERIOD ||
- nextType == TokenType.LT ||
- nextType == TokenType.OPEN_PAREN) {
- return modifiers;
- }
- Keyword keyword = _currentToken.keyword;
- if (keyword == Keyword.ABSTRACT) {
- if (modifiers.abstractKeyword != null) {
- _reportErrorForCurrentToken(
- ParserErrorCode.DUPLICATED_MODIFIER, [_currentToken.lexeme]);
- _advance();
- } else {
- modifiers.abstractKeyword = getAndAdvance();
- }
- } else if (keyword == Keyword.CONST) {
- if (modifiers.constKeyword != null) {
- _reportErrorForCurrentToken(
- ParserErrorCode.DUPLICATED_MODIFIER, [_currentToken.lexeme]);
- _advance();
- } else {
- modifiers.constKeyword = getAndAdvance();
- }
- } else if (keyword == Keyword.COVARIANT) {
- if (modifiers.covariantKeyword != null) {
- _reportErrorForCurrentToken(
- ParserErrorCode.DUPLICATED_MODIFIER, [_currentToken.lexeme]);
- _advance();
- } else {
- modifiers.covariantKeyword = getAndAdvance();
- }
- } else if (keyword == Keyword.EXTERNAL) {
- if (modifiers.externalKeyword != null) {
- _reportErrorForCurrentToken(
- ParserErrorCode.DUPLICATED_MODIFIER, [_currentToken.lexeme]);
- _advance();
- } else {
- modifiers.externalKeyword = getAndAdvance();
- }
- } else if (keyword == Keyword.FACTORY) {
- if (modifiers.factoryKeyword != null) {
- _reportErrorForCurrentToken(
- ParserErrorCode.DUPLICATED_MODIFIER, [_currentToken.lexeme]);
- _advance();
- } else {
- modifiers.factoryKeyword = getAndAdvance();
- }
- } else if (keyword == Keyword.FINAL) {
- if (modifiers.finalKeyword != null) {
- _reportErrorForCurrentToken(
- ParserErrorCode.DUPLICATED_MODIFIER, [_currentToken.lexeme]);
- _advance();
- } else {
- modifiers.finalKeyword = getAndAdvance();
- }
- } else if (keyword == Keyword.STATIC) {
- if (modifiers.staticKeyword != null) {
- _reportErrorForCurrentToken(
- ParserErrorCode.DUPLICATED_MODIFIER, [_currentToken.lexeme]);
- _advance();
- } else {
- modifiers.staticKeyword = getAndAdvance();
- }
- } else if (keyword == Keyword.VAR) {
- if (modifiers.varKeyword != null) {
- _reportErrorForCurrentToken(
- ParserErrorCode.DUPLICATED_MODIFIER, [_currentToken.lexeme]);
- _advance();
- } else {
- modifiers.varKeyword = getAndAdvance();
- }
- } else {
- progress = false;
- }
- }
- return modifiers;
- }
-
- /// Parse a multiplicative expression. Return the multiplicative expression
- /// that was parsed.
- ///
- /// multiplicativeExpression ::=
- /// unaryExpression (multiplicativeOperator unaryExpression)*
- /// | 'super' (multiplicativeOperator unaryExpression)+
- Expression parseMultiplicativeExpression() {
- Expression expression;
- if (_currentToken.keyword == Keyword.SUPER &&
- _currentToken.next.type.isMultiplicativeOperator) {
- expression = astFactory.superExpression(getAndAdvance());
- } else {
- expression = parseUnaryExpression();
- }
- while (_currentToken.type.isMultiplicativeOperator) {
- expression = astFactory.binaryExpression(
- expression, getAndAdvance(), parseUnaryExpression());
- }
- return expression;
- }
-
- /// Parse a new expression. Return the new expression that was parsed.
- ///
- /// This method assumes that the current token matches `Keyword.NEW`.
- ///
- /// newExpression ::=
- /// instanceCreationExpression
InstanceCreationExpression parseNewExpression() =>
- parseInstanceCreationExpression(getAndAdvance());
+ parseExpression2() as InstanceCreationExpression;
- /// Parse a non-labeled statement. Return the non-labeled statement that was
- /// parsed.
- ///
- /// nonLabeledStatement ::=
- /// block
- /// | assertStatement
- /// | breakStatement
- /// | continueStatement
- /// | doStatement
- /// | forStatement
- /// | ifStatement
- /// | returnStatement
- /// | switchStatement
- /// | tryStatement
- /// | whileStatement
- /// | variableDeclarationList ';'
- /// | expressionStatement
- /// | functionSignature functionBody
- Statement parseNonLabeledStatement() {
- // TODO(brianwilkerson) Pass the comment and metadata on where appropriate.
- CommentAndMetadata commentAndMetadata = parseCommentAndMetadata();
- TokenType type = _currentToken.type;
- if (type == TokenType.OPEN_CURLY_BRACKET) {
- if (_tokenMatches(_peek(), TokenType.STRING)) {
- Token afterString = skipStringLiteral(_currentToken.next);
- if (afterString != null && afterString.type == TokenType.COLON) {
- return astFactory.expressionStatement(
- parseExpression2(), _expect(TokenType.SEMICOLON));
- }
- }
- return parseBlock();
- } else if (type.isKeyword && !_currentToken.keyword.isBuiltInOrPseudo) {
- Keyword keyword = _currentToken.keyword;
- // TODO(jwren) compute some metrics to figure out a better order for this
- // if-then sequence to optimize performance
- if (keyword == Keyword.ASSERT) {
- return parseAssertStatement();
- } else if (keyword == Keyword.BREAK) {
- return parseBreakStatement();
- } else if (keyword == Keyword.CONTINUE) {
- return parseContinueStatement();
- } else if (keyword == Keyword.DO) {
- return parseDoStatement();
- } else if (keyword == Keyword.FOR) {
- return parseForStatement();
- } else if (keyword == Keyword.IF) {
- return parseIfStatement();
- } else if (keyword == Keyword.RETHROW) {
- return astFactory.expressionStatement(
- parseRethrowExpression(), _expect(TokenType.SEMICOLON));
- } else if (keyword == Keyword.RETURN) {
- return parseReturnStatement();
- } else if (keyword == Keyword.SWITCH) {
- return parseSwitchStatement();
- } else if (keyword == Keyword.THROW) {
- return astFactory.expressionStatement(
- parseThrowExpression(), _expect(TokenType.SEMICOLON));
- } else if (keyword == Keyword.TRY) {
- return parseTryStatement();
- } else if (keyword == Keyword.WHILE) {
- return parseWhileStatement();
- } else if (keyword == Keyword.VAR || keyword == Keyword.FINAL) {
- return parseVariableDeclarationStatementAfterMetadata(
- commentAndMetadata);
- } else if (keyword == Keyword.VOID) {
- TypeAnnotation returnType;
- if (_atGenericFunctionTypeAfterReturnType(_peek())) {
- returnType = parseTypeAnnotation(false);
- } else {
- returnType = astFactory.typeName(
- astFactory.simpleIdentifier(getAndAdvance()), null);
- }
- Token next = _currentToken.next;
- if (_matchesIdentifier() &&
- next.matchesAny(const <TokenType>[
- TokenType.OPEN_PAREN,
- TokenType.OPEN_CURLY_BRACKET,
- TokenType.FUNCTION,
- TokenType.LT
- ])) {
- return _parseFunctionDeclarationStatementAfterReturnType(
- commentAndMetadata, returnType);
- } else if (_matchesIdentifier() &&
- next.matchesAny(const <TokenType>[
- TokenType.EQ,
- TokenType.COMMA,
- TokenType.SEMICOLON
- ])) {
- return _parseVariableDeclarationStatementAfterType(
- commentAndMetadata, null, returnType);
- } else {
- //
- // We have found an error of some kind. Try to recover.
- //
- if (_matches(TokenType.CLOSE_CURLY_BRACKET)) {
- //
- // We appear to have found an incomplete statement at the end of a
- // block. Parse it as a variable declaration.
- //
- return _parseVariableDeclarationStatementAfterType(
- commentAndMetadata, null, returnType);
- }
- _reportErrorForCurrentToken(ParserErrorCode.MISSING_STATEMENT);
- // TODO(brianwilkerson) Recover from this error.
- return astFactory
- .emptyStatement(_createSyntheticToken(TokenType.SEMICOLON));
- }
- } else if (keyword == Keyword.CONST) {
- Token next = _currentToken.next;
- if (next.matchesAny(const <TokenType>[
- TokenType.LT,
- TokenType.OPEN_CURLY_BRACKET,
- TokenType.OPEN_SQUARE_BRACKET,
- TokenType.INDEX
- ])) {
- return astFactory.expressionStatement(
- parseExpression2(), _expect(TokenType.SEMICOLON));
- } else if (_tokenMatches(next, TokenType.IDENTIFIER)) {
- Token afterType = skipTypeName(next);
- if (afterType != null) {
- if (_tokenMatches(afterType, TokenType.OPEN_PAREN) ||
- (_tokenMatches(afterType, TokenType.PERIOD) &&
- _tokenMatches(afterType.next, TokenType.IDENTIFIER) &&
- _tokenMatches(afterType.next.next, TokenType.OPEN_PAREN))) {
- return astFactory.expressionStatement(
- parseExpression2(), _expect(TokenType.SEMICOLON));
- }
- }
- }
- return parseVariableDeclarationStatementAfterMetadata(
- commentAndMetadata);
- } else if (keyword == Keyword.NEW ||
- keyword == Keyword.TRUE ||
- keyword == Keyword.FALSE ||
- keyword == Keyword.NULL ||
- keyword == Keyword.SUPER ||
- keyword == Keyword.THIS) {
- return astFactory.expressionStatement(
- parseExpression2(), _expect(TokenType.SEMICOLON));
- } else {
- //
- // We have found an error of some kind. Try to recover.
- //
- _reportErrorForCurrentToken(ParserErrorCode.MISSING_STATEMENT);
- return astFactory
- .emptyStatement(_createSyntheticToken(TokenType.SEMICOLON));
- }
- } else if (_atGenericFunctionTypeAfterReturnType(_currentToken)) {
- TypeAnnotation returnType = parseTypeAnnotation(false);
- Token next = _currentToken.next;
- if (_matchesIdentifier() &&
- next.matchesAny(const <TokenType>[
- TokenType.OPEN_PAREN,
- TokenType.OPEN_CURLY_BRACKET,
- TokenType.FUNCTION,
- TokenType.LT
- ])) {
- return _parseFunctionDeclarationStatementAfterReturnType(
- commentAndMetadata, returnType);
- } else if (_matchesIdentifier() &&
- next.matchesAny(const <TokenType>[
- TokenType.EQ,
- TokenType.COMMA,
- TokenType.SEMICOLON
- ])) {
- return _parseVariableDeclarationStatementAfterType(
- commentAndMetadata, null, returnType);
- } else {
- //
- // We have found an error of some kind. Try to recover.
- //
- if (_matches(TokenType.CLOSE_CURLY_BRACKET)) {
- //
- // We appear to have found an incomplete statement at the end of a
- // block. Parse it as a variable declaration.
- //
- return _parseVariableDeclarationStatementAfterType(
- commentAndMetadata, null, returnType);
- }
- _reportErrorForCurrentToken(ParserErrorCode.MISSING_STATEMENT);
- // TODO(brianwilkerson) Recover from this error.
- return astFactory
- .emptyStatement(_createSyntheticToken(TokenType.SEMICOLON));
- }
- } else if (_inGenerator && _matchesKeyword(Keyword.YIELD)) {
- return parseYieldStatement();
- } else if (_inAsync && _matchesKeyword(Keyword.AWAIT)) {
- if (_tokenMatchesKeyword(_peek(), Keyword.FOR)) {
- return parseForStatement();
- }
- return astFactory.expressionStatement(
- parseExpression2(), _expect(TokenType.SEMICOLON));
- } else if (_matchesKeyword(Keyword.AWAIT) &&
- _tokenMatchesKeyword(_peek(), Keyword.FOR)) {
- Token awaitToken = _currentToken;
- Statement statement = parseForStatement();
- if (!(statement is ForStatement && statement.forLoopParts is ForParts)) {
- _reportErrorForToken(
- CompileTimeErrorCode.ASYNC_FOR_IN_WRONG_CONTEXT, awaitToken);
- }
- return statement;
- } else if (type == TokenType.SEMICOLON) {
- return parseEmptyStatement();
- } else if (isInitializedVariableDeclaration()) {
- return parseVariableDeclarationStatementAfterMetadata(commentAndMetadata);
- } else if (isFunctionDeclaration()) {
- return parseFunctionDeclarationStatement();
- } else if (type == TokenType.CLOSE_CURLY_BRACKET) {
- _reportErrorForCurrentToken(ParserErrorCode.MISSING_STATEMENT);
- return astFactory
- .emptyStatement(_createSyntheticToken(TokenType.SEMICOLON));
- } else {
- return astFactory.expressionStatement(
- parseExpression2(), _expect(TokenType.SEMICOLON));
- }
- }
+ Expression parsePostfixExpression() => parseExpression2();
- /// Parse a normal formal parameter. Return the normal formal parameter that
- /// was parsed.
- ///
- /// normalFormalParameter ::=
- /// functionSignature
- /// | fieldFormalParameter
- /// | simpleFormalParameter
- ///
- /// functionSignature:
- /// metadata returnType? identifier typeParameters? formalParameterList
- ///
- /// fieldFormalParameter ::=
- /// metadata finalConstVarOrType? 'this' '.' identifier
- ///
- /// simpleFormalParameter ::=
- /// declaredIdentifier
- /// | metadata identifier
- NormalFormalParameter parseNormalFormalParameter(
- {bool inFunctionType = false}) {
- Token covariantKeyword;
- CommentAndMetadata commentAndMetadata = parseCommentAndMetadata();
- if (_matchesKeyword(Keyword.COVARIANT)) {
- // Check to ensure that 'covariant' isn't being used as the parameter name.
- Token next = _peek();
- if (_tokenMatchesKeyword(next, Keyword.FINAL) ||
- _tokenMatchesKeyword(next, Keyword.CONST) ||
- _tokenMatchesKeyword(next, Keyword.VAR) ||
- _tokenMatchesKeyword(next, Keyword.THIS) ||
- _tokenMatchesKeyword(next, Keyword.VOID) ||
- _tokenMatchesIdentifier(next)) {
- covariantKeyword = getAndAdvance();
- }
- }
- FinalConstVarOrType holder = parseFinalConstVarOrType(!inFunctionType,
- inFunctionType: inFunctionType);
- Token thisKeyword;
- Token period;
- if (_matchesKeyword(Keyword.THIS)) {
- thisKeyword = getAndAdvance();
- period = _expect(TokenType.PERIOD);
- }
- if (!_matchesIdentifier() && inFunctionType) {
- return astFactory.simpleFormalParameter2(
- comment: commentAndMetadata.comment,
- metadata: commentAndMetadata.metadata,
- covariantKeyword: covariantKeyword,
- keyword: holder.keyword,
- type: holder.type,
- identifier: null);
- }
- SimpleIdentifier identifier = parseSimpleIdentifier();
- TypeParameterList typeParameters = _parseGenericMethodTypeParameters();
- if (_matches(TokenType.OPEN_PAREN)) {
- FormalParameterList parameters = _parseFormalParameterListUnchecked();
- if (thisKeyword == null) {
- if (holder.keyword != null) {
- _reportErrorForToken(
- ParserErrorCode.FUNCTION_TYPED_PARAMETER_VAR, holder.keyword);
- }
- return astFactory.functionTypedFormalParameter2(
- comment: commentAndMetadata.comment,
- metadata: commentAndMetadata.metadata,
- covariantKeyword: covariantKeyword,
- returnType: holder.type,
- identifier: astFactory.simpleIdentifier(identifier.token,
- isDeclaration: true),
- typeParameters: typeParameters,
- parameters: parameters);
- } else {
- return astFactory.fieldFormalParameter2(
- comment: commentAndMetadata.comment,
- metadata: commentAndMetadata.metadata,
- covariantKeyword: covariantKeyword,
- keyword: holder.keyword,
- type: holder.type,
- thisKeyword: thisKeyword,
- period: period,
- identifier: identifier,
- typeParameters: typeParameters,
- parameters: parameters);
- }
- } else if (typeParameters != null) {
- // TODO(brianwilkerson) Report an error. It looks like a function-typed
- // parameter with no parameter list.
- //_reportErrorForToken(ParserErrorCode.MISSING_PARAMETERS, typeParameters.endToken);
- }
- TypeAnnotation type = holder.type;
- if (type != null &&
- holder.keyword != null &&
- _tokenMatchesKeyword(holder.keyword, Keyword.VAR)) {
- _reportErrorForToken(ParserErrorCode.VAR_AND_TYPE, holder.keyword);
- }
- if (thisKeyword != null) {
- // TODO(brianwilkerson) If there are type parameters but no parameters,
- // should we create a synthetic empty parameter list here so we can
- // capture the type parameters?
- return astFactory.fieldFormalParameter2(
- comment: commentAndMetadata.comment,
- metadata: commentAndMetadata.metadata,
- covariantKeyword: covariantKeyword,
- keyword: holder.keyword,
- type: type,
- thisKeyword: thisKeyword,
- period: period,
- identifier: identifier);
- }
- return astFactory.simpleFormalParameter2(
- comment: commentAndMetadata.comment,
- metadata: commentAndMetadata.metadata,
- covariantKeyword: covariantKeyword,
- keyword: holder.keyword,
- type: type,
- identifier:
- astFactory.simpleIdentifier(identifier.token, isDeclaration: true));
- }
+ Identifier parsePrefixedIdentifier() => parseExpression2() as Identifier;
- /// Parse an operator declaration. The [commentAndMetadata] is the
- /// documentation comment and metadata to be associated with the declaration.
- /// The [externalKeyword] is the 'external' token. The [returnType] is the
- /// return type that has already been parsed, or `null` if there was no return
- /// type. Return the operator declaration that was parsed.
- ///
- /// operatorDeclaration ::=
- /// operatorSignature (';' | functionBody)
- ///
- /// operatorSignature ::=
- /// 'external'? returnType? 'operator' operator formalParameterList
- MethodDeclaration parseOperator(CommentAndMetadata commentAndMetadata,
- Token externalKeyword, TypeName returnType) {
- Token operatorKeyword;
- if (_matchesKeyword(Keyword.OPERATOR)) {
- operatorKeyword = getAndAdvance();
- } else {
- _reportErrorForToken(
- ParserErrorCode.MISSING_KEYWORD_OPERATOR, _currentToken);
- operatorKeyword = _createSyntheticKeyword(Keyword.OPERATOR);
- }
- return _parseOperatorAfterKeyword(
- commentAndMetadata, externalKeyword, returnType, operatorKeyword);
- }
-
- /// Parse a part or part-of directive. The [commentAndMetadata] is the
- /// metadata to be associated with the directive. Return the part or part-of
- /// directive that was parsed.
- ///
- /// This method assumes that the current token matches `Keyword.PART`.
- ///
- /// partDirective ::=
- /// metadata 'part' stringLiteral ';'
- ///
- /// partOfDirective ::=
- /// metadata 'part' 'of' identifier ';'
- Directive parsePartOrPartOfDirective(CommentAndMetadata commentAndMetadata) {
- if (_tokenMatchesKeyword(_peek(), Keyword.OF)) {
- return _parsePartOfDirective(commentAndMetadata);
- }
- return _parsePartDirective(commentAndMetadata);
- }
-
- /// Parse a postfix expression. Return the postfix expression that was parsed.
- ///
- /// postfixExpression ::=
- /// assignableExpression postfixOperator
- /// | primary selector*
- ///
- /// selector ::=
- /// assignableSelector
- /// | argumentPart
- Expression parsePostfixExpression() {
- Expression operand = parseAssignableExpression(true);
- TokenType type = _currentToken.type;
- if (type == TokenType.OPEN_SQUARE_BRACKET ||
- type == TokenType.PERIOD ||
- type == TokenType.QUESTION_PERIOD ||
- type == TokenType.OPEN_PAREN ||
- type == TokenType.LT ||
- type == TokenType.INDEX) {
- do {
- if (_isLikelyArgumentList()) {
- TypeArgumentList typeArguments = _parseOptionalTypeArguments();
- ArgumentList argumentList = parseArgumentList();
- Expression currentOperand = operand;
- if (currentOperand is PropertyAccess) {
- operand = astFactory.methodInvocation(
- currentOperand.target,
- currentOperand.operator,
- currentOperand.propertyName,
- typeArguments,
- argumentList);
- } else {
- operand = astFactory.functionExpressionInvocation(
- operand, typeArguments, argumentList);
- }
- } else if (enableOptionalNewAndConst &&
- operand is Identifier &&
- _isLikelyNamedInstanceCreation()) {
- TypeArgumentList typeArguments = _parseOptionalTypeArguments();
- Token period = _expect(TokenType.PERIOD);
- SimpleIdentifier name = parseSimpleIdentifier();
- ArgumentList argumentList = parseArgumentList();
- TypeName typeName = astFactory.typeName(operand, typeArguments);
- operand = astFactory.instanceCreationExpression(null,
- astFactory.constructorName(typeName, period, name), argumentList);
- } else {
- operand = parseAssignableSelector(operand, true);
- }
- type = _currentToken.type;
- } while (type == TokenType.OPEN_SQUARE_BRACKET ||
- type == TokenType.PERIOD ||
- type == TokenType.QUESTION_PERIOD ||
- type == TokenType.OPEN_PAREN ||
- type == TokenType.INDEX);
- return operand;
- }
- if (!_currentToken.type.isIncrementOperator) {
- return operand;
- }
- _ensureAssignable(operand);
- Token operator = getAndAdvance();
- return astFactory.postfixExpression(operand, operator);
- }
-
- /// Parse a prefixed identifier. Return the prefixed identifier that was
- /// parsed.
- ///
- /// prefixedIdentifier ::=
- /// identifier ('.' identifier)?
- Identifier parsePrefixedIdentifier() {
- return _parsePrefixedIdentifierAfterIdentifier(parseSimpleIdentifier());
- }
-
- /// Parse a primary expression. Return the primary expression that was parsed.
- ///
- /// primary ::=
- /// thisExpression
- /// | 'super' unconditionalAssignableSelector
- /// | functionExpression
- /// | literal
- /// | identifier
- /// | newExpression
- /// | constObjectExpression
- /// | '(' expression ')'
- /// | argumentDefinitionTest
- ///
- /// literal ::=
- /// nullLiteral
- /// | booleanLiteral
- /// | numericLiteral
- /// | stringLiteral
- /// | symbolLiteral
- /// | mapLiteral
- /// | listLiteral
Expression parsePrimaryExpression() {
- if (_matchesIdentifier()) {
- // TODO(brianwilkerson) The code below was an attempt to recover from an
- // error case, but it needs to be applied as a recovery only after we
- // know that parsing it as an identifier doesn't work. Leaving the code as
- // a reminder of how to recover.
-// if (isFunctionExpression(_peek())) {
-// //
-// // Function expressions were allowed to have names at one point, but this is now illegal.
-// //
-// reportError(ParserErrorCode.NAMED_FUNCTION_EXPRESSION, getAndAdvance());
-// return parseFunctionExpression();
-// }
- return _parsePrefixedIdentifierUnchecked();
- }
- TokenType type = _currentToken.type;
- if (type == TokenType.STRING) {
- return parseStringLiteral();
- } else if (type == TokenType.INT) {
- Token token = getAndAdvance();
- int value;
- try {
- value = int.parse(token.lexeme);
- } on FormatException {
- // The invalid format should have been reported by the scanner.
- }
- return astFactory.integerLiteral(token, value);
- }
- Keyword keyword = _currentToken.keyword;
- if (keyword == Keyword.NULL) {
- return astFactory.nullLiteral(getAndAdvance());
- } else if (keyword == Keyword.NEW) {
- return parseNewExpression();
- } else if (keyword == Keyword.THIS) {
- return astFactory.thisExpression(getAndAdvance());
- } else if (keyword == Keyword.SUPER) {
- return parseAssignableSelector(
- astFactory.superExpression(getAndAdvance()), false,
- allowConditional: false);
- } else if (keyword == Keyword.FALSE) {
- return astFactory.booleanLiteral(getAndAdvance(), false);
- } else if (keyword == Keyword.TRUE) {
- return astFactory.booleanLiteral(getAndAdvance(), true);
- }
- if (type == TokenType.DOUBLE) {
- Token token = getAndAdvance();
- double value = 0.0;
- try {
- value = double.parse(token.lexeme);
- } on FormatException {
- // The invalid format should have been reported by the scanner.
- }
- return astFactory.doubleLiteral(token, value);
- } else if (type == TokenType.HEXADECIMAL) {
- Token token = getAndAdvance();
- int value;
- try {
- value = int.parse(token.lexeme);
- } on FormatException {
- // The invalid format should have been reported by the scanner.
- }
- return astFactory.integerLiteral(token, value);
- } else if (keyword == Keyword.CONST) {
- return parseConstExpression();
- } else if (type == TokenType.OPEN_PAREN) {
- if (isFunctionExpression(_currentToken)) {
- return parseFunctionExpression();
- }
- Token leftParenthesis = getAndAdvance();
- bool wasInInitializer = _inInitializer;
- _inInitializer = false;
- try {
- Expression expression = parseExpression2();
- Token rightParenthesis = _expect(TokenType.CLOSE_PAREN);
- return astFactory.parenthesizedExpression(
- leftParenthesis, expression, rightParenthesis);
- } finally {
- _inInitializer = wasInInitializer;
- }
- } else if (type == TokenType.LT) {
- if (isFunctionExpression(currentToken)) {
- return parseFunctionExpression();
- }
- return parseListOrMapLiteral(null);
- } else if (type == TokenType.OPEN_CURLY_BRACKET) {
- return parseMapLiteral(null, null);
- } else if (type == TokenType.OPEN_SQUARE_BRACKET ||
- type == TokenType.INDEX) {
- return parseListLiteral(null, null);
- } else if (type == TokenType.QUESTION &&
- _tokenMatches(_peek(), TokenType.IDENTIFIER)) {
- _reportErrorForCurrentToken(
- ParserErrorCode.UNEXPECTED_TOKEN, [_currentToken.lexeme]);
- _advance();
- return parsePrimaryExpression();
- } else if (keyword == Keyword.VOID) {
- //
- // Recover from having a return type of "void" where a return type is not
- // expected.
- //
- // TODO(brianwilkerson) Improve this error message.
- _reportErrorForCurrentToken(
- ParserErrorCode.UNEXPECTED_TOKEN, [_currentToken.lexeme]);
- _advance();
- return parsePrimaryExpression();
- } else if (type == TokenType.HASH) {
- return parseSymbolLiteral();
- } else {
- _reportErrorForCurrentToken(ParserErrorCode.MISSING_IDENTIFIER);
- return createSyntheticIdentifier();
- }
+ currentToken = fastaParser
+ .parsePrimary(fastaParser.syntheticPreviousToken(currentToken),
+ fasta.IdentifierContext.expression)
+ .next;
+ return astBuilder.pop() as Expression;
}
- /// Parse a redirecting constructor invocation. The flag [hasPeriod] should be
- /// `true` if the `this` is followed by a period. Return the redirecting
- /// constructor invocation that was parsed.
- ///
- /// This method assumes that the current token matches `Keyword.THIS`.
- ///
- /// redirectingConstructorInvocation ::=
- /// 'this' ('.' identifier)? arguments
- RedirectingConstructorInvocation parseRedirectingConstructorInvocation(
- bool hasPeriod) {
- Token keyword = getAndAdvance();
- Token period;
- SimpleIdentifier constructorName;
- if (hasPeriod) {
- period = getAndAdvance();
- if (_matchesIdentifier()) {
- constructorName = _parseSimpleIdentifierUnchecked(isDeclaration: false);
- } else {
- _reportErrorForCurrentToken(ParserErrorCode.MISSING_IDENTIFIER);
- constructorName = createSyntheticIdentifier(isDeclaration: false);
- _advance();
- }
- }
- ArgumentList argumentList = _parseArgumentListChecked();
- return astFactory.redirectingConstructorInvocation(
- keyword, period, constructorName, argumentList);
- }
+ Expression parseRelationalExpression() => parseExpression2();
- /// Parse a relational expression. Return the relational expression that was
- /// parsed.
- ///
- /// relationalExpression ::=
- /// bitwiseOrExpression ('is' '!'? type | 'as' type | relationalOperator bitwiseOrExpression)?
- /// | 'super' relationalOperator bitwiseOrExpression
- Expression parseRelationalExpression() {
- if (_currentToken.keyword == Keyword.SUPER &&
- _currentToken.next.type.isRelationalOperator) {
- Expression expression = astFactory.superExpression(getAndAdvance());
- Token operator = getAndAdvance();
- return astFactory.binaryExpression(
- expression, operator, parseBitwiseOrExpression());
- }
- Expression expression = parseBitwiseOrExpression();
- Keyword keyword = _currentToken.keyword;
- if (keyword == Keyword.AS) {
- Token asOperator = getAndAdvance();
- return astFactory.asExpression(
- expression, asOperator, parseTypeNotVoid(true));
- } else if (keyword == Keyword.IS) {
- Token isOperator = getAndAdvance();
- Token notOperator;
- if (_matches(TokenType.BANG)) {
- notOperator = getAndAdvance();
- }
- TypeAnnotation type = parseTypeNotVoid(true);
- return astFactory.isExpression(expression, isOperator, notOperator, type);
- } else if (_currentToken.type.isRelationalOperator) {
- Token operator = getAndAdvance();
- return astFactory.binaryExpression(
- expression, operator, parseBitwiseOrExpression());
- }
- return expression;
- }
+ Expression parseRethrowExpression() => parseExpression2();
- /// Parse a rethrow expression. Return the rethrow expression that was parsed.
- ///
- /// This method assumes that the current token matches `Keyword.RETHROW`.
- ///
- /// rethrowExpression ::=
- /// 'rethrow'
- Expression parseRethrowExpression() =>
- astFactory.rethrowExpression(getAndAdvance());
+ Expression parseShiftExpression() => parseExpression2();
- /// Parse a return statement. Return the return statement that was parsed.
- ///
- /// This method assumes that the current token matches `Keyword.RETURN`.
- ///
- /// returnStatement ::=
- /// 'return' expression? ';'
- Statement parseReturnStatement() {
- Token returnKeyword = getAndAdvance();
- if (_matches(TokenType.SEMICOLON)) {
- return astFactory.returnStatement(returnKeyword, null, getAndAdvance());
- }
- Expression expression = parseExpression2();
- Token semicolon = _expect(TokenType.SEMICOLON);
- return astFactory.returnStatement(returnKeyword, expression, semicolon);
- }
-
- /// Parse a setter. The [commentAndMetadata] is the documentation comment and
- /// metadata to be associated with the declaration. The [externalKeyword] is
- /// the 'external' token. The [staticKeyword] is the static keyword, or `null`
- /// if the setter is not static. The [returnType] is the return type that has
- /// already been parsed, or `null` if there was no return type. Return the
- /// setter that was parsed.
- ///
- /// This method assumes that the current token matches `Keyword.SET`.
- ///
- /// setter ::=
- /// setterSignature functionBody?
- ///
- /// setterSignature ::=
- /// 'external'? 'static'? returnType? 'set' identifier formalParameterList
- MethodDeclaration parseSetter(CommentAndMetadata commentAndMetadata,
- Token externalKeyword, Token staticKeyword, TypeAnnotation returnType) {
- Token propertyKeyword = getAndAdvance();
- SimpleIdentifier name = parseSimpleIdentifier(isDeclaration: true);
- FormalParameterList parameters = parseFormalParameterList();
- _validateFormalParameterList(parameters);
- FunctionBody body = parseFunctionBody(
- externalKeyword != null || staticKeyword == null,
- ParserErrorCode.STATIC_SETTER_WITHOUT_BODY,
- false);
- if (externalKeyword != null && body is! EmptyFunctionBody) {
- _reportErrorForCurrentToken(ParserErrorCode.EXTERNAL_SETTER_WITH_BODY);
- }
- return astFactory.methodDeclaration(
- commentAndMetadata.comment,
- commentAndMetadata.metadata,
- externalKeyword,
- staticKeyword,
- returnType,
- propertyKeyword,
- null,
- name,
- null,
- parameters,
- body);
- }
-
- /// Parse a shift expression. Return the shift expression that was parsed.
- ///
- /// shiftExpression ::=
- /// additiveExpression (shiftOperator additiveExpression)*
- /// | 'super' (shiftOperator additiveExpression)+
- Expression parseShiftExpression() {
- Expression expression;
- if (_currentToken.keyword == Keyword.SUPER &&
- _currentToken.next.type.isShiftOperator) {
- expression = astFactory.superExpression(getAndAdvance());
- } else {
- expression = parseAdditiveExpression();
- }
- while (_currentToken.type.isShiftOperator) {
- expression = astFactory.binaryExpression(
- expression, getAndAdvance(), parseAdditiveExpression());
- }
- return expression;
- }
-
- /// Parse a simple identifier. Return the simple identifier that was parsed.
- ///
- /// identifier ::=
- /// IDENTIFIER
SimpleIdentifier parseSimpleIdentifier(
- {bool allowKeyword = false, bool isDeclaration = false}) {
- if (_matchesIdentifier() ||
- (allowKeyword && _tokenMatchesIdentifierOrKeyword(_currentToken))) {
- return _parseSimpleIdentifierUnchecked(isDeclaration: isDeclaration);
- }
- _reportErrorForCurrentToken(ParserErrorCode.MISSING_IDENTIFIER);
- return createSyntheticIdentifier(isDeclaration: isDeclaration);
- }
+ {bool allowKeyword = false, bool isDeclaration = false}) =>
+ parseExpression2() as SimpleIdentifier;
- /// Parse a statement, starting with the given [token]. Return the statement
- /// that was parsed, or `null` if the tokens do not represent a recognizable
- /// statement.
Statement parseStatement(Token token) {
- _currentToken = token;
+ currentToken = token;
return parseStatement2();
}
- /// Parse a statement. Return the statement that was parsed.
- ///
- /// statement ::=
- /// label* nonLabeledStatement
Statement parseStatement2() {
- if (_treeDepth > _MAX_TREE_DEPTH) {
- throw _TooDeepTreeError();
- }
- _treeDepth++;
- try {
- List<Label> labels;
- while (
- _matchesIdentifier() && _currentToken.next.type == TokenType.COLON) {
- Label label = parseLabel(isDeclaration: true);
- if (labels == null) {
- labels = <Label>[label];
- } else {
- labels.add(label);
- }
- }
- Statement statement = parseNonLabeledStatement();
- if (labels == null) {
- return statement;
- }
- return astFactory.labeledStatement(labels, statement);
- } finally {
- _treeDepth--;
- }
+ currentToken = fastaParser
+ .parseStatement(fastaParser.syntheticPreviousToken(currentToken))
+ .next;
+ return astBuilder.pop() as Statement;
}
- /// Parse a sequence of statements, starting with the given [token]. Return
- /// the statements that were parsed, or `null` if the tokens do not represent
- /// a recognizable sequence of statements.
- List<Statement> parseStatements(Token token) {
- _currentToken = token;
- return _parseStatementList();
+ StringLiteral parseStringLiteral() => parseExpression2() as StringLiteral;
+
+ SymbolLiteral parseSymbolLiteral() => parseExpression2() as SymbolLiteral;
+
+ Expression parseThrowExpression() => parseExpression2();
+
+ Expression parseThrowExpressionWithoutCascade() => parseExpression2();
+
+ AnnotatedNode parseTopLevelDeclaration(bool isDirective) {
+ currentToken = fastaParser.parseTopLevelDeclaration(currentToken);
+ return (isDirective ? astBuilder.directives : astBuilder.declarations)
+ .removeLast();
}
- /// Parse a string literal. Return the string literal that was parsed.
- ///
- /// stringLiteral ::=
- /// MULTI_LINE_STRING+
- /// | SINGLE_LINE_STRING+
- StringLiteral parseStringLiteral() {
- if (_matches(TokenType.STRING)) {
- return _parseStringLiteralUnchecked();
- }
- _reportErrorForCurrentToken(ParserErrorCode.EXPECTED_STRING_LITERAL);
- return createSyntheticStringLiteral();
- }
-
- /// Parse a super constructor invocation. Return the super constructor
- /// invocation that was parsed.
- ///
- /// This method assumes that the current token matches [Keyword.SUPER].
- ///
- /// superConstructorInvocation ::=
- /// 'super' ('.' identifier)? arguments
- SuperConstructorInvocation parseSuperConstructorInvocation() {
- Token keyword = getAndAdvance();
- Token period;
- SimpleIdentifier constructorName;
- if (_matches(TokenType.PERIOD)) {
- period = getAndAdvance();
- constructorName = parseSimpleIdentifier();
- }
- ArgumentList argumentList = _parseArgumentListChecked();
- return astFactory.superConstructorInvocation(
- keyword, period, constructorName, argumentList);
- }
-
- /// Parse a switch statement. Return the switch statement that was parsed.
- ///
- /// switchStatement ::=
- /// 'switch' '(' expression ')' '{' switchCase* defaultCase? '}'
- ///
- /// switchCase ::=
- /// label* ('case' expression ':') statements
- ///
- /// defaultCase ::=
- /// label* 'default' ':' statements
- SwitchStatement parseSwitchStatement() {
- bool wasInSwitch = _inSwitch;
- _inSwitch = true;
- try {
- HashSet<String> definedLabels = HashSet<String>();
- Token keyword = _expectKeyword(Keyword.SWITCH);
- Token leftParenthesis = _expect(TokenType.OPEN_PAREN);
- Expression expression = parseExpression2();
- Token rightParenthesis = _expect(TokenType.CLOSE_PAREN);
- Token leftBracket = _expect(TokenType.OPEN_CURLY_BRACKET);
- Token defaultKeyword;
- List<SwitchMember> members = <SwitchMember>[];
- TokenType type = _currentToken.type;
- while (type != TokenType.EOF && type != TokenType.CLOSE_CURLY_BRACKET) {
- List<Label> labels = <Label>[];
- while (
- _matchesIdentifier() && _tokenMatches(_peek(), TokenType.COLON)) {
- SimpleIdentifier identifier =
- _parseSimpleIdentifierUnchecked(isDeclaration: true);
- String label = identifier.token.lexeme;
- if (definedLabels.contains(label)) {
- _reportErrorForToken(
- ParserErrorCode.DUPLICATE_LABEL_IN_SWITCH_STATEMENT,
- identifier.token,
- [label]);
- } else {
- definedLabels.add(label);
- }
- Token colon = getAndAdvance();
- labels.add(astFactory.label(identifier, colon));
- }
- Keyword keyword = _currentToken.keyword;
- if (keyword == Keyword.CASE) {
- Token caseKeyword = getAndAdvance();
- Expression caseExpression = parseExpression2();
- Token colon = _expect(TokenType.COLON);
- members.add(astFactory.switchCase(labels, caseKeyword, caseExpression,
- colon, _parseStatementList()));
- if (defaultKeyword != null) {
- _reportErrorForToken(
- ParserErrorCode.SWITCH_HAS_CASE_AFTER_DEFAULT_CASE,
- caseKeyword);
- }
- } else if (keyword == Keyword.DEFAULT) {
- if (defaultKeyword != null) {
- _reportErrorForToken(
- ParserErrorCode.SWITCH_HAS_MULTIPLE_DEFAULT_CASES, _peek());
- }
- defaultKeyword = getAndAdvance();
- Token colon = _expect(TokenType.COLON);
- members.add(astFactory.switchDefault(
- labels, defaultKeyword, colon, _parseStatementList()));
- } else {
- // We need to advance, otherwise we could end up in an infinite loop,
- // but this could be a lot smarter about recovering from the error.
- _reportErrorForCurrentToken(ParserErrorCode.EXPECTED_CASE_OR_DEFAULT);
- bool atEndOrNextMember() {
- TokenType type = _currentToken.type;
- if (type == TokenType.EOF ||
- type == TokenType.CLOSE_CURLY_BRACKET) {
- return true;
- }
- Keyword keyword = _currentToken.keyword;
- return keyword == Keyword.CASE || keyword == Keyword.DEFAULT;
- }
-
- while (!atEndOrNextMember()) {
- _advance();
- }
- }
- type = _currentToken.type;
- }
- Token rightBracket = _expect(TokenType.CLOSE_CURLY_BRACKET);
- return astFactory.switchStatement(keyword, leftParenthesis, expression,
- rightParenthesis, leftBracket, members, rightBracket);
- } finally {
- _inSwitch = wasInSwitch;
- }
- }
-
- /// Parse a symbol literal. Return the symbol literal that was parsed.
- ///
- /// This method assumes that the current token matches [TokenType.HASH].
- ///
- /// symbolLiteral ::=
- /// '#' identifier ('.' identifier)*
- SymbolLiteral parseSymbolLiteral() {
- Token poundSign = getAndAdvance();
- List<Token> components = <Token>[];
- if (_matchesIdentifier()) {
- components.add(getAndAdvance());
- while (_optional(TokenType.PERIOD)) {
- if (_matchesIdentifier()) {
- components.add(getAndAdvance());
- } else {
- _reportErrorForCurrentToken(ParserErrorCode.MISSING_IDENTIFIER);
- components.add(_createSyntheticToken(TokenType.IDENTIFIER));
- break;
- }
- }
- } else if (_currentToken.isOperator) {
- components.add(getAndAdvance());
- } else if (_matchesKeyword(Keyword.VOID)) {
- components.add(getAndAdvance());
- } else {
- _reportErrorForCurrentToken(ParserErrorCode.MISSING_IDENTIFIER);
- components.add(_createSyntheticToken(TokenType.IDENTIFIER));
- }
- return astFactory.symbolLiteral(poundSign, components);
- }
-
- /// Parse a throw expression. Return the throw expression that was parsed.
- ///
- /// This method assumes that the current token matches [Keyword.THROW].
- ///
- /// throwExpression ::=
- /// 'throw' expression
- Expression parseThrowExpression() {
- Token keyword = getAndAdvance();
- TokenType type = _currentToken.type;
- if (type == TokenType.SEMICOLON || type == TokenType.CLOSE_PAREN) {
- _reportErrorForToken(
- ParserErrorCode.MISSING_EXPRESSION_IN_THROW, _currentToken);
- return astFactory.throwExpression(keyword, createSyntheticIdentifier());
- }
- Expression expression = parseExpression2();
- return astFactory.throwExpression(keyword, expression);
- }
-
- /// Parse a throw expression. Return the throw expression that was parsed.
- ///
- /// This method assumes that the current token matches [Keyword.THROW].
- ///
- /// throwExpressionWithoutCascade ::=
- /// 'throw' expressionWithoutCascade
- Expression parseThrowExpressionWithoutCascade() {
- Token keyword = getAndAdvance();
- TokenType type = _currentToken.type;
- if (type == TokenType.SEMICOLON || type == TokenType.CLOSE_PAREN) {
- _reportErrorForToken(
- ParserErrorCode.MISSING_EXPRESSION_IN_THROW, _currentToken);
- return astFactory.throwExpression(keyword, createSyntheticIdentifier());
- }
- Expression expression = parseExpressionWithoutCascade();
- return astFactory.throwExpression(keyword, expression);
- }
-
- /// Parse a try statement. Return the try statement that was parsed.
- ///
- /// This method assumes that the current token matches [Keyword.TRY].
- ///
- /// tryStatement ::=
- /// 'try' block (onPart+ finallyPart? | finallyPart)
- ///
- /// onPart ::=
- /// catchPart block
- /// | 'on' type catchPart? block
- ///
- /// catchPart ::=
- /// 'catch' '(' identifier (',' identifier)? ')'
- ///
- /// finallyPart ::=
- /// 'finally' block
- Statement parseTryStatement() {
- Token tryKeyword = getAndAdvance();
- Block body = _parseBlockChecked();
- List<CatchClause> catchClauses = <CatchClause>[];
- Block finallyClause;
- while (_matchesKeyword(Keyword.ON) || _matchesKeyword(Keyword.CATCH)) {
- Token onKeyword;
- TypeName exceptionType;
- if (_matchesKeyword(Keyword.ON)) {
- onKeyword = getAndAdvance();
- exceptionType = parseTypeNotVoid(false);
- }
- Token catchKeyword;
- Token leftParenthesis;
- SimpleIdentifier exceptionParameter;
- Token comma;
- SimpleIdentifier stackTraceParameter;
- Token rightParenthesis;
- if (_matchesKeyword(Keyword.CATCH)) {
- catchKeyword = getAndAdvance();
- leftParenthesis = _expect(TokenType.OPEN_PAREN);
- exceptionParameter = parseSimpleIdentifier(isDeclaration: true);
- if (_matches(TokenType.COMMA)) {
- comma = getAndAdvance();
- stackTraceParameter = parseSimpleIdentifier(isDeclaration: true);
- }
- rightParenthesis = _expect(TokenType.CLOSE_PAREN);
- }
- Block catchBody = _parseBlockChecked();
- catchClauses.add(astFactory.catchClause(
- onKeyword,
- exceptionType,
- catchKeyword,
- leftParenthesis,
- exceptionParameter,
- comma,
- stackTraceParameter,
- rightParenthesis,
- catchBody));
- }
- Token finallyKeyword;
- if (_matchesKeyword(Keyword.FINALLY)) {
- finallyKeyword = getAndAdvance();
- finallyClause = _parseBlockChecked();
- } else if (catchClauses.isEmpty) {
- _reportErrorForCurrentToken(ParserErrorCode.MISSING_CATCH_OR_FINALLY);
- }
- return astFactory.tryStatement(
- tryKeyword, body, catchClauses, finallyKeyword, finallyClause);
- }
-
- /// Parse a type alias. The [commentAndMetadata] is the metadata to be
- /// associated with the member. Return the type alias that was parsed.
- ///
- /// This method assumes that the current token matches [Keyword.TYPEDEF].
- ///
- /// typeAlias ::=
- /// 'typedef' typeAliasBody
- /// | genericTypeAlias
- ///
- /// typeAliasBody ::=
- /// functionTypeAlias
- ///
- /// functionTypeAlias ::=
- /// functionPrefix typeParameterList? formalParameterList ';'
- ///
- /// functionPrefix ::=
- /// returnType? name
- TypeAlias parseTypeAlias(CommentAndMetadata commentAndMetadata) {
- Token keyword = getAndAdvance();
- if (_matchesIdentifier()) {
- Token next = _peek();
- if (_tokenMatches(next, TokenType.LT)) {
- next = _skipTypeParameterList(next);
- if (next != null && _tokenMatches(next, TokenType.EQ)) {
- TypeAlias typeAlias =
- parseGenericTypeAlias(commentAndMetadata, keyword);
- return typeAlias;
- }
- } else if (_tokenMatches(next, TokenType.EQ)) {
- TypeAlias typeAlias =
- parseGenericTypeAlias(commentAndMetadata, keyword);
- return typeAlias;
- }
- }
- return _parseFunctionTypeAlias(commentAndMetadata, keyword);
- }
-
- /// Parse a type.
- ///
- /// type ::=
- /// typeWithoutFunction
- /// | functionType
TypeAnnotation parseTypeAnnotation(bool inExpression) {
- TypeAnnotation type;
- if (_atGenericFunctionTypeAfterReturnType(_currentToken)) {
- // Generic function type with no return type.
- type = parseGenericFunctionTypeAfterReturnType(null);
- } else {
- type = parseTypeWithoutFunction(inExpression);
- }
- while (_atGenericFunctionTypeAfterReturnType(_currentToken)) {
- type = parseGenericFunctionTypeAfterReturnType(type);
- }
- return type;
+ Token previous = fastaParser.syntheticPreviousToken(currentToken);
+ currentToken = fasta
+ .computeType(previous, true, !inExpression)
+ .parseType(previous, fastaParser)
+ .next;
+ return astBuilder.pop() as TypeAnnotation;
}
- /// Parse a list of type arguments. Return the type argument list that was
- /// parsed.
- ///
- /// This method assumes that the current token matches `TokenType.LT`.
- ///
- /// typeArguments ::=
- /// '<' typeList '>'
- ///
- /// typeList ::=
- /// type (',' type)*
TypeArgumentList parseTypeArgumentList() {
- Token leftBracket = getAndAdvance();
- List<TypeAnnotation> arguments = <TypeAnnotation>[
- parseTypeAnnotation(false)
- ];
- while (_optional(TokenType.COMMA)) {
- arguments.add(parseTypeAnnotation(false));
- }
- Token rightBracket = _expectGt();
- return astFactory.typeArgumentList(leftBracket, arguments, rightBracket);
+ Token previous = fastaParser.syntheticPreviousToken(currentToken);
+ currentToken = fasta
+ .computeTypeParamOrArg(previous)
+ .parseArguments(previous, fastaParser)
+ .next;
+ return astBuilder.pop() as TypeArgumentList;
}
- /// Parse a type which is not void and is not a function type. Return the type
- /// that was parsed.
- ///
- /// typeNotVoidWithoutFunction ::=
- /// qualified typeArguments?
- // TODO(eernst): Rename this to `parseTypeNotVoidWithoutFunction`?
- // Apparently, it was named `parseTypeName` before type arguments existed.
TypeName parseTypeName(bool inExpression) {
- return _parseTypeName(inExpression);
+ Token previous = fastaParser.syntheticPreviousToken(currentToken);
+ currentToken = fasta
+ .computeType(previous, true, !inExpression)
+ .parseType(previous, fastaParser)
+ .next;
+ return astBuilder.pop() as TypeName;
}
- /// Parse a type which is not `void`.
- ///
- /// typeNotVoid ::=
- /// functionType
- /// | typeNotVoidWithoutFunction
- TypeAnnotation parseTypeNotVoid(bool inExpression) {
- TypeAnnotation type;
- if (_atGenericFunctionTypeAfterReturnType(_currentToken)) {
- // Generic function type with no return type.
- type = parseGenericFunctionTypeAfterReturnType(null);
- } else if (_currentToken.keyword == Keyword.VOID &&
- _atGenericFunctionTypeAfterReturnType(_currentToken.next)) {
- type = astFactory.typeName(
- astFactory.simpleIdentifier(getAndAdvance()), null);
- } else {
- type = parseTypeName(inExpression);
- }
- while (_atGenericFunctionTypeAfterReturnType(_currentToken)) {
- type = parseGenericFunctionTypeAfterReturnType(type);
- }
- return type;
- }
-
- /// Parse a type parameter. Return the type parameter that was parsed.
- ///
- /// typeParameter ::=
- /// metadata name ('extends' bound)?
TypeParameter parseTypeParameter() {
- CommentAndMetadata commentAndMetadata = parseCommentAndMetadata();
- SimpleIdentifier name = parseSimpleIdentifier(isDeclaration: true);
- if (_matchesKeyword(Keyword.EXTENDS)) {
- Token keyword = getAndAdvance();
- TypeAnnotation bound = parseTypeNotVoid(false);
- return astFactory.typeParameter(commentAndMetadata.comment,
- commentAndMetadata.metadata, name, keyword, bound);
- }
- return astFactory.typeParameter(commentAndMetadata.comment,
- commentAndMetadata.metadata, name, null, null);
+ currentToken = SyntheticBeginToken(TokenType.LT, 0)
+ ..endGroup = SyntheticToken(TokenType.GT, 0)
+ ..setNext(currentToken);
+ appendToken(currentToken, currentToken.endGroup);
+ TypeParameterList typeParams = parseTypeParameterList();
+ return typeParams.typeParameters[0];
}
- /// Parse a list of type parameters. Return the list of type parameters that
- /// were parsed.
- ///
- /// This method assumes that the current token matches `TokenType.LT`.
- ///
- /// typeParameterList ::=
- /// '<' typeParameter (',' typeParameter)* '>'
TypeParameterList parseTypeParameterList() {
- Token leftBracket = getAndAdvance();
- List<TypeParameter> typeParameters = <TypeParameter>[parseTypeParameter()];
- while (_optional(TokenType.COMMA)) {
- typeParameters.add(parseTypeParameter());
- }
- Token rightBracket = _expectGt();
- return astFactory.typeParameterList(
- leftBracket, typeParameters, rightBracket);
+ Token token = fastaParser.syntheticPreviousToken(currentToken);
+ currentToken = fasta
+ .computeTypeParamOrArg(token, true)
+ .parseVariables(token, fastaParser)
+ .next;
+ return astBuilder.pop() as TypeParameterList;
}
- /// Parse a type which is not a function type.
- ///
- /// typeWithoutFunction ::=
- /// `void`
- /// | typeNotVoidWithoutFunction
- TypeAnnotation parseTypeWithoutFunction(bool inExpression) {
- if (_currentToken.keyword == Keyword.VOID) {
- return astFactory.typeName(
- astFactory.simpleIdentifier(getAndAdvance()), null);
- } else {
- return parseTypeName(inExpression);
- }
- }
-
- /// Parse a unary expression. Return the unary expression that was parsed.
- ///
- /// unaryExpression ::=
- /// prefixOperator unaryExpression
- /// | awaitExpression
- /// | postfixExpression
- /// | unaryOperator 'super'
- /// | '-' 'super'
- /// | incrementOperator assignableExpression
- Expression parseUnaryExpression() {
- TokenType type = _currentToken.type;
- if (type == TokenType.MINUS ||
- type == TokenType.BANG ||
- type == TokenType.TILDE) {
- Token operator = getAndAdvance();
- if (_matchesKeyword(Keyword.SUPER)) {
- TokenType nextType = _peek().type;
- if (nextType == TokenType.OPEN_SQUARE_BRACKET ||
- nextType == TokenType.PERIOD) {
- // "prefixOperator unaryExpression"
- // --> "prefixOperator postfixExpression"
- // --> "prefixOperator primary selector*"
- // --> "prefixOperator 'super' assignableSelector selector*"
- return astFactory.prefixExpression(operator, parseUnaryExpression());
- }
- return astFactory.prefixExpression(
- operator, astFactory.superExpression(getAndAdvance()));
- }
- return astFactory.prefixExpression(operator, parseUnaryExpression());
- } else if (_currentToken.type.isIncrementOperator) {
- Token operator = getAndAdvance();
- if (_matchesKeyword(Keyword.SUPER)) {
- TokenType nextType = _peek().type;
- if (nextType == TokenType.OPEN_SQUARE_BRACKET ||
- nextType == TokenType.PERIOD) {
- // --> "prefixOperator 'super' assignableSelector selector*"
- return astFactory.prefixExpression(operator, parseUnaryExpression());
- }
- //
- // Even though it is not valid to use an incrementing operator
- // ('++' or '--') before 'super', we can (and therefore must) interpret
- // "--super" as semantically equivalent to "-(-super)". Unfortunately,
- // we cannot do the same for "++super" because "+super" is also not
- // valid.
- //
- if (type == TokenType.MINUS_MINUS) {
- Token firstOperator = _createToken(operator, TokenType.MINUS);
- Token secondOperator = Token(TokenType.MINUS, operator.offset + 1);
- secondOperator.setNext(_currentToken);
- firstOperator.setNext(secondOperator);
- operator.previous.setNext(firstOperator);
- return astFactory.prefixExpression(
- firstOperator,
- astFactory.prefixExpression(
- secondOperator, astFactory.superExpression(getAndAdvance())));
- }
- // Invalid operator before 'super'
- _reportErrorForCurrentToken(
- ParserErrorCode.INVALID_OPERATOR_FOR_SUPER, [operator.lexeme]);
- return astFactory.prefixExpression(
- operator, astFactory.superExpression(getAndAdvance()));
- }
- return astFactory.prefixExpression(
- operator, parseAssignableExpression(false));
- } else if (type == TokenType.PLUS) {
- _reportErrorForCurrentToken(ParserErrorCode.MISSING_IDENTIFIER);
- return createSyntheticIdentifier();
- } else if (_inAsync && _matchesKeyword(Keyword.AWAIT)) {
- return parseAwaitExpression();
- }
- return parsePostfixExpression();
- }
-
- /// Parse a variable declaration. Return the variable declaration that was
- /// parsed.
- ///
- /// variableDeclaration ::=
- /// identifier ('=' expression)?
- VariableDeclaration parseVariableDeclaration() {
- // TODO(paulberry): prior to the fix for bug 23204, we permitted
- // annotations before variable declarations (e.g. "String @deprecated s;").
- // Although such constructions are prohibited by the spec, we may want to
- // consider handling them anyway to allow for better parser recovery in the
- // event that the user erroneously tries to use them. However, as a
- // counterargument, this would likely degrade parser recovery in the event
- // of a construct like "class C { int @deprecated foo() {} }" (i.e. the
- // user is in the middle of inserting "int bar;" prior to
- // "@deprecated foo() {}").
- SimpleIdentifier name = parseSimpleIdentifier(isDeclaration: true);
- Token equals;
- Expression initializer;
- if (_matches(TokenType.EQ)) {
- equals = getAndAdvance();
- initializer = parseExpression2();
- }
- return astFactory.variableDeclaration(name, equals, initializer);
- }
-
- /// Parse a variable declaration list. The [commentAndMetadata] is the
- /// metadata to be associated with the variable declaration list. Return the
- /// variable declaration list that was parsed.
- ///
- /// variableDeclarationList ::=
- /// finalConstVarOrType variableDeclaration (',' variableDeclaration)*
- VariableDeclarationList parseVariableDeclarationListAfterMetadata(
- CommentAndMetadata commentAndMetadata) {
- FinalConstVarOrType holder = parseFinalConstVarOrType(false);
- return parseVariableDeclarationListAfterType(
- commentAndMetadata, holder.keyword, holder.type);
- }
-
- /// Parse a variable declaration list. The [commentAndMetadata] is the
- /// metadata to be associated with the variable declaration list, or `null`
- /// if there is no attempt at parsing the comment and metadata. The [keyword]
- /// is the token representing the 'final', 'const' or 'var' keyword, or
- /// `null` if there is no keyword. The [type] is the type of the variables in
- /// the list. Return the variable declaration list that was parsed.
- ///
- /// variableDeclarationList ::=
- /// finalConstVarOrType variableDeclaration (',' variableDeclaration)*
- VariableDeclarationList parseVariableDeclarationListAfterType(
- CommentAndMetadata commentAndMetadata,
- Token keyword,
- TypeAnnotation type) {
- if (type != null &&
- keyword != null &&
- _tokenMatchesKeyword(keyword, Keyword.VAR)) {
- _reportErrorForToken(ParserErrorCode.VAR_AND_TYPE, keyword);
- }
- List<VariableDeclaration> variables = <VariableDeclaration>[
- parseVariableDeclaration()
- ];
- while (_optional(TokenType.COMMA)) {
- variables.add(parseVariableDeclaration());
- }
- return astFactory.variableDeclarationList(commentAndMetadata?.comment,
- commentAndMetadata?.metadata, keyword, type, variables);
- }
-
- /// Parse a variable declaration statement. The [commentAndMetadata] is the
- /// metadata to be associated with the variable declaration statement, or
- /// `null` if there is no attempt at parsing the comment and metadata. Return
- /// the variable declaration statement that was parsed.
- ///
- /// variableDeclarationStatement ::=
- /// variableDeclarationList ';'
- VariableDeclarationStatement parseVariableDeclarationStatementAfterMetadata(
- CommentAndMetadata commentAndMetadata) {
- // Token startToken = currentToken;
- VariableDeclarationList variableList =
- parseVariableDeclarationListAfterMetadata(commentAndMetadata);
-// if (!matches(TokenType.SEMICOLON)) {
-// if (matches(startToken, Keyword.VAR) && isTypedIdentifier(startToken.getNext())) {
-// // TODO(brianwilkerson) This appears to be of the form "var type variable". We should do
-// // a better job of recovering in this case.
-// }
-// }
- Token semicolon = _expect(TokenType.SEMICOLON);
- return astFactory.variableDeclarationStatement(variableList, semicolon);
- }
-
- /// Parse a while statement. Return the while statement that was parsed.
- ///
- /// This method assumes that the current token matches [Keyword.WHILE].
- ///
- /// whileStatement ::=
- /// 'while' '(' expression ')' statement
- Statement parseWhileStatement() {
- bool wasInLoop = _inLoop;
- _inLoop = true;
- try {
- Token keyword = getAndAdvance();
- Token leftParenthesis = _expect(TokenType.OPEN_PAREN);
- Expression condition = parseExpression2();
- Token rightParenthesis = _expect(TokenType.CLOSE_PAREN);
- Statement body = parseStatement2();
- return astFactory.whileStatement(
- keyword, leftParenthesis, condition, rightParenthesis, body);
- } finally {
- _inLoop = wasInLoop;
- }
- }
-
- /// Parse a with clause. Return the with clause that was parsed.
- ///
- /// This method assumes that the current token matches `Keyword.WITH`.
- ///
- /// withClause ::=
- /// 'with' typeName (',' typeName)*
- WithClause parseWithClause() {
- Token withKeyword = getAndAdvance();
- List<TypeName> types = <TypeName>[];
- do {
- TypeName typeName = parseTypeName(false);
- types.add(typeName);
- } while (_optional(TokenType.COMMA));
- return astFactory.withClause(withKeyword, types);
- }
-
- /// Parse a yield statement. Return the yield statement that was parsed.
- ///
- /// This method assumes that the current token matches [Keyword.YIELD].
- ///
- /// yieldStatement ::=
- /// 'yield' '*'? expression ';'
- YieldStatement parseYieldStatement() {
- Token yieldToken = getAndAdvance();
- Token star;
- if (_matches(TokenType.STAR)) {
- star = getAndAdvance();
- }
- Expression expression = parseExpression2();
- Token semicolon = _expect(TokenType.SEMICOLON);
- return astFactory.yieldStatement(yieldToken, star, expression, semicolon);
- }
-
- /// Parse a formal parameter list, starting at the [startToken], without
- /// actually creating a formal parameter list or changing the current token.
- /// Return the token following the parameter list that was parsed, or `null`
- /// if the given token is not the first token in a valid parameter list.
- ///
- /// This method must be kept in sync with [parseFormalParameterList].
- Token skipFormalParameterList(Token startToken) {
- if (!_tokenMatches(startToken, TokenType.OPEN_PAREN)) {
- return null;
- }
- return (startToken as BeginToken).endToken?.next;
- }
-
- /// Parse the portion of a generic function type after the return type,
- /// starting at the [startToken], without actually creating a generic function
- /// type or changing the current token. Return the token following the generic
- /// function type that was parsed, or `null` if the given token is not the
- /// first token in a valid generic function type.
- ///
- /// This method must be kept in sync with
- /// [parseGenericFunctionTypeAfterReturnType].
- Token skipGenericFunctionTypeAfterReturnType(Token startToken) {
- Token next = startToken.next; // Skip 'Function'
- if (_tokenMatches(next, TokenType.LT)) {
- next = skipTypeParameterList(next);
- if (next == null) {
- return null;
- }
- }
- return skipFormalParameterList(next);
- }
-
- /// Parse a prefixed identifier, starting at the [startToken], without
- /// actually creating a prefixed identifier or changing the current token.
- /// Return the token following the prefixed identifier that was parsed, or
- /// `null` if the given token is not the first token in a valid prefixed
- /// identifier.
- ///
- /// This method must be kept in sync with [parsePrefixedIdentifier].
- ///
- /// prefixedIdentifier ::=
- /// identifier ('.' identifier)?
- Token skipPrefixedIdentifier(Token startToken) {
- Token token = skipSimpleIdentifier(startToken);
- if (token == null) {
- return null;
- } else if (!_tokenMatches(token, TokenType.PERIOD)) {
- return token;
- }
- token = token.next;
- Token nextToken = skipSimpleIdentifier(token);
- if (nextToken != null) {
- return nextToken;
- } else if (_tokenMatches(token, TokenType.CLOSE_PAREN) ||
- _tokenMatches(token, TokenType.COMMA)) {
- // If the `id.` is followed by something that cannot produce a valid
- // structure then assume this is a prefixed identifier but missing the
- // trailing identifier
- return token;
- }
- return null;
- }
-
- /// Parse a simple identifier, starting at the [startToken], without actually
- /// creating a simple identifier or changing the current token. Return the
- /// token following the simple identifier that was parsed, or `null` if the
- /// given token is not the first token in a valid simple identifier.
- ///
- /// This method must be kept in sync with [parseSimpleIdentifier].
- ///
- /// identifier ::=
- /// IDENTIFIER
- Token skipSimpleIdentifier(Token startToken) {
- if (_tokenMatches(startToken, TokenType.IDENTIFIER) ||
- _tokenMatchesPseudoKeyword(startToken)) {
- return startToken.next;
- }
- return null;
- }
-
- /// Parse a string literal, starting at the [startToken], without actually
- /// creating a string literal or changing the current token. Return the token
- /// following the string literal that was parsed, or `null` if the given token
- /// is not the first token in a valid string literal.
- ///
- /// This method must be kept in sync with [parseStringLiteral].
- ///
- /// stringLiteral ::=
- /// MULTI_LINE_STRING+
- /// | SINGLE_LINE_STRING+
- Token skipStringLiteral(Token startToken) {
- Token token = startToken;
- while (token != null && _tokenMatches(token, TokenType.STRING)) {
- token = token.next;
- TokenType type = token.type;
- if (type == TokenType.STRING_INTERPOLATION_EXPRESSION ||
- type == TokenType.STRING_INTERPOLATION_IDENTIFIER) {
- token = _skipStringInterpolation(token);
- }
- }
- if (identical(token, startToken)) {
- return null;
- }
- return token;
- }
-
- /// Parse a type annotation, starting at the [startToken], without actually
- /// creating a type annotation or changing the current token. Return the token
- /// following the type annotation that was parsed, or `null` if the given
- /// token is not the first token in a valid type annotation.
- ///
- /// This method must be kept in sync with [parseTypeAnnotation].
- Token skipTypeAnnotation(Token startToken) {
- Token next;
- if (_atGenericFunctionTypeAfterReturnType(startToken)) {
- // Generic function type with no return type.
- next = skipGenericFunctionTypeAfterReturnType(startToken);
- } else {
- next = skipTypeWithoutFunction(startToken);
- }
- while (next != null && _atGenericFunctionTypeAfterReturnType(next)) {
- next = skipGenericFunctionTypeAfterReturnType(next);
- }
- return next;
- }
-
- /// Parse a list of type arguments, starting at the [startToken], without
- /// actually creating a type argument list or changing the current token.
- /// Return the token following the type argument list that was parsed, or
- /// `null` if the given token is not the first token in a valid type argument
- /// list.
- ///
- /// This method must be kept in sync with [parseTypeArgumentList].
- ///
- /// typeArguments ::=
- /// '<' typeList '>'
- ///
- /// typeList ::=
- /// type (',' type)*
- Token skipTypeArgumentList(Token startToken) {
- Token token = startToken;
- if (!_tokenMatches(token, TokenType.LT)) {
- return null;
- }
- token = skipTypeAnnotation(token.next);
- if (token == null) {
- // If the start token '<' is followed by '>'
- // then assume this should be type argument list but is missing a type
- token = startToken.next;
- if (_tokenMatches(token, TokenType.GT)) {
- return token.next;
- }
- return null;
- }
- while (_tokenMatches(token, TokenType.COMMA)) {
- token = skipTypeAnnotation(token.next);
- if (token == null) {
- return null;
- }
- }
- if (token.type == TokenType.GT) {
- return token.next;
- } else if (token.type == TokenType.GT_GT) {
- Token second = Token(TokenType.GT, token.offset + 1);
- second.setNextWithoutSettingPrevious(token.next);
- return second;
- }
- return null;
- }
-
- /// Parse a type name, starting at the [startToken], without actually creating
- /// a type name or changing the current token. Return the token following the
- /// type name that was parsed, or `null` if the given token is not the first
- /// token in a valid type name.
- ///
- /// This method must be kept in sync with [parseTypeName].
- ///
- /// type ::=
- /// qualified typeArguments?
- Token skipTypeName(Token startToken) {
- Token token = skipPrefixedIdentifier(startToken);
- if (token == null) {
- return null;
- }
- if (_tokenMatches(token, TokenType.LT)) {
- token = skipTypeArgumentList(token);
- }
- return token;
- }
-
- /// Parse a type parameter list, starting at the [startToken], without
- /// actually creating a type parameter list or changing the current token.
- /// Return the token following the type parameter list that was parsed, or
- /// `null` if the given token is not the first token in a valid type parameter
- /// list.
- ///
- /// This method must be kept in sync with [parseTypeParameterList].
- Token skipTypeParameterList(Token startToken) {
- if (!_tokenMatches(startToken, TokenType.LT)) {
- return null;
- }
- int depth = 1;
- Token previous = startToken;
- Token next = startToken.next;
- while (next != previous) {
- if (_tokenMatches(next, TokenType.LT)) {
- depth++;
- } else if (_tokenMatches(next, TokenType.GT)) {
- depth--;
- if (depth == 0) {
- return next.next;
- }
- }
- previous = next;
- next = next.next;
- }
- return null;
- }
-
- /// Parse a typeWithoutFunction, starting at the [startToken], without
- /// actually creating a TypeAnnotation or changing the current token. Return
- /// the token following the typeWithoutFunction that was parsed, or `null` if
- /// the given token is not the first token in a valid typeWithoutFunction.
- ///
- /// This method must be kept in sync with [parseTypeWithoutFunction].
- Token skipTypeWithoutFunction(Token startToken) {
- if (startToken.keyword == Keyword.VOID) {
- return startToken.next;
- } else {
- return skipTypeName(startToken);
- }
- }
-
- /// Advance to the next token in the token stream.
- void _advance() {
- _currentToken = _currentToken.next;
- }
-
- /// Append the character equivalent of the given [codePoint] to the given
- /// [builder]. Use the [startIndex] and [endIndex] to report an error, and
- /// don't append anything to the builder, if the code point is invalid. The
- /// [escapeSequence] is the escape sequence that was parsed to produce the
- /// code point (used for error reporting).
- void _appendCodePoint(StringBuffer buffer, String source, int codePoint,
- int startIndex, int endIndex) {
- if (codePoint < 0 || codePoint > Character.MAX_CODE_POINT) {
- String escapeSequence = source.substring(startIndex, endIndex + 1);
- _reportErrorForCurrentToken(
- ParserErrorCode.INVALID_CODE_POINT, [escapeSequence]);
- return;
- }
- if (codePoint < Character.MAX_VALUE) {
- buffer.writeCharCode(codePoint);
- } else {
- buffer.write(Character.toChars(codePoint));
- }
- }
-
- /// Return `true` if we are positioned at the keyword 'Function' in a generic
- /// function type alias.
- bool _atGenericFunctionTypeAfterReturnType(Token startToken) {
- if (_tokenMatchesKeyword(startToken, Keyword.FUNCTION)) {
- Token next = startToken.next;
- if (next != null &&
- (_tokenMatches(next, TokenType.OPEN_PAREN) ||
- _tokenMatches(next, TokenType.LT))) {
- return true;
- }
- }
- return false;
- }
-
- void _configureFeatures(FeatureSet featureSet) {
- if (featureSet.isEnabled(Feature.control_flow_collections)) {
- throw UnimplementedError('control_flow_collections experiment'
- ' not supported by analyzer parser');
- }
- if (featureSet.isEnabled(Feature.non_nullable)) {
- throw UnimplementedError(
- 'non-nullable experiment not supported by analyzer parser');
- }
- if (featureSet.isEnabled(Feature.spread_collections)) {
- throw UnimplementedError(
- 'spread_collections experiment not supported by analyzer parser');
- }
- if (featureSet.isEnabled(Feature.triple_shift)) {
- throw UnimplementedError('triple_shift experiment'
- ' not supported by analyzer parser');
- }
- _featureSet = featureSet;
- }
-
- /// Convert the given [method] declaration into the nearest valid top-level
- /// function declaration (that is, the function declaration that most closely
- /// captures the components of the given method declaration).
- FunctionDeclaration _convertToFunctionDeclaration(MethodDeclaration method) =>
- astFactory.functionDeclaration(
- method.documentationComment,
- method.metadata,
- method.externalKeyword,
- method.returnType,
- method.propertyKeyword,
- method.name,
- astFactory.functionExpression(
- method.typeParameters, method.parameters, method.body));
-
- /// Return `true` if the current token could be the start of a compilation
- /// unit member. This method is used for recovery purposes to decide when to
- /// stop skipping tokens after finding an error while parsing a compilation
- /// unit member.
- bool _couldBeStartOfCompilationUnitMember() {
- Keyword keyword = _currentToken.keyword;
- Token next = _currentToken.next;
- TokenType nextType = next.type;
- if ((keyword == Keyword.IMPORT ||
- keyword == Keyword.EXPORT ||
- keyword == Keyword.LIBRARY ||
- keyword == Keyword.PART) &&
- nextType != TokenType.PERIOD &&
- nextType != TokenType.LT) {
- // This looks like the start of a directive
- return true;
- } else if (keyword == Keyword.CLASS) {
- // This looks like the start of a class definition
- return true;
- } else if (keyword == Keyword.TYPEDEF &&
- nextType != TokenType.PERIOD &&
- nextType != TokenType.LT) {
- // This looks like the start of a typedef
- return true;
- } else if (keyword == Keyword.VOID ||
- ((keyword == Keyword.GET || keyword == Keyword.SET) &&
- _tokenMatchesIdentifier(next)) ||
- (keyword == Keyword.OPERATOR && _isOperator(next))) {
- // This looks like the start of a function
- return true;
- } else if (_matchesIdentifier()) {
- if (nextType == TokenType.OPEN_PAREN) {
- // This looks like the start of a function
- return true;
- }
- Token token = skipTypeAnnotation(_currentToken);
- if (token == null) {
- return false;
- }
- // TODO(brianwilkerson) This looks wrong; should we be checking 'token'?
- if (keyword == Keyword.GET ||
- keyword == Keyword.SET ||
- (keyword == Keyword.OPERATOR && _isOperator(next)) ||
- _matchesIdentifier()) {
- return true;
- }
- }
- return false;
- }
-
- /// Return a synthetic token representing the given [keyword].
- Token _createSyntheticKeyword(Keyword keyword) =>
- _injectToken(SyntheticKeywordToken(keyword, _currentToken.offset));
-
- /// Return a synthetic token with the given [type].
- Token _createSyntheticToken(TokenType type) =>
- _injectToken(StringToken(type, "", _currentToken.offset));
-
- /// Create and return a new token with the given [type]. The token will
- /// replace the first portion of the given [token], so it will have the same
- /// offset and will have any comments that might have preceded the token.
- Token _createToken(Token token, TokenType type, {bool isBegin = false}) {
- CommentToken comments = token.precedingComments;
- if (comments == null) {
- if (isBegin) {
- return BeginToken(type, token.offset);
- }
- return Token(type, token.offset);
- } else if (isBegin) {
- return BeginToken(type, token.offset, comments);
- }
- return Token(type, token.offset, comments);
- }
-
- /// Check that the given [expression] is assignable and report an error if it
- /// isn't.
- ///
- /// assignableExpression ::=
- /// primary (arguments* assignableSelector)+
- /// | 'super' unconditionalAssignableSelector
- /// | identifier
- ///
- /// unconditionalAssignableSelector ::=
- /// '[' expression ']'
- /// | '.' identifier
- ///
- /// assignableSelector ::=
- /// unconditionalAssignableSelector
- /// | '?.' identifier
- void _ensureAssignable(Expression expression) {
- if (expression != null && !expression.isAssignable) {
- _reportErrorForCurrentToken(
- ParserErrorCode.ILLEGAL_ASSIGNMENT_TO_NON_ASSIGNABLE);
- }
- }
-
- /// If the current token has the expected type, return it after advancing to
- /// the next token. Otherwise report an error and return the current token
- /// without advancing.
- ///
- /// Note that the method [_expectGt] should be used if the argument to this
- /// method would be [TokenType.GT].
- ///
- /// The [type] is the type of token that is expected.
- Token _expect(TokenType type) {
- if (_matches(type)) {
- return getAndAdvance();
- }
- // Remove uses of this method in favor of matches?
- // Pass in the error code to use to report the error?
- if (type == TokenType.SEMICOLON) {
- if (_tokenMatches(_currentToken.next, TokenType.SEMICOLON)) {
- _reportErrorForCurrentToken(
- ParserErrorCode.UNEXPECTED_TOKEN, [_currentToken.lexeme]);
- _advance();
- return getAndAdvance();
- }
- _reportErrorForToken(ParserErrorCode.EXPECTED_TOKEN,
- _currentToken.previous, [type.lexeme]);
- return _createSyntheticToken(TokenType.SEMICOLON);
- }
- _reportErrorForCurrentToken(ParserErrorCode.EXPECTED_TOKEN, [type.lexeme]);
- return _createSyntheticToken(type);
- }
-
- /// If the current token has the type [TokenType.GT], return it after
- /// advancing to the next token. Otherwise report an error and create a
- /// synthetic token.
- Token _expectGt() {
- if (_matchesGt()) {
- return getAndAdvance();
- }
- _reportErrorForCurrentToken(
- ParserErrorCode.EXPECTED_TOKEN, [TokenType.GT.lexeme]);
- return _createSyntheticToken(TokenType.GT);
- }
-
- /// If the current token is a keyword matching the given [keyword], return it
- /// after advancing to the next token. Otherwise report an error and return
- /// the current token without advancing.
- Token _expectKeyword(Keyword keyword) {
- if (_matchesKeyword(keyword)) {
- return getAndAdvance();
- }
- // Remove uses of this method in favor of matches?
- // Pass in the error code to use to report the error?
- _reportErrorForCurrentToken(
- ParserErrorCode.EXPECTED_TOKEN, [keyword.lexeme]);
- return _currentToken;
- }
-
- /// Search the given list of [ranges] for a range that contains the given
- /// [index]. Return the range that was found, or `null` if none of the ranges
- /// contain the index.
- List<int> _findRange(List<List<int>> ranges, int index) {
- int rangeCount = ranges.length;
- for (int i = 0; i < rangeCount; i++) {
- List<int> range = ranges[i];
- if (range[0] <= index && index <= range[1]) {
- return range;
- } else if (index < range[0]) {
- return null;
- }
- }
- return null;
- }
-
- /// Return a list of the ranges of characters in the given [comment] that
- /// should be treated as code blocks.
- List<List<int>> _getCodeBlockRanges(String comment) {
- List<List<int>> ranges = <List<int>>[];
- int length = comment.length;
- if (length < 3) {
- return ranges;
- }
- int index = 0;
- int firstChar = comment.codeUnitAt(0);
- if (firstChar == 0x2F) {
- int secondChar = comment.codeUnitAt(1);
- int thirdChar = comment.codeUnitAt(2);
- if ((secondChar == 0x2A && thirdChar == 0x2A) ||
- (secondChar == 0x2F && thirdChar == 0x2F)) {
- index = 3;
- }
- }
- if (StringUtilities.startsWith4(comment, index, 0x20, 0x20, 0x20, 0x20)) {
- int end = index + 4;
- while (end < length &&
- comment.codeUnitAt(end) != 0xD &&
- comment.codeUnitAt(end) != 0xA) {
- end = end + 1;
- }
- ranges.add(<int>[index, end]);
- index = end;
- }
- while (index < length) {
- int currentChar = comment.codeUnitAt(index);
- if (currentChar == 0xD || currentChar == 0xA) {
- index = index + 1;
- while (index < length &&
- Character.isWhitespace(comment.codeUnitAt(index))) {
- index = index + 1;
- }
- if (StringUtilities.startsWith6(
- comment, index, 0x2A, 0x20, 0x20, 0x20, 0x20, 0x20)) {
- int end = index + 6;
- while (end < length &&
- comment.codeUnitAt(end) != 0xD &&
- comment.codeUnitAt(end) != 0xA) {
- end = end + 1;
- }
- ranges.add(<int>[index, end]);
- index = end;
- }
- } else if (index + 1 < length &&
- currentChar == 0x5B &&
- comment.codeUnitAt(index + 1) == 0x3A) {
- int end = StringUtilities.indexOf2(comment, index + 2, 0x3A, 0x5D);
- if (end < 0) {
- end = length;
- }
- ranges.add(<int>[index, end]);
- index = end + 1;
- } else {
- index = index + 1;
- }
- }
- return ranges;
- }
-
- /// Return the end token associated with the given [beginToken], or `null` if
- /// either the given token is not a begin token or it does not have an end
- /// token associated with it.
- Token _getEndToken(Token beginToken) {
- if (beginToken is BeginToken) {
- return beginToken.endToken;
- }
- return null;
- }
-
- /// Inject the given [token] into the token stream immediately before the
- /// current token.
- Token _injectToken(Token token) {
- Token previous = _currentToken.previous;
- token.setNext(_currentToken);
- previous.setNext(token);
- return token;
- }
-
- /// Return `true` if the given [character] is a valid hexadecimal digit.
- bool _isHexDigit(int character) =>
- (0x30 <= character && character <= 0x39) ||
- (0x41 <= character && character <= 0x46) ||
- (0x61 <= character && character <= 0x66);
-
- bool _isLikelyArgumentList() {
- // Try to reduce the amount of lookahead required here before enabling
- // generic methods.
- if (_matches(TokenType.OPEN_PAREN)) {
- return true;
- }
- Token token = skipTypeArgumentList(_currentToken);
- return token != null && _tokenMatches(token, TokenType.OPEN_PAREN);
- }
-
- /// Return `true` if it looks like we have found the invocation of a named
- /// constructor following the name of the type:
- /// ```
- /// typeArguments? '.' identifier '('
- /// ```
- bool _isLikelyNamedInstanceCreation() {
- Token token = skipTypeArgumentList(_currentToken);
- if (token != null && _tokenMatches(token, TokenType.PERIOD)) {
- token = skipSimpleIdentifier(token.next);
- if (token != null && _tokenMatches(token, TokenType.OPEN_PAREN)) {
- return true;
- }
- }
- return false;
- }
-
- /// Given that we have just found bracketed text within the given [comment],
- /// look to see whether that text is (a) followed by a parenthesized link
- /// address, (b) followed by a colon, or (c) followed by optional whitespace
- /// and another square bracket. The [rightIndex] is the index of the right
- /// bracket. Return `true` if the bracketed text is followed by a link
- /// address.
- ///
- /// This method uses the syntax described by the
- /// <a href="http://daringfireball.net/projects/markdown/syntax">markdown</a>
- /// project.
- bool _isLinkText(String comment, int rightIndex) {
- int length = comment.length;
- int index = rightIndex + 1;
- if (index >= length) {
- return false;
- }
- int nextChar = comment.codeUnitAt(index);
- if (nextChar == 0x28 || nextChar == 0x3A) {
- return true;
- }
- while (Character.isWhitespace(nextChar)) {
- index = index + 1;
- if (index >= length) {
- return false;
- }
- nextChar = comment.codeUnitAt(index);
- }
- return nextChar == 0x5B;
- }
-
- /// Return `true` if the given [startToken] appears to be the beginning of an
- /// operator declaration.
- bool _isOperator(Token startToken) {
- // Accept any operator here, even if it is not user definable.
- if (!startToken.isOperator) {
- return false;
- }
- // Token "=" means that it is actually a field initializer.
- if (startToken.type == TokenType.EQ) {
- return false;
- }
- // Consume all operator tokens.
- Token token = startToken.next;
- while (token.isOperator) {
- token = token.next;
- }
- // Formal parameter list is expect now.
- return _tokenMatches(token, TokenType.OPEN_PAREN);
- }
-
- bool _isPeekGenericTypeParametersAndOpenParen() {
- Token token = _skipTypeParameterList(_peek());
- return token != null && _tokenMatches(token, TokenType.OPEN_PAREN);
- }
-
- /// Return `true` if the [startToken] appears to be the first token of a type
- /// name that is followed by a variable or field formal parameter.
- bool _isTypedIdentifier(Token startToken) {
- Token token = skipTypeAnnotation(startToken);
- if (token == null) {
- return false;
- } else if (_tokenMatchesIdentifier(token)) {
- return true;
- } else if (_tokenMatchesKeyword(token, Keyword.THIS) &&
- _tokenMatches(token.next, TokenType.PERIOD) &&
- _tokenMatchesIdentifier(token.next.next)) {
- return true;
- } else if (startToken.next != token &&
- !_tokenMatches(token, TokenType.OPEN_PAREN)) {
- // The type is more than a simple identifier, so it should be assumed to
- // be a type name.
- return true;
- }
- return false;
- }
-
- /// Return `true` if the given [expression] is a primary expression that is
- /// allowed to be an assignable expression without any assignable selector.
- bool _isValidAssignableExpression(Expression expression) {
- if (expression is SimpleIdentifier) {
- return true;
- } else if (expression is PropertyAccess) {
- return expression.target is SuperExpression;
- } else if (expression is IndexExpression) {
- return expression.target is SuperExpression;
- }
- return false;
- }
-
- /// Increments the error reporting lock level. If level is more than `0`, then
- /// [reportError] wont report any error.
- void _lockErrorListener() {
- _errorListenerLock++;
- }
-
- /// Return `true` if the current token has the given [type]. Note that the
- /// method [_matchesGt] should be used if the argument to this method would be
- /// [TokenType.GT].
- bool _matches(TokenType type) => _currentToken.type == type;
-
- /// Return `true` if the current token has a type of [TokenType.GT]. Note that
- /// this method, unlike other variants, will modify the token stream if
- /// possible to match desired type. In particular, if the next token is either
- /// a '>>' or '>>>', the token stream will be re-written and `true` will be
- /// returned.
- bool _matchesGt() {
- TokenType currentType = _currentToken.type;
- if (currentType == TokenType.GT) {
- return true;
- } else if (currentType == TokenType.GT_GT) {
- Token first = _createToken(_currentToken, TokenType.GT);
- Token second = Token(TokenType.GT, _currentToken.offset + 1);
- second.setNext(_currentToken.next);
- first.setNext(second);
- _currentToken.previous.setNext(first);
- _currentToken = first;
- return true;
- } else if (currentType == TokenType.GT_EQ) {
- Token first = _createToken(_currentToken, TokenType.GT);
- Token second = Token(TokenType.EQ, _currentToken.offset + 1);
- second.setNext(_currentToken.next);
- first.setNext(second);
- _currentToken.previous.setNext(first);
- _currentToken = first;
- return true;
- } else if (currentType == TokenType.GT_GT_EQ) {
- int offset = _currentToken.offset;
- Token first = _createToken(_currentToken, TokenType.GT);
- Token second = Token(TokenType.GT, offset + 1);
- Token third = Token(TokenType.EQ, offset + 2);
- third.setNext(_currentToken.next);
- second.setNext(third);
- first.setNext(second);
- _currentToken.previous.setNext(first);
- _currentToken = first;
- return true;
- }
- return false;
- }
-
- /// Return `true` if the current token is a valid identifier. Valid
- /// identifiers include built-in identifiers (pseudo-keywords).
- bool _matchesIdentifier() => _tokenMatchesIdentifier(_currentToken);
-
- /// Return `true` if the current token matches the given [keyword].
- bool _matchesKeyword(Keyword keyword) =>
- _tokenMatchesKeyword(_currentToken, keyword);
-
- /// If the current token has the given [type], then advance to the next token
- /// and return `true`. Otherwise, return `false` without advancing. This
- /// method should not be invoked with an argument value of [TokenType.GT].
- bool _optional(TokenType type) {
- if (_currentToken.type == type) {
- _advance();
- return true;
- }
- return false;
- }
-
- /// Parse an argument list when we need to check for an open paren and recover
- /// when there isn't one. Return the argument list that was parsed.
- ArgumentList _parseArgumentListChecked() {
- if (_matches(TokenType.OPEN_PAREN)) {
- return parseArgumentList();
- }
- _reportErrorForCurrentToken(
- ParserErrorCode.EXPECTED_TOKEN, [TokenType.OPEN_PAREN.lexeme]);
- // Recovery: Look to see whether there is a close paren that isn't matched
- // to an open paren and if so parse the list of arguments as normal.
- return astFactory.argumentList(_createSyntheticToken(TokenType.OPEN_PAREN),
- null, _createSyntheticToken(TokenType.CLOSE_PAREN));
- }
-
- /// Parse an assert within a constructor's initializer list. Return the
- /// assert.
- ///
- /// This method assumes that the current token matches `Keyword.ASSERT`.
- ///
- /// assertInitializer ::=
- /// 'assert' '(' expression [',' expression] ')'
- AssertInitializer _parseAssertInitializer() {
- Token keyword = getAndAdvance();
- Token leftParen = _expect(TokenType.OPEN_PAREN);
- Expression expression = parseExpression2();
- Token comma;
- Expression message;
- if (_matches(TokenType.COMMA)) {
- comma = getAndAdvance();
- if (_matches(TokenType.CLOSE_PAREN)) {
- comma;
- } else {
- message = parseExpression2();
- if (_matches(TokenType.COMMA)) {
- getAndAdvance();
- }
- }
- }
- Token rightParen = _expect(TokenType.CLOSE_PAREN);
- return astFactory.assertInitializer(
- keyword, leftParen, expression, comma, message, rightParen);
- }
-
- /// Parse a block when we need to check for an open curly brace and recover
- /// when there isn't one. Return the block that was parsed.
- ///
- /// block ::=
- /// '{' statements '}'
- Block _parseBlockChecked() {
- if (_matches(TokenType.OPEN_CURLY_BRACKET)) {
- return parseBlock();
- }
- // TODO(brianwilkerson) Improve the error message.
- _reportErrorForCurrentToken(
- ParserErrorCode.EXPECTED_TOKEN, [TokenType.OPEN_CURLY_BRACKET.lexeme]);
- // Recovery: Check for an unmatched closing curly bracket and parse
- // statements until it is reached.
- return astFactory.block(_createSyntheticToken(TokenType.OPEN_CURLY_BRACKET),
- null, _createSyntheticToken(TokenType.CLOSE_CURLY_BRACKET));
- }
-
- /// Parse a list of class members. The [className] is the name of the class
- /// whose members are being parsed. The [closingBracket] is the closing
- /// bracket for the class, or `null` if the closing bracket is missing.
- /// Return the list of class members that were parsed.
- ///
- /// classMembers ::=
- /// (metadata memberDefinition)*
- List<ClassMember> _parseClassMembers(String className, Token closingBracket) {
- List<ClassMember> members = <ClassMember>[];
- Token memberStart = _currentToken;
- TokenType type = _currentToken.type;
- Keyword keyword = _currentToken.keyword;
- while (type != TokenType.EOF &&
- type != TokenType.CLOSE_CURLY_BRACKET &&
- (closingBracket != null ||
- (keyword != Keyword.CLASS && keyword != Keyword.TYPEDEF))) {
- if (type == TokenType.SEMICOLON) {
- _reportErrorForToken(ParserErrorCode.UNEXPECTED_TOKEN, _currentToken,
- [_currentToken.lexeme]);
- _advance();
- } else {
- ClassMember member = parseClassMember(className);
- if (member != null) {
- members.add(member);
- }
- }
- if (identical(_currentToken, memberStart)) {
- _reportErrorForToken(ParserErrorCode.UNEXPECTED_TOKEN, _currentToken,
- [_currentToken.lexeme]);
- _advance();
- }
- memberStart = _currentToken;
- type = _currentToken.type;
- keyword = _currentToken.keyword;
- }
- return members;
- }
-
- /// Parse a class type alias. The [commentAndMetadata] is the metadata to be
- /// associated with the member. The [abstractKeyword] is the token
- /// representing the 'abstract' keyword. The [classKeyword] is the token
- /// representing the 'class' keyword. The [className] is the name of the
- /// alias, and the [typeParameters] are the type parameters following the
- /// name. Return the class type alias that was parsed.
- ///
- /// classTypeAlias ::=
- /// identifier typeParameters? '=' 'abstract'? mixinApplication
- ///
- /// mixinApplication ::=
- /// type withClause implementsClause? ';'
- ClassTypeAlias _parseClassTypeAliasAfterName(
- CommentAndMetadata commentAndMetadata,
- Token abstractKeyword,
- Token classKeyword,
- SimpleIdentifier className,
- TypeParameterList typeParameters) {
- Token equals = _expect(TokenType.EQ);
- TypeName superclass = parseTypeName(false);
- WithClause withClause;
- if (_matchesKeyword(Keyword.WITH)) {
- withClause = parseWithClause();
- } else {
- _reportErrorForCurrentToken(
- ParserErrorCode.EXPECTED_TOKEN, [Keyword.WITH.lexeme]);
- }
- ImplementsClause implementsClause;
- if (_matchesKeyword(Keyword.IMPLEMENTS)) {
- implementsClause = parseImplementsClause();
- }
- Token semicolon;
- if (_matches(TokenType.SEMICOLON)) {
- semicolon = getAndAdvance();
- } else {
- if (_matches(TokenType.OPEN_CURLY_BRACKET)) {
- _reportErrorForCurrentToken(
- ParserErrorCode.EXPECTED_TOKEN, [TokenType.SEMICOLON.lexeme]);
- Token leftBracket = getAndAdvance();
- _parseClassMembers(className.name, _getEndToken(leftBracket));
- _expect(TokenType.CLOSE_CURLY_BRACKET);
- } else {
- _reportErrorForToken(ParserErrorCode.EXPECTED_TOKEN,
- _currentToken.previous, [TokenType.SEMICOLON.lexeme]);
- }
- semicolon = _createSyntheticToken(TokenType.SEMICOLON);
- }
- return astFactory.classTypeAlias(
- commentAndMetadata.comment,
- commentAndMetadata.metadata,
- classKeyword,
- className,
- typeParameters,
- equals,
- abstractKeyword,
- superclass,
- withClause,
- implementsClause,
- semicolon);
- }
-
- /// Parse a list of configurations. Return the configurations that were
- /// parsed, or `null` if there are no configurations.
- List<Configuration> _parseConfigurations() {
- List<Configuration> configurations;
- while (_matchesKeyword(Keyword.IF)) {
- configurations ??= <Configuration>[];
- configurations.add(parseConfiguration());
- }
- return configurations;
- }
-
- ConstructorDeclaration _parseConstructor(
- CommentAndMetadata commentAndMetadata,
- Token externalKeyword,
- Token constKeyword,
- Token factoryKeyword,
- SimpleIdentifier returnType,
- Token period,
- SimpleIdentifier name,
- FormalParameterList parameters) {
- bool bodyAllowed = externalKeyword == null;
- Token separator;
- List<ConstructorInitializer> initializers;
- if (_matches(TokenType.COLON)) {
- separator = getAndAdvance();
- initializers = <ConstructorInitializer>[];
- do {
- Keyword keyword = _currentToken.keyword;
- if (keyword == Keyword.THIS) {
- TokenType nextType = _peek().type;
- if (nextType == TokenType.OPEN_PAREN) {
- bodyAllowed = false;
- initializers.add(parseRedirectingConstructorInvocation(false));
- } else if (nextType == TokenType.PERIOD &&
- _tokenMatches(_peekAt(3), TokenType.OPEN_PAREN)) {
- bodyAllowed = false;
- initializers.add(parseRedirectingConstructorInvocation(true));
- } else {
- initializers.add(parseConstructorFieldInitializer(true));
- }
- } else if (keyword == Keyword.SUPER) {
- initializers.add(parseSuperConstructorInvocation());
- } else if (_matches(TokenType.OPEN_CURLY_BRACKET) ||
- _matches(TokenType.FUNCTION)) {
- _reportErrorForCurrentToken(ParserErrorCode.MISSING_INITIALIZER);
- } else if (_matchesKeyword(Keyword.ASSERT)) {
- initializers.add(_parseAssertInitializer());
- } else {
- initializers.add(parseConstructorFieldInitializer(false));
- }
- } while (_optional(TokenType.COMMA));
- if (factoryKeyword != null) {
- _reportErrorForToken(
- ParserErrorCode.FACTORY_WITH_INITIALIZERS, factoryKeyword);
- }
- }
- ConstructorName redirectedConstructor;
- FunctionBody body;
- if (_matches(TokenType.EQ)) {
- separator = getAndAdvance();
- redirectedConstructor = parseConstructorName();
- body = astFactory.emptyFunctionBody(_expect(TokenType.SEMICOLON));
- if (factoryKeyword == null) {
- _reportErrorForNode(
- ParserErrorCode.REDIRECTION_IN_NON_FACTORY_CONSTRUCTOR,
- redirectedConstructor);
- }
- } else {
- body =
- parseFunctionBody(true, ParserErrorCode.MISSING_FUNCTION_BODY, false);
- if (constKeyword != null &&
- factoryKeyword != null &&
- externalKeyword == null &&
- body is! NativeFunctionBody) {
- _reportErrorForToken(ParserErrorCode.CONST_FACTORY, factoryKeyword);
- } else if (body is EmptyFunctionBody) {
- if (factoryKeyword != null &&
- externalKeyword == null &&
- _parseFunctionBodies) {
- _reportErrorForToken(
- ParserErrorCode.FACTORY_WITHOUT_BODY, factoryKeyword);
- }
- } else {
- if (constKeyword != null && body is! NativeFunctionBody) {
- _reportErrorForNode(
- ParserErrorCode.CONST_CONSTRUCTOR_WITH_BODY, body);
- } else if (externalKeyword != null) {
- _reportErrorForNode(
- ParserErrorCode.EXTERNAL_CONSTRUCTOR_WITH_BODY, body);
- } else if (!bodyAllowed) {
- _reportErrorForNode(
- ParserErrorCode.REDIRECTING_CONSTRUCTOR_WITH_BODY, body);
- }
- }
- }
- return astFactory.constructorDeclaration(
- commentAndMetadata.comment,
- commentAndMetadata.metadata,
- externalKeyword,
- constKeyword,
- factoryKeyword,
- returnType,
- period,
- name,
- parameters,
- separator,
- initializers,
- redirectedConstructor,
- body);
- }
-
- /// Parse an enum constant declaration. Return the enum constant declaration
- /// that was parsed.
- ///
- /// Specified:
- ///
- /// enumConstant ::=
- /// id
- ///
- /// Actual:
- ///
- /// enumConstant ::=
- /// metadata id
- EnumConstantDeclaration _parseEnumConstantDeclaration() {
- CommentAndMetadata commentAndMetadata = parseCommentAndMetadata();
- SimpleIdentifier name;
- if (_matchesIdentifier()) {
- name = _parseSimpleIdentifierUnchecked(isDeclaration: true);
- } else {
- name = createSyntheticIdentifier();
- }
- return astFactory.enumConstantDeclaration(
- commentAndMetadata.comment, commentAndMetadata.metadata, name);
- }
-
- /// Parse a list of formal parameters given that the list starts with the
- /// given [leftParenthesis]. Return the formal parameters that were parsed.
- FormalParameterList _parseFormalParameterListAfterParen(Token leftParenthesis,
- {bool inFunctionType = false}) {
- if (_matches(TokenType.CLOSE_PAREN)) {
- return astFactory.formalParameterList(
- leftParenthesis, null, null, null, getAndAdvance());
- }
- //
- // Even though it is invalid to have default parameters outside of brackets,
- // required parameters inside of brackets, or multiple groups of default and
- // named parameters, we allow all of these cases so that we can recover
- // better.
- //
- List<FormalParameter> parameters = <FormalParameter>[];
- Token leftSquareBracket;
- Token rightSquareBracket;
- Token leftCurlyBracket;
- Token rightCurlyBracket;
- ParameterKind kind = ParameterKind.REQUIRED;
- bool firstParameter = true;
- bool reportedMultiplePositionalGroups = false;
- bool reportedMultipleNamedGroups = false;
- bool reportedMixedGroups = false;
- bool wasOptionalParameter = false;
- Token initialToken;
- do {
- if (firstParameter) {
- firstParameter = false;
- } else if (!_optional(TokenType.COMMA)) {
- // TODO(brianwilkerson) The token is wrong, we need to recover from this
- // case.
- if (_getEndToken(leftParenthesis) != null) {
- _reportErrorForCurrentToken(
- ParserErrorCode.EXPECTED_TOKEN, [TokenType.COMMA.lexeme]);
- } else {
- _reportErrorForToken(ParserErrorCode.MISSING_CLOSING_PARENTHESIS,
- _currentToken.previous);
- break;
- }
- }
- initialToken = _currentToken;
- //
- // Handle the beginning of parameter groups.
- //
- TokenType type = _currentToken.type;
- if (type == TokenType.OPEN_SQUARE_BRACKET) {
- wasOptionalParameter = true;
- if (leftSquareBracket != null && !reportedMultiplePositionalGroups) {
- _reportErrorForCurrentToken(
- ParserErrorCode.MULTIPLE_POSITIONAL_PARAMETER_GROUPS);
- reportedMultiplePositionalGroups = true;
- }
- if (leftCurlyBracket != null && !reportedMixedGroups) {
- _reportErrorForCurrentToken(ParserErrorCode.MIXED_PARAMETER_GROUPS);
- reportedMixedGroups = true;
- }
- leftSquareBracket = getAndAdvance();
- kind = ParameterKind.POSITIONAL;
- } else if (type == TokenType.OPEN_CURLY_BRACKET) {
- wasOptionalParameter = true;
- if (leftCurlyBracket != null && !reportedMultipleNamedGroups) {
- _reportErrorForCurrentToken(
- ParserErrorCode.MULTIPLE_NAMED_PARAMETER_GROUPS);
- reportedMultipleNamedGroups = true;
- }
- if (leftSquareBracket != null && !reportedMixedGroups) {
- _reportErrorForCurrentToken(ParserErrorCode.MIXED_PARAMETER_GROUPS);
- reportedMixedGroups = true;
- }
- leftCurlyBracket = getAndAdvance();
- kind = ParameterKind.NAMED;
- }
- //
- // Parse and record the parameter.
- //
- FormalParameter parameter =
- parseFormalParameter(kind, inFunctionType: inFunctionType);
- parameters.add(parameter);
- if (kind == ParameterKind.REQUIRED && wasOptionalParameter) {
- _reportErrorForNode(
- ParserErrorCode.NORMAL_BEFORE_OPTIONAL_PARAMETERS, parameter);
- }
- //
- // Handle the end of parameter groups.
- //
- // TODO(brianwilkerson) Improve the detection and reporting of missing and
- // mismatched delimiters.
- type = _currentToken.type;
-
- // Advance past trailing commas as appropriate.
- if (type == TokenType.COMMA) {
- // Only parse commas trailing normal (non-positional/named) params.
- if (rightSquareBracket == null && rightCurlyBracket == null) {
- Token next = _peek();
- if (next.type == TokenType.CLOSE_PAREN ||
- next.type == TokenType.CLOSE_CURLY_BRACKET ||
- next.type == TokenType.CLOSE_SQUARE_BRACKET) {
- _advance();
- type = _currentToken.type;
- }
- }
- }
-
- if (type == TokenType.CLOSE_SQUARE_BRACKET) {
- rightSquareBracket = getAndAdvance();
- if (leftSquareBracket == null) {
- if (leftCurlyBracket != null) {
- _reportErrorForCurrentToken(
- ParserErrorCode.WRONG_TERMINATOR_FOR_PARAMETER_GROUP,
- ['}', ']']);
- rightCurlyBracket = rightSquareBracket;
- rightSquareBracket;
- // Skip over synthetic closer inserted by fasta
- // since we've already reported an error
- if (_currentToken.type == TokenType.CLOSE_CURLY_BRACKET &&
- _currentToken.isSynthetic) {
- _advance();
- }
- } else {
- _reportErrorForCurrentToken(
- ParserErrorCode.UNEXPECTED_TERMINATOR_FOR_PARAMETER_GROUP,
- ["["]);
- }
- }
- kind = ParameterKind.REQUIRED;
- } else if (type == TokenType.CLOSE_CURLY_BRACKET) {
- rightCurlyBracket = getAndAdvance();
- if (leftCurlyBracket == null) {
- if (leftSquareBracket != null) {
- _reportErrorForCurrentToken(
- ParserErrorCode.WRONG_TERMINATOR_FOR_PARAMETER_GROUP,
- [']', '}']);
- rightSquareBracket = rightCurlyBracket;
- rightCurlyBracket;
- // Skip over synthetic closer inserted by fasta
- // since we've already reported an error
- if (_currentToken.type == TokenType.CLOSE_SQUARE_BRACKET &&
- _currentToken.isSynthetic) {
- _advance();
- }
- } else {
- _reportErrorForCurrentToken(
- ParserErrorCode.UNEXPECTED_TERMINATOR_FOR_PARAMETER_GROUP,
- ["{"]);
- }
- }
- kind = ParameterKind.REQUIRED;
- }
- } while (!_matches(TokenType.CLOSE_PAREN) &&
- !identical(initialToken, _currentToken));
- Token rightParenthesis = _expect(TokenType.CLOSE_PAREN);
- //
- // Check that the groups were closed correctly.
- //
- if (leftSquareBracket != null && rightSquareBracket == null) {
- _reportErrorForCurrentToken(
- ParserErrorCode.MISSING_TERMINATOR_FOR_PARAMETER_GROUP, ["]"]);
- }
- if (leftCurlyBracket != null && rightCurlyBracket == null) {
- _reportErrorForCurrentToken(
- ParserErrorCode.MISSING_TERMINATOR_FOR_PARAMETER_GROUP, ["}"]);
- }
- //
- // Build the parameter list.
- //
- leftSquareBracket ??= leftCurlyBracket;
- rightSquareBracket ??= rightCurlyBracket;
- return astFactory.formalParameterList(leftParenthesis, parameters,
- leftSquareBracket, rightSquareBracket, rightParenthesis);
- }
-
- /// Parse a list of formal parameters. Return the formal parameters that were
- /// parsed.
- ///
- /// This method assumes that the current token matches `TokenType.OPEN_PAREN`.
- FormalParameterList _parseFormalParameterListUnchecked(
- {bool inFunctionType = false}) {
- return _parseFormalParameterListAfterParen(getAndAdvance(),
- inFunctionType: inFunctionType);
- }
-
- /// Parse a function declaration statement. The [commentAndMetadata] is the
- /// documentation comment and metadata to be associated with the declaration.
- /// The [returnType] is the return type, or `null` if there is no return type.
- /// Return the function declaration statement that was parsed.
- ///
- /// functionDeclarationStatement ::=
- /// functionSignature functionBody
- Statement _parseFunctionDeclarationStatementAfterReturnType(
- CommentAndMetadata commentAndMetadata, TypeAnnotation returnType) {
- FunctionDeclaration declaration =
- parseFunctionDeclaration(commentAndMetadata, null, returnType);
- Token propertyKeyword = declaration.propertyKeyword;
- if (propertyKeyword != null) {
- if (propertyKeyword.keyword == Keyword.GET) {
- _reportErrorForToken(
- ParserErrorCode.GETTER_IN_FUNCTION, propertyKeyword);
- } else {
- _reportErrorForToken(
- ParserErrorCode.SETTER_IN_FUNCTION, propertyKeyword);
- }
- }
- return astFactory.functionDeclarationStatement(declaration);
- }
-
- /// Parse a function type alias. The [commentAndMetadata] is the metadata to
- /// be associated with the member. The [keyword] is the token representing the
- /// 'typedef' keyword. Return the function type alias that was parsed.
- ///
- /// functionTypeAlias ::=
- /// functionPrefix typeParameterList? formalParameterList ';'
- ///
- /// functionPrefix ::=
- /// returnType? name
- FunctionTypeAlias _parseFunctionTypeAlias(
- CommentAndMetadata commentAndMetadata, Token keyword) {
- TypeAnnotation returnType;
- if (hasReturnTypeInTypeAlias) {
- returnType = parseTypeAnnotation(false);
- }
- SimpleIdentifier name = parseSimpleIdentifier(isDeclaration: true);
- TypeParameterList typeParameters;
- if (_matches(TokenType.LT)) {
- typeParameters = parseTypeParameterList();
- }
- TokenType type = _currentToken.type;
- if (type == TokenType.SEMICOLON || type == TokenType.EOF) {
- _reportErrorForCurrentToken(ParserErrorCode.MISSING_TYPEDEF_PARAMETERS);
- FormalParameterList parameters = astFactory.formalParameterList(
- _createSyntheticToken(TokenType.OPEN_PAREN),
- null,
- null,
- null,
- _createSyntheticToken(TokenType.CLOSE_PAREN));
- Token semicolon = _expect(TokenType.SEMICOLON);
- return astFactory.functionTypeAlias(
- commentAndMetadata.comment,
- commentAndMetadata.metadata,
- keyword,
- returnType,
- name,
- typeParameters,
- parameters,
- semicolon);
- } else if (type == TokenType.OPEN_PAREN) {
- FormalParameterList parameters = _parseFormalParameterListUnchecked();
- _validateFormalParameterList(parameters);
- Token semicolon = _expect(TokenType.SEMICOLON);
- return astFactory.functionTypeAlias(
- commentAndMetadata.comment,
- commentAndMetadata.metadata,
- keyword,
- returnType,
- name,
- typeParameters,
- parameters,
- semicolon);
- } else {
- _reportErrorForCurrentToken(ParserErrorCode.MISSING_TYPEDEF_PARAMETERS);
- // Recovery: At the very least we should skip to the start of the next
- // valid compilation unit member, allowing for the possibility of finding
- // the typedef parameters before that point.
- return astFactory.functionTypeAlias(
- commentAndMetadata.comment,
- commentAndMetadata.metadata,
- keyword,
- returnType,
- name,
- typeParameters,
- astFactory.formalParameterList(
- _createSyntheticToken(TokenType.OPEN_PAREN),
- null,
- null,
- null,
- _createSyntheticToken(TokenType.CLOSE_PAREN)),
- _createSyntheticToken(TokenType.SEMICOLON));
- }
- }
-
- /// Parse the generic method or function's type parameters.
- ///
- /// For backwards compatibility this can optionally use comments.
- /// See [parseGenericMethodComments].
- TypeParameterList _parseGenericMethodTypeParameters() {
- if (_matches(TokenType.LT)) {
- return parseTypeParameterList();
- }
- return null;
- }
-
- /// Parse a library name. The [missingNameError] is the error code to be used
- /// if the library name is missing. The [missingNameToken] is the token
- /// associated with the error produced if the library name is missing. Return
- /// the library name that was parsed.
- ///
- /// libraryName ::=
- /// libraryIdentifier
- LibraryIdentifier _parseLibraryName(
- ParserErrorCode missingNameError, Token missingNameToken) {
- if (_matchesIdentifier()) {
- return parseLibraryIdentifier();
- } else if (_matches(TokenType.STRING)) {
- // Recovery: This should be extended to handle arbitrary tokens until we
- // can find a token that can start a compilation unit member.
- StringLiteral string = parseStringLiteral();
- _reportErrorForNode(ParserErrorCode.NON_IDENTIFIER_LIBRARY_NAME, string);
- } else {
- _reportErrorForToken(missingNameError, missingNameToken);
- }
- return astFactory
- .libraryIdentifier(<SimpleIdentifier>[createSyntheticIdentifier()]);
- }
-
- /// Parse a method declaration. The [commentAndMetadata] is the documentation
- /// comment and metadata to be associated with the declaration. The
- /// [externalKeyword] is the 'external' token. The [staticKeyword] is the
- /// static keyword, or `null` if the getter is not static. The [returnType] is
- /// the return type of the method. The [name] is the name of the method. The
- /// [parameters] is the parameters to the method. Return the method
- /// declaration that was parsed.
- ///
- /// functionDeclaration ::=
- /// ('external' 'static'?)? functionSignature functionBody
- /// | 'external'? functionSignature ';'
- MethodDeclaration _parseMethodDeclarationAfterParameters(
- CommentAndMetadata commentAndMetadata,
- Token externalKeyword,
- Token staticKeyword,
- TypeAnnotation returnType,
- SimpleIdentifier name,
- TypeParameterList typeParameters,
- FormalParameterList parameters) {
- FunctionBody body = parseFunctionBody(
- externalKeyword != null || staticKeyword == null,
- ParserErrorCode.MISSING_FUNCTION_BODY,
- false);
- if (externalKeyword != null) {
- if (body is! EmptyFunctionBody) {
- _reportErrorForNode(ParserErrorCode.EXTERNAL_METHOD_WITH_BODY, body);
- }
- } else if (staticKeyword != null) {
- if (body is EmptyFunctionBody && _parseFunctionBodies) {
- _reportErrorForNode(ParserErrorCode.ABSTRACT_STATIC_METHOD, body);
- }
- }
- return astFactory.methodDeclaration(
- commentAndMetadata.comment,
- commentAndMetadata.metadata,
- externalKeyword,
- staticKeyword,
- returnType,
- null,
- null,
- name,
- typeParameters,
- parameters,
- body);
- }
-
- /// Parse a method declaration. The [commentAndMetadata] is the documentation
- /// comment and metadata to be associated with the declaration. The
- /// [externalKeyword] is the 'external' token. The [staticKeyword] is the
- /// static keyword, or `null` if the getter is not static. The [returnType] is
- /// the return type of the method. Return the method declaration that was
- /// parsed.
- ///
- /// functionDeclaration ::=
- /// 'external'? 'static'? functionSignature functionBody
- /// | 'external'? functionSignature ';'
- MethodDeclaration _parseMethodDeclarationAfterReturnType(
- CommentAndMetadata commentAndMetadata,
- Token externalKeyword,
- Token staticKeyword,
- TypeAnnotation returnType) {
- SimpleIdentifier methodName = parseSimpleIdentifier(isDeclaration: true);
- TypeParameterList typeParameters = _parseGenericMethodTypeParameters();
- FormalParameterList parameters;
- TokenType type = _currentToken.type;
- // TODO(brianwilkerson) Figure out why we care what the current token is if
- // it isn't a paren.
- if (type != TokenType.OPEN_PAREN &&
- (type == TokenType.OPEN_CURLY_BRACKET || type == TokenType.FUNCTION)) {
- _reportErrorForToken(
- ParserErrorCode.MISSING_METHOD_PARAMETERS, _currentToken.previous);
- parameters = astFactory.formalParameterList(
- _createSyntheticToken(TokenType.OPEN_PAREN),
- null,
- null,
- null,
- _createSyntheticToken(TokenType.CLOSE_PAREN));
- } else {
- parameters = parseFormalParameterList();
- }
- _validateFormalParameterList(parameters);
- return _parseMethodDeclarationAfterParameters(
- commentAndMetadata,
- externalKeyword,
- staticKeyword,
- returnType,
- methodName,
- typeParameters,
- parameters);
- }
-
- /// Parse a class native clause. Return the native clause that was parsed.
- ///
- /// This method assumes that the current token matches `_NATIVE`.
- ///
- /// classNativeClause ::=
- /// 'native' name
- NativeClause _parseNativeClause() {
- Token keyword = getAndAdvance();
- StringLiteral name = parseStringLiteral();
- return astFactory.nativeClause(keyword, name);
- }
-
- /// Parse an operator declaration starting after the 'operator' keyword. The
- /// [commentAndMetadata] is the documentation comment and metadata to be
- /// associated with the declaration. The [externalKeyword] is the 'external'
- /// token. The [returnType] is the return type that has already been parsed,
- /// or `null` if there was no return type. The [operatorKeyword] is the
- /// 'operator' keyword. Return the operator declaration that was parsed.
- ///
- /// operatorDeclaration ::=
- /// operatorSignature (';' | functionBody)
- ///
- /// operatorSignature ::=
- /// 'external'? returnType? 'operator' operator formalParameterList
- MethodDeclaration _parseOperatorAfterKeyword(
- CommentAndMetadata commentAndMetadata,
- Token externalKeyword,
- TypeAnnotation returnType,
- Token operatorKeyword) {
- if (!_currentToken.isUserDefinableOperator) {
- _reportErrorForCurrentToken(
- _currentToken.type == TokenType.EQ_EQ_EQ
- ? ParserErrorCode.INVALID_OPERATOR
- : ParserErrorCode.NON_USER_DEFINABLE_OPERATOR,
- [_currentToken.lexeme]);
- }
- SimpleIdentifier name =
- astFactory.simpleIdentifier(getAndAdvance(), isDeclaration: true);
- if (_matches(TokenType.EQ)) {
- Token previous = _currentToken.previous;
- if ((_tokenMatches(previous, TokenType.EQ_EQ) ||
- _tokenMatches(previous, TokenType.BANG_EQ)) &&
- _currentToken.offset == previous.offset + 2) {
- _reportErrorForCurrentToken(ParserErrorCode.INVALID_OPERATOR,
- ["${previous.lexeme}${_currentToken.lexeme}"]);
- _advance();
- }
- }
- FormalParameterList parameters = parseFormalParameterList();
- _validateFormalParameterList(parameters);
- FunctionBody body =
- parseFunctionBody(true, ParserErrorCode.MISSING_FUNCTION_BODY, false);
- if (externalKeyword != null && body is! EmptyFunctionBody) {
- _reportErrorForCurrentToken(ParserErrorCode.EXTERNAL_OPERATOR_WITH_BODY);
- }
- return astFactory.methodDeclaration(
- commentAndMetadata.comment,
- commentAndMetadata.metadata,
- externalKeyword,
- null,
- returnType,
- null,
- operatorKeyword,
- name,
- null,
- parameters,
- body);
- }
-
- /// Parse a return type if one is given, otherwise return `null` without
- /// advancing. Return the return type that was parsed.
- TypeAnnotation _parseOptionalReturnType() {
- Keyword keyword = _currentToken.keyword;
- if (keyword == Keyword.VOID) {
- if (_atGenericFunctionTypeAfterReturnType(_peek())) {
- return parseTypeAnnotation(false);
- }
- return astFactory.typeName(
- astFactory.simpleIdentifier(getAndAdvance()), null);
- } else if (_matchesIdentifier()) {
- Token next = _peek();
- if (keyword != Keyword.GET &&
- keyword != Keyword.SET &&
- keyword != Keyword.OPERATOR &&
- (_tokenMatchesIdentifier(next) ||
- _tokenMatches(next, TokenType.LT))) {
- Token afterTypeParameters = _skipTypeParameterList(next);
- if (afterTypeParameters != null &&
- _tokenMatches(afterTypeParameters, TokenType.OPEN_PAREN)) {
- // If the identifier is followed by type parameters and a parenthesis,
- // then the identifier is the name of a generic method, not a return
- // type.
- return null;
- }
- return parseTypeAnnotation(false);
- }
- Token next2 = next.next;
- Token next3 = next2.next;
- if (_tokenMatches(next, TokenType.PERIOD) &&
- _tokenMatchesIdentifier(next2) &&
- (_tokenMatchesIdentifier(next3) ||
- _tokenMatches(next3, TokenType.LT))) {
- return parseTypeAnnotation(false);
- }
- }
- return null;
- }
-
- /// Parse a [TypeArgumentList] if present, otherwise return null.
- /// This also supports the comment form, if enabled: `/*<T>*/`
- TypeArgumentList _parseOptionalTypeArguments() {
- if (_matches(TokenType.LT)) {
- return parseTypeArgumentList();
- }
- return null;
- }
-
- /// Parse a part directive. The [commentAndMetadata] is the metadata to be
- /// associated with the directive. Return the part or part-of directive that
- /// was parsed.
- ///
- /// This method assumes that the current token matches `Keyword.PART`.
- ///
- /// partDirective ::=
- /// metadata 'part' stringLiteral ';'
- Directive _parsePartDirective(CommentAndMetadata commentAndMetadata) {
- Token partKeyword = getAndAdvance();
- StringLiteral partUri = _parseUri();
- Token semicolon = _expect(TokenType.SEMICOLON);
- return astFactory.partDirective(commentAndMetadata.comment,
- commentAndMetadata.metadata, partKeyword, partUri, semicolon);
- }
-
- /// Parse a part-of directive. The [commentAndMetadata] is the metadata to be
- /// associated with the directive. Return the part or part-of directive that
- /// was parsed.
- ///
- /// This method assumes that the current token matches [Keyword.PART] and that
- /// the following token matches the identifier 'of'.
- ///
- /// partOfDirective ::=
- /// metadata 'part' 'of' identifier ';'
- Directive _parsePartOfDirective(CommentAndMetadata commentAndMetadata) {
- Token partKeyword = getAndAdvance();
- Token ofKeyword = getAndAdvance();
- if (_matches(TokenType.STRING)) {
- StringLiteral libraryUri = _parseUri();
- Token semicolon = _expect(TokenType.SEMICOLON);
- return astFactory.partOfDirective(
- commentAndMetadata.comment,
- commentAndMetadata.metadata,
- partKeyword,
- ofKeyword,
- libraryUri,
- null,
- semicolon);
- }
- LibraryIdentifier libraryName = _parseLibraryName(
- ParserErrorCode.MISSING_NAME_IN_PART_OF_DIRECTIVE, ofKeyword);
- Token semicolon = _expect(TokenType.SEMICOLON);
- return astFactory.partOfDirective(
- commentAndMetadata.comment,
- commentAndMetadata.metadata,
- partKeyword,
- ofKeyword,
- null,
- libraryName,
- semicolon);
- }
-
- /// Parse a prefixed identifier given that the given [qualifier] was already
- /// parsed. Return the prefixed identifier that was parsed.
- ///
- /// prefixedIdentifier ::=
- /// identifier ('.' identifier)?
- Identifier _parsePrefixedIdentifierAfterIdentifier(
- SimpleIdentifier qualifier) {
- if (!_matches(TokenType.PERIOD)) {
- return qualifier;
- }
- Token period = getAndAdvance();
- SimpleIdentifier qualified = parseSimpleIdentifier();
- return astFactory.prefixedIdentifier(qualifier, period, qualified);
- }
-
- /// Parse a prefixed identifier. Return the prefixed identifier that was
- /// parsed.
- ///
- /// This method assumes that the current token matches an identifier.
- ///
- /// prefixedIdentifier ::=
- /// identifier ('.' identifier)?
- Identifier _parsePrefixedIdentifierUnchecked() {
- return _parsePrefixedIdentifierAfterIdentifier(
- _parseSimpleIdentifierUnchecked());
- }
-
- /// Parse a simple identifier. Return the simple identifier that was parsed.
- ///
- /// This method assumes that the current token matches an identifier.
- ///
- /// identifier ::=
- /// IDENTIFIER
- SimpleIdentifier _parseSimpleIdentifierUnchecked(
- {bool isDeclaration = false}) {
- String lexeme = _currentToken.lexeme;
- if ((_inAsync || _inGenerator) && (lexeme == _AWAIT || lexeme == _YIELD)) {
- _reportErrorForCurrentToken(
- ParserErrorCode.ASYNC_KEYWORD_USED_AS_IDENTIFIER);
- }
- return astFactory.simpleIdentifier(getAndAdvance(),
- isDeclaration: isDeclaration);
- }
-
- /// Parse a list of statements within a switch statement. Return the
- /// statements that were parsed.
- ///
- /// statements ::=
- /// statement*
- List<Statement> _parseStatementList() {
- List<Statement> statements = <Statement>[];
- Token statementStart = _currentToken;
- TokenType type = _currentToken.type;
- while (type != TokenType.EOF &&
- type != TokenType.CLOSE_CURLY_BRACKET &&
- !isSwitchMember()) {
- statements.add(parseStatement2());
- if (identical(_currentToken, statementStart)) {
- _reportErrorForToken(ParserErrorCode.UNEXPECTED_TOKEN, _currentToken,
- [_currentToken.lexeme]);
- _advance();
- }
- statementStart = _currentToken;
- type = _currentToken.type;
- }
- return statements;
- }
-
- /// Parse a string literal that contains interpolations. Return the string
- /// literal that was parsed.
- ///
- /// This method assumes that the current token matches either
- /// [TokenType.STRING_INTERPOLATION_EXPRESSION] or
- /// [TokenType.STRING_INTERPOLATION_IDENTIFIER].
- StringInterpolation _parseStringInterpolation(Token string) {
- List<InterpolationElement> elements = <InterpolationElement>[
- astFactory.interpolationString(
- string, computeStringValue(string.lexeme, true, false))
- ];
- bool hasMore = true;
- bool isExpression = _matches(TokenType.STRING_INTERPOLATION_EXPRESSION);
- while (hasMore) {
- if (isExpression) {
- Token openToken = getAndAdvance();
- bool wasInInitializer = _inInitializer;
- _inInitializer = false;
- try {
- Expression expression = parseExpression2();
- Token rightBracket = _expect(TokenType.CLOSE_CURLY_BRACKET);
- elements.add(astFactory.interpolationExpression(
- openToken, expression, rightBracket));
- } finally {
- _inInitializer = wasInInitializer;
- }
- } else {
- Token openToken = getAndAdvance();
- Expression expression;
- if (_matchesKeyword(Keyword.THIS)) {
- expression = astFactory.thisExpression(getAndAdvance());
- } else {
- expression = parseSimpleIdentifier();
- }
- elements.add(
- astFactory.interpolationExpression(openToken, expression, null));
- }
- if (_matches(TokenType.STRING)) {
- string = getAndAdvance();
- isExpression = _matches(TokenType.STRING_INTERPOLATION_EXPRESSION);
- hasMore =
- isExpression || _matches(TokenType.STRING_INTERPOLATION_IDENTIFIER);
- elements.add(astFactory.interpolationString(
- string, computeStringValue(string.lexeme, false, !hasMore)));
- } else {
- hasMore = false;
- }
- }
- return astFactory.stringInterpolation(elements);
- }
-
- /// Parse a string literal. Return the string literal that was parsed.
- ///
- /// This method assumes that the current token matches `TokenType.STRING`.
- ///
- /// stringLiteral ::=
- /// MULTI_LINE_STRING+
- /// | SINGLE_LINE_STRING+
- StringLiteral _parseStringLiteralUnchecked() {
- List<StringLiteral> strings = <StringLiteral>[];
- do {
- Token string = getAndAdvance();
- if (_matches(TokenType.STRING_INTERPOLATION_EXPRESSION) ||
- _matches(TokenType.STRING_INTERPOLATION_IDENTIFIER)) {
- strings.add(_parseStringInterpolation(string));
- } else {
- strings.add(astFactory.simpleStringLiteral(
- string, computeStringValue(string.lexeme, true, true)));
- }
- } while (_matches(TokenType.STRING));
- return strings.length == 1
- ? strings[0]
- : astFactory.adjacentStrings(strings);
- }
-
- /// Parse a type annotation, possibly superseded by a type name in a comment.
- /// Return the type name that was parsed.
- ///
- /// This method assumes that the current token is an identifier.
- ///
- /// type ::=
- /// qualified typeArguments?
- TypeAnnotation _parseTypeAnnotationAfterIdentifier() {
- return parseTypeAnnotation(false);
- }
-
- TypeName _parseTypeName(bool inExpression) {
- Identifier typeName;
- if (_matchesIdentifier()) {
- typeName = _parsePrefixedIdentifierUnchecked();
- } else if (_matchesKeyword(Keyword.VAR)) {
- _reportErrorForCurrentToken(ParserErrorCode.VAR_AS_TYPE_NAME);
- typeName = astFactory.simpleIdentifier(getAndAdvance());
- } else {
- typeName = createSyntheticIdentifier();
- _reportErrorForCurrentToken(ParserErrorCode.EXPECTED_TYPE_NAME);
- }
- TypeArgumentList typeArguments = _parseOptionalTypeArguments();
- return astFactory.typeName(typeName, typeArguments);
- }
-
- /// Parse a string literal representing a URI. Return the string literal that
- /// was parsed.
- StringLiteral _parseUri() {
- // TODO(brianwilkerson) Should this function also return true for valid
- // top-level keywords?
- bool isKeywordAfterUri(Token token) =>
- token.lexeme == Keyword.AS.lexeme ||
- token.lexeme == _HIDE ||
- token.lexeme == _SHOW;
- TokenType type = _currentToken.type;
- if (type != TokenType.STRING &&
- type != TokenType.SEMICOLON &&
- !isKeywordAfterUri(_currentToken)) {
- // Attempt to recover in the case where the URI was not enclosed in
- // quotes.
- Token token = _currentToken;
- bool isValidInUri(Token token) {
- TokenType type = token.type;
- return type == TokenType.COLON ||
- type == TokenType.SLASH ||
- type == TokenType.PERIOD ||
- type == TokenType.PERIOD_PERIOD ||
- type == TokenType.PERIOD_PERIOD_PERIOD ||
- type == TokenType.INT ||
- type == TokenType.DOUBLE;
- }
-
- while ((_tokenMatchesIdentifier(token) && !isKeywordAfterUri(token)) ||
- isValidInUri(token)) {
- token = token.next;
- }
- if (_tokenMatches(token, TokenType.SEMICOLON) ||
- isKeywordAfterUri(token)) {
- Token endToken = token.previous;
- token = _currentToken;
- int endOffset = token.end;
- StringBuffer buffer = StringBuffer();
- buffer.write(token.lexeme);
- while (token != endToken) {
- token = token.next;
- if (token.offset != endOffset || token.precedingComments != null) {
- return parseStringLiteral();
- }
- buffer.write(token.lexeme);
- endOffset = token.end;
- }
- String value = buffer.toString();
- Token newToken =
- StringToken(TokenType.STRING, "'$value'", _currentToken.offset);
- _reportErrorForToken(
- ParserErrorCode.NON_STRING_LITERAL_AS_URI, newToken);
- _currentToken = endToken.next;
- return astFactory.simpleStringLiteral(newToken, value);
- }
- }
- return parseStringLiteral();
- }
-
- /// Parse a variable declaration statement. The [commentAndMetadata] is the
- /// metadata to be associated with the variable declaration statement, or
- /// `null` if there is no attempt at parsing the comment and metadata. The
- /// [keyword] is the token representing the 'final', 'const' or 'var' keyword,
- /// or `null` if there is no keyword. The [type] is the type of the variables
- /// in the list. Return the variable declaration statement that was parsed.
- ///
- /// variableDeclarationStatement ::=
- /// variableDeclarationList ';'
- VariableDeclarationStatement _parseVariableDeclarationStatementAfterType(
- CommentAndMetadata commentAndMetadata,
- Token keyword,
- TypeAnnotation type) {
- VariableDeclarationList variableList =
- parseVariableDeclarationListAfterType(
- commentAndMetadata, keyword, type);
- Token semicolon = _expect(TokenType.SEMICOLON);
- return astFactory.variableDeclarationStatement(variableList, semicolon);
- }
-
- /// Return the token that is immediately after the current token. This is
- /// equivalent to [_peekAt](1).
- Token _peek() => _currentToken.next;
-
- /// Return the token that is the given [distance] after the current token,
- /// where the distance is the number of tokens to look ahead. A distance of
- /// `0` is the current token, `1` is the next token, etc.
- Token _peekAt(int distance) {
- Token token = _currentToken;
- for (int i = 0; i < distance; i++) {
- token = token.next;
- }
- return token;
- }
-
- String _removeGitHubInlineCode(String comment) {
- int index = 0;
- while (true) {
- int beginIndex = comment.indexOf('`', index);
- if (beginIndex == -1) {
- break;
- }
- int endIndex = comment.indexOf('`', beginIndex + 1);
- if (endIndex == -1) {
- break;
- }
- comment = comment.substring(0, beginIndex + 1) +
- ' ' * (endIndex - beginIndex - 1) +
- comment.substring(endIndex);
- index = endIndex + 1;
- }
- return comment;
- }
-
- /// Report the given [error].
- void _reportError(AnalysisError error) {
- if (_errorListenerLock != 0) {
- return;
- }
- _errorListener.onError(error);
- }
-
- /// Report an error with the given [errorCode] and [arguments] associated with
- /// the current token.
- void _reportErrorForCurrentToken(ParserErrorCode errorCode,
- [List<Object> arguments]) {
- _reportErrorForToken(errorCode, _currentToken, arguments);
- }
-
- /// Report an error with the given [errorCode] and [arguments] associated with
- /// the given [node].
- void _reportErrorForNode(ParserErrorCode errorCode, AstNode node,
- [List<Object> arguments]) {
- _reportError(
- AnalysisError(_source, node.offset, node.length, errorCode, arguments));
- }
-
- /// Report an error with the given [errorCode] and [arguments] associated with
- /// the given [token].
- void _reportErrorForToken(ErrorCode errorCode, Token token,
- [List<Object> arguments]) {
- if (token.type == TokenType.EOF) {
- token = token.previous;
- }
- _reportError(AnalysisError(_source, token.offset, math.max(token.length, 1),
- errorCode, arguments));
- }
-
- /// Skips a block with all containing blocks.
- void _skipBlock() {
- Token endToken = (_currentToken as BeginToken).endToken;
- if (endToken == null) {
- endToken = _currentToken.next;
- while (!identical(endToken, _currentToken)) {
- _currentToken = endToken;
- endToken = _currentToken.next;
- }
- _reportErrorForToken(
- ParserErrorCode.EXPECTED_TOKEN, _currentToken.previous, ["}"]);
- } else {
- _currentToken = endToken.next;
- }
- }
-
- /// Parse the 'final', 'const', 'var' or type preceding a variable
- /// declaration, starting at the given token, without actually creating a
- /// type or changing the current token. Return the token following the type
- /// that was parsed, or `null` if the given token is not the first token in a
- /// valid type. The [startToken] is the token at which parsing is to begin.
- /// Return the token following the type that was parsed.
- ///
- /// finalConstVarOrType ::=
- /// | 'final' type?
- /// | 'const' type?
- /// | 'var'
- /// | type
- Token _skipFinalConstVarOrType(Token startToken) {
- Keyword keyword = startToken.keyword;
- if (keyword == Keyword.FINAL || keyword == Keyword.CONST) {
- Token next = startToken.next;
- if (_tokenMatchesIdentifier(next)) {
- Token next2 = next.next;
- // "Type parameter" or "Type<" or "prefix.Type"
- if (_tokenMatchesIdentifier(next2) ||
- _tokenMatches(next2, TokenType.LT) ||
- _tokenMatches(next2, TokenType.PERIOD)) {
- return skipTypeName(next);
- }
- // "parameter"
- return next;
- }
- } else if (keyword == Keyword.VAR) {
- return startToken.next;
- } else if (_tokenMatchesIdentifier(startToken)) {
- Token next = startToken.next;
- if (_tokenMatchesIdentifier(next) ||
- _tokenMatches(next, TokenType.LT) ||
- _tokenMatchesKeyword(next, Keyword.THIS) ||
- (_tokenMatches(next, TokenType.PERIOD) &&
- _tokenMatchesIdentifier(next.next) &&
- (_tokenMatchesIdentifier(next.next.next) ||
- _tokenMatches(next.next.next, TokenType.LT) ||
- _tokenMatchesKeyword(next.next.next, Keyword.THIS)))) {
- return skipTypeAnnotation(startToken);
- }
- }
- return null;
- }
-
- /// Parse a list of formal parameters, starting at the [startToken], without
- /// actually creating a formal parameter list or changing the current token.
- /// Return the token following the formal parameter list that was parsed, or
- /// `null` if the given token is not the first token in a valid list of formal
- /// parameter.
- ///
- /// Note that unlike other skip methods, this method uses a heuristic. In the
- /// worst case, the parameters could be prefixed by metadata, which would
- /// require us to be able to skip arbitrary expressions. Rather than duplicate
- /// the logic of most of the parse methods we simply look for something that
- /// is likely to be a list of parameters and then skip to returning the token
- /// after the closing parenthesis.
- ///
- /// This method must be kept in sync with [parseFormalParameterList].
- ///
- /// formalParameterList ::=
- /// '(' ')'
- /// | '(' normalFormalParameters (',' optionalFormalParameters)? ')'
- /// | '(' optionalFormalParameters ')'
- ///
- /// normalFormalParameters ::=
- /// normalFormalParameter (',' normalFormalParameter)*
- ///
- /// optionalFormalParameters ::=
- /// optionalPositionalFormalParameters
- /// | namedFormalParameters
- ///
- /// optionalPositionalFormalParameters ::=
- /// '[' defaultFormalParameter (',' defaultFormalParameter)* ']'
- ///
- /// namedFormalParameters ::=
- /// '{' defaultNamedParameter (',' defaultNamedParameter)* '}'
- Token _skipFormalParameterList(Token startToken) {
- if (!_tokenMatches(startToken, TokenType.OPEN_PAREN)) {
- return null;
- }
- Token next = startToken.next;
- if (_tokenMatches(next, TokenType.CLOSE_PAREN)) {
- return next.next;
- }
- //
- // Look to see whether the token after the open parenthesis is something
- // that should only occur at the beginning of a parameter list.
- //
- if (next.matchesAny(const <TokenType>[
- TokenType.AT,
- TokenType.OPEN_SQUARE_BRACKET,
- TokenType.OPEN_CURLY_BRACKET
- ]) ||
- _tokenMatchesKeyword(next, Keyword.VOID) ||
- (_tokenMatchesIdentifier(next) &&
- (next.next.matchesAny(
- const <TokenType>[TokenType.COMMA, TokenType.CLOSE_PAREN])))) {
- return _skipPastMatchingToken(startToken);
- }
- //
- // Look to see whether the first parameter is a function typed parameter
- // without a return type.
- //
- if (_tokenMatchesIdentifier(next) &&
- _tokenMatches(next.next, TokenType.OPEN_PAREN)) {
- Token afterParameters = _skipFormalParameterList(next.next);
- if (afterParameters != null &&
- afterParameters.matchesAny(
- const <TokenType>[TokenType.COMMA, TokenType.CLOSE_PAREN])) {
- return _skipPastMatchingToken(startToken);
- }
- }
- //
- // Look to see whether the first parameter has a type or is a function typed
- // parameter with a return type.
- //
- Token afterType = _skipFinalConstVarOrType(next);
- if (afterType == null) {
- return null;
- }
- if (skipSimpleIdentifier(afterType) == null) {
- return null;
- }
- return _skipPastMatchingToken(startToken);
- }
-
- /// If the [startToken] is a begin token with an associated end token, then
- /// return the token following the end token. Otherwise, return `null`.
- Token _skipPastMatchingToken(Token startToken) {
- if (startToken is! BeginToken) {
- return null;
- }
- Token closeParen = (startToken as BeginToken).endToken;
- if (closeParen == null) {
- return null;
- }
- return closeParen.next;
- }
-
- /// Parse a string literal that contains interpolations, starting at the
- /// [startToken], without actually creating a string literal or changing the
- /// current token. Return the token following the string literal that was
- /// parsed, or `null` if the given token is not the first token in a valid
- /// string literal.
- ///
- /// This method must be kept in sync with [parseStringInterpolation].
- Token _skipStringInterpolation(Token startToken) {
- Token token = startToken;
- TokenType type = token.type;
- while (type == TokenType.STRING_INTERPOLATION_EXPRESSION ||
- type == TokenType.STRING_INTERPOLATION_IDENTIFIER) {
- if (type == TokenType.STRING_INTERPOLATION_EXPRESSION) {
- token = token.next;
- type = token.type;
- //
- // Rather than verify that the following tokens represent a valid
- // expression, we simply skip tokens until we reach the end of the
- // interpolation, being careful to handle nested string literals.
- //
- int bracketNestingLevel = 1;
- while (bracketNestingLevel > 0) {
- if (type == TokenType.EOF) {
- return null;
- } else if (type == TokenType.OPEN_CURLY_BRACKET) {
- bracketNestingLevel++;
- token = token.next;
- } else if (type == TokenType.CLOSE_CURLY_BRACKET) {
- bracketNestingLevel--;
- token = token.next;
- } else if (type == TokenType.STRING) {
- token = skipStringLiteral(token);
- if (token == null) {
- return null;
- }
- } else {
- token = token.next;
- }
- type = token.type;
- }
- token = token.next;
- type = token.type;
- } else {
- token = token.next;
- if (token.type != TokenType.IDENTIFIER) {
- return null;
- }
- token = token.next;
- }
- type = token.type;
- if (type == TokenType.STRING) {
- token = token.next;
- type = token.type;
- }
- }
- return token;
- }
-
- /// Parse a list of type parameters, starting at the [startToken], without
- /// actually creating a type parameter list or changing the current token.
- /// Return the token following the type parameter list that was parsed, or
- /// `null` if the given token is not the first token in a valid type parameter
- /// list.
- ///
- /// This method must be kept in sync with [parseTypeParameterList].
- ///
- /// typeParameterList ::=
- /// '<' typeParameter (',' typeParameter)* '>'
- Token _skipTypeParameterList(Token startToken) {
- if (!_tokenMatches(startToken, TokenType.LT)) {
- return null;
- }
- //
- // We can't skip a type parameter because it can be preceded by metadata,
- // so we just assume that everything before the matching end token is valid.
- //
- int depth = 1;
- Token next = startToken.next;
- while (depth > 0) {
- if (_tokenMatches(next, TokenType.EOF)) {
- return null;
- } else if (_tokenMatches(next, TokenType.LT)) {
- depth++;
- } else if (_tokenMatches(next, TokenType.GT)) {
- depth--;
- } else if (_tokenMatches(next, TokenType.GT_EQ)) {
- if (depth == 1) {
- Token fakeEquals = Token(TokenType.EQ, next.offset + 2);
- fakeEquals.setNextWithoutSettingPrevious(next.next);
- return fakeEquals;
- }
- depth--;
- } else if (_tokenMatches(next, TokenType.GT_GT)) {
- depth -= 2;
- } else if (_tokenMatches(next, TokenType.GT_GT_EQ)) {
- if (depth < 2) {
- return null;
- } else if (depth == 2) {
- Token fakeEquals = Token(TokenType.EQ, next.offset + 2);
- fakeEquals.setNextWithoutSettingPrevious(next.next);
- return fakeEquals;
- }
- depth -= 2;
- }
- next = next.next;
- }
- return next;
- }
-
- /// Assuming that the current token is an index token ('[]'), split it into
- /// two tokens ('[' and ']'), leaving the left bracket as the current token.
- void _splitIndex() {
- // Split the token into two separate tokens.
- BeginToken leftBracket = _createToken(
- _currentToken, TokenType.OPEN_SQUARE_BRACKET,
- isBegin: true);
- Token rightBracket =
- Token(TokenType.CLOSE_SQUARE_BRACKET, _currentToken.offset + 1);
- leftBracket.endToken = rightBracket;
- rightBracket.setNext(_currentToken.next);
- leftBracket.setNext(rightBracket);
- _currentToken.previous.setNext(leftBracket);
- _currentToken = leftBracket;
- }
-
- /// Return `true` if the given [token] has the given [type].
- bool _tokenMatches(Token token, TokenType type) => token.type == type;
-
- /// Return `true` if the given [token] is a valid identifier. Valid
- /// identifiers include built-in identifiers (pseudo-keywords).
- bool _tokenMatchesIdentifier(Token token) =>
- _tokenMatches(token, TokenType.IDENTIFIER) ||
- _tokenMatchesPseudoKeyword(token);
-
- /// Return `true` if the given [token] is either an identifier or a keyword.
- bool _tokenMatchesIdentifierOrKeyword(Token token) =>
- _tokenMatches(token, TokenType.IDENTIFIER) || token.type.isKeyword;
-
- /// Return `true` if the given [token] matches the given [keyword].
- bool _tokenMatchesKeyword(Token token, Keyword keyword) =>
- token.keyword == keyword;
-
- /// Return `true` if the given [token] matches a pseudo keyword.
- bool _tokenMatchesPseudoKeyword(Token token) =>
- token.keyword?.isBuiltInOrPseudo ?? false;
-
- /// Translate the characters at the given [index] in the given [lexeme],
- /// appending the translated character to the given [buffer]. The index is
- /// assumed to be valid.
- int _translateCharacter(StringBuffer buffer, String lexeme, int index) {
- int currentChar = lexeme.codeUnitAt(index);
- if (currentChar != 0x5C) {
- buffer.writeCharCode(currentChar);
- return index + 1;
- }
- //
- // We have found an escape sequence, so we parse the string to determine
- // what kind of escape sequence and what character to add to the builder.
- //
- int length = lexeme.length;
- int currentIndex = index + 1;
- if (currentIndex >= length) {
- // Illegal escape sequence: no char after escape.
- // This cannot actually happen because it would require the escape
- // character to be the last character in the string, but if it were it
- // would escape the closing quote, leaving the string unclosed.
- // reportError(ParserErrorCode.MISSING_CHAR_IN_ESCAPE_SEQUENCE);
- return length;
- }
- currentChar = lexeme.codeUnitAt(currentIndex);
- if (currentChar == 0x6E) {
- buffer.writeCharCode(0xA);
- // newline
- } else if (currentChar == 0x72) {
- buffer.writeCharCode(0xD);
- // carriage return
- } else if (currentChar == 0x66) {
- buffer.writeCharCode(0xC);
- // form feed
- } else if (currentChar == 0x62) {
- buffer.writeCharCode(0x8);
- // backspace
- } else if (currentChar == 0x74) {
- buffer.writeCharCode(0x9);
- // tab
- } else if (currentChar == 0x76) {
- buffer.writeCharCode(0xB);
- // vertical tab
- } else if (currentChar == 0x78) {
- if (currentIndex + 2 >= length) {
- // Illegal escape sequence: not enough hex digits
- _reportErrorForCurrentToken(ParserErrorCode.INVALID_HEX_ESCAPE);
- return length;
- }
- int firstDigit = lexeme.codeUnitAt(currentIndex + 1);
- int secondDigit = lexeme.codeUnitAt(currentIndex + 2);
- if (!_isHexDigit(firstDigit) || !_isHexDigit(secondDigit)) {
- // Illegal escape sequence: invalid hex digit
- _reportErrorForCurrentToken(ParserErrorCode.INVALID_HEX_ESCAPE);
- } else {
- int charCode = (Character.digit(firstDigit, 16) << 4) +
- Character.digit(secondDigit, 16);
- buffer.writeCharCode(charCode);
- }
- return currentIndex + 3;
- } else if (currentChar == 0x75) {
- currentIndex++;
- if (currentIndex >= length) {
- // Illegal escape sequence: not enough hex digits
- _reportErrorForCurrentToken(ParserErrorCode.INVALID_UNICODE_ESCAPE);
- return length;
- }
- currentChar = lexeme.codeUnitAt(currentIndex);
- if (currentChar == 0x7B) {
- currentIndex++;
- if (currentIndex >= length) {
- // Illegal escape sequence: incomplete escape
- _reportErrorForCurrentToken(ParserErrorCode.INVALID_UNICODE_ESCAPE);
- return length;
- }
- currentChar = lexeme.codeUnitAt(currentIndex);
- int digitCount = 0;
- int value = 0;
- while (currentChar != 0x7D) {
- if (!_isHexDigit(currentChar)) {
- // Illegal escape sequence: invalid hex digit
- _reportErrorForCurrentToken(ParserErrorCode.INVALID_UNICODE_ESCAPE);
- currentIndex++;
- while (currentIndex < length &&
- lexeme.codeUnitAt(currentIndex) != 0x7D) {
- currentIndex++;
- }
- return currentIndex + 1;
- }
- digitCount++;
- value = (value << 4) + Character.digit(currentChar, 16);
- currentIndex++;
- if (currentIndex >= length) {
- // Illegal escape sequence: incomplete escape
- _reportErrorForCurrentToken(ParserErrorCode.INVALID_UNICODE_ESCAPE);
- return length;
- }
- currentChar = lexeme.codeUnitAt(currentIndex);
- }
- if (digitCount < 1 || digitCount > 6) {
- // Illegal escape sequence: not enough or too many hex digits
- _reportErrorForCurrentToken(ParserErrorCode.INVALID_UNICODE_ESCAPE);
- }
- _appendCodePoint(buffer, lexeme, value, index, currentIndex);
- return currentIndex + 1;
- } else {
- if (currentIndex + 3 >= length) {
- // Illegal escape sequence: not enough hex digits
- _reportErrorForCurrentToken(ParserErrorCode.INVALID_UNICODE_ESCAPE);
- return length;
- }
- int firstDigit = currentChar;
- int secondDigit = lexeme.codeUnitAt(currentIndex + 1);
- int thirdDigit = lexeme.codeUnitAt(currentIndex + 2);
- int fourthDigit = lexeme.codeUnitAt(currentIndex + 3);
- if (!_isHexDigit(firstDigit) ||
- !_isHexDigit(secondDigit) ||
- !_isHexDigit(thirdDigit) ||
- !_isHexDigit(fourthDigit)) {
- // Illegal escape sequence: invalid hex digits
- _reportErrorForCurrentToken(ParserErrorCode.INVALID_UNICODE_ESCAPE);
- } else {
- _appendCodePoint(
- buffer,
- lexeme,
- (((((Character.digit(firstDigit, 16) << 4) +
- Character.digit(secondDigit, 16)) <<
- 4) +
- Character.digit(thirdDigit, 16)) <<
- 4) +
- Character.digit(fourthDigit, 16),
- index,
- currentIndex + 3);
- }
- return currentIndex + 4;
- }
- } else {
- buffer.writeCharCode(currentChar);
- }
- return currentIndex + 1;
- }
-
- /// Decrements the error reporting lock level. If level is more than `0`, then
- /// [reportError] wont report any error.
- void _unlockErrorListener() {
- if (_errorListenerLock == 0) {
- throw StateError("Attempt to unlock not locked error listener.");
- }
- _errorListenerLock--;
- }
-
- /// Validate that the given [parameterList] does not contain any field
- /// initializers.
- void _validateFormalParameterList(FormalParameterList parameterList) {
- for (FormalParameter parameter in parameterList.parameters) {
- if (parameter is FieldFormalParameter) {
- _reportErrorForNode(
- ParserErrorCode.FIELD_INITIALIZER_OUTSIDE_CONSTRUCTOR,
- parameter.identifier);
- }
- }
- }
-
- /// Validate that the given set of [modifiers] is appropriate for a class and
- /// return the 'abstract' keyword if there is one.
- Token _validateModifiersForClass(Modifiers modifiers) {
- _validateModifiersForTopLevelDeclaration(modifiers);
- if (modifiers.constKeyword != null) {
- _reportErrorForToken(ParserErrorCode.CONST_CLASS, modifiers.constKeyword);
- }
- if (modifiers.externalKeyword != null) {
- _reportErrorForToken(
- ParserErrorCode.EXTERNAL_CLASS, modifiers.externalKeyword);
- }
- if (modifiers.finalKeyword != null) {
- _reportErrorForToken(ParserErrorCode.FINAL_CLASS, modifiers.finalKeyword);
- }
- if (modifiers.varKeyword != null) {
- _reportErrorForToken(ParserErrorCode.VAR_CLASS, modifiers.varKeyword);
- }
- return modifiers.abstractKeyword;
- }
-
- /// Validate that the given set of [modifiers] is appropriate for a
- /// constructor and return the 'const' keyword if there is one.
- Token _validateModifiersForConstructor(Modifiers modifiers) {
- if (modifiers.abstractKeyword != null) {
- _reportErrorForToken(
- ParserErrorCode.ABSTRACT_CLASS_MEMBER, modifiers.abstractKeyword);
- }
- if (modifiers.covariantKeyword != null) {
- _reportErrorForToken(
- ParserErrorCode.COVARIANT_CONSTRUCTOR, modifiers.covariantKeyword);
- }
- if (modifiers.finalKeyword != null) {
- _reportErrorForToken(
- ParserErrorCode.FINAL_CONSTRUCTOR, modifiers.finalKeyword);
- }
- if (modifiers.staticKeyword != null) {
- _reportErrorForToken(
- ParserErrorCode.STATIC_CONSTRUCTOR, modifiers.staticKeyword);
- }
- if (modifiers.varKeyword != null) {
- _reportErrorForToken(
- ParserErrorCode.CONSTRUCTOR_WITH_RETURN_TYPE, modifiers.varKeyword);
- }
- Token externalKeyword = modifiers.externalKeyword;
- Token constKeyword = modifiers.constKeyword;
- Token factoryKeyword = modifiers.factoryKeyword;
- if (externalKeyword != null &&
- constKeyword != null &&
- constKeyword.offset < externalKeyword.offset) {
- _reportErrorForToken(
- ParserErrorCode.MODIFIER_OUT_OF_ORDER, externalKeyword);
- }
- if (externalKeyword != null &&
- factoryKeyword != null &&
- factoryKeyword.offset < externalKeyword.offset) {
- _reportErrorForToken(
- ParserErrorCode.MODIFIER_OUT_OF_ORDER, externalKeyword);
- }
- return constKeyword;
- }
-
- /// Validate that the given set of [modifiers] is appropriate for an enum and
- /// return the 'abstract' keyword if there is one.
- void _validateModifiersForEnum(Modifiers modifiers) {
- _validateModifiersForTopLevelDeclaration(modifiers);
- if (modifiers.abstractKeyword != null) {
- _reportErrorForToken(
- ParserErrorCode.ABSTRACT_ENUM, modifiers.abstractKeyword);
- }
- if (modifiers.constKeyword != null) {
- _reportErrorForToken(ParserErrorCode.CONST_ENUM, modifiers.constKeyword);
- }
- if (modifiers.externalKeyword != null) {
- _reportErrorForToken(
- ParserErrorCode.EXTERNAL_ENUM, modifiers.externalKeyword);
- }
- if (modifiers.finalKeyword != null) {
- _reportErrorForToken(ParserErrorCode.FINAL_ENUM, modifiers.finalKeyword);
- }
- if (modifiers.varKeyword != null) {
- _reportErrorForToken(ParserErrorCode.VAR_ENUM, modifiers.varKeyword);
- }
- }
-
- /// Validate that the given set of [modifiers] is appropriate for a field and
- /// return the 'final', 'const' or 'var' keyword if there is one.
- Token _validateModifiersForField(Modifiers modifiers) {
- if (modifiers.abstractKeyword != null) {
- _reportErrorForCurrentToken(ParserErrorCode.ABSTRACT_CLASS_MEMBER);
- }
- if (modifiers.externalKeyword != null) {
- _reportErrorForToken(
- ParserErrorCode.EXTERNAL_FIELD, modifiers.externalKeyword);
- }
- if (modifiers.factoryKeyword != null) {
- _reportErrorForToken(
- ParserErrorCode.NON_CONSTRUCTOR_FACTORY, modifiers.factoryKeyword);
- }
- Token staticKeyword = modifiers.staticKeyword;
- Token covariantKeyword = modifiers.covariantKeyword;
- Token constKeyword = modifiers.constKeyword;
- Token finalKeyword = modifiers.finalKeyword;
- Token varKeyword = modifiers.varKeyword;
- if (constKeyword != null) {
- if (covariantKeyword != null) {
- _reportErrorForToken(
- ParserErrorCode.MODIFIER_OUT_OF_ORDER, covariantKeyword);
- }
- if (finalKeyword != null) {
- _reportErrorForToken(ParserErrorCode.CONST_AND_FINAL, finalKeyword);
- }
- if (varKeyword != null) {
- _reportErrorForToken(ParserErrorCode.MODIFIER_OUT_OF_ORDER, varKeyword);
- }
- if (staticKeyword != null && constKeyword.offset < staticKeyword.offset) {
- _reportErrorForToken(
- ParserErrorCode.MODIFIER_OUT_OF_ORDER, staticKeyword);
- }
- } else if (finalKeyword != null) {
- if (covariantKeyword != null) {
- _reportErrorForToken(
- ParserErrorCode.FINAL_AND_COVARIANT, covariantKeyword);
- }
- if (varKeyword != null) {
- _reportErrorForToken(ParserErrorCode.FINAL_AND_VAR, varKeyword);
- }
- if (staticKeyword != null && finalKeyword.offset < staticKeyword.offset) {
- _reportErrorForToken(
- ParserErrorCode.MODIFIER_OUT_OF_ORDER, staticKeyword);
- }
- } else if (varKeyword != null) {
- if (staticKeyword != null && varKeyword.offset < staticKeyword.offset) {
- _reportErrorForToken(
- ParserErrorCode.MODIFIER_OUT_OF_ORDER, staticKeyword);
- }
- if (covariantKeyword != null &&
- varKeyword.offset < covariantKeyword.offset) {
- _reportErrorForToken(
- ParserErrorCode.MODIFIER_OUT_OF_ORDER, covariantKeyword);
- }
- }
- if (covariantKeyword != null && staticKeyword != null) {
- _reportErrorForToken(ParserErrorCode.COVARIANT_AND_STATIC, staticKeyword);
- }
- return Token.lexicallyFirst([constKeyword, finalKeyword, varKeyword]);
- }
-
- /// Validate that the given set of [modifiers] is appropriate for a local
- /// function.
- void _validateModifiersForFunctionDeclarationStatement(Modifiers modifiers) {
- if (modifiers.abstractKeyword != null ||
- modifiers.constKeyword != null ||
- modifiers.externalKeyword != null ||
- modifiers.factoryKeyword != null ||
- modifiers.finalKeyword != null ||
- modifiers.staticKeyword != null ||
- modifiers.varKeyword != null) {
- _reportErrorForCurrentToken(
- ParserErrorCode.LOCAL_FUNCTION_DECLARATION_MODIFIER);
- }
- }
-
- /// Validate that the given set of [modifiers] is appropriate for a getter,
- /// setter, or method.
- void _validateModifiersForGetterOrSetterOrMethod(Modifiers modifiers) {
- if (modifiers.abstractKeyword != null) {
- _reportErrorForCurrentToken(ParserErrorCode.ABSTRACT_CLASS_MEMBER);
- }
- if (modifiers.constKeyword != null) {
- _reportErrorForToken(
- ParserErrorCode.CONST_METHOD, modifiers.constKeyword);
- }
- if (modifiers.covariantKeyword != null) {
- _reportErrorForToken(
- ParserErrorCode.COVARIANT_MEMBER, modifiers.covariantKeyword);
- }
- if (modifiers.factoryKeyword != null) {
- _reportErrorForToken(
- ParserErrorCode.NON_CONSTRUCTOR_FACTORY, modifiers.factoryKeyword);
- }
- if (modifiers.finalKeyword != null) {
- _reportErrorForToken(
- ParserErrorCode.FINAL_METHOD, modifiers.finalKeyword);
- }
- if (modifiers.varKeyword != null) {
- _reportErrorForToken(
- ParserErrorCode.VAR_RETURN_TYPE, modifiers.varKeyword);
- }
- Token externalKeyword = modifiers.externalKeyword;
- Token staticKeyword = modifiers.staticKeyword;
- if (externalKeyword != null &&
- staticKeyword != null &&
- staticKeyword.offset < externalKeyword.offset) {
- _reportErrorForToken(
- ParserErrorCode.MODIFIER_OUT_OF_ORDER, externalKeyword);
- }
- }
-
- /// Validate that the given set of [modifiers] is appropriate for a getter,
- /// setter, or method.
- void _validateModifiersForOperator(Modifiers modifiers) {
- if (modifiers.abstractKeyword != null) {
- _reportErrorForCurrentToken(ParserErrorCode.ABSTRACT_CLASS_MEMBER);
- }
- if (modifiers.constKeyword != null) {
- _reportErrorForToken(
- ParserErrorCode.CONST_METHOD, modifiers.constKeyword);
- }
- if (modifiers.factoryKeyword != null) {
- _reportErrorForToken(
- ParserErrorCode.NON_CONSTRUCTOR_FACTORY, modifiers.factoryKeyword);
- }
- if (modifiers.finalKeyword != null) {
- _reportErrorForToken(
- ParserErrorCode.FINAL_METHOD, modifiers.finalKeyword);
- }
- if (modifiers.staticKeyword != null) {
- _reportErrorForToken(
- ParserErrorCode.STATIC_OPERATOR, modifiers.staticKeyword);
- }
- if (modifiers.varKeyword != null) {
- _reportErrorForToken(
- ParserErrorCode.VAR_RETURN_TYPE, modifiers.varKeyword);
- }
- }
-
- /// Validate that the given set of [modifiers] is appropriate for a top-level
- /// declaration.
- void _validateModifiersForTopLevelDeclaration(Modifiers modifiers) {
- if (modifiers.covariantKeyword != null) {
- _reportErrorForToken(ParserErrorCode.COVARIANT_TOP_LEVEL_DECLARATION,
- modifiers.covariantKeyword);
- }
- if (modifiers.factoryKeyword != null) {
- _reportErrorForToken(ParserErrorCode.FACTORY_TOP_LEVEL_DECLARATION,
- modifiers.factoryKeyword);
- }
- if (modifiers.staticKeyword != null) {
- _reportErrorForToken(ParserErrorCode.STATIC_TOP_LEVEL_DECLARATION,
- modifiers.staticKeyword);
- }
- }
-
- /// Validate that the given set of [modifiers] is appropriate for a top-level
- /// function.
- void _validateModifiersForTopLevelFunction(Modifiers modifiers) {
- _validateModifiersForTopLevelDeclaration(modifiers);
- if (modifiers.abstractKeyword != null) {
- _reportErrorForCurrentToken(ParserErrorCode.ABSTRACT_TOP_LEVEL_FUNCTION);
- }
- if (modifiers.constKeyword != null) {
- _reportErrorForToken(ParserErrorCode.CONST_CLASS, modifiers.constKeyword);
- }
- if (modifiers.finalKeyword != null) {
- _reportErrorForToken(ParserErrorCode.FINAL_CLASS, modifiers.finalKeyword);
- }
- if (modifiers.varKeyword != null) {
- _reportErrorForToken(
- ParserErrorCode.VAR_RETURN_TYPE, modifiers.varKeyword);
- }
- }
-
- /// Validate that the given set of [modifiers] is appropriate for a field and
- /// return the 'final', 'const' or 'var' keyword if there is one.
- Token _validateModifiersForTopLevelVariable(Modifiers modifiers) {
- _validateModifiersForTopLevelDeclaration(modifiers);
- if (modifiers.abstractKeyword != null) {
- _reportErrorForCurrentToken(ParserErrorCode.ABSTRACT_TOP_LEVEL_VARIABLE);
- }
- if (modifiers.externalKeyword != null) {
- _reportErrorForToken(
- ParserErrorCode.EXTERNAL_FIELD, modifiers.externalKeyword);
- }
- Token constKeyword = modifiers.constKeyword;
- Token finalKeyword = modifiers.finalKeyword;
- Token varKeyword = modifiers.varKeyword;
- if (constKeyword != null) {
- if (finalKeyword != null) {
- _reportErrorForToken(ParserErrorCode.CONST_AND_FINAL, finalKeyword);
- }
- if (varKeyword != null) {
- _reportErrorForToken(ParserErrorCode.MODIFIER_OUT_OF_ORDER, varKeyword);
- }
- } else if (finalKeyword != null) {
- if (varKeyword != null) {
- _reportErrorForToken(ParserErrorCode.FINAL_AND_VAR, varKeyword);
- }
- }
- return Token.lexicallyFirst([constKeyword, finalKeyword, varKeyword]);
- }
-
- /// Validate that the given set of [modifiers] is appropriate for a class and
- /// return the 'abstract' keyword if there is one.
- void _validateModifiersForTypedef(Modifiers modifiers) {
- _validateModifiersForTopLevelDeclaration(modifiers);
- if (modifiers.abstractKeyword != null) {
- _reportErrorForToken(
- ParserErrorCode.ABSTRACT_TYPEDEF, modifiers.abstractKeyword);
- }
- if (modifiers.constKeyword != null) {
- _reportErrorForToken(
- ParserErrorCode.CONST_TYPEDEF, modifiers.constKeyword);
- }
- if (modifiers.externalKeyword != null) {
- _reportErrorForToken(
- ParserErrorCode.EXTERNAL_TYPEDEF, modifiers.externalKeyword);
- }
- if (modifiers.finalKeyword != null) {
- _reportErrorForToken(
- ParserErrorCode.FINAL_TYPEDEF, modifiers.finalKeyword);
- }
- if (modifiers.varKeyword != null) {
- _reportErrorForToken(ParserErrorCode.VAR_TYPEDEF, modifiers.varKeyword);
- }
- }
+ Expression parseUnaryExpression() => parseExpression2();
}
-
-/// Instances of this class are thrown when the parser detects that AST has
-/// too many nested expressions to be parsed safely and avoid possibility of
-/// [StackOverflowError] in the parser or during later analysis.
-class _TooDeepTreeError {}
diff --git a/pkg/analyzer/lib/src/generated/parser_fasta.dart b/pkg/analyzer/lib/src/generated/parser_fasta.dart
deleted file mode 100644
index c43c75f..0000000
--- a/pkg/analyzer/lib/src/generated/parser_fasta.dart
+++ /dev/null
@@ -1,394 +0,0 @@
-// Copyright (c) 2017, 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.
-
-part of analyzer.parser;
-
-/// Proxy implementation of the analyzer parser, implemented in terms of the
-/// Fasta parser.
-abstract class ParserAdapter implements Parser {
- @override
- Token currentToken;
-
- /// The fasta parser being wrapped.
- final fasta.Parser fastaParser;
-
- /// The builder which creates the analyzer AST data structures
- /// based on the Fasta parser.
- final AstBuilder astBuilder;
-
- ParserAdapter(this.currentToken, ErrorReporter errorReporter, Uri fileUri,
- FeatureSet featureSet,
- {bool allowNativeClause = false})
- : fastaParser = fasta.Parser(null),
- astBuilder = AstBuilder(errorReporter, fileUri, true, featureSet) {
- fastaParser.listener = astBuilder;
- astBuilder.parser = fastaParser;
- astBuilder.allowNativeClause = allowNativeClause;
- }
-
- @override
- set allowNativeClause(bool value) {
- astBuilder.allowNativeClause = value;
- }
-
- @override
- bool get enableOptionalNewAndConst => false;
-
- @override
- set enableOptionalNewAndConst(bool enable) {}
-
- @override
- set enableSetLiterals(bool value) {
- // TODO(danrubel): Remove this method once the reference to this flag
- // has been removed from dartfmt.
- }
-
- @override
- set parseFunctionBodies(bool parseFunctionBodies) {
- astBuilder.parseFunctionBodies = parseFunctionBodies;
- }
-
- @override
- set parseGenericMethods(_) {}
-
- /// Append the given token to the end of the token stream,
- /// and update the token's offset.
- void appendToken(Token token, Token newToken) {
- while (!token.next.isEof) {
- token = token.next;
- }
- newToken
- ..offset = token.end
- ..setNext(token.next);
- token.setNext(newToken);
- }
-
- @override
- Expression parseAdditiveExpression() => parseExpression2();
-
- @override
- Annotation parseAnnotation() {
- currentToken = fastaParser
- .parseMetadata(fastaParser.syntheticPreviousToken(currentToken))
- .next;
- return astBuilder.pop() as Annotation;
- }
-
- @override
- Expression parseArgument() {
- currentToken = SimpleToken(TokenType.OPEN_PAREN, 0)..setNext(currentToken);
- appendToken(currentToken, SimpleToken(TokenType.CLOSE_PAREN, 0));
- currentToken = fastaParser
- .parseArguments(fastaParser.syntheticPreviousToken(currentToken))
- .next;
- var invocation = astBuilder.pop() as MethodInvocation;
- return invocation.argumentList.arguments[0];
- }
-
- @override
- ArgumentList parseArgumentList() {
- currentToken = fastaParser
- .parseArguments(fastaParser.syntheticPreviousToken(currentToken))
- .next;
- var result = astBuilder.pop();
- return result is MethodInvocation
- ? result.argumentList
- : result as ArgumentList;
- }
-
- @override
- Expression parseAssignableExpression(bool primaryAllowed) =>
- parseExpression2();
-
- @override
- Expression parseBitwiseAndExpression() => parseExpression2();
-
- @override
- Expression parseBitwiseOrExpression() => parseExpression2();
-
- @override
- Expression parseBitwiseXorExpression() => parseExpression2();
-
- @override
- ClassMember parseClassMember(String className) {
- astBuilder.classDeclaration = astFactory.classDeclaration(
- null,
- null,
- null,
- Token(Keyword.CLASS, 0),
- astFactory.simpleIdentifier(
- fasta.StringToken.fromString(TokenType.IDENTIFIER, className, 6)),
- null,
- null,
- null,
- null,
- null /* leftBracket */,
- <ClassMember>[],
- null /* rightBracket */,
- ) as ClassDeclarationImpl;
- // TODO(danrubel): disambiguate between class and mixin
- currentToken = fastaParser.parseClassMember(currentToken, className);
- //currentToken = fastaParser.parseMixinMember(currentToken);
- ClassDeclaration declaration = astBuilder.classDeclaration;
- astBuilder.classDeclaration = null;
- return declaration.members.isNotEmpty ? declaration.members[0] : null;
- }
-
- @override
- List<Combinator> parseCombinators() {
- currentToken = fastaParser
- .parseCombinatorStar(fastaParser.syntheticPreviousToken(currentToken))
- .next;
- return astBuilder.pop() as List<Combinator>;
- }
-
- @override
- CompilationUnit parseCompilationUnit(Token token) {
- currentToken = token;
- return parseCompilationUnit2();
- }
-
- @override
- CompilationUnit parseCompilationUnit2() {
- currentToken = fastaParser.parseUnit(currentToken);
- return astBuilder.pop() as CompilationUnit;
- }
-
- @override
- Expression parseConditionalExpression() => parseExpression2();
-
- @override
- Configuration parseConfiguration() {
- currentToken = fastaParser
- .parseConditionalUri(fastaParser.syntheticPreviousToken(currentToken))
- .next;
- return astBuilder.pop() as Configuration;
- }
-
- @override
- Expression parseConstExpression() => parseExpression2();
-
- @override
- CompilationUnit parseDirectives(Token token) {
- currentToken = token;
- return parseDirectives2();
- }
-
- @override
- CompilationUnit parseDirectives2() {
- currentToken = fastaParser.parseDirectives(currentToken);
- return astBuilder.pop() as CompilationUnit;
- }
-
- @override
- DottedName parseDottedName() {
- currentToken = fastaParser
- .parseDottedName(fastaParser.syntheticPreviousToken(currentToken))
- .next;
- return astBuilder.pop() as DottedName;
- }
-
- @override
- Expression parseEqualityExpression() => parseExpression2();
-
- @override
- Expression parseExpression(Token token) {
- currentToken = token;
- return parseExpression2();
- }
-
- @override
- Expression parseExpression2() {
- currentToken = fastaParser
- .parseExpression(fastaParser.syntheticPreviousToken(currentToken))
- .next;
- return astBuilder.pop() as Expression;
- }
-
- @override
- Expression parseExpressionWithoutCascade() => parseExpression2();
-
- @override
- FormalParameterList parseFormalParameterList({bool inFunctionType = false}) {
- currentToken = fastaParser
- .parseFormalParametersRequiredOpt(
- fastaParser.syntheticPreviousToken(currentToken),
- inFunctionType
- ? fasta.MemberKind.GeneralizedFunctionType
- : fasta.MemberKind.NonStaticMethod)
- .next;
- return astBuilder.pop() as FormalParameterList;
- }
-
- @override
- FunctionBody parseFunctionBody(
- bool mayBeEmpty, ParserErrorCode emptyErrorCode, bool inExpression) {
- currentToken = fastaParser.parseAsyncModifierOpt(
- fastaParser.syntheticPreviousToken(currentToken));
- currentToken =
- fastaParser.parseFunctionBody(currentToken, inExpression, mayBeEmpty);
- return astBuilder.pop() as FunctionBody;
- }
-
- @override
- FunctionExpression parseFunctionExpression() =>
- parseExpression2() as FunctionExpression;
-
- @override
- Expression parseLogicalAndExpression() => parseExpression2();
-
- @override
- Expression parseLogicalOrExpression() => parseExpression2();
-
- @override
- Expression parseMultiplicativeExpression() => parseExpression2();
-
- @override
- InstanceCreationExpression parseNewExpression() =>
- parseExpression2() as InstanceCreationExpression;
-
- @override
- Expression parsePostfixExpression() => parseExpression2();
-
- @override
- Identifier parsePrefixedIdentifier() => parseExpression2() as Identifier;
-
- @override
- Expression parsePrimaryExpression() {
- currentToken = fastaParser
- .parsePrimary(fastaParser.syntheticPreviousToken(currentToken),
- fasta.IdentifierContext.expression)
- .next;
- return astBuilder.pop() as Expression;
- }
-
- @override
- Expression parseRelationalExpression() => parseExpression2();
-
- @override
- Expression parseRethrowExpression() => parseExpression2();
-
- @override
- Expression parseShiftExpression() => parseExpression2();
-
- @override
- SimpleIdentifier parseSimpleIdentifier(
- {bool allowKeyword = false, bool isDeclaration = false}) =>
- parseExpression2() as SimpleIdentifier;
-
- @override
- Statement parseStatement(Token token) {
- currentToken = token;
- return parseStatement2();
- }
-
- @override
- Statement parseStatement2() {
- currentToken = fastaParser
- .parseStatement(fastaParser.syntheticPreviousToken(currentToken))
- .next;
- return astBuilder.pop() as Statement;
- }
-
- @override
- StringLiteral parseStringLiteral() => parseExpression2() as StringLiteral;
-
- @override
- SymbolLiteral parseSymbolLiteral() => parseExpression2() as SymbolLiteral;
-
- @override
- Expression parseThrowExpression() => parseExpression2();
-
- @override
- Expression parseThrowExpressionWithoutCascade() => parseExpression2();
-
- AnnotatedNode parseTopLevelDeclaration(bool isDirective) {
- currentToken = fastaParser.parseTopLevelDeclaration(currentToken);
- return (isDirective ? astBuilder.directives : astBuilder.declarations)
- .removeLast();
- }
-
- @override
- TypeAnnotation parseTypeAnnotation(bool inExpression) {
- Token previous = fastaParser.syntheticPreviousToken(currentToken);
- currentToken = fasta
- .computeType(previous, true, !inExpression)
- .parseType(previous, fastaParser)
- .next;
- return astBuilder.pop() as TypeAnnotation;
- }
-
- @override
- TypeArgumentList parseTypeArgumentList() {
- Token previous = fastaParser.syntheticPreviousToken(currentToken);
- currentToken = fasta
- .computeTypeParamOrArg(previous)
- .parseArguments(previous, fastaParser)
- .next;
- return astBuilder.pop() as TypeArgumentList;
- }
-
- @override
- TypeName parseTypeName(bool inExpression) {
- Token previous = fastaParser.syntheticPreviousToken(currentToken);
- currentToken = fasta
- .computeType(previous, true, !inExpression)
- .parseType(previous, fastaParser)
- .next;
- return astBuilder.pop() as TypeName;
- }
-
- @override
- TypeParameter parseTypeParameter() {
- currentToken = SyntheticBeginToken(TokenType.LT, 0)
- ..endGroup = SyntheticToken(TokenType.GT, 0)
- ..setNext(currentToken);
- appendToken(currentToken, currentToken.endGroup);
- TypeParameterList typeParams = parseTypeParameterList();
- return typeParams.typeParameters[0];
- }
-
- @override
- TypeParameterList parseTypeParameterList() {
- Token token = fastaParser.syntheticPreviousToken(currentToken);
- currentToken = fasta
- .computeTypeParamOrArg(token, true)
- .parseVariables(token, fastaParser)
- .next;
- return astBuilder.pop() as TypeParameterList;
- }
-
- @override
- Expression parseUnaryExpression() => parseExpression2();
-}
-
-/// Replacement parser based on Fasta.
-class _Parser2 extends ParserAdapter {
- /// The source being parsed.
- @override
- final Source _source;
-
- @override
- bool enableUriInPartOf = true;
-
- factory _Parser2(
- Source source, AnalysisErrorListener errorListener, FeatureSet featureSet,
- {bool allowNativeClause = false}) {
- var errorReporter = ErrorReporter(
- errorListener,
- source,
- isNonNullableByDefault: featureSet.isEnabled(Feature.non_nullable),
- );
- return _Parser2._(source, errorReporter, source.uri, featureSet,
- allowNativeClause: allowNativeClause);
- }
-
- _Parser2._(this._source, ErrorReporter errorReporter, Uri fileUri,
- FeatureSet featureSet, {bool allowNativeClause = false})
- : super(null, errorReporter, fileUri, featureSet,
- allowNativeClause: allowNativeClause);
-
- @override
- dynamic noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
-}
diff --git a/pkg/analyzer/lib/src/summary2/apply_resolution.dart b/pkg/analyzer/lib/src/summary2/apply_resolution.dart
index 7c6d20e..ce90149 100644
--- a/pkg/analyzer/lib/src/summary2/apply_resolution.dart
+++ b/pkg/analyzer/lib/src/summary2/apply_resolution.dart
@@ -2,6 +2,8 @@
// 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.
+import 'dart:math';
+
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/ast/standard_ast_factory.dart';
import 'package:analyzer/dart/ast/visitor.dart';
@@ -11,6 +13,7 @@
import 'package:analyzer/src/dart/ast/utilities.dart';
import 'package:analyzer/src/dart/element/element.dart';
import 'package:analyzer/src/dart/resolver/variance.dart';
+import 'package:analyzer/src/exception/exception.dart';
import 'package:analyzer/src/summary2/ast_binary_tag.dart';
import 'package:analyzer/src/summary2/bundle_reader.dart';
import 'package:analyzer/src/summary2/linked_unit_context.dart';
@@ -143,12 +146,25 @@
element.isSimplyBounded = _resolution.readByte() != 0;
_enclosingElements.add(element);
- node.typeParameters?.accept(this);
- node.extendsClause?.accept(this);
- node.nativeClause?.accept(this);
- node.withClause?.accept(this);
- node.implementsClause?.accept(this);
- _namedCompilationUnitMember(node);
+ try {
+ node.typeParameters?.accept(this);
+ node.extendsClause?.accept(this);
+ node.nativeClause?.accept(this);
+ node.withClause?.accept(this);
+ node.implementsClause?.accept(this);
+ _namedCompilationUnitMember(node);
+ } catch (e, stackTrace) {
+ // TODO(scheglov) Remove after fixing http://dartbug.com/44449
+ var headerStr = _astCodeBeforeMarkerOrMaxLength(node, '{', 1000);
+ throw CaughtExceptionWithFiles(e, stackTrace, {
+ 'state': '''
+element: ${element.reference}
+header: $headerStr
+resolution.bytes.length: ${_resolution.bytes.length}
+resolution.byteOffset: ${_resolution.byteOffset}
+''',
+ });
+ }
_enclosingElements.removeLast();
}
@@ -625,16 +641,29 @@
_enclosingElements.add(element.enclosingElement);
_enclosingElements.add(element);
- node.typeParameters?.accept(this);
- node.returnType?.accept(this);
- node.parameters?.accept(this);
- node.metadata?.accept(this);
+ try {
+ node.typeParameters?.accept(this);
+ node.returnType?.accept(this);
+ node.parameters?.accept(this);
+ node.metadata?.accept(this);
- element.returnType = _nextType();
- _setTopLevelInferenceError(element);
- if (element is MethodElementImpl) {
- element.isOperatorEqualWithParameterTypeFromObject =
- _resolution.readByte() != 0;
+ element.returnType = _nextType();
+ _setTopLevelInferenceError(element);
+ if (element is MethodElementImpl) {
+ element.isOperatorEqualWithParameterTypeFromObject =
+ _resolution.readByte() != 0;
+ }
+ } catch (e, stackTrace) {
+ // TODO(scheglov) Remove after fixing http://dartbug.com/44449
+ var headerStr = _astCodeBeforeMarkerOrMaxLength(node, '{', 1000);
+ throw CaughtExceptionWithFiles(e, stackTrace, {
+ 'state': '''
+element: ${element.reference}
+header: $headerStr
+resolution.bytes.length: ${_resolution.bytes.length}
+resolution.byteOffset: ${_resolution.byteOffset}
+''',
+ });
}
_enclosingElements.removeLast();
@@ -1180,6 +1209,17 @@
node.uri.accept(this);
}
+ /// TODO(scheglov) Remove after fixing http://dartbug.com/44449
+ static String _astCodeBeforeMarkerOrMaxLength(
+ AstNode node, String marker, int maxLength) {
+ var nodeStr = '$node';
+ var indexOfBody = nodeStr.indexOf(marker);
+ if (indexOfBody == -1) {
+ indexOfBody = min(maxLength, nodeStr.length);
+ }
+ return nodeStr.substring(0, indexOfBody);
+ }
+
static Variance _decodeVariance(int encoding) {
if (encoding == 0) {
return null;
diff --git a/pkg/analyzer/lib/src/summary2/bundle_reader.dart b/pkg/analyzer/lib/src/summary2/bundle_reader.dart
index 1b6e4b4..5b56415 100644
--- a/pkg/analyzer/lib/src/summary2/bundle_reader.dart
+++ b/pkg/analyzer/lib/src/summary2/bundle_reader.dart
@@ -585,6 +585,12 @@
this._byteOffset,
);
+ /// TODO(scheglov) Remove after fixing http://dartbug.com/44449
+ int get byteOffset => _byteOffset;
+
+ /// TODO(scheglov) Remove after fixing http://dartbug.com/44449
+ Uint8List get bytes => _unitReader._resolutionReader.bytes;
+
Element nextElement() {
var memberFlags = readByte();
var element = _readRawElement();
diff --git a/pkg/analyzer/test/dart/ast/ast_test.dart b/pkg/analyzer/test/dart/ast/ast_test.dart
index ba3b7ed..6894bca 100644
--- a/pkg/analyzer/test/dart/ast/ast_test.dart
+++ b/pkg/analyzer/test/dart/ast/ast_test.dart
@@ -943,7 +943,6 @@
source,
listener,
featureSet: featureSet,
- useFasta: true,
).parseCompilationUnit(tokens);
}
return _unit;
diff --git a/pkg/analyzer/test/generated/parser_fasta_test.dart b/pkg/analyzer/test/generated/parser_fasta_test.dart
index 34b6b84..05d5f54 100644
--- a/pkg/analyzer/test/generated/parser_fasta_test.dart
+++ b/pkg/analyzer/test/generated/parser_fasta_test.dart
@@ -4,8 +4,6 @@
import 'package:_fe_analyzer_shared/src/parser/async_modifier.dart';
import 'package:_fe_analyzer_shared/src/parser/parser.dart' as fasta;
-import 'package:_fe_analyzer_shared/src/scanner/error_token.dart'
- show ErrorToken;
import 'package:_fe_analyzer_shared/src/scanner/scanner.dart' as fasta;
import 'package:_fe_analyzer_shared/src/scanner/scanner.dart'
show ScannerConfiguration, ScannerResult, scanString;
@@ -17,11 +15,9 @@
import 'package:analyzer/error/error.dart';
import 'package:analyzer/error/listener.dart' show ErrorReporter;
import 'package:analyzer/src/dart/ast/ast.dart';
-import 'package:analyzer/src/dart/ast/token.dart';
import 'package:analyzer/src/dart/scanner/scanner.dart';
import 'package:analyzer/src/error/codes.dart';
import 'package:analyzer/src/fasta/ast_builder.dart';
-import 'package:analyzer/src/generated/parser.dart' as analyzer;
import 'package:analyzer/src/generated/utilities_dart.dart';
import 'package:analyzer/src/string_source.dart';
import 'package:pub_semver/src/version.dart';
@@ -29,12 +25,13 @@
import 'package:test_reflective_loader/test_reflective_loader.dart';
import '../util/ast_type_matchers.dart';
-import 'parser_fasta_listener.dart';
import 'parser_test.dart';
import 'test_support.dart';
main() {
defineReflectiveSuite(() {
+ // TODO(srawlins): Move each of these test classes into [parser_test.dart];
+ // merge with mixins, as each mixin is only used once now; remove this file.
defineReflectiveTests(ClassMemberParserTest_Fasta);
defineReflectiveTests(ExtensionMethodsParserTest_Fasta);
defineReflectiveTests(CollectionLiteralParserTest);
@@ -1190,7 +1187,6 @@
}
}
-/// Tests of the fasta parser based on [ErrorParserTest].
@reflectiveTest
class ErrorParserTest_Fasta extends FastaParserTestCase
with ErrorParserTestMixin {
@@ -1905,13 +1901,10 @@
}
@override
- GatheringErrorListener get listener => _parserProxy._errorListener;
+ GatheringErrorListener get listener => _parserProxy.errorListener;
@override
- analyzer.Parser get parser => _parserProxy;
-
- @override
- bool get usingFastaParser => true;
+ ParserProxy get parser => _parserProxy;
void assertErrors({List<ErrorCode> codes, List<ExpectedError> errors}) {
if (codes != null) {
@@ -1927,13 +1920,13 @@
@override
void assertErrorsWithCodes(List<ErrorCode> expectedErrorCodes) {
- _parserProxy._errorListener.assertErrorsWithCodes(
+ _parserProxy.errorListener.assertErrorsWithCodes(
_toFastaGeneratedAnalyzerErrorCodes(expectedErrorCodes));
}
@override
void assertNoErrors() {
- _parserProxy._errorListener.assertNoErrors();
+ _parserProxy.errorListener.assertNoErrors();
}
@override
@@ -3508,214 +3501,6 @@
}
}
-/// Proxy implementation of the analyzer parser, implemented in terms of the
-/// Fasta parser.
-///
-/// This allows many of the analyzer parser tests to be run on Fasta, even if
-/// they call into the analyzer parser class directly.
-class ParserProxy extends analyzer.ParserAdapter {
- /// The error listener to which scanner and parser errors will be reported.
- final GatheringErrorListener _errorListener;
-
- ForwardingTestListener _eventListener;
-
- final int expectedEndOffset;
-
- /// Creates a [ParserProxy] which is prepared to begin parsing at the given
- /// Fasta token.
- factory ParserProxy(analyzer.Token firstToken, FeatureSet featureSet,
- {bool allowNativeClause = false, int expectedEndOffset}) {
- TestSource source = TestSource();
- var errorListener = GatheringErrorListener(checkRanges: true);
- var errorReporter = ErrorReporter(
- errorListener,
- source,
- isNonNullableByDefault: false,
- );
- return ParserProxy._(
- firstToken, errorReporter, null, errorListener, featureSet,
- allowNativeClause: allowNativeClause,
- expectedEndOffset: expectedEndOffset);
- }
-
- ParserProxy._(analyzer.Token firstToken, ErrorReporter errorReporter,
- Uri fileUri, this._errorListener, FeatureSet featureSet,
- {bool allowNativeClause = false, this.expectedEndOffset})
- : super(firstToken, errorReporter, fileUri, featureSet,
- allowNativeClause: allowNativeClause) {
- _eventListener = ForwardingTestListener(astBuilder);
- fastaParser.listener = _eventListener;
- }
-
- @override
- noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
-
- @override
- Annotation parseAnnotation() {
- return _run('MetadataStar', () => super.parseAnnotation());
- }
-
- @override
- ArgumentList parseArgumentList() {
- return _run('unspecified', () => super.parseArgumentList());
- }
-
- @override
- ClassMember parseClassMember(String className) {
- return _run('ClassOrMixinBody', () => super.parseClassMember(className));
- }
-
- @override
- List<Combinator> parseCombinators() {
- return _run('Import', () => super.parseCombinators());
- }
-
- @override
- List<CommentReference> parseCommentReferences(
- List<DocumentationCommentToken> tokens) {
- for (int index = 0; index < tokens.length - 1; ++index) {
- analyzer.Token next = tokens[index].next;
- if (next == null) {
- tokens[index].setNext(tokens[index + 1]);
- } else {
- expect(next, tokens[index + 1]);
- }
- }
- expect(tokens[tokens.length - 1].next, isNull);
- List<CommentReference> references =
- astBuilder.parseCommentReferences(tokens.first);
- if (astBuilder.stack.isNotEmpty) {
- throw 'Expected empty stack, but found:'
- '\n ${astBuilder.stack.values.join('\n ')}';
- }
- return references;
- }
-
- @override
- CompilationUnit parseCompilationUnit2() {
- CompilationUnit result = super.parseCompilationUnit2();
- expect(currentToken.isEof, isTrue, reason: currentToken.lexeme);
- expect(astBuilder.stack, hasLength(0));
- _eventListener.expectEmpty();
- return result;
- }
-
- @override
- Configuration parseConfiguration() {
- return _run('ConditionalUris', () => super.parseConfiguration());
- }
-
- @override
- DottedName parseDottedName() {
- return _run('unspecified', () => super.parseDottedName());
- }
-
- @override
- Expression parseExpression2() {
- return _run('unspecified', () => super.parseExpression2());
- }
-
- @override
- FormalParameterList parseFormalParameterList({bool inFunctionType = false}) {
- return _run('unspecified',
- () => super.parseFormalParameterList(inFunctionType: inFunctionType));
- }
-
- @override
- FunctionBody parseFunctionBody(
- bool mayBeEmpty, ParserErrorCode emptyErrorCode, bool inExpression) {
- Token lastToken;
- FunctionBody body = _run('unspecified', () {
- FunctionBody body =
- super.parseFunctionBody(mayBeEmpty, emptyErrorCode, inExpression);
- lastToken = currentToken;
- currentToken = currentToken.next;
- return body;
- });
- if (!inExpression) {
- if (![';', '}'].contains(lastToken.lexeme)) {
- fail('Expected ";" or "}", but found: ${lastToken.lexeme}');
- }
- }
- return body;
- }
-
- @override
- Expression parsePrimaryExpression() {
- return _run('unspecified', () => super.parsePrimaryExpression());
- }
-
- @override
- Statement parseStatement(Token token) {
- return _run('unspecified', () => super.parseStatement(token));
- }
-
- @override
- Statement parseStatement2() {
- return _run('unspecified', () => super.parseStatement2());
- }
-
- @override
- AnnotatedNode parseTopLevelDeclaration(bool isDirective) {
- return _run(
- 'CompilationUnit', () => super.parseTopLevelDeclaration(isDirective));
- }
-
- @override
- TypeAnnotation parseTypeAnnotation(bool inExpression) {
- return _run('unspecified', () => super.parseTypeAnnotation(inExpression));
- }
-
- @override
- TypeArgumentList parseTypeArgumentList() {
- return _run('unspecified', () => super.parseTypeArgumentList());
- }
-
- @override
- TypeName parseTypeName(bool inExpression) {
- return _run('unspecified', () => super.parseTypeName(inExpression));
- }
-
- @override
- TypeParameter parseTypeParameter() {
- return _run('unspecified', () => super.parseTypeParameter());
- }
-
- @override
- TypeParameterList parseTypeParameterList() {
- return _run('unspecified', () => super.parseTypeParameterList());
- }
-
- /// Runs the specified function and returns the result. It checks the
- /// enclosing listener events, that the parse consumed all of the tokens, and
- /// that the result stack is empty.
- _run(String enclosingEvent, Function() f) {
- _eventListener.begin(enclosingEvent);
-
- // Simulate error handling of parseUnit by skipping error tokens
- // before parsing and reporting them after parsing is complete.
- Token errorToken = currentToken;
- currentToken = fastaParser.skipErrorTokens(currentToken);
- var result = f();
- fastaParser.reportAllErrorTokens(errorToken);
-
- _eventListener.end(enclosingEvent);
-
- String lexeme = currentToken is ErrorToken
- ? currentToken.runtimeType.toString()
- : currentToken.lexeme;
- if (expectedEndOffset == null) {
- expect(currentToken.isEof, isTrue, reason: lexeme);
- } else {
- expect(currentToken.offset, expectedEndOffset, reason: lexeme);
- }
- expect(astBuilder.stack, hasLength(0));
- expect(astBuilder.directives, hasLength(0));
- expect(astBuilder.declarations, hasLength(0));
- return result;
- }
-}
-
@reflectiveTest
class RecoveryParserTest_Fasta extends FastaParserTestCase
with RecoveryParserTestMixin {
diff --git a/pkg/analyzer/test/generated/parser_test.dart b/pkg/analyzer/test/generated/parser_test.dart
index 340cb84..a563d4b 100644
--- a/pkg/analyzer/test/generated/parser_test.dart
+++ b/pkg/analyzer/test/generated/parser_test.dart
@@ -4,9 +4,10 @@
import 'package:_fe_analyzer_shared/src/scanner/abstract_scanner.dart'
show AbstractScanner;
+import 'package:_fe_analyzer_shared/src/scanner/error_token.dart'
+ show ErrorToken;
import 'package:_fe_analyzer_shared/src/scanner/errors.dart';
-import 'package:_fe_analyzer_shared/src/scanner/scanner.dart'
- show ScannerResult, scanString;
+import 'package:_fe_analyzer_shared/src/scanner/scanner.dart' as fasta;
import 'package:analyzer/dart/analysis/features.dart';
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/ast/standard_ast_factory.dart';
@@ -15,10 +16,11 @@
import 'package:analyzer/error/error.dart';
import 'package:analyzer/error/listener.dart';
import 'package:analyzer/src/dart/ast/ast.dart'
- show InstanceCreationExpressionImpl;
+ show ClassDeclarationImpl, InstanceCreationExpressionImpl;
import 'package:analyzer/src/dart/ast/token.dart';
import 'package:analyzer/src/error/codes.dart';
-import 'package:analyzer/src/generated/parser.dart';
+import 'package:analyzer/src/generated/parser.dart' show ParserErrorCode;
+import 'package:analyzer/src/generated/parser.dart' as analyzer;
import 'package:analyzer/src/generated/source.dart';
import 'package:analyzer/src/generated/testing/token_factory.dart';
import 'package:analyzer/src/generated/utilities_dart.dart';
@@ -26,26 +28,12 @@
import 'package:test_reflective_loader/test_reflective_loader.dart';
import '../util/ast_type_matchers.dart';
+import 'parser_fasta_listener.dart';
import 'test_support.dart';
main() {
- // The fasta parser has a parallel set of tests in parser_fasta_test.dart
- if (Parser.useFasta) {
- test('useFasta', () => true);
- return;
- }
-
defineReflectiveSuite(() {
- defineReflectiveTests(ClassMemberParserTest);
- defineReflectiveTests(ComplexParserTest);
- defineReflectiveTests(ErrorParserTest);
- defineReflectiveTests(ExpressionParserTest);
- defineReflectiveTests(FormalParameterParserTest);
defineReflectiveTests(NonErrorParserTest);
- defineReflectiveTests(RecoveryParserTest);
- defineReflectiveTests(SimpleParserTest);
- defineReflectiveTests(StatementParserTest);
- defineReflectiveTests(TopLevelParserTest);
});
}
@@ -72,10 +60,7 @@
/// Get the parser used by the test.
///
/// Caller must first invoke [createParser].
- Parser get parser;
-
- /// Flag indicating whether the fasta parser is being used.
- bool get usingFastaParser;
+ analyzer.Parser get parser;
/// Assert that the number and codes of errors occurred during parsing is the
/// same as the [expectedErrorCodes].
@@ -228,6 +213,13 @@
VariableDeclarationList parseVariableDeclarationList(String source);
}
+/// This class just narrows the type of [parser] to [ParserProxy].
+abstract class AbstractParserViaProxyTestCase
+ implements AbstractParserTestCase {
+ @override
+ ParserProxy get parser;
+}
+
/// Instances of the class `AstValidator` are used to validate the correct
/// construction of an AST structure.
class AstValidator extends UnifyingAstVisitor<void> {
@@ -295,18 +287,8 @@
}
}
-@reflectiveTest
-class ClassMemberParserTest extends ParserTestCase
- with ClassMemberParserTestMixin {
- @failingTest
- @override
- void test_parseAwaitExpression_inSync() {
- super.test_parseAwaitExpression_inSync();
- }
-}
-
/// Tests which exercise the parser using a class member.
-mixin ClassMemberParserTestMixin implements AbstractParserTestCase {
+mixin ClassMemberParserTestMixin implements AbstractParserViaProxyTestCase {
void test_parseAwaitExpression_asStatement_inAsync() {
createParser('m() async { await x; }');
ClassMember member = parser.parseClassMember('C');
@@ -341,30 +323,16 @@
createParser('m() { return await x + await y; }');
MethodDeclaration method = parser.parseClassMember('C');
expect(method, isNotNull);
- listener.assertErrors(usingFastaParser
- ? [
- expectedError(ParserErrorCode.UNEXPECTED_TOKEN, 13, 5),
- expectedError(ParserErrorCode.UNEXPECTED_TOKEN, 23, 5)
- ]
- : [
- // This test requires better error recovery than we currently have.
- // In particular, we need to be able to distinguish
- // between an await expression in the wrong context,
- // and the use of 'await' as an identifier.
- expectedError(ParserErrorCode.EXPECTED_TOKEN, 13, 5),
- expectedError(ParserErrorCode.UNEXPECTED_TOKEN, 29, 1)
- ]);
+ listener.assertErrors([
+ expectedError(ParserErrorCode.UNEXPECTED_TOKEN, 13, 5),
+ expectedError(ParserErrorCode.UNEXPECTED_TOKEN, 23, 5)
+ ]);
FunctionBody body = method.body;
expect(body, isBlockFunctionBody);
Statement statement = (body as BlockFunctionBody).block.statements[0];
expect(statement, isReturnStatement);
Expression expression = (statement as ReturnStatement).expression;
expect(expression, isBinaryExpression);
- if (!usingFastaParser) {
- // TODO(danrubel): capture `await` keywords in fasta generated AST
- expect((expression as BinaryExpression).leftOperand, isAwaitExpression);
- expect((expression as BinaryExpression).rightOperand, isAwaitExpression);
- }
}
void test_parseClassMember_constructor_withDocComment() {
@@ -606,15 +574,9 @@
createParser('var for;');
ClassMember member = parser.parseClassMember('C');
expect(member, isNotNull);
- listener.assertErrors(usingFastaParser
- ? [
- expectedError(
- ParserErrorCode.EXPECTED_IDENTIFIER_BUT_GOT_KEYWORD, 4, 3)
- ]
- : [
- expectedError(ParserErrorCode.MISSING_IDENTIFIER, 4, 3),
- expectedError(ParserErrorCode.UNEXPECTED_TOKEN, 4, 3)
- ]);
+ listener.assertErrors([
+ expectedError(ParserErrorCode.EXPECTED_IDENTIFIER_BUT_GOT_KEYWORD, 4, 3)
+ ]);
}
void test_parseClassMember_field_nameMissing() {
@@ -629,12 +591,8 @@
createParser('var "";');
ClassMember member = parser.parseClassMember('C');
expect(member, isNotNull);
- listener.assertErrors(usingFastaParser
- ? [expectedError(ParserErrorCode.MISSING_IDENTIFIER, 4, 2)]
- : [
- expectedError(ParserErrorCode.MISSING_IDENTIFIER, 4, 2),
- expectedError(ParserErrorCode.UNEXPECTED_TOKEN, 4, 2)
- ]);
+ listener.assertErrors(
+ [expectedError(ParserErrorCode.MISSING_IDENTIFIER, 4, 2)]);
}
void test_parseClassMember_field_static() {
@@ -921,13 +879,9 @@
createParser('static int get C => 0;');
ClassMember member = parser.parseClassMember('C');
expect(member, isNotNull);
- if (usingFastaParser) {
- listener.assertErrors([
- expectedError(ParserErrorCode.MEMBER_WITH_CLASS_NAME, 15, 1),
- ]);
- } else {
- assertNoErrors();
- }
+ listener.assertErrors([
+ expectedError(ParserErrorCode.MEMBER_WITH_CLASS_NAME, 15, 1),
+ ]);
expect(member, isMethodDeclaration);
MethodDeclaration method = member;
expect(method.documentationComment, isNull);
@@ -1015,63 +969,43 @@
void test_parseClassMember_method_native_missing_literal_not_allowed() {
allowNativeClause = false;
_parseClassMember_method_native_missing_literal();
- if (usingFastaParser) {
- listener.assertErrors([
- expectedError(ParserErrorCode.NATIVE_CLAUSE_SHOULD_BE_ANNOTATION, 4, 6),
- ]);
- } else {
- assertNoErrors();
- }
+ listener.assertErrors([
+ expectedError(ParserErrorCode.NATIVE_CLAUSE_SHOULD_BE_ANNOTATION, 4, 6),
+ ]);
}
void test_parseClassMember_method_native_not_allowed() {
allowNativeClause = false;
_parseClassMember_method_native();
- if (usingFastaParser) {
- listener.assertErrors([
- expectedError(ParserErrorCode.NATIVE_CLAUSE_SHOULD_BE_ANNOTATION, 4, 6),
- ]);
- } else {
- assertNoErrors();
- }
+ listener.assertErrors([
+ expectedError(ParserErrorCode.NATIVE_CLAUSE_SHOULD_BE_ANNOTATION, 4, 6),
+ ]);
}
void test_parseClassMember_method_native_with_body_allowed() {
allowNativeClause = true;
_parseClassMember_method_native_with_body();
- if (usingFastaParser) {
- // TODO(brianwilkerson) Convert codes to errors when highlighting is fixed.
- assertErrorsWithCodes([
- ParserErrorCode.EXTERNAL_METHOD_WITH_BODY,
- ]);
+ // TODO(brianwilkerson) Convert codes to errors when highlighting is fixed.
+ assertErrorsWithCodes([
+ ParserErrorCode.EXTERNAL_METHOD_WITH_BODY,
+ ]);
// listener.assertErrors([
// expectedError(ParserErrorCode.EXTERNAL_METHOD_WITH_BODY, 17, 2),
// ]);
- } else {
- assertErrorsWithCodes([
- ParserErrorCode.EXPECTED_TOKEN,
- ]);
- }
}
void test_parseClassMember_method_native_with_body_not_allowed() {
allowNativeClause = false;
_parseClassMember_method_native_with_body();
- if (usingFastaParser) {
- // TODO(brianwilkerson) Convert codes to errors when highlighting is fixed.
- assertErrorsWithCodes([
- ParserErrorCode.NATIVE_CLAUSE_SHOULD_BE_ANNOTATION,
- ParserErrorCode.EXTERNAL_METHOD_WITH_BODY,
- ]);
+ // TODO(brianwilkerson) Convert codes to errors when highlighting is fixed.
+ assertErrorsWithCodes([
+ ParserErrorCode.NATIVE_CLAUSE_SHOULD_BE_ANNOTATION,
+ ParserErrorCode.EXTERNAL_METHOD_WITH_BODY,
+ ]);
// listener.assertErrors([
// expectedError(ParserErrorCode.NATIVE_CLAUSE_SHOULD_BE_ANNOTATION, 4, 6),
// expectedError(ParserErrorCode.EXTERNAL_METHOD_WITH_BODY, 17, 2),
// ]);
- } else {
- assertErrorsWithCodes([
- ParserErrorCode.EXPECTED_TOKEN,
- ]);
- }
}
void test_parseClassMember_method_operator_noType() {
@@ -1193,13 +1127,9 @@
createParser('static void set C(_) {}');
ClassMember member = parser.parseClassMember('C');
expect(member, isNotNull);
- if (usingFastaParser) {
- listener.assertErrors([
- expectedError(ParserErrorCode.MEMBER_WITH_CLASS_NAME, 16, 1),
- ]);
- } else {
- assertNoErrors();
- }
+ listener.assertErrors([
+ expectedError(ParserErrorCode.MEMBER_WITH_CLASS_NAME, 16, 1),
+ ]);
expect(member, isMethodDeclaration);
MethodDeclaration method = member;
expect(method.documentationComment, isNull);
@@ -1270,7 +1200,6 @@
}
void test_parseClassMember_method_static_mixin() {
- if (!usingFastaParser) return;
var unit = parseCompilationUnit('mixin C { static void m() {} }');
MixinDeclaration c = unit.declarations[0];
MethodDeclaration method = c.members[0];
@@ -1838,10 +1767,6 @@
}
}
-/// Tests of the analyzer parser based on [ComplexParserTestMixin].
-@reflectiveTest
-class ComplexParserTest extends ParserTestCase with ComplexParserTestMixin {}
-
/// The class `ComplexParserTest` defines parser tests that test the parsing of
/// more complex code fragments or the interactions between multiple parsing
/// methods. For example, tests to ensure that the precedence of operations is
@@ -2326,22 +2251,9 @@
}
}
-/// The class `ErrorParserTest` defines parser tests that test the parsing
-/// of code to ensure that errors are correctly reported,
-/// and in some cases, not reported.
-@reflectiveTest
-class ErrorParserTest extends ParserTestCase with ErrorParserTestMixin {
- void test_missingIdentifier_number() {
- createParser('1');
- SimpleIdentifier expression = parser.parseSimpleIdentifier();
- expectNotNullIfNoErrors(expression);
- listener.assertErrors(
- [expectedError(ParserErrorCode.MISSING_IDENTIFIER, 0, 1)]);
- expect(expression.isSynthetic, isTrue);
- }
-}
-
-mixin ErrorParserTestMixin implements AbstractParserTestCase {
+/// This defines parser tests that test the parsing of code to ensure that
+/// errors are correctly reported, and in some cases, not reported.
+mixin ErrorParserTestMixin implements AbstractParserViaProxyTestCase {
void test_abstractClassMember_constructor() {
createParser('abstract C.c();');
ClassMember member = parser.parseClassMember('C');
@@ -2457,13 +2369,10 @@
}
void test_classInClass_abstract() {
- parseCompilationUnit("class C { abstract class B {} }",
- errors: usingFastaParser
- ? [
- expectedError(ParserErrorCode.ABSTRACT_CLASS_MEMBER, 10, 8),
- expectedError(ParserErrorCode.CLASS_IN_CLASS, 19, 5)
- ]
- : [expectedError(ParserErrorCode.CLASS_IN_CLASS, 19, 5)]);
+ parseCompilationUnit("class C { abstract class B {} }", errors: [
+ expectedError(ParserErrorCode.ABSTRACT_CLASS_MEMBER, 10, 8),
+ expectedError(ParserErrorCode.CLASS_IN_CLASS, 19, 5)
+ ]);
}
void test_classInClass_nonAbstract() {
@@ -2477,17 +2386,11 @@
createParser('class A = abstract B with C;', expectedEndOffset: 21);
CompilationUnitMember member = parseFullCompilationUnitMember();
expectNotNullIfNoErrors(member);
- listener.assertErrors(usingFastaParser
- ? [
- expectedError(
- CompileTimeErrorCode.BUILT_IN_IDENTIFIER_AS_TYPE, 10, 8),
- expectedError(ParserErrorCode.EXPECTED_TOKEN, 19, 1),
- expectedError(ParserErrorCode.EXPECTED_TOKEN, 19, 1)
- ]
- : [
- expectedError(ParserErrorCode.EXPECTED_TOKEN, 0, 0),
- expectedError(ParserErrorCode.EXPECTED_TOKEN, 0, 0)
- ]);
+ listener.assertErrors([
+ expectedError(CompileTimeErrorCode.BUILT_IN_IDENTIFIER_AS_TYPE, 10, 8),
+ expectedError(ParserErrorCode.EXPECTED_TOKEN, 19, 1),
+ expectedError(ParserErrorCode.EXPECTED_TOKEN, 19, 1)
+ ]);
}
void test_colonInPlaceOfIn() {
@@ -2534,15 +2437,12 @@
}
void test_constEnum() {
- parseCompilationUnit("const enum E {ONE}",
- errors: usingFastaParser
- ? [
- // Fasta interprets the `const` as a malformed top level const
- // and `enum` as the start of an enum declaration.
- expectedError(ParserErrorCode.MISSING_IDENTIFIER, 6, 4),
- expectedError(ParserErrorCode.EXPECTED_TOKEN, 6, 4),
- ]
- : [expectedError(ParserErrorCode.CONST_ENUM, 0, 5)]);
+ parseCompilationUnit("const enum E {ONE}", errors: [
+ // Fasta interprets the `const` as a malformed top level const
+ // and `enum` as the start of an enum declaration.
+ expectedError(ParserErrorCode.MISSING_IDENTIFIER, 6, 4),
+ expectedError(ParserErrorCode.EXPECTED_TOKEN, 6, 4),
+ ]);
}
void test_constFactory() {
@@ -2576,56 +2476,34 @@
void test_constructorPartial() {
createParser('class C { C< }');
parser.parseCompilationUnit2();
- listener.assertErrors(usingFastaParser
- ? [
- expectedError(ParserErrorCode.TYPE_PARAMETER_ON_CONSTRUCTOR, 11, 2),
- expectedError(ParserErrorCode.MISSING_IDENTIFIER, 13, 1),
- expectedError(ParserErrorCode.MISSING_METHOD_PARAMETERS, 10, 1),
- expectedError(ParserErrorCode.MISSING_FUNCTION_BODY, 13, 1),
- ]
- : [
- expectedError(ParserErrorCode.EXPECTED_TYPE_NAME, 13, 1),
- expectedError(ParserErrorCode.EXPECTED_TOKEN, 13, 1),
- expectedError(ParserErrorCode.MISSING_IDENTIFIER, 13, 1),
- expectedError(ParserErrorCode.EXPECTED_TOKEN, 13, 1)
- ]);
+ listener.assertErrors([
+ expectedError(ParserErrorCode.TYPE_PARAMETER_ON_CONSTRUCTOR, 11, 2),
+ expectedError(ParserErrorCode.MISSING_IDENTIFIER, 13, 1),
+ expectedError(ParserErrorCode.MISSING_METHOD_PARAMETERS, 10, 1),
+ expectedError(ParserErrorCode.MISSING_FUNCTION_BODY, 13, 1),
+ ]);
}
void test_constructorPartial2() {
createParser('class C { C<@Foo }');
parser.parseCompilationUnit2();
- listener.assertErrors(usingFastaParser
- ? [
- expectedError(ParserErrorCode.TYPE_PARAMETER_ON_CONSTRUCTOR, 11, 6),
- expectedError(ParserErrorCode.MISSING_IDENTIFIER, 17, 1),
- expectedError(ParserErrorCode.MISSING_METHOD_PARAMETERS, 10, 1),
- expectedError(ParserErrorCode.MISSING_FUNCTION_BODY, 17, 1)
- ]
- : [
- expectedError(ParserErrorCode.EXPECTED_TYPE_NAME, 12, 1),
- expectedError(ParserErrorCode.EXPECTED_TOKEN, 12, 1),
- expectedError(ParserErrorCode.EXPECTED_CLASS_MEMBER, 12, 1),
- expectedError(ParserErrorCode.EXPECTED_CLASS_MEMBER, 17, 1)
- ]);
+ listener.assertErrors([
+ expectedError(ParserErrorCode.TYPE_PARAMETER_ON_CONSTRUCTOR, 11, 6),
+ expectedError(ParserErrorCode.MISSING_IDENTIFIER, 17, 1),
+ expectedError(ParserErrorCode.MISSING_METHOD_PARAMETERS, 10, 1),
+ expectedError(ParserErrorCode.MISSING_FUNCTION_BODY, 17, 1)
+ ]);
}
void test_constructorPartial3() {
createParser('class C { C<@Foo @Bar() }');
parser.parseCompilationUnit2();
- listener.assertErrors(usingFastaParser
- ? [
- expectedError(
- ParserErrorCode.TYPE_PARAMETER_ON_CONSTRUCTOR, 11, 13),
- expectedError(ParserErrorCode.MISSING_IDENTIFIER, 24, 1),
- expectedError(ParserErrorCode.MISSING_METHOD_PARAMETERS, 10, 1),
- expectedError(ParserErrorCode.MISSING_FUNCTION_BODY, 24, 1)
- ]
- : [
- expectedError(ParserErrorCode.EXPECTED_TYPE_NAME, 12, 1),
- expectedError(ParserErrorCode.EXPECTED_TOKEN, 12, 1),
- expectedError(ParserErrorCode.EXPECTED_CLASS_MEMBER, 12, 1),
- expectedError(ParserErrorCode.EXPECTED_CLASS_MEMBER, 24, 1)
- ]);
+ listener.assertErrors([
+ expectedError(ParserErrorCode.TYPE_PARAMETER_ON_CONSTRUCTOR, 11, 13),
+ expectedError(ParserErrorCode.MISSING_IDENTIFIER, 24, 1),
+ expectedError(ParserErrorCode.MISSING_METHOD_PARAMETERS, 10, 1),
+ expectedError(ParserErrorCode.MISSING_FUNCTION_BODY, 24, 1)
+ ]);
}
void test_constructorWithReturnType() {
@@ -2641,21 +2519,17 @@
createParser('var C() {}');
ClassMember member = parser.parseClassMember('C');
expectNotNullIfNoErrors(member);
- listener.assertErrors(usingFastaParser
- ? [expectedError(ParserErrorCode.VAR_RETURN_TYPE, 0, 3)]
- : [expectedError(ParserErrorCode.CONSTRUCTOR_WITH_RETURN_TYPE, 0, 3)]);
+ listener
+ .assertErrors([expectedError(ParserErrorCode.VAR_RETURN_TYPE, 0, 3)]);
}
void test_constTypedef() {
- parseCompilationUnit("const typedef F();",
- errors: usingFastaParser
- ? [
- // Fasta interprets the `const` as a malformed top level const
- // and `typedef` as the start of an typedef declaration.
- expectedError(ParserErrorCode.MISSING_IDENTIFIER, 6, 7),
- expectedError(ParserErrorCode.EXPECTED_TOKEN, 6, 7),
- ]
- : [expectedError(ParserErrorCode.CONST_TYPEDEF, 0, 5)]);
+ parseCompilationUnit("const typedef F();", errors: [
+ // Fasta interprets the `const` as a malformed top level const
+ // and `typedef` as the start of an typedef declaration.
+ expectedError(ParserErrorCode.MISSING_IDENTIFIER, 6, 7),
+ expectedError(ParserErrorCode.EXPECTED_TOKEN, 6, 7),
+ ]);
}
void test_continueOutsideOfLoop_continueInDoStatement() {
@@ -2749,41 +2623,32 @@
// This is currently reporting EXPECTED_TOKEN for a missing semicolon, but
// this would be a better error message.
parseStatement("covariant int x;");
- listener.assertErrors(usingFastaParser
- ? [expectedError(ParserErrorCode.EXTRANEOUS_MODIFIER, 0, 9)]
- : [expectedError(ParserErrorCode.EXPECTED_TOKEN, 0, 9)]);
+ listener.assertErrors(
+ [expectedError(ParserErrorCode.EXTRANEOUS_MODIFIER, 0, 9)]);
}
void test_covariantConstructor() {
createParser('class C { covariant C(); }');
ClassDeclaration member = parseFullCompilationUnitMember();
expectNotNullIfNoErrors(member);
- listener.assertErrors([
- expectedError(
- usingFastaParser
- ? ParserErrorCode.COVARIANT_MEMBER
- : ParserErrorCode.COVARIANT_CONSTRUCTOR,
- 10,
- 9)
- ]);
+ listener
+ .assertErrors([expectedError(ParserErrorCode.COVARIANT_MEMBER, 10, 9)]);
}
void test_covariantMember_getter_noReturnType() {
createParser('static covariant get x => 0;');
ClassMember member = parser.parseClassMember('C');
expectNotNullIfNoErrors(member);
- listener.assertErrors(usingFastaParser
- ? [expectedError(ParserErrorCode.COVARIANT_AND_STATIC, 7, 9)]
- : [expectedError(ParserErrorCode.COVARIANT_MEMBER, 7, 9)]);
+ listener.assertErrors(
+ [expectedError(ParserErrorCode.COVARIANT_AND_STATIC, 7, 9)]);
}
void test_covariantMember_getter_returnType() {
createParser('static covariant int get x => 0;');
ClassMember member = parser.parseClassMember('C');
expectNotNullIfNoErrors(member);
- listener.assertErrors(usingFastaParser
- ? [expectedError(ParserErrorCode.COVARIANT_AND_STATIC, 7, 9)]
- : [expectedError(ParserErrorCode.COVARIANT_MEMBER, 7, 9)]);
+ listener.assertErrors(
+ [expectedError(ParserErrorCode.COVARIANT_AND_STATIC, 7, 9)]);
}
void test_covariantMember_method() {
@@ -2846,18 +2711,12 @@
void test_directiveAfterDeclaration_classBeforeDirective() {
// TODO(brianwilkerson) Remove codes when highlighting is fixed.
CompilationUnit unit = parseCompilationUnit("class Foo{} library l;",
- codes: usingFastaParser
- ? [ParserErrorCode.LIBRARY_DIRECTIVE_NOT_FIRST]
- : [ParserErrorCode.DIRECTIVE_AFTER_DECLARATION],
- errors: usingFastaParser
- ? [
- expectedError(
- ParserErrorCode.LIBRARY_DIRECTIVE_NOT_FIRST, 12, 10)
- ]
- : [
- expectedError(
- ParserErrorCode.DIRECTIVE_AFTER_DECLARATION, 12, 10)
- ]);
+ codes: [
+ ParserErrorCode.LIBRARY_DIRECTIVE_NOT_FIRST
+ ],
+ errors: [
+ expectedError(ParserErrorCode.LIBRARY_DIRECTIVE_NOT_FIRST, 12, 10)
+ ]);
expect(unit, isNotNull);
}
@@ -2975,47 +2834,26 @@
void test_expectedCaseOrDefault() {
SwitchStatement statement = parseStatement('switch (e) {break;}');
expectNotNullIfNoErrors(statement);
- listener.assertErrors(usingFastaParser
- ? [expectedError(ParserErrorCode.EXPECTED_TOKEN, 12, 5)]
- : [expectedError(ParserErrorCode.EXPECTED_CASE_OR_DEFAULT, 12, 5)]);
+ listener
+ .assertErrors([expectedError(ParserErrorCode.EXPECTED_TOKEN, 12, 5)]);
}
void test_expectedClassMember_inClass_afterType() {
- parseCompilationUnit('class C{ heart 2 heart }',
- errors: usingFastaParser
- ? [
- expectedError(
- ParserErrorCode.MISSING_CONST_FINAL_VAR_OR_TYPE, 9, 5),
- expectedError(ParserErrorCode.EXPECTED_TOKEN, 9, 5),
- expectedError(ParserErrorCode.EXPECTED_CLASS_MEMBER, 15, 1),
- expectedError(
- ParserErrorCode.MISSING_CONST_FINAL_VAR_OR_TYPE, 17, 5),
- expectedError(ParserErrorCode.EXPECTED_TOKEN, 17, 5)
- ]
- : [
- expectedError(ParserErrorCode.UNEXPECTED_TOKEN, 15, 1),
- expectedError(ParserErrorCode.EXPECTED_CLASS_MEMBER, 15, 1),
- expectedError(ParserErrorCode.EXPECTED_CLASS_MEMBER, 15, 1),
- expectedError(ParserErrorCode.MISSING_IDENTIFIER, 23, 1),
- expectedError(ParserErrorCode.EXPECTED_TOKEN, 23, 1)
- ]);
+ parseCompilationUnit('class C{ heart 2 heart }', errors: [
+ expectedError(ParserErrorCode.MISSING_CONST_FINAL_VAR_OR_TYPE, 9, 5),
+ expectedError(ParserErrorCode.EXPECTED_TOKEN, 9, 5),
+ expectedError(ParserErrorCode.EXPECTED_CLASS_MEMBER, 15, 1),
+ expectedError(ParserErrorCode.MISSING_CONST_FINAL_VAR_OR_TYPE, 17, 5),
+ expectedError(ParserErrorCode.EXPECTED_TOKEN, 17, 5)
+ ]);
}
void test_expectedClassMember_inClass_beforeType() {
- parseCompilationUnit('class C { 4 score }',
- errors: usingFastaParser
- ? [
- expectedError(ParserErrorCode.EXPECTED_CLASS_MEMBER, 10, 1),
- expectedError(
- ParserErrorCode.MISSING_CONST_FINAL_VAR_OR_TYPE, 12, 5),
- expectedError(ParserErrorCode.EXPECTED_TOKEN, 12, 5)
- ]
- : [
- expectedError(ParserErrorCode.EXPECTED_CLASS_MEMBER, 10, 1),
- expectedError(ParserErrorCode.UNEXPECTED_TOKEN, 10, 1),
- expectedError(ParserErrorCode.MISSING_IDENTIFIER, 18, 1),
- expectedError(ParserErrorCode.EXPECTED_TOKEN, 18, 1)
- ]);
+ parseCompilationUnit('class C { 4 score }', errors: [
+ expectedError(ParserErrorCode.EXPECTED_CLASS_MEMBER, 10, 1),
+ expectedError(ParserErrorCode.MISSING_CONST_FINAL_VAR_OR_TYPE, 12, 5),
+ expectedError(ParserErrorCode.EXPECTED_TOKEN, 12, 5)
+ ]);
}
void test_expectedExecutable_afterAnnotation_atEOF() {
@@ -3026,87 +2864,49 @@
}
void test_expectedExecutable_inClass_afterVoid() {
- parseCompilationUnit('class C { void 2 void }',
- errors: usingFastaParser
- ? [
- expectedError(ParserErrorCode.MISSING_IDENTIFIER, 15, 1),
- expectedError(ParserErrorCode.EXPECTED_TOKEN, 17, 4),
- expectedError(ParserErrorCode.MISSING_IDENTIFIER, 22, 1),
- expectedError(ParserErrorCode.EXPECTED_TOKEN, 22, 1)
- ]
- : [
- expectedError(ParserErrorCode.EXPECTED_EXECUTABLE, 15, 1),
- expectedError(ParserErrorCode.EXPECTED_CLASS_MEMBER, 15, 1),
- expectedError(ParserErrorCode.UNEXPECTED_TOKEN, 15, 1),
- expectedError(ParserErrorCode.EXPECTED_EXECUTABLE, 22, 1),
- ]);
+ parseCompilationUnit('class C { void 2 void }', errors: [
+ expectedError(ParserErrorCode.MISSING_IDENTIFIER, 15, 1),
+ expectedError(ParserErrorCode.EXPECTED_TOKEN, 17, 4),
+ expectedError(ParserErrorCode.MISSING_IDENTIFIER, 22, 1),
+ expectedError(ParserErrorCode.EXPECTED_TOKEN, 22, 1)
+ ]);
}
void test_expectedExecutable_topLevel_afterType() {
- CompilationUnit unit = parseCompilationUnit('heart 2 heart',
- errors: usingFastaParser
- ? [
- expectedError(
- ParserErrorCode.MISSING_CONST_FINAL_VAR_OR_TYPE, 0, 5),
- expectedError(ParserErrorCode.EXPECTED_TOKEN, 0, 5),
- expectedError(ParserErrorCode.EXPECTED_EXECUTABLE, 6, 1),
- expectedError(
- ParserErrorCode.MISSING_CONST_FINAL_VAR_OR_TYPE, 8, 5),
- expectedError(ParserErrorCode.EXPECTED_TOKEN, 8, 5),
- ]
- : [
- expectedError(ParserErrorCode.EXPECTED_EXECUTABLE, 6, 1),
- expectedError(ParserErrorCode.EXPECTED_EXECUTABLE, 6, 1),
- expectedError(ParserErrorCode.UNEXPECTED_TOKEN, 6, 1),
- expectedError(ParserErrorCode.EXPECTED_EXECUTABLE, 8, 5)
- ]);
+ CompilationUnit unit = parseCompilationUnit('heart 2 heart', errors: [
+ expectedError(ParserErrorCode.MISSING_CONST_FINAL_VAR_OR_TYPE, 0, 5),
+ expectedError(ParserErrorCode.EXPECTED_TOKEN, 0, 5),
+ expectedError(ParserErrorCode.EXPECTED_EXECUTABLE, 6, 1),
+ expectedError(ParserErrorCode.MISSING_CONST_FINAL_VAR_OR_TYPE, 8, 5),
+ expectedError(ParserErrorCode.EXPECTED_TOKEN, 8, 5),
+ ]);
expect(unit, isNotNull);
}
void test_expectedExecutable_topLevel_afterVoid() {
- CompilationUnit unit = parseCompilationUnit('void 2 void',
- errors: usingFastaParser
- ? [
- expectedError(ParserErrorCode.MISSING_IDENTIFIER, 5, 1),
- expectedError(ParserErrorCode.EXPECTED_TOKEN, 5, 1),
- expectedError(ParserErrorCode.EXPECTED_EXECUTABLE, 5, 1),
- expectedError(ParserErrorCode.MISSING_IDENTIFIER, 11, 0),
- expectedError(ParserErrorCode.EXPECTED_TOKEN, 11, 0),
- ]
- : [
- expectedError(ParserErrorCode.EXPECTED_EXECUTABLE, 6, 1),
- expectedError(ParserErrorCode.EXPECTED_EXECUTABLE, 6, 1),
- expectedError(ParserErrorCode.UNEXPECTED_TOKEN, 6, 1),
- expectedError(ParserErrorCode.EXPECTED_EXECUTABLE, 8, 5)
- ]);
+ CompilationUnit unit = parseCompilationUnit('void 2 void', errors: [
+ expectedError(ParserErrorCode.MISSING_IDENTIFIER, 5, 1),
+ expectedError(ParserErrorCode.EXPECTED_TOKEN, 5, 1),
+ expectedError(ParserErrorCode.EXPECTED_EXECUTABLE, 5, 1),
+ expectedError(ParserErrorCode.MISSING_IDENTIFIER, 11, 0),
+ expectedError(ParserErrorCode.EXPECTED_TOKEN, 11, 0),
+ ]);
expect(unit, isNotNull);
}
void test_expectedExecutable_topLevel_beforeType() {
- parseCompilationUnit('4 score',
- errors: usingFastaParser
- ? [
- expectedError(ParserErrorCode.EXPECTED_EXECUTABLE, 0, 1),
- expectedError(
- ParserErrorCode.MISSING_CONST_FINAL_VAR_OR_TYPE, 2, 5),
- expectedError(ParserErrorCode.EXPECTED_TOKEN, 2, 5),
- ]
- : [
- expectedError(ParserErrorCode.EXPECTED_EXECUTABLE, 0, 1),
- expectedError(ParserErrorCode.UNEXPECTED_TOKEN, 0, 1),
- expectedError(ParserErrorCode.EXPECTED_EXECUTABLE, 2, 5),
- ]);
+ parseCompilationUnit('4 score', errors: [
+ expectedError(ParserErrorCode.EXPECTED_EXECUTABLE, 0, 1),
+ expectedError(ParserErrorCode.MISSING_CONST_FINAL_VAR_OR_TYPE, 2, 5),
+ expectedError(ParserErrorCode.EXPECTED_TOKEN, 2, 5),
+ ]);
}
void test_expectedExecutable_topLevel_eof() {
- parseCompilationUnit('x',
- errors: usingFastaParser
- ? [
- expectedError(
- ParserErrorCode.MISSING_CONST_FINAL_VAR_OR_TYPE, 0, 1),
- expectedError(ParserErrorCode.EXPECTED_TOKEN, 0, 1)
- ]
- : [expectedError(ParserErrorCode.EXPECTED_EXECUTABLE, 0, 1)]);
+ parseCompilationUnit('x', errors: [
+ expectedError(ParserErrorCode.MISSING_CONST_FINAL_VAR_OR_TYPE, 0, 1),
+ expectedError(ParserErrorCode.EXPECTED_TOKEN, 0, 1)
+ ]);
}
void test_expectedInterpolationIdentifier() {
@@ -3151,9 +2951,8 @@
createParser('(x, y z)');
ArgumentList list = parser.parseArgumentList();
expectNotNullIfNoErrors(list);
- listener.assertErrors(usingFastaParser
- ? [expectedError(ParserErrorCode.EXPECTED_TOKEN, 6, 1)]
- : [expectedError(ParserErrorCode.EXPECTED_TOKEN, 4, 1)]);
+ listener
+ .assertErrors([expectedError(ParserErrorCode.EXPECTED_TOKEN, 6, 1)]);
}
void test_expectedToken_parseStatement_afterVoid() {
@@ -3246,23 +3045,15 @@
}
void test_exportAsType() {
- parseCompilationUnit('export<dynamic> foo;',
- errors: usingFastaParser
- ? [
- expectedError(
- CompileTimeErrorCode.BUILT_IN_IDENTIFIER_AS_TYPE, 0, 6)
- ]
- : []);
+ parseCompilationUnit('export<dynamic> foo;', errors: [
+ expectedError(CompileTimeErrorCode.BUILT_IN_IDENTIFIER_AS_TYPE, 0, 6)
+ ]);
}
void test_exportAsType_inClass() {
- parseCompilationUnit('class C { export<dynamic> foo; }',
- errors: usingFastaParser
- ? [
- expectedError(
- CompileTimeErrorCode.BUILT_IN_IDENTIFIER_AS_TYPE, 10, 6)
- ]
- : []);
+ parseCompilationUnit('class C { export<dynamic> foo; }', errors: [
+ expectedError(CompileTimeErrorCode.BUILT_IN_IDENTIFIER_AS_TYPE, 10, 6)
+ ]);
}
void test_exportDirectiveAfterPartDirective() {
@@ -3305,30 +3096,18 @@
createParser('external factory C() {}');
ClassMember member = parser.parseClassMember('C');
expectNotNullIfNoErrors(member);
- listener.assertErrors([
- expectedError(
- usingFastaParser
- ? ParserErrorCode.EXTERNAL_FACTORY_WITH_BODY
- : ParserErrorCode.EXTERNAL_CONSTRUCTOR_WITH_BODY,
- 21,
- 1)
- ]);
+ listener.assertErrors(
+ [expectedError(ParserErrorCode.EXTERNAL_FACTORY_WITH_BODY, 21, 1)]);
}
void test_externalConstructorWithBody_named() {
createParser('external C.c() {}');
ClassMember member = parser.parseClassMember('C');
expectNotNullIfNoErrors(member);
- if (usingFastaParser) {
- // TODO(brianwilkerson) Convert codes to errors when highlighting is fixed.
- listener
- .assertErrorsWithCodes([ParserErrorCode.EXTERNAL_METHOD_WITH_BODY]);
+ // TODO(brianwilkerson) Convert codes to errors when highlighting is fixed.
+ listener.assertErrorsWithCodes([ParserErrorCode.EXTERNAL_METHOD_WITH_BODY]);
// listener.assertErrors(
// [expectedError(ParserErrorCode.EXTERNAL_METHOD_WITH_BODY, 15, 2)]);
- } else {
- listener.assertErrorsWithCodes(
- [ParserErrorCode.EXTERNAL_CONSTRUCTOR_WITH_BODY]);
- }
}
void test_externalEnum() {
@@ -3340,12 +3119,8 @@
createParser('external const A f;');
ClassMember member = parser.parseClassMember('C');
expectNotNullIfNoErrors(member);
- if (usingFastaParser) {
- listener.assertErrors(
- [expectedError(CompileTimeErrorCode.CONST_NOT_INITIALIZED, 17, 1)]);
- } else {
- listener.assertErrorsWithCodes([ParserErrorCode.EXTERNAL_FIELD]);
- }
+ listener.assertErrors(
+ [expectedError(CompileTimeErrorCode.CONST_NOT_INITIALIZED, 17, 1)]);
}
void test_externalField_final() {
@@ -3380,16 +3155,10 @@
createParser('external int get x {}');
ClassMember member = parser.parseClassMember('C');
expectNotNullIfNoErrors(member);
- if (usingFastaParser) {
- // TODO(brianwilkerson) Convert codes to errors when highlighting is fixed.
- listener
- .assertErrorsWithCodes([ParserErrorCode.EXTERNAL_METHOD_WITH_BODY]);
+ // TODO(brianwilkerson) Convert codes to errors when highlighting is fixed.
+ listener.assertErrorsWithCodes([ParserErrorCode.EXTERNAL_METHOD_WITH_BODY]);
// listener.assertErrors(
// [expectedError(ParserErrorCode.EXTERNAL_METHOD_WITH_BODY, 19, 2)]);
- } else {
- listener
- .assertErrorsWithCodes([ParserErrorCode.EXTERNAL_GETTER_WITH_BODY]);
- }
}
void test_externalMethodWithBody() {
@@ -3406,32 +3175,20 @@
createParser('external operator +(int value) {}');
ClassMember member = parser.parseClassMember('C');
expectNotNullIfNoErrors(member);
- if (usingFastaParser) {
- // TODO(brianwilkerson) Convert codes to errors when highlighting is fixed.
- listener
- .assertErrorsWithCodes([ParserErrorCode.EXTERNAL_METHOD_WITH_BODY]);
+ // TODO(brianwilkerson) Convert codes to errors when highlighting is fixed.
+ listener.assertErrorsWithCodes([ParserErrorCode.EXTERNAL_METHOD_WITH_BODY]);
// listener.assertErrors(
// [expectedError(ParserErrorCode.EXTERNAL_METHOD_WITH_BODY, 31, 2)]);
- } else {
- listener
- .assertErrorsWithCodes([ParserErrorCode.EXTERNAL_OPERATOR_WITH_BODY]);
- }
}
void test_externalSetterWithBody() {
createParser('external set x(int value) {}');
ClassMember member = parser.parseClassMember('C');
expectNotNullIfNoErrors(member);
- if (usingFastaParser) {
- // TODO(brianwilkerson) Convert codes to errors when highlighting is fixed.
- listener
- .assertErrorsWithCodes([ParserErrorCode.EXTERNAL_METHOD_WITH_BODY]);
+ // TODO(brianwilkerson) Convert codes to errors when highlighting is fixed.
+ listener.assertErrorsWithCodes([ParserErrorCode.EXTERNAL_METHOD_WITH_BODY]);
// listener.assertErrors(
// [expectedError(ParserErrorCode.EXTERNAL_METHOD_WITH_BODY, 26, 2)]);
- } else {
- listener
- .assertErrorsWithCodes([ParserErrorCode.EXTERNAL_SETTER_WITH_BODY]);
- }
}
void test_externalTypedef() {
@@ -3443,38 +3200,24 @@
createParser('(int a, , int b)');
FormalParameterList list = parser.parseFormalParameterList();
expectNotNullIfNoErrors(list);
- listener.assertErrors(usingFastaParser
- ? [expectedError(ParserErrorCode.MISSING_IDENTIFIER, 8, 1)]
- : [
- expectedError(ParserErrorCode.MISSING_IDENTIFIER, 8, 1),
- expectedError(ParserErrorCode.EXPECTED_TOKEN, 8, 1)
- ]);
+ listener.assertErrors(
+ [expectedError(ParserErrorCode.MISSING_IDENTIFIER, 8, 1)]);
}
void test_extraCommaTrailingNamedParameterGroup() {
createParser('({int b},)');
FormalParameterList list = parser.parseFormalParameterList();
expectNotNullIfNoErrors(list);
- listener.assertErrors(usingFastaParser
- ? [expectedError(ParserErrorCode.EXPECTED_TOKEN, 8, 1)]
- : [
- expectedError(ParserErrorCode.MISSING_IDENTIFIER, 9, 1),
- expectedError(
- ParserErrorCode.NORMAL_BEFORE_OPTIONAL_PARAMETERS, 9, 1)
- ]);
+ listener
+ .assertErrors([expectedError(ParserErrorCode.EXPECTED_TOKEN, 8, 1)]);
}
void test_extraCommaTrailingPositionalParameterGroup() {
createParser('([int b],)');
FormalParameterList list = parser.parseFormalParameterList();
expectNotNullIfNoErrors(list);
- listener.assertErrors(usingFastaParser
- ? [expectedError(ParserErrorCode.EXPECTED_TOKEN, 8, 1)]
- : [
- expectedError(ParserErrorCode.MISSING_IDENTIFIER, 9, 1),
- expectedError(
- ParserErrorCode.NORMAL_BEFORE_OPTIONAL_PARAMETERS, 9, 1)
- ]);
+ listener
+ .assertErrors([expectedError(ParserErrorCode.EXPECTED_TOKEN, 8, 1)]);
}
void test_extraTrailingCommaInParameterList() {
@@ -3507,21 +3250,16 @@
createParser('factory C() : x = 3 {}', expectedEndOffset: 12);
ClassMember member = parser.parseClassMember('C');
expectNotNullIfNoErrors(member);
- listener.assertErrors(usingFastaParser
- ? [expectedError(ParserErrorCode.MISSING_FUNCTION_BODY, 12, 1)]
- : [expectedError(ParserErrorCode.FACTORY_WITH_INITIALIZERS, 12, 1)]);
+ listener.assertErrors(
+ [expectedError(ParserErrorCode.MISSING_FUNCTION_BODY, 12, 1)]);
}
void test_factoryWithoutBody() {
createParser('factory C();');
ClassMember member = parser.parseClassMember('C');
expectNotNullIfNoErrors(member);
- if (usingFastaParser) {
- listener.assertErrors(
- [expectedError(ParserErrorCode.MISSING_FUNCTION_BODY, 11, 1)]);
- } else {
- listener.assertErrorsWithCodes([ParserErrorCode.FACTORY_WITHOUT_BODY]);
- }
+ listener.assertErrors(
+ [expectedError(ParserErrorCode.MISSING_FUNCTION_BODY, 11, 1)]);
}
void test_fieldInitializerOutsideConstructor() {
@@ -3537,12 +3275,10 @@
createParser('final covariant f = null;');
ClassMember member = parser.parseClassMember('C');
expectNotNullIfNoErrors(member);
- listener.assertErrors(usingFastaParser
- ? [
- expectedError(ParserErrorCode.MODIFIER_OUT_OF_ORDER, 6, 9),
- expectedError(ParserErrorCode.FINAL_AND_COVARIANT, 6, 9)
- ]
- : [expectedError(ParserErrorCode.FINAL_AND_COVARIANT, 6, 9)]);
+ listener.assertErrors([
+ expectedError(ParserErrorCode.MODIFIER_OUT_OF_ORDER, 6, 9),
+ expectedError(ParserErrorCode.FINAL_AND_COVARIANT, 6, 9)
+ ]);
}
void test_finalAndVar() {
@@ -3571,83 +3307,54 @@
createParser('final C() {}');
ClassMember member = parser.parseClassMember('C');
expectNotNullIfNoErrors(member);
- if (usingFastaParser) {
- listener.assertErrors(
- [expectedError(ParserErrorCode.EXTRANEOUS_MODIFIER, 0, 5)]);
- } else {
- listener.assertErrorsWithCodes([ParserErrorCode.FINAL_CONSTRUCTOR]);
- }
+ listener.assertErrors(
+ [expectedError(ParserErrorCode.EXTRANEOUS_MODIFIER, 0, 5)]);
}
void test_finalEnum() {
- parseCompilationUnit("final enum E {ONE}",
- errors: usingFastaParser
- ? [
- // Fasta interprets the `final` as a malformed top level final
- // and `enum` as the start of a enum declaration.
- expectedError(ParserErrorCode.MISSING_IDENTIFIER, 6, 4),
- expectedError(ParserErrorCode.EXPECTED_TOKEN, 6, 4),
- ]
- : [expectedError(ParserErrorCode.FINAL_ENUM, 0, 5)]);
+ parseCompilationUnit("final enum E {ONE}", errors: [
+ // Fasta interprets the `final` as a malformed top level final
+ // and `enum` as the start of a enum declaration.
+ expectedError(ParserErrorCode.MISSING_IDENTIFIER, 6, 4),
+ expectedError(ParserErrorCode.EXPECTED_TOKEN, 6, 4),
+ ]);
}
void test_finalMethod() {
createParser('final int m() {}');
ClassMember member = parser.parseClassMember('C');
expectNotNullIfNoErrors(member);
- if (usingFastaParser) {
- listener.assertErrors(
- [expectedError(ParserErrorCode.EXTRANEOUS_MODIFIER, 0, 5)]);
- } else {
- listener.assertErrorsWithCodes([ParserErrorCode.FINAL_METHOD]);
- }
+ listener.assertErrors(
+ [expectedError(ParserErrorCode.EXTRANEOUS_MODIFIER, 0, 5)]);
}
void test_finalTypedef() {
- parseCompilationUnit("final typedef F();",
- errors: usingFastaParser
- ? [
- // Fasta interprets the `final` as a malformed top level final
- // and `typedef` as the start of an typedef declaration.
- expectedError(ParserErrorCode.MISSING_IDENTIFIER, 6, 7),
- expectedError(ParserErrorCode.EXPECTED_TOKEN, 6, 7),
- ]
- : [expectedError(ParserErrorCode.FINAL_TYPEDEF, 0, 5)]);
+ parseCompilationUnit("final typedef F();", errors: [
+ // Fasta interprets the `final` as a malformed top level final
+ // and `typedef` as the start of an typedef declaration.
+ expectedError(ParserErrorCode.MISSING_IDENTIFIER, 6, 7),
+ expectedError(ParserErrorCode.EXPECTED_TOKEN, 6, 7),
+ ]);
}
void test_functionTypedField_invalidType_abstract() {
- if (usingFastaParser) {
- parseCompilationUnit("Function(abstract) x = null;", errors: [
- expectedError(CompileTimeErrorCode.BUILT_IN_IDENTIFIER_AS_TYPE, 9, 8)
- ]);
- }
+ parseCompilationUnit("Function(abstract) x = null;", errors: [
+ expectedError(CompileTimeErrorCode.BUILT_IN_IDENTIFIER_AS_TYPE, 9, 8)
+ ]);
}
void test_functionTypedField_invalidType_class() {
- if (usingFastaParser) {
- parseCompilationUnit("Function(class) x = null;",
- errors: usingFastaParser
- ? [
- expectedError(ParserErrorCode.EXPECTED_TYPE_NAME, 9, 5),
- expectedError(
- ParserErrorCode.EXPECTED_IDENTIFIER_BUT_GOT_KEYWORD, 9, 5)
- ]
- : [expectedError(ParserErrorCode.EXPECTED_TYPE_NAME, 9, 5)]);
- }
+ parseCompilationUnit("Function(class) x = null;", errors: [
+ expectedError(ParserErrorCode.EXPECTED_TYPE_NAME, 9, 5),
+ expectedError(ParserErrorCode.EXPECTED_IDENTIFIER_BUT_GOT_KEYWORD, 9, 5)
+ ]);
}
void test_functionTypedParameter_const() {
- parseCompilationUnit("void f(const x()) {}",
- errors: usingFastaParser
- ? [
- expectedError(ParserErrorCode.EXTRANEOUS_MODIFIER, 7, 5),
- expectedError(
- ParserErrorCode.FUNCTION_TYPED_PARAMETER_VAR, 7, 5)
- ]
- : [
- expectedError(
- ParserErrorCode.FUNCTION_TYPED_PARAMETER_VAR, 7, 5)
- ]);
+ parseCompilationUnit("void f(const x()) {}", errors: [
+ expectedError(ParserErrorCode.EXTRANEOUS_MODIFIER, 7, 5),
+ expectedError(ParserErrorCode.FUNCTION_TYPED_PARAMETER_VAR, 7, 5)
+ ]);
}
void test_functionTypedParameter_final() {
@@ -3657,19 +3364,11 @@
}
void test_functionTypedParameter_incomplete1() {
- parseCompilationUnit("void f(int Function(",
- errors: usingFastaParser
- ? [
- expectedError(ScannerErrorCode.EXPECTED_TOKEN, 20, 1),
- expectedError(ScannerErrorCode.EXPECTED_TOKEN, 20, 1),
- expectedError(ParserErrorCode.MISSING_FUNCTION_BODY, 20, 0),
- ]
- : [
- expectedError(ScannerErrorCode.EXPECTED_TOKEN, 20, 0),
- expectedError(ScannerErrorCode.EXPECTED_TOKEN, 20, 0),
- expectedError(ParserErrorCode.MISSING_FUNCTION_BODY, 20, 0),
- expectedError(ParserErrorCode.MISSING_IDENTIFIER, 20, 0),
- ]);
+ parseCompilationUnit("void f(int Function(", errors: [
+ expectedError(ScannerErrorCode.EXPECTED_TOKEN, 20, 1),
+ expectedError(ScannerErrorCode.EXPECTED_TOKEN, 20, 1),
+ expectedError(ParserErrorCode.MISSING_FUNCTION_BODY, 20, 0),
+ ]);
}
void test_functionTypedParameter_var() {
@@ -3686,21 +3385,17 @@
}
void test_genericFunctionType_asIdentifier2() {
- if (usingFastaParser) {
- createParser('int Function() {}');
- CompilationUnit unit = parser.parseCompilationUnit2();
- expectNotNullIfNoErrors(unit);
- listener.assertErrors([]);
- }
+ createParser('int Function() {}');
+ CompilationUnit unit = parser.parseCompilationUnit2();
+ expectNotNullIfNoErrors(unit);
+ listener.assertErrors([]);
}
void test_genericFunctionType_asIdentifier3() {
- if (usingFastaParser) {
- createParser('int Function() => 0;');
- CompilationUnit unit = parser.parseCompilationUnit2();
- expectNotNullIfNoErrors(unit);
- listener.assertErrors([]);
- }
+ createParser('int Function() => 0;');
+ CompilationUnit unit = parser.parseCompilationUnit2();
+ expectNotNullIfNoErrors(unit);
+ listener.assertErrors([]);
}
void test_genericFunctionType_extraLessThan() {
@@ -3710,55 +3405,42 @@
}''');
CompilationUnit unit = parser.parseCompilationUnit2();
expectNotNullIfNoErrors(unit);
- listener.assertErrors(usingFastaParser
- ? [
- expectedError(ParserErrorCode.EXPECTED_TYPE_NAME, 30, 1),
- expectedError(ParserErrorCode.EXPECTED_TOKEN, 30, 1)
- ]
- : [expectedError(ParserErrorCode.UNEXPECTED_TOKEN, 30, 1)]);
+ listener.assertErrors([
+ expectedError(ParserErrorCode.EXPECTED_TYPE_NAME, 30, 1),
+ expectedError(ParserErrorCode.EXPECTED_TOKEN, 30, 1)
+ ]);
}
void test_getterInFunction_block_noReturnType() {
Statement result =
parseStatement("get x { return _x; }", expectedEndOffset: 4);
- if (usingFastaParser) {
- // Fasta considers `get` to be an identifier in this situation.
- // TODO(danrubel): Investigate better recovery.
- ExpressionStatement statement = result;
- listener
- .assertErrors([expectedError(ParserErrorCode.EXPECTED_TOKEN, 0, 3)]);
- expect(statement.expression.toSource(), 'get');
- } else {
- FunctionDeclarationStatement statement = result;
- listener.assertErrors(
- [expectedError(ParserErrorCode.GETTER_IN_FUNCTION, 0, 3)]);
- expect(
- statement.functionDeclaration.functionExpression.parameters, isNull);
- }
+ // Fasta considers `get` to be an identifier in this situation.
+ // TODO(danrubel): Investigate better recovery.
+ ExpressionStatement statement = result;
+ listener
+ .assertErrors([expectedError(ParserErrorCode.EXPECTED_TOKEN, 0, 3)]);
+ expect(statement.expression.toSource(), 'get');
}
void test_getterInFunction_block_returnType() {
// Fasta considers `get` to be an identifier in this situation.
parseStatement("int get x { return _x; }", expectedEndOffset: 8);
- listener.assertErrors(usingFastaParser
- ? [expectedError(ParserErrorCode.EXPECTED_TOKEN, 4, 3)]
- : [expectedError(ParserErrorCode.GETTER_IN_FUNCTION, 4, 3)]);
+ listener
+ .assertErrors([expectedError(ParserErrorCode.EXPECTED_TOKEN, 4, 3)]);
}
void test_getterInFunction_expression_noReturnType() {
// Fasta considers `get` to be an identifier in this situation.
parseStatement("get x => _x;", expectedEndOffset: 4);
- listener.assertErrors(usingFastaParser
- ? [expectedError(ParserErrorCode.EXPECTED_TOKEN, 0, 3)]
- : [expectedError(ParserErrorCode.GETTER_IN_FUNCTION, 0, 3)]);
+ listener
+ .assertErrors([expectedError(ParserErrorCode.EXPECTED_TOKEN, 0, 3)]);
}
void test_getterInFunction_expression_returnType() {
// Fasta considers `get` to be an identifier in this situation.
parseStatement("int get x => _x;", expectedEndOffset: 8);
- listener.assertErrors(usingFastaParser
- ? [expectedError(ParserErrorCode.EXPECTED_TOKEN, 4, 3)]
- : [expectedError(ParserErrorCode.GETTER_IN_FUNCTION, 4, 3)]);
+ listener
+ .assertErrors([expectedError(ParserErrorCode.EXPECTED_TOKEN, 4, 3)]);
}
void test_getterWithParameters() {
@@ -3773,30 +3455,18 @@
void test_illegalAssignmentToNonAssignable_assign_int() {
parseStatement("0 = 1;");
- listener.assertErrors(usingFastaParser
- ? [
- expectedError(ParserErrorCode.MISSING_ASSIGNABLE_SELECTOR, 0, 1),
- expectedError(
- ParserErrorCode.ILLEGAL_ASSIGNMENT_TO_NON_ASSIGNABLE, 0, 1),
- ]
- : [
- expectedError(
- ParserErrorCode.ILLEGAL_ASSIGNMENT_TO_NON_ASSIGNABLE, 4, 1)
- ]);
+ listener.assertErrors([
+ expectedError(ParserErrorCode.MISSING_ASSIGNABLE_SELECTOR, 0, 1),
+ expectedError(ParserErrorCode.ILLEGAL_ASSIGNMENT_TO_NON_ASSIGNABLE, 0, 1),
+ ]);
}
void test_illegalAssignmentToNonAssignable_assign_this() {
parseStatement("this = 1;");
- listener.assertErrors(usingFastaParser
- ? [
- expectedError(ParserErrorCode.MISSING_ASSIGNABLE_SELECTOR, 0, 4),
- expectedError(
- ParserErrorCode.ILLEGAL_ASSIGNMENT_TO_NON_ASSIGNABLE, 0, 4)
- ]
- : [
- expectedError(
- ParserErrorCode.ILLEGAL_ASSIGNMENT_TO_NON_ASSIGNABLE, 7, 1)
- ]);
+ listener.assertErrors([
+ expectedError(ParserErrorCode.MISSING_ASSIGNABLE_SELECTOR, 0, 4),
+ expectedError(ParserErrorCode.ILLEGAL_ASSIGNMENT_TO_NON_ASSIGNABLE, 0, 4)
+ ]);
}
void test_illegalAssignmentToNonAssignable_postfix_minusMinus_literal() {
@@ -3868,32 +3538,21 @@
void test_initializedVariableInForEach_localFunction() {
Statement statement = parseStatement('for (f()) {}');
expectNotNullIfNoErrors(statement);
- listener.assertErrors(usingFastaParser
- ? [
- expectedError(ParserErrorCode.EXPECTED_TOKEN, 7, 1),
- expectedError(ParserErrorCode.MISSING_IDENTIFIER, 8, 1),
- expectedError(ParserErrorCode.EXPECTED_TOKEN, 8, 1)
- ]
- : [
- expectedError(ParserErrorCode.EXPECTED_TOKEN, 7, 1),
- expectedError(ParserErrorCode.MISSING_IDENTIFIER, 8, 1),
- expectedError(ParserErrorCode.EXPECTED_TOKEN, 8, 1)
- ]);
+ listener.assertErrors([
+ expectedError(ParserErrorCode.EXPECTED_TOKEN, 7, 1),
+ expectedError(ParserErrorCode.MISSING_IDENTIFIER, 8, 1),
+ expectedError(ParserErrorCode.EXPECTED_TOKEN, 8, 1)
+ ]);
}
void test_initializedVariableInForEach_localFunction2() {
Statement statement = parseStatement('for (T f()) {}');
expectNotNullIfNoErrors(statement);
- listener.assertErrors(usingFastaParser
- ? [
- expectedError(ParserErrorCode.EXPECTED_TOKEN, 7, 1),
- expectedError(ParserErrorCode.MISSING_IDENTIFIER, 9, 1),
- expectedError(ParserErrorCode.EXPECTED_TOKEN, 9, 1)
- ]
- : [
- expectedError(ParserErrorCode.EXPECTED_TOKEN, 5, 1),
- expectedError(ParserErrorCode.EXPECTED_TOKEN, 9, 1)
- ]);
+ listener.assertErrors([
+ expectedError(ParserErrorCode.EXPECTED_TOKEN, 7, 1),
+ expectedError(ParserErrorCode.MISSING_IDENTIFIER, 9, 1),
+ expectedError(ParserErrorCode.EXPECTED_TOKEN, 9, 1)
+ ]);
}
void test_initializedVariableInForEach_var() {
@@ -3959,12 +3618,8 @@
createParser("C.*();");
ClassMember member = parser.parseClassMember('C');
expectNotNullIfNoErrors(member);
- listener.assertErrors(usingFastaParser
- ? [expectedError(ParserErrorCode.MISSING_IDENTIFIER, 2, 1)]
- : [
- expectedError(ParserErrorCode.MISSING_IDENTIFIER, 2, 1),
- expectedError(ParserErrorCode.MISSING_KEYWORD_OPERATOR, 2, 1)
- ]);
+ listener.assertErrors(
+ [expectedError(ParserErrorCode.MISSING_IDENTIFIER, 2, 1)]);
}
void test_invalidConstructorName_with() {
@@ -3972,10 +3627,7 @@
ClassMember member = parser.parseClassMember('C');
expectNotNullIfNoErrors(member);
listener.assertErrors([
- usingFastaParser
- ? expectedError(
- ParserErrorCode.EXPECTED_IDENTIFIER_BUT_GOT_KEYWORD, 2, 4)
- : expectedError(ParserErrorCode.INVALID_CONSTRUCTOR_NAME, 0, 1)
+ expectedError(ParserErrorCode.EXPECTED_IDENTIFIER_BUT_GOT_KEYWORD, 2, 4)
]);
}
@@ -3983,35 +3635,18 @@
createParser("C() : super = 42;");
ClassMember member = parser.parseClassMember('C');
expectNotNullIfNoErrors(member);
- listener.assertErrors(usingFastaParser
- ? [expectedError(ParserErrorCode.MISSING_ASSIGNABLE_SELECTOR, 6, 5)]
- : [
- expectedError(ParserErrorCode.EXPECTED_TOKEN, 14, 1),
- expectedError(ParserErrorCode.EXPECTED_TYPE_NAME, 16, 2),
- expectedError(ParserErrorCode.UNEXPECTED_TOKEN, 16, 2),
- expectedError(
- ParserErrorCode.REDIRECTION_IN_NON_FACTORY_CONSTRUCTOR, 16, 0),
- ]);
+ listener.assertErrors(
+ [expectedError(ParserErrorCode.MISSING_ASSIGNABLE_SELECTOR, 6, 5)]);
}
void test_invalidConstructorSuperFieldAssignment() {
createParser("C() : super.a = 42;");
ClassMember member = parser.parseClassMember('C');
expectNotNullIfNoErrors(member);
- listener.assertErrors(usingFastaParser
- ? [
- expectedError(
- ParserErrorCode.FIELD_INITIALIZED_OUTSIDE_DECLARING_CLASS,
- 12,
- 1)
- ]
- : [
- expectedError(ParserErrorCode.EXPECTED_TOKEN, 14, 1),
- expectedError(ParserErrorCode.EXPECTED_TYPE_NAME, 16, 2),
- expectedError(ParserErrorCode.UNEXPECTED_TOKEN, 16, 2),
- expectedError(
- ParserErrorCode.REDIRECTION_IN_NON_FACTORY_CONSTRUCTOR, 16, 0),
- ]);
+ listener.assertErrors([
+ expectedError(
+ ParserErrorCode.FIELD_INITIALIZED_OUTSIDE_DECLARING_CLASS, 12, 1)
+ ]);
}
void test_invalidHexEscape_invalidDigit() {
@@ -4029,36 +3664,20 @@
void test_invalidInlineFunctionType() {
parseCompilationUnit(
'typedef F = int Function(int a());',
- errors: usingFastaParser
- ? [
- expectedError(
- CompileTimeErrorCode.INVALID_INLINE_FUNCTION_TYPE, 30, 1)
- ]
- : [],
+ errors: [
+ expectedError(CompileTimeErrorCode.INVALID_INLINE_FUNCTION_TYPE, 30, 1)
+ ],
);
}
void test_invalidInterpolation_missingClosingBrace_issue35900() {
- parseCompilationUnit(r"main () { print('${x' '); }",
- errors: usingFastaParser
- ? [
- expectedError(ScannerErrorCode.EXPECTED_TOKEN, 23, 1),
- expectedError(
- ScannerErrorCode.UNTERMINATED_STRING_LITERAL, 26, 1),
- expectedError(ParserErrorCode.EXPECTED_TOKEN, 20, 3),
- expectedError(ParserErrorCode.EXPECTED_STRING_LITERAL, 23, 1),
- expectedError(ParserErrorCode.EXPECTED_EXECUTABLE, 27, 0),
- ]
- : [
- expectedError(ScannerErrorCode.EXPECTED_TOKEN, 23, 1),
- expectedError(
- ScannerErrorCode.UNTERMINATED_STRING_LITERAL, 26, 1),
- expectedError(ParserErrorCode.EXPECTED_TOKEN, 20, 3),
- expectedError(ParserErrorCode.EXPECTED_TOKEN, 23, 1),
- expectedError(ParserErrorCode.EXPECTED_TOKEN, 23, 1),
- expectedError(ParserErrorCode.EXPECTED_EXECUTABLE, 23, 1),
- expectedError(ParserErrorCode.UNEXPECTED_TOKEN, 23, 1),
- ]);
+ parseCompilationUnit(r"main () { print('${x' '); }", errors: [
+ expectedError(ScannerErrorCode.EXPECTED_TOKEN, 23, 1),
+ expectedError(ScannerErrorCode.UNTERMINATED_STRING_LITERAL, 26, 1),
+ expectedError(ParserErrorCode.EXPECTED_TOKEN, 20, 3),
+ expectedError(ParserErrorCode.EXPECTED_STRING_LITERAL, 23, 1),
+ expectedError(ParserErrorCode.EXPECTED_EXECUTABLE, 27, 0),
+ ]);
}
void test_invalidInterpolationIdentifier_startWithDigit() {
@@ -4077,14 +3696,9 @@
}
void test_invalidOperator() {
- CompilationUnit unit =
- parseCompilationUnit('class C { void operator ===(x) { } }',
- errors: usingFastaParser
- ? [expectedError(ScannerErrorCode.UNSUPPORTED_OPERATOR, 24, 1)]
- : [
- expectedError(ScannerErrorCode.UNSUPPORTED_OPERATOR, 24, 1),
- expectedError(ParserErrorCode.INVALID_OPERATOR, 24, 3)
- ]);
+ CompilationUnit unit = parseCompilationUnit(
+ 'class C { void operator ===(x) { } }',
+ errors: [expectedError(ScannerErrorCode.UNSUPPORTED_OPERATOR, 24, 1)]);
expect(unit, isNotNull);
}
@@ -4092,22 +3706,10 @@
createParser('class C { int operator unary- => 0; }');
CompilationUnit unit = parser.parseCompilationUnit2();
expectNotNullIfNoErrors(unit);
- listener.assertErrors(usingFastaParser
- ? [
- expectedError(ParserErrorCode.UNEXPECTED_TOKEN, 23, 5),
- expectedError(ParserErrorCode.MISSING_METHOD_PARAMETERS, 28, 1)
- ]
- : [
- expectedError(ParserErrorCode.EXPECTED_TOKEN, 14, 8),
- expectedError(ParserErrorCode.EXPECTED_CLASS_MEMBER, 28, 1),
- expectedError(ParserErrorCode.EXPECTED_CLASS_MEMBER, 28, 1),
- expectedError(ParserErrorCode.UNEXPECTED_TOKEN, 28, 1),
- expectedError(ParserErrorCode.EXPECTED_CLASS_MEMBER, 30, 2),
- expectedError(ParserErrorCode.UNEXPECTED_TOKEN, 30, 2),
- expectedError(ParserErrorCode.EXPECTED_CLASS_MEMBER, 33, 1),
- expectedError(ParserErrorCode.UNEXPECTED_TOKEN, 33, 1),
- expectedError(ParserErrorCode.UNEXPECTED_TOKEN, 34, 1)
- ]);
+ listener.assertErrors([
+ expectedError(ParserErrorCode.UNEXPECTED_TOKEN, 23, 5),
+ expectedError(ParserErrorCode.MISSING_METHOD_PARAMETERS, 28, 1)
+ ]);
}
void test_invalidOperatorAfterSuper_assignableExpression() {
@@ -4115,22 +3717,14 @@
expectNotNullIfNoErrors(expression);
listener.assertErrors([
expectedError(
- usingFastaParser
- ? ParserErrorCode.INVALID_OPERATOR_QUESTIONMARK_PERIOD_FOR_SUPER
- : ParserErrorCode.INVALID_OPERATOR_FOR_SUPER,
- 5,
- 2)
+ ParserErrorCode.INVALID_OPERATOR_QUESTIONMARK_PERIOD_FOR_SUPER, 5, 2)
]);
}
void test_invalidOperatorAfterSuper_primaryExpression() {
Expression expression = parseExpression('super?.v', errors: [
expectedError(
- usingFastaParser
- ? ParserErrorCode.INVALID_OPERATOR_QUESTIONMARK_PERIOD_FOR_SUPER
- : ParserErrorCode.INVALID_OPERATOR_FOR_SUPER,
- 5,
- 2)
+ ParserErrorCode.INVALID_OPERATOR_QUESTIONMARK_PERIOD_FOR_SUPER, 5, 2)
]);
expectNotNullIfNoErrors(expression);
}
@@ -4139,11 +3733,8 @@
createParser('++super');
Expression expression = parser.parseUnaryExpression();
expectNotNullIfNoErrors(expression);
- listener.assertErrors([
- usingFastaParser
- ? expectedError(ParserErrorCode.MISSING_ASSIGNABLE_SELECTOR, 2, 5)
- : expectedError(ParserErrorCode.INVALID_OPERATOR_FOR_SUPER, 0, 2)
- ]);
+ listener.assertErrors(
+ [expectedError(ParserErrorCode.MISSING_ASSIGNABLE_SELECTOR, 2, 5)]);
}
void test_invalidPropertyAccess_this() {
@@ -4155,84 +3746,52 @@
createParser('foo() async* => 0;');
CompilationUnit unit = parser.parseCompilationUnit2();
expectNotNullIfNoErrors(unit);
- listener.assertErrors(usingFastaParser
- ? [expectedError(CompileTimeErrorCode.RETURN_IN_GENERATOR, 13, 2)]
- : [expectedError(ParserErrorCode.INVALID_STAR_AFTER_ASYNC, 11, 1)]);
+ listener.assertErrors(
+ [expectedError(CompileTimeErrorCode.RETURN_IN_GENERATOR, 13, 2)]);
}
void test_invalidSync() {
createParser('foo() sync* => 0;');
CompilationUnit unit = parser.parseCompilationUnit2();
expectNotNullIfNoErrors(unit);
- listener.assertErrors(usingFastaParser
- ? [expectedError(CompileTimeErrorCode.RETURN_IN_GENERATOR, 12, 2)]
- : [expectedError(ParserErrorCode.INVALID_SYNC, 0, 4)]);
+ listener.assertErrors(
+ [expectedError(CompileTimeErrorCode.RETURN_IN_GENERATOR, 12, 2)]);
}
void test_invalidTopLevelSetter() {
parseCompilationUnit("var set foo; main(){}", errors: [
expectedError(ParserErrorCode.VAR_RETURN_TYPE, 0, 3),
- usingFastaParser
- ? expectedError(ParserErrorCode.MISSING_FUNCTION_PARAMETERS, 8, 3)
- : expectedError(ParserErrorCode.MISSING_FUNCTION_PARAMETERS, 11, 1),
+ expectedError(ParserErrorCode.MISSING_FUNCTION_PARAMETERS, 8, 3),
expectedError(ParserErrorCode.MISSING_FUNCTION_BODY, 11, 1)
]);
}
void test_invalidTopLevelVar() {
- parseCompilationUnit("var Function(var arg);",
- errors: usingFastaParser
- ? [
- expectedError(ParserErrorCode.VAR_RETURN_TYPE, 0, 3),
- expectedError(ParserErrorCode.MISSING_FUNCTION_BODY, 21, 1),
- ]
- : [
- expectedError(ParserErrorCode.EXPECTED_EXECUTABLE, 21, 2),
- expectedError(ParserErrorCode.UNEXPECTED_TOKEN, 21, 2),
- ]);
+ parseCompilationUnit("var Function(var arg);", errors: [
+ expectedError(ParserErrorCode.VAR_RETURN_TYPE, 0, 3),
+ expectedError(ParserErrorCode.MISSING_FUNCTION_BODY, 21, 1),
+ ]);
}
void test_invalidTypedef() {
- parseCompilationUnit("typedef var Function(var arg);",
- errors: usingFastaParser
- ? [
- expectedError(ParserErrorCode.MISSING_IDENTIFIER, 8, 3),
- expectedError(ParserErrorCode.MISSING_TYPEDEF_PARAMETERS, 8, 3),
- expectedError(ParserErrorCode.EXPECTED_TOKEN, 8, 3),
- expectedError(ParserErrorCode.VAR_RETURN_TYPE, 8, 3),
- expectedError(ParserErrorCode.MISSING_FUNCTION_BODY, 29, 1),
- ]
- : [
- expectedError(ParserErrorCode.MISSING_IDENTIFIER, 8, 3),
- expectedError(ParserErrorCode.MISSING_TYPEDEF_PARAMETERS, 8, 3),
- expectedError(ParserErrorCode.EXPECTED_EXECUTABLE, 29, 2),
- expectedError(ParserErrorCode.UNEXPECTED_TOKEN, 29, 2),
- ]);
+ parseCompilationUnit("typedef var Function(var arg);", errors: [
+ expectedError(ParserErrorCode.MISSING_IDENTIFIER, 8, 3),
+ expectedError(ParserErrorCode.MISSING_TYPEDEF_PARAMETERS, 8, 3),
+ expectedError(ParserErrorCode.EXPECTED_TOKEN, 8, 3),
+ expectedError(ParserErrorCode.VAR_RETURN_TYPE, 8, 3),
+ expectedError(ParserErrorCode.MISSING_FUNCTION_BODY, 29, 1),
+ ]);
}
void test_invalidTypedef2() {
// https://github.com/dart-lang/sdk/issues/31171
parseCompilationUnit(
"typedef T = typedef F = Map<String, dynamic> Function();",
- errors: usingFastaParser
- ? [
- expectedError(ParserErrorCode.EXPECTED_TYPE_NAME, 12, 7),
- expectedError(ParserErrorCode.EXPECTED_TOKEN, 12, 7),
- expectedError(
- ParserErrorCode.INVALID_GENERIC_FUNCTION_TYPE, 10, 1),
- ]
- : [
- expectedError(ParserErrorCode.EXPECTED_TOKEN, 12, 7),
- expectedError(
- ParserErrorCode.INVALID_GENERIC_FUNCTION_TYPE, 20, 1),
- expectedError(
- ParserErrorCode.MISSING_CONST_FINAL_VAR_OR_TYPE, 20, 1),
- expectedError(ParserErrorCode.EXPECTED_TOKEN, 36, 7),
- expectedError(ParserErrorCode.EXPECTED_EXECUTABLE, 43, 1),
- expectedError(ParserErrorCode.UNEXPECTED_TOKEN, 43, 1),
- expectedError(ParserErrorCode.EXPECTED_EXECUTABLE, 55, 1),
- expectedError(ParserErrorCode.UNEXPECTED_TOKEN, 55, 1),
- ]);
+ errors: [
+ expectedError(ParserErrorCode.EXPECTED_TYPE_NAME, 12, 7),
+ expectedError(ParserErrorCode.EXPECTED_TOKEN, 12, 7),
+ expectedError(ParserErrorCode.INVALID_GENERIC_FUNCTION_TYPE, 10, 1),
+ ]);
}
void test_invalidUnicodeEscape_incomplete_noDigits() {
@@ -4273,12 +3832,8 @@
void test_invalidUnicodeEscape_tooManyDigits_variable() {
Expression expression = parseStringLiteral("'\\u{12345678}'");
expectNotNullIfNoErrors(expression);
- listener.assertErrors(usingFastaParser
- ? [expectedError(ParserErrorCode.INVALID_CODE_POINT, 1, 9)]
- : [
- expectedError(ParserErrorCode.INVALID_UNICODE_ESCAPE, 1, 12),
- expectedError(ParserErrorCode.INVALID_CODE_POINT, 1, 12)
- ]);
+ listener.assertErrors(
+ [expectedError(ParserErrorCode.INVALID_CODE_POINT, 1, 9)]);
}
void test_libraryDirectiveNotFirst() {
@@ -4305,51 +3860,29 @@
BlockFunctionBody body = member.body;
expect(body.block.statements, hasLength(1));
FunctionDeclarationStatement statement = body.block.statements[0];
- if (usingFastaParser) {
- expect(statement.functionDeclaration.metadata, hasLength(1));
- Annotation metadata = statement.functionDeclaration.metadata[0];
- expect(metadata.name.name, 'Foo');
- }
+ expect(statement.functionDeclaration.metadata, hasLength(1));
+ Annotation metadata = statement.functionDeclaration.metadata[0];
+ expect(metadata.name.name, 'Foo');
}
void test_localFunctionDeclarationModifier_abstract() {
parseCompilationUnit("class C { m() { abstract f() {} } }",
- errors: usingFastaParser
- ? [expectedError(ParserErrorCode.EXTRANEOUS_MODIFIER, 16, 8)]
- : [
- expectedError(
- ParserErrorCode.LOCAL_FUNCTION_DECLARATION_MODIFIER, 16, 8)
- ]);
+ errors: [expectedError(ParserErrorCode.EXTRANEOUS_MODIFIER, 16, 8)]);
}
void test_localFunctionDeclarationModifier_external() {
parseCompilationUnit("class C { m() { external f() {} } }",
- errors: usingFastaParser
- ? [expectedError(ParserErrorCode.EXTRANEOUS_MODIFIER, 16, 8)]
- : [
- expectedError(
- ParserErrorCode.LOCAL_FUNCTION_DECLARATION_MODIFIER, 16, 8)
- ]);
+ errors: [expectedError(ParserErrorCode.EXTRANEOUS_MODIFIER, 16, 8)]);
}
void test_localFunctionDeclarationModifier_factory() {
parseCompilationUnit("class C { m() { factory f() {} } }",
- errors: usingFastaParser
- ? [expectedError(ParserErrorCode.EXPECTED_TOKEN, 16, 7)]
- : [
- expectedError(
- ParserErrorCode.LOCAL_FUNCTION_DECLARATION_MODIFIER, 16, 7)
- ]);
+ errors: [expectedError(ParserErrorCode.EXPECTED_TOKEN, 16, 7)]);
}
void test_localFunctionDeclarationModifier_static() {
parseCompilationUnit("class C { m() { static f() {} } }",
- errors: usingFastaParser
- ? [expectedError(ParserErrorCode.EXTRANEOUS_MODIFIER, 16, 6)]
- : [
- expectedError(
- ParserErrorCode.LOCAL_FUNCTION_DECLARATION_MODIFIER, 16, 6)
- ]);
+ errors: [expectedError(ParserErrorCode.EXTRANEOUS_MODIFIER, 16, 6)]);
}
void test_method_invalidTypeParameterExtends() {
@@ -4359,19 +3892,11 @@
createParser('f<E>(E extends num p);');
ClassMember member = parser.parseClassMember('C');
expectNotNullIfNoErrors(member);
- listener.assertErrors(usingFastaParser
- ? [expectedError(ParserErrorCode.EXPECTED_TOKEN, 7, 7)]
- : [
- expectedError(ParserErrorCode.MISSING_IDENTIFIER, 0,
- 0), // `extends` is a keyword
- expectedError(ParserErrorCode.EXPECTED_TOKEN, 0, 0), // comma
- expectedError(ParserErrorCode.EXPECTED_TOKEN, 0, 0), // close paren
- expectedError(ParserErrorCode.MISSING_FUNCTION_BODY, 0, 0)
- ]);
+ listener
+ .assertErrors([expectedError(ParserErrorCode.EXPECTED_TOKEN, 7, 7)]);
expect(member, isMethodDeclaration);
MethodDeclaration method = member;
- expect(
- method.parameters.toString(), usingFastaParser ? '(E)' : '(E, extends)',
+ expect(method.parameters.toString(), '(E)',
reason: 'parser recovers what it can');
}
@@ -4379,15 +3904,8 @@
createParser('void m<E, hello!>() {}');
ClassMember member = parser.parseClassMember('C');
expectNotNullIfNoErrors(member);
- listener.assertErrors(usingFastaParser
- ? [expectedError(ParserErrorCode.EXPECTED_TOKEN, 10, 5)]
- : [
- expectedError(ParserErrorCode.EXPECTED_TOKEN, 0, 0) /*>*/,
- expectedError(ParserErrorCode.MISSING_IDENTIFIER, 0, 0),
- expectedError(ParserErrorCode.EXPECTED_TOKEN, 0, 0) /*(*/,
- expectedError(ParserErrorCode.EXPECTED_TOKEN, 0, 0) /*)*/,
- expectedError(ParserErrorCode.MISSING_FUNCTION_BODY, 0, 0)
- ]);
+ listener
+ .assertErrors([expectedError(ParserErrorCode.EXPECTED_TOKEN, 10, 5)]);
expect(member, isMethodDeclaration);
MethodDeclaration method = member;
expect(method.typeParameters.toString(), '<E, hello>',
@@ -4516,16 +4034,14 @@
// to parse it as an expression statement. It isn't clear what the best
// error message is in this case.
parseStatement("int f => x;");
- listener.assertErrors(usingFastaParser
- ? [expectedError(ParserErrorCode.MISSING_FUNCTION_PARAMETERS, 6, 2)]
- : [expectedError(ParserErrorCode.EXPECTED_TOKEN, 0, 3)]);
+ listener.assertErrors(
+ [expectedError(ParserErrorCode.MISSING_FUNCTION_PARAMETERS, 6, 2)]);
}
void test_missingFunctionParameters_local_void_block() {
parseStatement("void f { return x;}", expectedEndOffset: 7);
- listener.assertErrors(usingFastaParser
- ? [expectedError(ParserErrorCode.EXPECTED_TOKEN, 5, 1)]
- : [expectedError(ParserErrorCode.MISSING_FUNCTION_PARAMETERS, 5, 1)]);
+ listener
+ .assertErrors([expectedError(ParserErrorCode.EXPECTED_TOKEN, 5, 1)]);
}
void test_missingFunctionParameters_local_void_expression() {
@@ -4574,16 +4090,10 @@
createParser('int}', expectedEndOffset: 3);
ClassMember member = parser.parseClassMember('C');
expectNotNullIfNoErrors(member);
- listener.assertErrors(usingFastaParser
- ? [
- expectedError(
- ParserErrorCode.MISSING_CONST_FINAL_VAR_OR_TYPE, 0, 3),
- expectedError(ParserErrorCode.EXPECTED_TOKEN, 0, 3)
- ]
- : [
- expectedError(ParserErrorCode.MISSING_IDENTIFIER, 3, 1),
- expectedError(ParserErrorCode.EXPECTED_TOKEN, 4, 1)
- ]);
+ listener.assertErrors([
+ expectedError(ParserErrorCode.MISSING_CONST_FINAL_VAR_OR_TYPE, 0, 3),
+ expectedError(ParserErrorCode.EXPECTED_TOKEN, 0, 3)
+ ]);
}
void test_missingIdentifier_inEnum() {
@@ -4606,15 +4116,8 @@
createParser('(a, [])');
FormalParameterList list = parser.parseFormalParameterList();
expectNotNullIfNoErrors(list);
- if (usingFastaParser) {
- listener.assertErrors(
- [expectedError(ParserErrorCode.MISSING_IDENTIFIER, 5, 1)]);
- } else {
- listener.assertErrors([
- expectedError(ParserErrorCode.MISSING_IDENTIFIER, 5, 1),
- expectedError(ParserErrorCode.EXPECTED_TOKEN, 5, 1)
- ]);
- }
+ listener.assertErrors(
+ [expectedError(ParserErrorCode.MISSING_IDENTIFIER, 5, 1)]);
}
void test_missingIdentifier_inSymbol_afterPeriod() {
@@ -4675,10 +4178,8 @@
createParser('void m {} }', expectedEndOffset: 10);
ClassMember member = parser.parseClassMember('C');
expectNotNullIfNoErrors(member);
- listener.assertErrors([
- expectedError(ParserErrorCode.MISSING_METHOD_PARAMETERS,
- usingFastaParser ? 5 : 7, 1)
- ]);
+ listener.assertErrors(
+ [expectedError(ParserErrorCode.MISSING_METHOD_PARAMETERS, 5, 1)]);
expect(member, isMethodDeclaration);
MethodDeclaration method = member;
expect(method.parameters, hasLength(0));
@@ -4688,10 +4189,8 @@
createParser('void m => null; }', expectedEndOffset: 16);
ClassMember member = parser.parseClassMember('C');
expectNotNullIfNoErrors(member);
- listener.assertErrors([
- expectedError(ParserErrorCode.MISSING_METHOD_PARAMETERS,
- usingFastaParser ? 5 : 7, 1)
- ]);
+ listener.assertErrors(
+ [expectedError(ParserErrorCode.MISSING_METHOD_PARAMETERS, 5, 1)]);
}
void test_missingNameForNamedParameter_colon() {
@@ -4699,16 +4198,10 @@
FormalParameter parameter =
parser.parseFormalParameterList(inFunctionType: true).parameters[0];
expectNotNullIfNoErrors(parameter);
- listener.assertErrors(usingFastaParser
- ? [
- expectedError(ParserErrorCode.MISSING_IDENTIFIER, 6, 1),
- expectedError(ParserErrorCode.DEFAULT_VALUE_IN_FUNCTION_TYPE, 6, 1)
- ]
- : [
- expectedError(ParserErrorCode.DEFAULT_VALUE_IN_FUNCTION_TYPE, 8, 1),
- expectedError(
- ParserErrorCode.MISSING_NAME_FOR_NAMED_PARAMETER, 7, 1)
- ]);
+ listener.assertErrors([
+ expectedError(ParserErrorCode.MISSING_IDENTIFIER, 6, 1),
+ expectedError(ParserErrorCode.DEFAULT_VALUE_IN_FUNCTION_TYPE, 6, 1)
+ ]);
expect(parameter.identifier, isNotNull);
}
@@ -4717,16 +4210,10 @@
FormalParameter parameter =
parser.parseFormalParameterList(inFunctionType: true).parameters[0];
expectNotNullIfNoErrors(parameter);
- listener.assertErrors(usingFastaParser
- ? [
- expectedError(ParserErrorCode.MISSING_IDENTIFIER, 6, 1),
- expectedError(ParserErrorCode.DEFAULT_VALUE_IN_FUNCTION_TYPE, 6, 1)
- ]
- : [
- expectedError(ParserErrorCode.DEFAULT_VALUE_IN_FUNCTION_TYPE, 8, 1),
- expectedError(
- ParserErrorCode.MISSING_NAME_FOR_NAMED_PARAMETER, 7, 1)
- ]);
+ listener.assertErrors([
+ expectedError(ParserErrorCode.MISSING_IDENTIFIER, 6, 1),
+ expectedError(ParserErrorCode.DEFAULT_VALUE_IN_FUNCTION_TYPE, 6, 1)
+ ]);
expect(parameter.identifier, isNotNull);
}
@@ -4735,36 +4222,20 @@
FormalParameter parameter =
parser.parseFormalParameterList(inFunctionType: true).parameters[0];
expectNotNullIfNoErrors(parameter);
- listener.assertErrors(usingFastaParser
- ? [expectedError(ParserErrorCode.MISSING_IDENTIFIER, 5, 1)]
- : [
- expectedError(
- ParserErrorCode.MISSING_NAME_FOR_NAMED_PARAMETER, 5, 1)
- ]);
+ listener.assertErrors(
+ [expectedError(ParserErrorCode.MISSING_IDENTIFIER, 5, 1)]);
expect(parameter.identifier, isNotNull);
}
void test_missingNameInLibraryDirective() {
- CompilationUnit unit = parseCompilationUnit("library;", errors: [
- expectedError(
- usingFastaParser
- ? ParserErrorCode.MISSING_IDENTIFIER
- : ParserErrorCode.MISSING_NAME_IN_LIBRARY_DIRECTIVE,
- 7,
- 1)
- ]);
+ CompilationUnit unit = parseCompilationUnit("library;",
+ errors: [expectedError(ParserErrorCode.MISSING_IDENTIFIER, 7, 1)]);
expect(unit, isNotNull);
}
void test_missingNameInPartOfDirective() {
- CompilationUnit unit = parseCompilationUnit("part of;", errors: [
- expectedError(
- usingFastaParser
- ? ParserErrorCode.EXPECTED_STRING_LITERAL
- : ParserErrorCode.MISSING_NAME_IN_PART_OF_DIRECTIVE,
- 7,
- 1)
- ]);
+ CompilationUnit unit = parseCompilationUnit("part of;",
+ errors: [expectedError(ParserErrorCode.EXPECTED_STRING_LITERAL, 7, 1)]);
expect(unit, isNotNull);
}
@@ -4784,20 +4255,17 @@
void test_missingStatement() {
parseStatement("is");
- listener.assertErrors(usingFastaParser
- ? [
- expectedError(ParserErrorCode.MISSING_IDENTIFIER, 0, 2),
- expectedError(ParserErrorCode.EXPECTED_TYPE_NAME, 2, 0),
- expectedError(ParserErrorCode.EXPECTED_TOKEN, 2, 0)
- ]
- : [expectedError(ParserErrorCode.MISSING_STATEMENT, 2, 0)]);
+ listener.assertErrors([
+ expectedError(ParserErrorCode.MISSING_IDENTIFIER, 0, 2),
+ expectedError(ParserErrorCode.EXPECTED_TYPE_NAME, 2, 0),
+ expectedError(ParserErrorCode.EXPECTED_TOKEN, 2, 0)
+ ]);
}
void test_missingStatement_afterVoid() {
parseStatement("void;");
- listener.assertErrors(usingFastaParser
- ? [expectedError(ParserErrorCode.MISSING_IDENTIFIER, 4, 1)]
- : [expectedError(ParserErrorCode.MISSING_STATEMENT, 4, 1)]);
+ listener.assertErrors(
+ [expectedError(ParserErrorCode.MISSING_IDENTIFIER, 4, 1)]);
}
void test_missingTerminatorForParameterGroup_named() {
@@ -4837,27 +4305,24 @@
void test_missingVariableInForEach() {
Statement statement = parseStatement('for (a < b in foo) {}');
expectNotNullIfNoErrors(statement);
- listener.assertErrors(usingFastaParser
- ? [expectedError(ParserErrorCode.UNEXPECTED_TOKEN, 7, 1)]
- : [expectedError(ParserErrorCode.MISSING_VARIABLE_IN_FOR_EACH, 5, 5)]);
+ listener
+ .assertErrors([expectedError(ParserErrorCode.UNEXPECTED_TOKEN, 7, 1)]);
}
void test_mixedParameterGroups_namedPositional() {
createParser('(a, {b}, [c])');
FormalParameterList list = parser.parseFormalParameterList();
expectNotNullIfNoErrors(list);
- listener.assertErrors(usingFastaParser
- ? [expectedError(ParserErrorCode.EXPECTED_TOKEN, 7, 1)]
- : [expectedError(ParserErrorCode.MIXED_PARAMETER_GROUPS, 9, 3)]);
+ listener
+ .assertErrors([expectedError(ParserErrorCode.EXPECTED_TOKEN, 7, 1)]);
}
void test_mixedParameterGroups_positionalNamed() {
createParser('(a, [b], {c})');
FormalParameterList list = parser.parseFormalParameterList();
expectNotNullIfNoErrors(list);
- listener.assertErrors(usingFastaParser
- ? [expectedError(ParserErrorCode.EXPECTED_TOKEN, 7, 1)]
- : [expectedError(ParserErrorCode.MIXED_PARAMETER_GROUPS, 9, 3)]);
+ listener
+ .assertErrors([expectedError(ParserErrorCode.EXPECTED_TOKEN, 7, 1)]);
}
void test_mixin_application_lacks_with_clause() {
@@ -4887,11 +4352,8 @@
createParser('(a, {b}, {c})');
FormalParameterList list = parser.parseFormalParameterList();
expectNotNullIfNoErrors(list);
- listener.assertErrors(usingFastaParser
- ? [expectedError(ParserErrorCode.EXPECTED_TOKEN, 7, 1)]
- : [
- expectedError(ParserErrorCode.MULTIPLE_NAMED_PARAMETER_GROUPS, 9, 3)
- ]);
+ listener
+ .assertErrors([expectedError(ParserErrorCode.EXPECTED_TOKEN, 7, 1)]);
}
void test_multiplePartOfDirectives() {
@@ -4904,22 +4366,15 @@
createParser('(a, [b], [c])');
FormalParameterList list = parser.parseFormalParameterList();
expectNotNullIfNoErrors(list);
- listener.assertErrors(usingFastaParser
- ? [expectedError(ParserErrorCode.EXPECTED_TOKEN, 7, 1)]
- : [
- expectedError(
- ParserErrorCode.MULTIPLE_POSITIONAL_PARAMETER_GROUPS, 9, 3)
- ]);
+ listener
+ .assertErrors([expectedError(ParserErrorCode.EXPECTED_TOKEN, 7, 1)]);
}
void test_multipleVariablesInForEach() {
Statement statement = parseStatement('for (int a, b in foo) {}');
expectNotNullIfNoErrors(statement);
- listener.assertErrors(usingFastaParser
- ? [expectedError(ParserErrorCode.UNEXPECTED_TOKEN, 10, 1)]
- : [
- expectedError(ParserErrorCode.MULTIPLE_VARIABLES_IN_FOR_EACH, 12, 1)
- ]);
+ listener
+ .assertErrors([expectedError(ParserErrorCode.UNEXPECTED_TOKEN, 10, 1)]);
}
void test_multipleWithClauses() {
@@ -4929,20 +4384,11 @@
void test_namedFunctionExpression() {
Expression expression;
- if (usingFastaParser) {
- createParser('f() {}');
- expression = parser.parsePrimaryExpression();
- listener.assertErrors(
- [expectedError(ParserErrorCode.NAMED_FUNCTION_EXPRESSION, 0, 1)]);
- expect(expression, isFunctionExpression);
- } else {
- expression = parsePrimaryExpression('f() {}');
- expectNotNullIfNoErrors(expression);
- // Should generate an error.
- //listener.assertErrors(
- // [expectedError(ParserErrorCode.NAMED_FUNCTION_EXPRESSION, 0, 1)]);
- //expect(expression, isFunctionExpression);
- }
+ createParser('f() {}');
+ expression = parser.parsePrimaryExpression();
+ listener.assertErrors(
+ [expectedError(ParserErrorCode.NAMED_FUNCTION_EXPRESSION, 0, 1)]);
+ expect(expression, isFunctionExpression);
}
void test_namedParameterOutsideGroup() {
@@ -4959,49 +4405,35 @@
createParser('factory int x;', expectedEndOffset: 12);
ClassMember member = parser.parseClassMember('C');
expectNotNullIfNoErrors(member);
- listener.assertErrors(usingFastaParser
- ? [
- expectedError(ParserErrorCode.MISSING_FUNCTION_PARAMETERS, 12, 1),
- expectedError(ParserErrorCode.MISSING_FUNCTION_BODY, 12, 1)
- ]
- : [expectedError(ParserErrorCode.NON_CONSTRUCTOR_FACTORY, 0, 7)]);
+ listener.assertErrors([
+ expectedError(ParserErrorCode.MISSING_FUNCTION_PARAMETERS, 12, 1),
+ expectedError(ParserErrorCode.MISSING_FUNCTION_BODY, 12, 1)
+ ]);
}
void test_nonConstructorFactory_method() {
createParser('factory int m() {}', expectedEndOffset: 12);
ClassMember member = parser.parseClassMember('C');
expectNotNullIfNoErrors(member);
- listener.assertErrors(usingFastaParser
- ? [
- expectedError(ParserErrorCode.MISSING_FUNCTION_PARAMETERS, 12, 1),
- expectedError(ParserErrorCode.MISSING_FUNCTION_BODY, 12, 1)
- ]
- : [expectedError(ParserErrorCode.NON_CONSTRUCTOR_FACTORY, 0, 7)]);
+ listener.assertErrors([
+ expectedError(ParserErrorCode.MISSING_FUNCTION_PARAMETERS, 12, 1),
+ expectedError(ParserErrorCode.MISSING_FUNCTION_BODY, 12, 1)
+ ]);
}
void test_nonIdentifierLibraryName_library() {
- CompilationUnit unit = parseCompilationUnit("library 'lib';", errors: [
- usingFastaParser
- ? expectedError(ParserErrorCode.MISSING_IDENTIFIER, 8, 5)
- : expectedError(ParserErrorCode.NON_IDENTIFIER_LIBRARY_NAME, 8, 5)
- ]);
+ CompilationUnit unit = parseCompilationUnit("library 'lib';",
+ errors: [expectedError(ParserErrorCode.MISSING_IDENTIFIER, 8, 5)]);
expect(unit, isNotNull);
}
void test_nonIdentifierLibraryName_partOf() {
- CompilationUnit unit = parseCompilationUnit("part of 3;",
- errors: usingFastaParser
- ? [
- expectedError(ParserErrorCode.EXPECTED_STRING_LITERAL, 8, 1),
- expectedError(ParserErrorCode.EXPECTED_TOKEN, 8, 1),
- expectedError(ParserErrorCode.EXPECTED_EXECUTABLE, 8, 1),
- expectedError(ParserErrorCode.UNEXPECTED_TOKEN, 9, 1)
- ]
- : [
- expectedError(
- ParserErrorCode.MISSING_NAME_IN_PART_OF_DIRECTIVE, 8, 1),
- expectedError(ParserErrorCode.UNEXPECTED_TOKEN, 8, 1)
- ]);
+ CompilationUnit unit = parseCompilationUnit("part of 3;", errors: [
+ expectedError(ParserErrorCode.EXPECTED_STRING_LITERAL, 8, 1),
+ expectedError(ParserErrorCode.EXPECTED_TOKEN, 8, 1),
+ expectedError(ParserErrorCode.EXPECTED_EXECUTABLE, 8, 1),
+ expectedError(ParserErrorCode.UNEXPECTED_TOKEN, 9, 1)
+ ]);
expect(unit, isNotNull);
}
@@ -5024,34 +4456,18 @@
createParser('operator +=(int x) => x + 1;');
ClassMember member = parser.parseClassMember('C');
expectNotNullIfNoErrors(member);
- listener.assertErrors([
- expectedError(
- usingFastaParser
- ? ParserErrorCode.INVALID_OPERATOR
- : ParserErrorCode.NON_USER_DEFINABLE_OPERATOR,
- 9,
- 2)
- ]);
+ listener
+ .assertErrors([expectedError(ParserErrorCode.INVALID_OPERATOR, 9, 2)]);
}
void test_optionalAfterNormalParameters_named() {
parseCompilationUnit("f({a}, b) {}",
- errors: usingFastaParser
- ? [expectedError(ParserErrorCode.EXPECTED_TOKEN, 5, 1)]
- : [
- expectedError(
- ParserErrorCode.NORMAL_BEFORE_OPTIONAL_PARAMETERS, 7, 1)
- ]);
+ errors: [expectedError(ParserErrorCode.EXPECTED_TOKEN, 5, 1)]);
}
void test_optionalAfterNormalParameters_positional() {
parseCompilationUnit("f([a], b) {}",
- errors: usingFastaParser
- ? [expectedError(ParserErrorCode.EXPECTED_TOKEN, 5, 1)]
- : [
- expectedError(
- ParserErrorCode.NORMAL_BEFORE_OPTIONAL_PARAMETERS, 7, 1)
- ]);
+ errors: [expectedError(ParserErrorCode.EXPECTED_TOKEN, 5, 1)]);
}
void test_parseCascadeSection_missingIdentifier() {
@@ -5094,18 +4510,10 @@
createParser('(a, b = 0)');
FormalParameterList list = parser.parseFormalParameterList();
expectNotNullIfNoErrors(list);
- listener.assertErrors(usingFastaParser
- ? [expectedError(ParserErrorCode.NAMED_PARAMETER_OUTSIDE_GROUP, 6, 1)]
- : [
- expectedError(
- ParserErrorCode.POSITIONAL_PARAMETER_OUTSIDE_GROUP, 4, 1)
- ]);
+ listener.assertErrors(
+ [expectedError(ParserErrorCode.NAMED_PARAMETER_OUTSIDE_GROUP, 6, 1)]);
expect(list.parameters[0].isRequired, isTrue);
- if (usingFastaParser) {
- expect(list.parameters[1].isNamed, isTrue);
- } else {
- expect(list.parameters[1].isOptionalPositional, isTrue);
- }
+ expect(list.parameters[1].isNamed, isTrue);
}
void test_redirectingConstructorWithBody_named() {
@@ -5113,8 +4521,7 @@
ClassMember member = parser.parseClassMember('C');
expectNotNullIfNoErrors(member);
listener.assertErrors([
- expectedError(ParserErrorCode.REDIRECTING_CONSTRUCTOR_WITH_BODY, 15,
- usingFastaParser ? 1 : 2)
+ expectedError(ParserErrorCode.REDIRECTING_CONSTRUCTOR_WITH_BODY, 15, 1)
]);
}
@@ -5123,8 +4530,7 @@
ClassMember member = parser.parseClassMember('C');
expectNotNullIfNoErrors(member);
listener.assertErrors([
- expectedError(ParserErrorCode.REDIRECTING_CONSTRUCTOR_WITH_BODY, 15,
- usingFastaParser ? 1 : 2)
+ expectedError(ParserErrorCode.REDIRECTING_CONSTRUCTOR_WITH_BODY, 15, 1)
]);
}
@@ -5140,16 +4546,14 @@
void test_setterInFunction_block() {
parseStatement("set x(v) {_x = v;}");
- listener.assertErrors(usingFastaParser
- ? [expectedError(ParserErrorCode.UNEXPECTED_TOKEN, 0, 3)]
- : [expectedError(ParserErrorCode.SETTER_IN_FUNCTION, 0, 3)]);
+ listener
+ .assertErrors([expectedError(ParserErrorCode.UNEXPECTED_TOKEN, 0, 3)]);
}
void test_setterInFunction_expression() {
parseStatement("set x(v) => _x = v;");
- listener.assertErrors(usingFastaParser
- ? [expectedError(ParserErrorCode.UNEXPECTED_TOKEN, 0, 3)]
- : [expectedError(ParserErrorCode.SETTER_IN_FUNCTION, 0, 3)]);
+ listener
+ .assertErrors([expectedError(ParserErrorCode.UNEXPECTED_TOKEN, 0, 3)]);
}
void test_staticAfterConst() {
@@ -5164,14 +4568,10 @@
createParser('const static int f;');
ClassMember member = parser.parseClassMember('C');
expectNotNullIfNoErrors(member);
- if (usingFastaParser) {
- listener.assertErrors([
- expectedError(ParserErrorCode.MODIFIER_OUT_OF_ORDER, 6, 6),
- expectedError(CompileTimeErrorCode.CONST_NOT_INITIALIZED, 17, 1)
- ]);
- } else {
- listener.assertErrorsWithCodes([ParserErrorCode.MODIFIER_OUT_OF_ORDER]);
- }
+ listener.assertErrors([
+ expectedError(ParserErrorCode.MODIFIER_OUT_OF_ORDER, 6, 6),
+ expectedError(CompileTimeErrorCode.CONST_NOT_INITIALIZED, 17, 1)
+ ]);
}
void test_staticAfterVar() {
@@ -5194,14 +4594,8 @@
createParser('static get m;');
ClassMember member = parser.parseClassMember('C');
expectNotNullIfNoErrors(member);
- listener.assertErrors([
- expectedError(
- usingFastaParser
- ? ParserErrorCode.MISSING_FUNCTION_BODY
- : ParserErrorCode.STATIC_GETTER_WITHOUT_BODY,
- 12,
- 1)
- ]);
+ listener.assertErrors(
+ [expectedError(ParserErrorCode.MISSING_FUNCTION_BODY, 12, 1)]);
}
void test_staticOperator_noReturnType() {
@@ -5224,14 +4618,8 @@
createParser('static set m(x);');
ClassMember member = parser.parseClassMember('C');
expectNotNullIfNoErrors(member);
- listener.assertErrors([
- expectedError(
- usingFastaParser
- ? ParserErrorCode.MISSING_FUNCTION_BODY
- : ParserErrorCode.STATIC_SETTER_WITHOUT_BODY,
- 15,
- 1)
- ]);
+ listener.assertErrors(
+ [expectedError(ParserErrorCode.MISSING_FUNCTION_BODY, 15, 1)]);
}
void test_staticTopLevelDeclaration_class() {
@@ -5269,29 +4657,15 @@
m() {
{
'${${
-''',
- codes: usingFastaParser
- ? [
- ScannerErrorCode.UNTERMINATED_STRING_LITERAL,
- ScannerErrorCode.EXPECTED_TOKEN,
- ScannerErrorCode.EXPECTED_TOKEN,
- ScannerErrorCode.EXPECTED_TOKEN,
- ScannerErrorCode.EXPECTED_TOKEN,
- ParserErrorCode.EXPECTED_TOKEN,
- ParserErrorCode.EXPECTED_TOKEN
- ]
- : [
- ScannerErrorCode.UNTERMINATED_STRING_LITERAL,
- ScannerErrorCode.EXPECTED_TOKEN,
- ScannerErrorCode.EXPECTED_TOKEN,
- ScannerErrorCode.EXPECTED_TOKEN,
- ScannerErrorCode.EXPECTED_TOKEN,
- ParserErrorCode.EXPECTED_TOKEN,
- ParserErrorCode.EXPECTED_TOKEN,
- ParserErrorCode.EXPECTED_TOKEN,
- ParserErrorCode.UNEXPECTED_TOKEN,
- ParserErrorCode.EXPECTED_EXECUTABLE,
- ]);
+''', codes: [
+ ScannerErrorCode.UNTERMINATED_STRING_LITERAL,
+ ScannerErrorCode.EXPECTED_TOKEN,
+ ScannerErrorCode.EXPECTED_TOKEN,
+ ScannerErrorCode.EXPECTED_TOKEN,
+ ScannerErrorCode.EXPECTED_TOKEN,
+ ParserErrorCode.EXPECTED_TOKEN,
+ ParserErrorCode.EXPECTED_TOKEN
+ ]);
}
void test_switchCase_missingColon() {
@@ -5351,13 +4725,7 @@
SwitchStatement statement =
parseStatement('switch (a) return;', expectedEndOffset: 11);
expect(statement, isNotNull);
- listener.assertErrors(usingFastaParser
- ? [expectedError(ParserErrorCode.EXPECTED_BODY, 9, 1)]
- : [
- expectedError(ParserErrorCode.EXPECTED_TOKEN, 11, 6),
- expectedError(ParserErrorCode.EXPECTED_CASE_OR_DEFAULT, 11, 6),
- expectedError(ParserErrorCode.EXPECTED_TOKEN, 11, 6)
- ]);
+ listener.assertErrors([expectedError(ParserErrorCode.EXPECTED_BODY, 9, 1)]);
}
void test_topLevel_getter() {
@@ -5378,20 +4746,15 @@
void test_topLevelOperator_withFunction() {
parseCompilationUnit('operator Function() x = null;',
- errors: usingFastaParser
- ? [expectedError(ParserErrorCode.TOP_LEVEL_OPERATOR, 0, 8)]
- : [
- // Should be generating an error here.
- ]);
+ errors: [expectedError(ParserErrorCode.TOP_LEVEL_OPERATOR, 0, 8)]);
}
void test_topLevelOperator_withoutOperator() {
createParser('+(bool x, bool y) => x | y;');
CompilationUnitMember member = parseFullCompilationUnitMember();
expectNotNullIfNoErrors(member);
- listener.assertErrors(usingFastaParser
- ? [expectedError(ParserErrorCode.TOP_LEVEL_OPERATOR, 0, 1)]
- : [expectedError(ParserErrorCode.EXPECTED_EXECUTABLE, 0, 1)]);
+ listener.assertErrors(
+ [expectedError(ParserErrorCode.TOP_LEVEL_OPERATOR, 0, 1)]);
}
void test_topLevelOperator_withoutType() {
@@ -5410,18 +4773,11 @@
}
void test_topLevelVariable_withMetadata() {
- parseCompilationUnit("String @A string;",
- codes: usingFastaParser
- ? [
- ParserErrorCode.MISSING_CONST_FINAL_VAR_OR_TYPE,
- ParserErrorCode.EXPECTED_TOKEN,
- ParserErrorCode.MISSING_CONST_FINAL_VAR_OR_TYPE
- ]
- : [
- ParserErrorCode.MISSING_IDENTIFIER,
- ParserErrorCode.EXPECTED_TOKEN,
- ParserErrorCode.MISSING_CONST_FINAL_VAR_OR_TYPE
- ]);
+ parseCompilationUnit("String @A string;", codes: [
+ ParserErrorCode.MISSING_CONST_FINAL_VAR_OR_TYPE,
+ ParserErrorCode.EXPECTED_TOKEN,
+ ParserErrorCode.MISSING_CONST_FINAL_VAR_OR_TYPE
+ ]);
}
void test_typedef_incomplete() {
@@ -5435,29 +4791,15 @@
main() {
Function<
}
-''',
- errors: usingFastaParser
- ? [
- expectedError(ParserErrorCode.EXPECTED_TOKEN, 49, 1),
- expectedError(ParserErrorCode.EXPECTED_EXECUTABLE, 51, 1),
- ]
- : [
- expectedError(ParserErrorCode.EXPECTED_TOKEN, 51, 1),
- expectedError(ParserErrorCode.UNEXPECTED_TOKEN, 51, 1),
- expectedError(ParserErrorCode.EXPECTED_EXECUTABLE, 55, 8)
- ]);
+''', errors: [
+ expectedError(ParserErrorCode.EXPECTED_TOKEN, 49, 1),
+ expectedError(ParserErrorCode.EXPECTED_EXECUTABLE, 51, 1),
+ ]);
}
void test_typedef_namedFunction() {
parseCompilationUnit('typedef void Function();',
- codes: usingFastaParser
- ? [ParserErrorCode.EXPECTED_IDENTIFIER_BUT_GOT_KEYWORD]
- : [
- ParserErrorCode.UNEXPECTED_TOKEN,
- ParserErrorCode.MISSING_IDENTIFIER,
- ParserErrorCode.EXPECTED_EXECUTABLE,
- ParserErrorCode.MISSING_TYPEDEF_PARAMETERS
- ]);
+ codes: [ParserErrorCode.EXPECTED_IDENTIFIER_BUT_GOT_KEYWORD]);
}
void test_typedefInClass_withoutReturnType() {
@@ -5473,48 +4815,32 @@
void test_unexpectedCommaThenInterpolation() {
// https://github.com/Dart-Code/Dart-Code/issues/1548
parseCompilationUnit(r"main() { String s = 'a' 'b', 'c$foo'; return s; }",
- errors: usingFastaParser
- ? [
- expectedError(ParserErrorCode.MISSING_IDENTIFIER, 29, 2),
- expectedError(ParserErrorCode.EXPECTED_TOKEN, 29, 2),
- ]
- : [
- expectedError(ParserErrorCode.MISSING_IDENTIFIER, 29, 2),
- expectedError(ParserErrorCode.EXPECTED_TOKEN, 29, 1),
- ]);
+ errors: [
+ expectedError(ParserErrorCode.MISSING_IDENTIFIER, 29, 2),
+ expectedError(ParserErrorCode.EXPECTED_TOKEN, 29, 2),
+ ]);
}
void test_unexpectedTerminatorForParameterGroup_named() {
createParser('(a, b})');
FormalParameterList list = parser.parseFormalParameterList();
expectNotNullIfNoErrors(list);
- listener.assertErrors([
- expectedError(
- usingFastaParser
- ? ParserErrorCode.EXPECTED_TOKEN
- : ParserErrorCode.UNEXPECTED_TERMINATOR_FOR_PARAMETER_GROUP,
- 5,
- 1)
- ]);
+ listener
+ .assertErrors([expectedError(ParserErrorCode.EXPECTED_TOKEN, 5, 1)]);
}
void test_unexpectedTerminatorForParameterGroup_optional() {
createParser('(a, b])');
FormalParameterList list = parser.parseFormalParameterList();
expectNotNullIfNoErrors(list);
- listener.assertErrors(usingFastaParser
- ? [expectedError(ParserErrorCode.EXPECTED_TOKEN, 5, 1)]
- : [
- expectedError(
- ParserErrorCode.UNEXPECTED_TERMINATOR_FOR_PARAMETER_GROUP, 5, 1)
- ]);
+ listener
+ .assertErrors([expectedError(ParserErrorCode.EXPECTED_TOKEN, 5, 1)]);
}
void test_unexpectedToken_endOfFieldDeclarationStatement() {
parseStatement("String s = (null));", expectedEndOffset: 17);
- listener.assertErrors(usingFastaParser
- ? [expectedError(ParserErrorCode.EXPECTED_TOKEN, 16, 1)]
- : [expectedError(ParserErrorCode.UNEXPECTED_TOKEN, 17, 1)]);
+ listener
+ .assertErrors([expectedError(ParserErrorCode.EXPECTED_TOKEN, 16, 1)]);
}
void test_unexpectedToken_invalidPostfixExpression() {
@@ -5538,14 +4864,8 @@
createParser('class C { int x; ; int y;}');
ClassDeclaration declaration = parseFullCompilationUnitMember();
expectNotNullIfNoErrors(declaration);
- listener.assertErrors([
- expectedError(
- usingFastaParser
- ? ParserErrorCode.EXPECTED_CLASS_MEMBER
- : ParserErrorCode.UNEXPECTED_TOKEN,
- 17,
- 1)
- ]);
+ listener.assertErrors(
+ [expectedError(ParserErrorCode.EXPECTED_CLASS_MEMBER, 17, 1)]);
}
void test_unexpectedToken_semicolonBetweenCompilationUnitMembers() {
@@ -5640,16 +4960,11 @@
expectNotNullIfNoErrors(expression);
listener.assertErrors(
[expectedError(ParserErrorCode.MISSING_IDENTIFIER, 0, 1)]);
- if (usingFastaParser) {
- BinaryExpression binaryExpression = expression;
- expect(binaryExpression.leftOperand.isSynthetic, isTrue);
- expect(binaryExpression.rightOperand.isSynthetic, isFalse);
- SimpleIdentifier identifier = binaryExpression.rightOperand;
- expect(identifier.name, 'x');
- } else {
- var identifier = expression as SimpleIdentifier;
- expect(identifier.isSynthetic, isTrue);
- }
+ BinaryExpression binaryExpression = expression;
+ expect(binaryExpression.leftOperand.isSynthetic, isTrue);
+ expect(binaryExpression.rightOperand.isSynthetic, isFalse);
+ SimpleIdentifier identifier = binaryExpression.rightOperand;
+ expect(identifier.name, 'x');
}
void test_varAndType_field() {
@@ -5661,9 +4976,7 @@
// This is currently reporting EXPECTED_TOKEN for a missing semicolon, but
// this would be a better error message.
parseStatement("var int x;");
- listener.assertErrors(usingFastaParser
- ? [expectedError(ParserErrorCode.VAR_AND_TYPE, 0, 3)]
- : [expectedError(ParserErrorCode.UNEXPECTED_TOKEN, 8, 1)]);
+ listener.assertErrors([expectedError(ParserErrorCode.VAR_AND_TYPE, 0, 3)]);
}
void test_varAndType_parameter() {
@@ -5672,9 +4985,7 @@
createParser('(var int x)');
FormalParameterList list = parser.parseFormalParameterList();
expectNotNullIfNoErrors(list);
- listener.assertErrors(usingFastaParser
- ? [expectedError(ParserErrorCode.VAR_AND_TYPE, 1, 3)]
- : [expectedError(ParserErrorCode.EXPECTED_TOKEN, 9, 1)]);
+ listener.assertErrors([expectedError(ParserErrorCode.VAR_AND_TYPE, 1, 3)]);
}
void test_varAndType_topLevelVariable() {
@@ -5685,33 +4996,25 @@
void test_varAsTypeName_as() {
parseExpression("x as var",
expectedEndOffset: 5,
- errors: usingFastaParser
- ? [expectedError(ParserErrorCode.EXPECTED_TYPE_NAME, 5, 3)]
- : [expectedError(ParserErrorCode.VAR_AS_TYPE_NAME, 7, 3)]);
+ errors: [expectedError(ParserErrorCode.EXPECTED_TYPE_NAME, 5, 3)]);
}
void test_varClass() {
- parseCompilationUnit("var class C {}",
- errors: usingFastaParser
- ? [
- // Fasta interprets the `var` as a malformed top level var
- // and `class` as the start of a class declaration.
- expectedError(ParserErrorCode.MISSING_IDENTIFIER, 4, 5),
- expectedError(ParserErrorCode.EXPECTED_TOKEN, 4, 5),
- ]
- : [expectedError(ParserErrorCode.VAR_CLASS, 0, 3)]);
+ parseCompilationUnit("var class C {}", errors: [
+ // Fasta interprets the `var` as a malformed top level var
+ // and `class` as the start of a class declaration.
+ expectedError(ParserErrorCode.MISSING_IDENTIFIER, 4, 5),
+ expectedError(ParserErrorCode.EXPECTED_TOKEN, 4, 5),
+ ]);
}
void test_varEnum() {
- parseCompilationUnit("var enum E {ONE}",
- errors: usingFastaParser
- ? [
- // Fasta interprets the `var` as a malformed top level var
- // and `enum` as the start of an enum declaration.
- expectedError(ParserErrorCode.MISSING_IDENTIFIER, 4, 4),
- expectedError(ParserErrorCode.EXPECTED_TOKEN, 4, 4),
- ]
- : [expectedError(ParserErrorCode.VAR_ENUM, 0, 3)]);
+ parseCompilationUnit("var enum E {ONE}", errors: [
+ // Fasta interprets the `var` as a malformed top level var
+ // and `enum` as the start of an enum declaration.
+ expectedError(ParserErrorCode.MISSING_IDENTIFIER, 4, 4),
+ expectedError(ParserErrorCode.EXPECTED_TOKEN, 4, 4),
+ ]);
}
void test_varReturnType() {
@@ -5723,15 +5026,12 @@
}
void test_varTypedef() {
- parseCompilationUnit("var typedef F();",
- errors: usingFastaParser
- ? [
- // Fasta interprets the `var` as a malformed top level var
- // and `typedef` as the start of an typedef declaration.
- expectedError(ParserErrorCode.MISSING_IDENTIFIER, 4, 7),
- expectedError(ParserErrorCode.EXPECTED_TOKEN, 4, 7),
- ]
- : [expectedError(ParserErrorCode.VAR_TYPEDEF, 0, 3)]);
+ parseCompilationUnit("var typedef F();", errors: [
+ // Fasta interprets the `var` as a malformed top level var
+ // and `typedef` as the start of an typedef declaration.
+ expectedError(ParserErrorCode.MISSING_IDENTIFIER, 4, 7),
+ expectedError(ParserErrorCode.EXPECTED_TOKEN, 4, 7),
+ ]);
}
void test_voidParameter() {
@@ -5814,18 +5114,10 @@
FormalParameterList list = parser.parseFormalParameterList();
expectNotNullIfNoErrors(list);
// fasta scanner generates '(a, {b, c]})' where '}' is synthetic
- if (usingFastaParser) {
- listener.assertErrors([
- expectedError(ParserErrorCode.EXPECTED_TOKEN, 9, 1),
- expectedError(ScannerErrorCode.EXPECTED_TOKEN, 10, 1)
- ]);
- } else {
- listener.assertErrors([
- expectedError(ScannerErrorCode.EXPECTED_TOKEN, 9, 1),
- expectedError(
- ParserErrorCode.WRONG_TERMINATOR_FOR_PARAMETER_GROUP, 9, 1)
- ]);
- }
+ listener.assertErrors([
+ expectedError(ParserErrorCode.EXPECTED_TOKEN, 9, 1),
+ expectedError(ScannerErrorCode.EXPECTED_TOKEN, 10, 1)
+ ]);
}
void test_wrongTerminatorForParameterGroup_optional() {
@@ -5833,25 +5125,13 @@
FormalParameterList list = parser.parseFormalParameterList();
expectNotNullIfNoErrors(list);
// fasta scanner generates '(a, [b, c}])' where ']' is synthetic
- if (usingFastaParser) {
- listener.assertErrors([
- expectedError(ParserErrorCode.EXPECTED_TOKEN, 9, 1),
- expectedError(ScannerErrorCode.EXPECTED_TOKEN, 10, 1)
- ]);
- } else {
- listener.assertErrors([
- expectedError(ScannerErrorCode.EXPECTED_TOKEN, 4, 1),
- expectedError(
- ParserErrorCode.WRONG_TERMINATOR_FOR_PARAMETER_GROUP, 10, 1)
- ]);
- }
+ listener.assertErrors([
+ expectedError(ParserErrorCode.EXPECTED_TOKEN, 9, 1),
+ expectedError(ScannerErrorCode.EXPECTED_TOKEN, 10, 1)
+ ]);
}
}
-@reflectiveTest
-class ExpressionParserTest extends ParserTestCase
- with ExpressionParserTestMixin {}
-
mixin ExpressionParserTestMixin implements AbstractParserTestCase {
void test_namedArgument() {
var invocation = parseExpression('m(a: 1, b: 2)') as MethodInvocation;
@@ -6467,7 +5747,7 @@
}
void test_parseExpression_assign_compound() {
- if (usingFastaParser && AbstractScanner.LAZY_ASSIGNMENT_ENABLED) {
+ if (AbstractScanner.LAZY_ASSIGNMENT_ENABLED) {
Expression expression = parseExpression('x ||= y');
var assignmentExpression = expression as AssignmentExpression;
expect(assignmentExpression.leftHandSide, isNotNull);
@@ -6487,13 +5767,10 @@
}
void test_parseExpression_constAndTypeParameters() {
- Expression expression = parseExpression('const <E>',
- codes: usingFastaParser
- ? [
- // TODO(danrubel): Improve this error message.
- ParserErrorCode.EXPECTED_TOKEN
- ]
- : [ParserErrorCode.EXPECTED_LIST_OR_MAP_LITERAL]);
+ Expression expression = parseExpression('const <E>', codes: [
+ // TODO(danrubel): Improve this error message.
+ ParserErrorCode.EXPECTED_TOKEN
+ ]);
expect(expression, isNotNull);
}
@@ -6708,37 +5985,19 @@
FunctionExpression expression =
parseFunctionExpression('const <E>(E i) => i++');
expect(expression, isNotNull);
- assertErrorsWithCodes(usingFastaParser
- ? [ParserErrorCode.UNEXPECTED_TOKEN]
- : [
- ParserErrorCode.EXPECTED_TOKEN,
- ParserErrorCode.EXPECTED_TOKEN,
- ParserErrorCode.MISSING_IDENTIFIER,
- ParserErrorCode.FUNCTION_TYPED_PARAMETER_VAR,
- ParserErrorCode.MISSING_CLOSING_PARENTHESIS,
- ]);
+ assertErrorsWithCodes([ParserErrorCode.UNEXPECTED_TOKEN]);
expect(expression.body, isNotNull);
- if (usingFastaParser) {
- expect(expression.typeParameters, isNotNull);
- expect(expression.parameters, isNotNull);
- expect((expression.body as ExpressionFunctionBody).semicolon, isNull);
- }
+ expect(expression.typeParameters, isNotNull);
+ expect(expression.parameters, isNotNull);
+ expect((expression.body as ExpressionFunctionBody).semicolon, isNull);
}
void test_parseFunctionExpression_functionInPlaceOfTypeName() {
Expression expression = parseExpression('<test(' ', (){});>[0, 1, 2]',
- codes: usingFastaParser
- ? [ParserErrorCode.EXPECTED_TOKEN]
- : [
- ParserErrorCode.EXPECTED_TOKEN,
- ParserErrorCode.MISSING_IDENTIFIER,
- ParserErrorCode.EXPECTED_LIST_OR_MAP_LITERAL,
- ]);
+ codes: [ParserErrorCode.EXPECTED_TOKEN]);
expect(expression, isNotNull);
- if (usingFastaParser) {
- ListLiteral literal = expression;
- expect(literal.typeArguments.arguments, hasLength(1));
- }
+ ListLiteral literal = expression;
+ expect(literal.typeArguments.arguments, hasLength(1));
}
void test_parseFunctionExpression_typeParameters() {
@@ -6873,9 +6132,6 @@
}
void test_parseInstanceCreationExpression_type_named_typeArguments_34403() {
- if (!usingFastaParser) {
- return;
- }
InstanceCreationExpressionImpl expression =
parseExpression('new a.b.c<C>()', errors: [
expectedError(
@@ -7491,9 +6747,7 @@
void test_parseRelationalExpression_as_chained() {
AsExpression asExpression = parseExpression('x as Y as Z',
- errors: usingFastaParser
- ? [expectedError(ParserErrorCode.UNEXPECTED_TOKEN, 7, 2)]
- : []);
+ errors: [expectedError(ParserErrorCode.UNEXPECTED_TOKEN, 7, 2)]);
expect(asExpression, isNotNull);
SimpleIdentifier identifier = asExpression.expression;
expect(identifier.name, 'x');
@@ -7566,9 +6820,7 @@
void test_parseRelationalExpression_is_chained() {
IsExpression isExpression = parseExpression('x is Y is! Z',
- errors: usingFastaParser
- ? [expectedError(ParserErrorCode.UNEXPECTED_TOKEN, 7, 2)]
- : []);
+ errors: [expectedError(ParserErrorCode.UNEXPECTED_TOKEN, 7, 2)]);
expect(isExpression, isNotNull);
SimpleIdentifier identifier = isExpression.expression;
expect(identifier.name, 'x');
@@ -8193,11 +7445,6 @@
}
}
-/// Tests of the analyzer parser based on [FormalParameterParserTestMixin].
-@reflectiveTest
-class FormalParameterParserTest extends ParserTestCase
- with FormalParameterParserTestMixin {}
-
/// The class [FormalParameterParserTestMixin] defines parser tests that test
/// the parsing of formal parameters.
mixin FormalParameterParserTestMixin implements AbstractParserTestCase {
@@ -8952,12 +8199,7 @@
void test_parseFormalParameterList_prefixedType_partial() {
FormalParameterList list = parseFormalParameterList('(io.)', errors: [
- expectedError(
- usingFastaParser
- ? ParserErrorCode.EXPECTED_TYPE_NAME
- : ParserErrorCode.MISSING_IDENTIFIER,
- 4,
- 1),
+ expectedError(ParserErrorCode.EXPECTED_TYPE_NAME, 4, 1),
expectedError(ParserErrorCode.MISSING_IDENTIFIER, 4, 1)
]);
expect(list, isNotNull);
@@ -8978,12 +8220,7 @@
void test_parseFormalParameterList_prefixedType_partial2() {
FormalParameterList list = parseFormalParameterList('(io.,a)', errors: [
- expectedError(
- usingFastaParser
- ? ParserErrorCode.EXPECTED_TYPE_NAME
- : ParserErrorCode.MISSING_IDENTIFIER,
- 4,
- 1),
+ expectedError(ParserErrorCode.EXPECTED_TYPE_NAME, 4, 1),
expectedError(ParserErrorCode.MISSING_IDENTIFIER, 4, 1)
]);
expect(list, isNotNull);
@@ -8998,8 +8235,7 @@
void test_parseNormalFormalParameter_field_const_noType() {
NormalFormalParameter parameter = parseNormalFormalParameter('const this.a',
- errorCodes:
- usingFastaParser ? [ParserErrorCode.EXTRANEOUS_MODIFIER] : []);
+ errorCodes: [ParserErrorCode.EXTRANEOUS_MODIFIER]);
expect(parameter, isNotNull);
expect(parameter, isFieldFormalParameter);
FieldFormalParameter fieldParameter = parameter;
@@ -9012,8 +8248,7 @@
void test_parseNormalFormalParameter_field_const_type() {
NormalFormalParameter parameter = parseNormalFormalParameter(
'const A this.a',
- errorCodes:
- usingFastaParser ? [ParserErrorCode.EXTRANEOUS_MODIFIER] : []);
+ errorCodes: [ParserErrorCode.EXTRANEOUS_MODIFIER]);
expect(parameter, isNotNull);
expect(parameter, isFieldFormalParameter);
FieldFormalParameter fieldParameter = parameter;
@@ -9257,8 +8492,7 @@
void test_parseNormalFormalParameter_simple_const_noType() {
NormalFormalParameter parameter = parseNormalFormalParameter('const a',
- errorCodes:
- usingFastaParser ? [ParserErrorCode.EXTRANEOUS_MODIFIER] : []);
+ errorCodes: [ParserErrorCode.EXTRANEOUS_MODIFIER]);
expect(parameter, isNotNull);
expect(parameter, isSimpleFormalParameter);
SimpleFormalParameter simpleParameter = parameter;
@@ -9269,8 +8503,7 @@
void test_parseNormalFormalParameter_simple_const_type() {
NormalFormalParameter parameter = parseNormalFormalParameter('const A a',
- errorCodes:
- usingFastaParser ? [ParserErrorCode.EXTRANEOUS_MODIFIER] : []);
+ errorCodes: [ParserErrorCode.EXTRANEOUS_MODIFIER]);
expect(parameter, isNotNull);
expect(parameter, isSimpleFormalParameter);
SimpleFormalParameter simpleParameter = parameter;
@@ -9377,6 +8610,244 @@
}
}
+/// Proxy implementation of the analyzer parser, implemented in terms of the
+/// Fasta parser.
+///
+/// This allows many of the analyzer parser tests to be run on Fasta, even if
+/// they call into the analyzer parser class directly.
+class ParserProxy extends analyzer.Parser {
+ /// The error listener to which scanner and parser errors will be reported.
+ final GatheringErrorListener errorListener;
+
+ ForwardingTestListener _eventListener;
+
+ final int expectedEndOffset;
+
+ /// Creates a [ParserProxy] which is prepared to begin parsing at the given
+ /// Fasta token.
+ factory ParserProxy(Token firstToken, FeatureSet featureSet,
+ {bool allowNativeClause = false, int expectedEndOffset}) {
+ TestSource source = TestSource();
+ var errorListener = GatheringErrorListener(checkRanges: true);
+ return ParserProxy._(firstToken, source, errorListener, featureSet,
+ allowNativeClause: allowNativeClause,
+ expectedEndOffset: expectedEndOffset);
+ }
+
+ ParserProxy._(Token firstToken, Source source, this.errorListener,
+ FeatureSet featureSet,
+ {bool allowNativeClause = false, this.expectedEndOffset})
+ : super(source, errorListener,
+ featureSet: featureSet, allowNativeClause: allowNativeClause) {
+ _eventListener = ForwardingTestListener(astBuilder);
+ fastaParser.listener = _eventListener;
+ currentToken = firstToken;
+ }
+
+ @override
+ noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
+
+ Annotation parseAnnotation() {
+ return _run('MetadataStar', () {
+ currentToken = fastaParser
+ .parseMetadata(fastaParser.syntheticPreviousToken(currentToken))
+ .next;
+ return astBuilder.pop() as Annotation;
+ });
+ }
+
+ ArgumentList parseArgumentList() {
+ return _run('unspecified', () {
+ currentToken = fastaParser
+ .parseArguments(fastaParser.syntheticPreviousToken(currentToken))
+ .next;
+ var result = astBuilder.pop();
+ return result is MethodInvocation
+ ? result.argumentList
+ : result as ArgumentList;
+ });
+ }
+
+ ClassMember parseClassMember(String className) {
+ return _run('ClassOrMixinBody', () {
+ astBuilder.classDeclaration = astFactory.classDeclaration(
+ null,
+ null,
+ null,
+ Token(Keyword.CLASS, 0),
+ astFactory.simpleIdentifier(
+ fasta.StringToken.fromString(TokenType.IDENTIFIER, className, 6)),
+ null,
+ null,
+ null,
+ null,
+ null /* leftBracket */,
+ <ClassMember>[],
+ null /* rightBracket */,
+ ) as ClassDeclarationImpl;
+ // TODO(danrubel): disambiguate between class and mixin
+ currentToken = fastaParser.parseClassMember(currentToken, className);
+ //currentToken = fastaParser.parseMixinMember(currentToken);
+ ClassDeclaration declaration = astBuilder.classDeclaration;
+ astBuilder.classDeclaration = null;
+ return declaration.members.isNotEmpty ? declaration.members[0] : null;
+ });
+ }
+
+ List<Combinator> parseCombinators() {
+ return _run('Import', () {
+ currentToken = fastaParser
+ .parseCombinatorStar(fastaParser.syntheticPreviousToken(currentToken))
+ .next;
+ return astBuilder.pop() as List<Combinator>;
+ });
+ }
+
+ List<CommentReference> parseCommentReferences(
+ List<DocumentationCommentToken> tokens) {
+ for (int index = 0; index < tokens.length - 1; ++index) {
+ Token next = tokens[index].next;
+ if (next == null) {
+ tokens[index].setNext(tokens[index + 1]);
+ } else {
+ expect(next, tokens[index + 1]);
+ }
+ }
+ expect(tokens[tokens.length - 1].next, isNull);
+ List<CommentReference> references =
+ astBuilder.parseCommentReferences(tokens.first);
+ if (astBuilder.stack.isNotEmpty) {
+ throw 'Expected empty stack, but found:'
+ '\n ${astBuilder.stack.values.join('\n ')}';
+ }
+ return references;
+ }
+
+ @override
+ CompilationUnit parseCompilationUnit2() {
+ var result = super.parseCompilationUnit2();
+ expect(currentToken.isEof, isTrue, reason: currentToken.lexeme);
+ expect(astBuilder.stack, hasLength(0));
+ _eventListener.expectEmpty();
+ return result;
+ }
+
+ @override
+ Configuration parseConfiguration() {
+ return _run('ConditionalUris', () => super.parseConfiguration());
+ }
+
+ @override
+ DottedName parseDottedName() {
+ return _run('unspecified', () => super.parseDottedName());
+ }
+
+ @override
+ Expression parseExpression2() {
+ return _run('unspecified', () => super.parseExpression2());
+ }
+
+ @override
+ FormalParameterList parseFormalParameterList({bool inFunctionType = false}) {
+ return _run('unspecified',
+ () => super.parseFormalParameterList(inFunctionType: inFunctionType));
+ }
+
+ @override
+ FunctionBody parseFunctionBody(
+ bool mayBeEmpty, ParserErrorCode emptyErrorCode, bool inExpression) {
+ Token lastToken;
+ FunctionBody body = _run('unspecified', () {
+ FunctionBody body =
+ super.parseFunctionBody(mayBeEmpty, emptyErrorCode, inExpression);
+ lastToken = currentToken;
+ currentToken = currentToken.next;
+ return body;
+ });
+ if (!inExpression) {
+ if (![';', '}'].contains(lastToken.lexeme)) {
+ fail('Expected ";" or "}", but found: ${lastToken.lexeme}');
+ }
+ }
+ return body;
+ }
+
+ @override
+ Expression parsePrimaryExpression() {
+ return _run('unspecified', () => super.parsePrimaryExpression());
+ }
+
+ @override
+ Statement parseStatement(Token token) {
+ return _run('unspecified', () => super.parseStatement(token));
+ }
+
+ @override
+ Statement parseStatement2() {
+ return _run('unspecified', () => super.parseStatement2());
+ }
+
+ @override
+ AnnotatedNode parseTopLevelDeclaration(bool isDirective) {
+ return _run(
+ 'CompilationUnit', () => super.parseTopLevelDeclaration(isDirective));
+ }
+
+ @override
+ TypeAnnotation parseTypeAnnotation(bool inExpression) {
+ return _run('unspecified', () => super.parseTypeAnnotation(inExpression));
+ }
+
+ @override
+ TypeArgumentList parseTypeArgumentList() {
+ return _run('unspecified', () => super.parseTypeArgumentList());
+ }
+
+ @override
+ TypeName parseTypeName(bool inExpression) {
+ return _run('unspecified', () => super.parseTypeName(inExpression));
+ }
+
+ @override
+ TypeParameter parseTypeParameter() {
+ return _run('unspecified', () => super.parseTypeParameter());
+ }
+
+ @override
+ TypeParameterList parseTypeParameterList() {
+ return _run('unspecified', () => super.parseTypeParameterList());
+ }
+
+ /// Runs the specified function and returns the result. It checks the
+ /// enclosing listener events, that the parse consumed all of the tokens, and
+ /// that the result stack is empty.
+ _run(String enclosingEvent, Function() f) {
+ _eventListener.begin(enclosingEvent);
+
+ // Simulate error handling of parseUnit by skipping error tokens
+ // before parsing and reporting them after parsing is complete.
+ Token errorToken = currentToken;
+ currentToken = fastaParser.skipErrorTokens(currentToken);
+ var result = f();
+ fastaParser.reportAllErrorTokens(errorToken);
+
+ _eventListener.end(enclosingEvent);
+
+ String lexeme = currentToken is ErrorToken
+ ? currentToken.runtimeType.toString()
+ : currentToken.lexeme;
+ if (expectedEndOffset == null) {
+ expect(currentToken.isEof, isTrue, reason: lexeme);
+ } else {
+ expect(currentToken.offset, expectedEndOffset, reason: lexeme);
+ }
+ expect(astBuilder.stack, hasLength(0));
+ expect(astBuilder.directives, hasLength(0));
+ expect(astBuilder.declarations, hasLength(0));
+ return result;
+ }
+}
+
/// Implementation of [AbstractParserTestCase] specialized for testing the
/// analyzer parser.
class ParserTestCase with ParserTestHelpers implements AbstractParserTestCase {
@@ -9408,10 +8879,7 @@
///
/// This field is typically initialized by invoking [createParser].
@override
- Parser parser;
-
- @override
- bool get usingFastaParser => Parser.useFasta;
+ analyzer.Parser parser;
@override
void assertErrorsWithCodes(List<ErrorCode> expectedErrorCodes) {
@@ -9432,13 +8900,15 @@
LanguageVersionToken languageVersion,
FeatureSet featureSet,
}) {
+ featureSet ??= FeatureSet.latestLanguageVersion();
Source source = TestSource();
listener = GatheringErrorListener();
- ScannerResult result = scanString(content, includeComments: true);
+ fasta.ScannerResult result =
+ fasta.scanString(content, includeComments: true);
listener.setLineInfo(source, result.lineStarts);
- parser = Parser(
+ parser = analyzer.Parser(
source,
listener,
featureSet: featureSet,
@@ -9475,36 +8945,23 @@
@override
Expression parseAssignableSelector(String code, bool optional,
{bool allowConditional = true}) {
- if (usingFastaParser) {
- if (optional) {
- if (code.isEmpty) {
- createParser('foo');
- } else {
- createParser('(foo)$code');
- }
+ if (optional) {
+ if (code.isEmpty) {
+ createParser('foo');
} else {
- createParser('foo$code');
+ createParser('(foo)$code');
}
- return parser.parseExpression2();
} else {
- Expression prefix =
- astFactory.simpleIdentifier(StringToken(TokenType.STRING, 'foo', 0));
- createParser(code);
- return parser.parseAssignableSelector(prefix, optional,
- allowConditional: allowConditional);
+ createParser('foo$code');
}
+ return parser.parseExpression2();
}
@override
AwaitExpression parseAwaitExpression(String code) {
- if (usingFastaParser) {
- createParser('() async => $code');
- var function = parser.parseExpression2() as FunctionExpression;
- return (function.body as ExpressionFunctionBody).expression;
- } else {
- createParser(code);
- return parser.parseAwaitExpression();
- }
+ createParser('() async => $code');
+ var function = parser.parseExpression2() as FunctionExpression;
+ return (function.body as ExpressionFunctionBody).expression;
}
@override
@@ -9527,14 +8984,9 @@
@override
Expression parseCascadeSection(String code) {
- if (usingFastaParser) {
- var statement = parseStatement('null$code;') as ExpressionStatement;
- var cascadeExpression = statement.expression as CascadeExpression;
- return cascadeExpression.cascadeSections.first;
- } else {
- createParser(code);
- return parser.parseCascadeSection();
- }
+ var statement = parseStatement('null$code;') as ExpressionStatement;
+ var cascadeExpression = statement.expression as CascadeExpression;
+ return cascadeExpression.cascadeSections.first;
}
@override
@@ -9569,10 +9021,11 @@
Source source = TestSource();
GatheringErrorListener listener = GatheringErrorListener();
- ScannerResult result = scanString(content, includeComments: true);
+ fasta.ScannerResult result =
+ fasta.scanString(content, includeComments: true);
listener.setLineInfo(source, result.lineStarts);
- Parser parser = Parser(
+ analyzer.Parser parser = analyzer.Parser(
source,
listener,
featureSet: FeatureSet.forTesting(),
@@ -9596,9 +9049,10 @@
Source source = NonExistingSource.unknown;
listener ??= AnalysisErrorListener.NULL_LISTENER;
- ScannerResult result = scanString(content, includeComments: true);
+ fasta.ScannerResult result =
+ fasta.scanString(content, includeComments: true);
- Parser parser = Parser(
+ analyzer.Parser parser = analyzer.Parser(
source,
listener,
featureSet: FeatureSet.forTesting(),
@@ -9671,16 +9125,11 @@
@override
List<Expression> parseExpressionList(String code) {
- if (usingFastaParser) {
- createParser('[$code]');
- return (parser.parseExpression2() as ListLiteral)
- .elements
- .toList()
- .cast<Expression>();
- } else {
- createParser(code);
- return parser.parseExpressionList();
- }
+ createParser('[$code]');
+ return (parser.parseExpression2() as ListLiteral)
+ .elements
+ .toList()
+ .cast<Expression>();
}
@override
@@ -9692,26 +9141,19 @@
@override
FormalParameter parseFormalParameter(String code, ParameterKind kind,
{List<ErrorCode> errorCodes = const <ErrorCode>[]}) {
- if (usingFastaParser) {
- String parametersCode;
- if (kind == ParameterKind.REQUIRED) {
- parametersCode = '($code)';
- } else if (kind == ParameterKind.POSITIONAL) {
- parametersCode = '([$code])';
- } else if (kind == ParameterKind.NAMED) {
- parametersCode = '({$code})';
- } else {
- fail('$kind');
- }
- FormalParameterList list = parseFormalParameterList(parametersCode,
- inFunctionType: false, errorCodes: errorCodes);
- return list.parameters.single;
+ String parametersCode;
+ if (kind == ParameterKind.REQUIRED) {
+ parametersCode = '($code)';
+ } else if (kind == ParameterKind.POSITIONAL) {
+ parametersCode = '([$code])';
+ } else if (kind == ParameterKind.NAMED) {
+ parametersCode = '({$code})';
} else {
- createParser(code);
- FormalParameter parameter = parser.parseFormalParameter(kind);
- assertErrorsWithCodes(errorCodes);
- return parameter;
+ fail('$kind');
}
+ FormalParameterList list = parseFormalParameterList(parametersCode,
+ inFunctionType: false, errorCodes: errorCodes);
+ return list.parameters.single;
}
@override
@@ -9732,15 +9174,12 @@
/// Parses a single top level member of a compilation unit (other than a
/// directive), including any comment and/or metadata that precedes it.
@override
- CompilationUnitMember parseFullCompilationUnitMember() => usingFastaParser
- ? parser.parseCompilationUnit2().declarations.first
- : parser.parseCompilationUnitMember(parser.parseCommentAndMetadata());
+ CompilationUnitMember parseFullCompilationUnitMember() =>
+ parser.parseCompilationUnit2().declarations.first;
@override
Directive parseFullDirective() {
- return usingFastaParser
- ? (parser as ParserAdapter).parseTopLevelDeclaration(true)
- : parser.parseDirective(parser.parseCommentAndMetadata());
+ return parser.parseTopLevelDeclaration(true);
}
@override
@@ -9752,50 +9191,30 @@
@override
InstanceCreationExpression parseInstanceCreationExpression(
String code, Token newToken) {
- if (usingFastaParser) {
- createParser('$newToken $code');
- return parser.parseExpression2();
- } else {
- createParser(code);
- return parser.parseInstanceCreationExpression(newToken);
- }
+ createParser('$newToken $code');
+ return parser.parseExpression2();
}
@override
ListLiteral parseListLiteral(
Token token, String typeArgumentsCode, String code) {
- if (usingFastaParser) {
- String sc = '';
- if (token != null) {
- sc += token.lexeme + ' ';
- }
- if (typeArgumentsCode != null) {
- sc += typeArgumentsCode;
- }
- sc += code;
- createParser(sc);
- return parser.parseExpression2();
- } else {
- TypeArgumentList typeArguments;
- if (typeArgumentsCode != null) {
- createParser(typeArgumentsCode);
- typeArguments = parser.parseTypeArgumentList();
- }
- createParser(code);
- return parser.parseListLiteral(token, typeArguments);
+ String sc = '';
+ if (token != null) {
+ sc += token.lexeme + ' ';
}
+ if (typeArgumentsCode != null) {
+ sc += typeArgumentsCode;
+ }
+ sc += code;
+ createParser(sc);
+ return parser.parseExpression2();
}
@override
TypedLiteral parseListOrMapLiteral(Token modifier, String code) {
- if (usingFastaParser) {
- String literalCode = modifier != null ? '$modifier $code' : code;
- createParser(literalCode);
- return parser.parseExpression2() as TypedLiteral;
- } else {
- createParser(code);
- return parser.parseListOrMapLiteral(modifier);
- }
+ String literalCode = modifier != null ? '$modifier $code' : code;
+ createParser(literalCode);
+ return parser.parseExpression2() as TypedLiteral;
}
@override
@@ -9813,37 +9232,22 @@
@override
SetOrMapLiteral parseMapLiteral(
Token token, String typeArgumentsCode, String code) {
- if (usingFastaParser) {
- String sc = '';
- if (token != null) {
- sc += token.lexeme + ' ';
- }
- if (typeArgumentsCode != null) {
- sc += typeArgumentsCode;
- }
- sc += code;
- createParser(sc);
- return parser.parseExpression2() as SetOrMapLiteral;
- } else {
- TypeArgumentList typeArguments;
- if (typeArgumentsCode != null) {
- createParser(typeArgumentsCode);
- typeArguments = parser.parseTypeArgumentList();
- }
- createParser(code);
- return parser.parseMapLiteral(token, typeArguments);
+ String sc = '';
+ if (token != null) {
+ sc += token.lexeme + ' ';
}
+ if (typeArgumentsCode != null) {
+ sc += typeArgumentsCode;
+ }
+ sc += code;
+ createParser(sc);
+ return parser.parseExpression2() as SetOrMapLiteral;
}
@override
MapLiteralEntry parseMapLiteralEntry(String code) {
- if (usingFastaParser) {
- var mapLiteral = parseMapLiteral(null, null, '{ $code }');
- return mapLiteral.elements.single;
- } else {
- createParser(code);
- return parser.parseMapLiteralEntry();
- }
+ var mapLiteral = parseMapLiteral(null, null, '{ $code }');
+ return mapLiteral.elements.single;
}
@override
@@ -9862,17 +9266,9 @@
NormalFormalParameter parseNormalFormalParameter(String code,
{bool inFunctionType = false,
List<ErrorCode> errorCodes = const <ErrorCode>[]}) {
- if (usingFastaParser) {
- FormalParameterList list = parseFormalParameterList('($code)',
- inFunctionType: inFunctionType, errorCodes: errorCodes);
- return list.parameters.single;
- } else {
- createParser(code);
- FormalParameter parameter =
- parser.parseNormalFormalParameter(inFunctionType: inFunctionType);
- assertErrorsWithCodes(errorCodes);
- return parameter;
- }
+ FormalParameterList list = parseFormalParameterList('($code)',
+ inFunctionType: inFunctionType, errorCodes: errorCodes);
+ return list.parameters.single;
}
@override
@@ -9930,10 +9326,11 @@
Source source = TestSource();
listener = GatheringErrorListener();
- ScannerResult result = scanString(content, includeComments: true);
+ fasta.ScannerResult result =
+ fasta.scanString(content, includeComments: true);
listener.setLineInfo(source, result.lineStarts);
- Parser parser = Parser(
+ analyzer.Parser parser = analyzer.Parser(
source,
listener,
featureSet: FeatureSet.forTesting(),
@@ -9944,37 +9341,6 @@
return statement;
}
- /// Parse the given source as a sequence of statements.
- ///
- /// @param source the source to be parsed
- /// @param expectedCount the number of statements that are expected
- /// @param errorCodes the error codes of the errors that are expected to be
- /// found
- /// @return the statements that were parsed
- /// @throws Exception if the source could not be parsed, if the number of
- /// statements does not match the expected count, if the compilation
- /// errors in the source do not match those that are expected, or if
- /// the result would have been `null`
- List<Statement> parseStatements(String content, int expectedCount,
- [List<ErrorCode> errorCodes = const <ErrorCode>[]]) {
- Source source = TestSource();
- GatheringErrorListener listener = GatheringErrorListener();
-
- ScannerResult result = scanString(content);
- listener.setLineInfo(source, result.lineStarts);
-
- Parser parser = Parser(
- source,
- listener,
- featureSet: FeatureSet.forTesting(),
- );
- parser.enableOptionalNewAndConst = enableOptionalNewAndConst;
- List<Statement> statements = parser.parseStatements(result.tokens);
- expect(statements, hasLength(expectedCount));
- listener.assertErrorsWithCodes(errorCodes);
- return statements;
- }
-
@override
Expression parseStringLiteral(String code) {
createParser(code);
@@ -10007,15 +9373,8 @@
@override
VariableDeclarationList parseVariableDeclarationList(String code) {
- if (usingFastaParser) {
- var statement = parseStatement('$code;') as VariableDeclarationStatement;
- return statement.variables;
- } else {
- createParser(code);
- CommentAndMetadata commentAndMetadata = parser.parseCommentAndMetadata();
- return parser
- .parseVariableDeclarationListAfterMetadata(commentAndMetadata);
- }
+ var statement = parseStatement('$code;') as VariableDeclarationStatement;
+ return statement.variables;
}
void setUp() {
@@ -10044,14 +9403,10 @@
}
}
-/// Tests of the analyzer parser based on [RecoveryParserTestMixin].
-@reflectiveTest
-class RecoveryParserTest extends ParserTestCase with RecoveryParserTestMixin {}
-
/// The class `RecoveryParserTest` defines parser tests that test the parsing of
/// invalid code sequences to ensure that the correct recovery steps are taken
/// in the parser.
-mixin RecoveryParserTestMixin implements AbstractParserTestCase {
+mixin RecoveryParserTestMixin implements AbstractParserViaProxyTestCase {
void test_additiveExpression_missing_LHS() {
BinaryExpression expression =
parseExpression("+ y", codes: [ParserErrorCode.MISSING_IDENTIFIER]);
@@ -10335,33 +9690,23 @@
void test_classTypeAlias_withBody() {
parseCompilationUnit(r'''
class A {}
-class B = Object with A {}''',
- codes: usingFastaParser
+class B = Object with A {}''', codes:
// TODO(danrubel): Consolidate and improve error message.
- ? [
- ParserErrorCode.EXPECTED_EXECUTABLE,
- ParserErrorCode.EXPECTED_TOKEN
- ]
- : [ParserErrorCode.EXPECTED_TOKEN]);
+ [
+ ParserErrorCode.EXPECTED_EXECUTABLE,
+ ParserErrorCode.EXPECTED_TOKEN
+ ]);
}
void test_combinator_badIdentifier() {
createParser('import "/testB.dart" show @');
parser.parseCompilationUnit2();
- listener.assertErrors(usingFastaParser
- ? [
- expectedError(ParserErrorCode.MISSING_IDENTIFIER, 26, 1),
- expectedError(ParserErrorCode.EXPECTED_TOKEN, 27, 0),
- expectedError(
- ParserErrorCode.MISSING_CONST_FINAL_VAR_OR_TYPE, 27, 0),
- expectedError(ParserErrorCode.EXPECTED_TOKEN, 27, 0)
- ]
- : [
- expectedError(ParserErrorCode.MISSING_IDENTIFIER, 26, 1),
- expectedError(ParserErrorCode.EXPECTED_TOKEN, 26, 1),
- expectedError(ParserErrorCode.MISSING_IDENTIFIER, 26, 1),
- expectedError(ParserErrorCode.EXPECTED_EXECUTABLE, 27, 1)
- ]);
+ listener.assertErrors([
+ expectedError(ParserErrorCode.MISSING_IDENTIFIER, 26, 1),
+ expectedError(ParserErrorCode.EXPECTED_TOKEN, 27, 0),
+ expectedError(ParserErrorCode.MISSING_CONST_FINAL_VAR_OR_TYPE, 27, 0),
+ expectedError(ParserErrorCode.EXPECTED_TOKEN, 27, 0)
+ ]);
}
void test_combinator_missingIdentifier() {
@@ -10446,17 +9791,6 @@
expect(expression.rightOperand.isSynthetic, isTrue);
}
- void test_equalityExpression_precedence_relational_left() {
- BinaryExpression expression = parseExpression("is ==", codes: [
- ParserErrorCode.EXPECTED_TYPE_NAME,
- ParserErrorCode.MISSING_IDENTIFIER,
- ParserErrorCode.MISSING_IDENTIFIER
- ]);
- if (!usingFastaParser) {
- expect(expression.leftOperand, isIsExpression);
- }
- }
-
void test_equalityExpression_precedence_relational_right() {
BinaryExpression expression = parseExpression("== is", codes: [
ParserErrorCode.EXPECTED_TYPE_NAME,
@@ -10513,26 +9847,15 @@
// The fasta parser does not use parseExpressionList when parsing for loops
// and instead parseExpressionList is mapped to parseExpression('[$code]')
// which allows and ignores an optional trailing comma.
- if (usingFastaParser) {
- assertNoErrors();
- expect(result, hasLength(3));
- } else {
- listener.assertErrors(
- [expectedError(ParserErrorCode.MISSING_IDENTIFIER, 8, 0)]);
- expect(result, hasLength(4));
- Expression syntheticExpression = result[3];
- expect(syntheticExpression, isSimpleIdentifier);
- expect(syntheticExpression.isSynthetic, isTrue);
- }
+ assertNoErrors();
+ expect(result, hasLength(3));
}
void test_functionExpression_in_ConstructorFieldInitializer() {
CompilationUnit unit =
parseCompilationUnit("class A { A() : a = (){}; var v; }", codes: [
ParserErrorCode.MISSING_IDENTIFIER,
- usingFastaParser
- ? ParserErrorCode.EXPECTED_CLASS_MEMBER
- : ParserErrorCode.UNEXPECTED_TOKEN
+ ParserErrorCode.EXPECTED_CLASS_MEMBER
]);
// Make sure we recovered and parsed "var v" correctly
ClassDeclaration declaration = unit.declarations[0] as ClassDeclaration;
@@ -10546,21 +9869,15 @@
}
void test_functionExpression_named() {
- parseExpression("m(f() => 0);", expectedEndOffset: 11, codes: [
- usingFastaParser
- ? ParserErrorCode.NAMED_FUNCTION_EXPRESSION
- : ParserErrorCode.EXPECTED_TOKEN
- ]);
+ parseExpression("m(f() => 0);",
+ expectedEndOffset: 11,
+ codes: [ParserErrorCode.NAMED_FUNCTION_EXPRESSION]);
}
void test_ifStatement_noElse_statement() {
parseStatement('if (x v) f(x);');
- listener.assertErrors(usingFastaParser
- ? [expectedError(ParserErrorCode.EXPECTED_TOKEN, 6, 1)]
- : [
- expectedError(ParserErrorCode.EXPECTED_TOKEN, 6, 1),
- expectedError(ParserErrorCode.EXPECTED_TOKEN, 6, 1)
- ]);
+ listener
+ .assertErrors([expectedError(ParserErrorCode.EXPECTED_TOKEN, 6, 1)]);
}
void test_importDirectivePartial_as() {
@@ -10621,26 +9938,17 @@
Expression expression =
(initializer as ConstructorFieldInitializer).expression;
expect(expression, isNotNull);
- expect(expression,
- usingFastaParser ? isMethodInvocation : isParenthesizedExpression);
+ expect(expression, isMethodInvocation);
}
void test_incomplete_constructorInitializers_this() {
createParser('C() : this {}');
ClassMember member = parser.parseClassMember('C');
expectNotNullIfNoErrors(member);
- listener.assertErrors(usingFastaParser
- ? [
- expectedError(ParserErrorCode.EXPECTED_TOKEN, 11, 1),
- expectedError(
- ParserErrorCode.MISSING_ASSIGNMENT_IN_INITIALIZER, 6, 4)
- ]
- : [
- expectedError(ParserErrorCode.EXPECTED_TOKEN, 11, 1),
- expectedError(ParserErrorCode.MISSING_IDENTIFIER, 11, 1),
- expectedError(
- ParserErrorCode.MISSING_ASSIGNMENT_IN_INITIALIZER, 11, 1)
- ]);
+ listener.assertErrors([
+ expectedError(ParserErrorCode.EXPECTED_TOKEN, 11, 1),
+ expectedError(ParserErrorCode.MISSING_ASSIGNMENT_IN_INITIALIZER, 6, 4)
+ ]);
}
void test_incomplete_constructorInitializers_thisField() {
@@ -10673,29 +9981,20 @@
void test_incomplete_functionExpression() {
var expression = parseExpression("() a => null",
- errors: usingFastaParser
- ? [expectedError(ParserErrorCode.UNEXPECTED_TOKEN, 3, 1)]
- : [expectedError(ParserErrorCode.MISSING_IDENTIFIER, 2, 1)]);
- if (usingFastaParser) {
- FunctionExpression functionExpression = expression;
- expect(functionExpression.parameters.parameters, hasLength(0));
- }
+ errors: [expectedError(ParserErrorCode.UNEXPECTED_TOKEN, 3, 1)]);
+ FunctionExpression functionExpression = expression;
+ expect(functionExpression.parameters.parameters, hasLength(0));
}
void test_incomplete_functionExpression2() {
var expression = parseExpression("() a {}",
- errors: usingFastaParser
- ? [expectedError(ParserErrorCode.UNEXPECTED_TOKEN, 3, 1)]
- : [expectedError(ParserErrorCode.MISSING_IDENTIFIER, 2, 1)]);
- if (usingFastaParser) {
- FunctionExpression functionExpression = expression;
- expect(functionExpression.parameters.parameters, hasLength(0));
- }
+ errors: [expectedError(ParserErrorCode.UNEXPECTED_TOKEN, 3, 1)]);
+ FunctionExpression functionExpression = expression;
+ expect(functionExpression.parameters.parameters, hasLength(0));
}
void test_incomplete_returnType() {
- if (usingFastaParser) {
- parseCompilationUnit(r'''
+ parseCompilationUnit(r'''
Map<Symbol, convertStringToSymbolMap(Map<String, dynamic> map) {
if (map == null) return null;
Map<Symbol, dynamic> result = new Map<Symbol, dynamic>();
@@ -10704,10 +10003,9 @@
});
return result;
}''', errors: [
- expectedError(ParserErrorCode.EXPECTED_TOKEN, 12, 24),
- expectedError(ParserErrorCode.MISSING_FUNCTION_PARAMETERS, 0, 3)
- ]);
- }
+ expectedError(ParserErrorCode.EXPECTED_TOKEN, 12, 24),
+ expectedError(ParserErrorCode.MISSING_FUNCTION_PARAMETERS, 0, 3)
+ ]);
}
void test_incomplete_topLevelFunction() {
@@ -10716,14 +10014,10 @@
}
void test_incomplete_topLevelVariable() {
- CompilationUnit unit = parseCompilationUnit("String",
- errors: usingFastaParser
- ? [
- expectedError(
- ParserErrorCode.MISSING_CONST_FINAL_VAR_OR_TYPE, 0, 6),
- expectedError(ParserErrorCode.EXPECTED_TOKEN, 0, 6)
- ]
- : [expectedError(ParserErrorCode.EXPECTED_EXECUTABLE, 0, 6)]);
+ CompilationUnit unit = parseCompilationUnit("String", errors: [
+ expectedError(ParserErrorCode.MISSING_CONST_FINAL_VAR_OR_TYPE, 0, 6),
+ expectedError(ParserErrorCode.EXPECTED_TOKEN, 0, 6)
+ ]);
NodeList<CompilationUnitMember> declarations = unit.declarations;
expect(declarations, hasLength(1));
CompilationUnitMember member = declarations[0];
@@ -10732,9 +10026,7 @@
(member as TopLevelVariableDeclaration).variables.variables;
expect(variables, hasLength(1));
SimpleIdentifier name = variables[0].name;
- // Analyzer considers 'String' to be the type
- // while fasta considers it to be the name.
- expect(name.isSynthetic, usingFastaParser ? isFalse : isTrue);
+ expect(name.isSynthetic, isFalse);
}
void test_incomplete_topLevelVariable_const() {
@@ -10840,11 +10132,7 @@
class C {
static c
}''', codes: [
- // Fasta considers the `c` to be the type
- // whereas analyzer considers it to be the identifier.
- usingFastaParser
- ? ParserErrorCode.MISSING_CONST_FINAL_VAR_OR_TYPE
- : ParserErrorCode.MISSING_IDENTIFIER,
+ ParserErrorCode.MISSING_CONST_FINAL_VAR_OR_TYPE,
ParserErrorCode.EXPECTED_TOKEN
]);
NodeList<CompilationUnitMember> declarations = unit.declarations;
@@ -10862,7 +10150,7 @@
NodeList<VariableDeclaration> fields = fieldList.variables;
expect(fields, hasLength(1));
VariableDeclaration field = fields[0];
- expect(field.name.isSynthetic, usingFastaParser ? isFalse : isTrue);
+ expect(field.name.isSynthetic, isFalse);
}
void test_incompleteField_static2() {
@@ -10893,11 +10181,7 @@
class C {
A
}''', codes: [
- // Fasta considers the `c` to be the type
- // whereas analyzer considers it to be the identifier.
- usingFastaParser
- ? ParserErrorCode.MISSING_CONST_FINAL_VAR_OR_TYPE
- : ParserErrorCode.MISSING_IDENTIFIER,
+ ParserErrorCode.MISSING_CONST_FINAL_VAR_OR_TYPE,
ParserErrorCode.EXPECTED_TOKEN
]);
NodeList<CompilationUnitMember> declarations = unit.declarations;
@@ -10914,13 +10198,8 @@
NodeList<VariableDeclaration> fields = fieldList.variables;
expect(fields, hasLength(1));
VariableDeclaration field = fields[0];
- if (usingFastaParser) {
- expect(type, isNull);
- expect(field.name.name, 'A');
- } else {
- expect(type.name.name, 'A');
- expect(field.name.isSynthetic, isTrue);
- }
+ expect(type, isNull);
+ expect(field.name.name, 'A');
}
void test_incompleteField_var() {
@@ -11083,13 +10362,7 @@
void test_incompleteTypeParameters3() {
CompilationUnit unit = parseCompilationUnit(r'''
class C<K extends L<T {
-}''',
- errors: usingFastaParser
- ? [expectedError(ParserErrorCode.EXPECTED_TOKEN, 20, 1)]
- : [
- expectedError(ParserErrorCode.EXPECTED_TOKEN, 20, 1),
- expectedError(ParserErrorCode.EXPECTED_TOKEN, 22, 1)
- ]);
+}''', errors: [expectedError(ParserErrorCode.EXPECTED_TOKEN, 20, 1)]);
// one class
List<CompilationUnitMember> declarations = unit.declarations;
expect(declarations, hasLength(1));
@@ -11109,72 +10382,42 @@
}
void test_invalidMapLiteral() {
- parseCompilationUnit("class C { var f = Map<A, B> {}; }",
- codes: usingFastaParser
- ? [
- // TODO(danrubel): Improve error message to indicate
- // that "Map" should be removed.
- ParserErrorCode.EXPECTED_TOKEN,
- ParserErrorCode.MISSING_KEYWORD_OPERATOR,
- ParserErrorCode.MISSING_METHOD_PARAMETERS,
- ParserErrorCode.EXPECTED_CLASS_MEMBER,
- ]
- : [
- ParserErrorCode.EXPECTED_TOKEN,
- ParserErrorCode.EXPECTED_CLASS_MEMBER,
- ParserErrorCode.EXPECTED_CLASS_MEMBER,
- ParserErrorCode.UNEXPECTED_TOKEN,
- ParserErrorCode.UNEXPECTED_TOKEN,
- ParserErrorCode.UNEXPECTED_TOKEN,
- ParserErrorCode.UNEXPECTED_TOKEN,
- ParserErrorCode.EXPECTED_EXECUTABLE,
- ]);
+ parseCompilationUnit("class C { var f = Map<A, B> {}; }", codes: [
+ // TODO(danrubel): Improve error message to indicate
+ // that "Map" should be removed.
+ ParserErrorCode.EXPECTED_TOKEN,
+ ParserErrorCode.MISSING_KEYWORD_OPERATOR,
+ ParserErrorCode.MISSING_METHOD_PARAMETERS,
+ ParserErrorCode.EXPECTED_CLASS_MEMBER,
+ ]);
}
void test_invalidTypeParameters() {
CompilationUnit unit = parseCompilationUnit(r'''
class C {
G<int double> g;
-}''',
- errors: usingFastaParser
- ? [expectedError(ParserErrorCode.EXPECTED_TOKEN, 18, 6)]
- : [
- expectedError(ParserErrorCode.EXPECTED_TOKEN, 18, 6),
- expectedError(ParserErrorCode.EXPECTED_TOKEN, 18, 6),
- expectedError(ParserErrorCode.EXPECTED_CLASS_MEMBER, 24, 1),
- expectedError(ParserErrorCode.UNEXPECTED_TOKEN, 24, 1),
- expectedError(
- ParserErrorCode.MISSING_CONST_FINAL_VAR_OR_TYPE, 26, 1)
- ]);
+}''', errors: [expectedError(ParserErrorCode.EXPECTED_TOKEN, 18, 6)]);
// one class
List<CompilationUnitMember> declarations = unit.declarations;
expect(declarations, hasLength(1));
// validate members
- if (usingFastaParser) {
- ClassDeclaration classDecl = declarations[0] as ClassDeclaration;
- expect(classDecl.members, hasLength(1));
- FieldDeclaration fields = classDecl.members.first;
- expect(fields.fields.variables, hasLength(1));
- VariableDeclaration field = fields.fields.variables.first;
- expect(field.name.name, 'g');
- }
+ ClassDeclaration classDecl = declarations[0] as ClassDeclaration;
+ expect(classDecl.members, hasLength(1));
+ FieldDeclaration fields = classDecl.members.first;
+ expect(fields.fields.variables, hasLength(1));
+ VariableDeclaration field = fields.fields.variables.first;
+ expect(field.name.name, 'g');
}
void test_isExpression_noType() {
CompilationUnit unit = parseCompilationUnit(
"class Bar<T extends Foo> {m(x){if (x is ) return;if (x is !)}}",
- codes: usingFastaParser
- ? [
- ParserErrorCode.EXPECTED_TYPE_NAME,
- ParserErrorCode.EXPECTED_TYPE_NAME,
- ParserErrorCode.MISSING_IDENTIFIER,
- ParserErrorCode.EXPECTED_TOKEN,
- ]
- : [
- ParserErrorCode.EXPECTED_TYPE_NAME,
- ParserErrorCode.EXPECTED_TYPE_NAME,
- ParserErrorCode.MISSING_STATEMENT
- ]);
+ codes: [
+ ParserErrorCode.EXPECTED_TYPE_NAME,
+ ParserErrorCode.EXPECTED_TYPE_NAME,
+ ParserErrorCode.MISSING_IDENTIFIER,
+ ParserErrorCode.EXPECTED_TOKEN,
+ ]);
ClassDeclaration declaration = unit.declarations[0] as ClassDeclaration;
MethodDeclaration method = declaration.members[0] as MethodDeclaration;
BlockFunctionBody body = method.body as BlockFunctionBody;
@@ -11186,170 +10429,75 @@
TypeAnnotation type = expression.type;
expect(type, isNotNull);
expect(type is TypeName && type.name.isSynthetic, isTrue);
- if (usingFastaParser) {
- ExpressionStatement thenStatement = ifStatement.thenStatement;
- expect(thenStatement.semicolon.isSynthetic, isTrue);
- SimpleIdentifier simpleId = thenStatement.expression;
- expect(simpleId.isSynthetic, isTrue);
- } else {
- expect(ifStatement.thenStatement, isEmptyStatement);
- }
+ ExpressionStatement thenStatement = ifStatement.thenStatement;
+ expect(thenStatement.semicolon.isSynthetic, isTrue);
+ SimpleIdentifier simpleId = thenStatement.expression;
+ expect(simpleId.isSynthetic, isTrue);
}
void test_issue_34610_get() {
- final unit = parseCompilationUnit('class C { get C.named => null; }',
- errors: usingFastaParser
- ? [
- expectedError(ParserErrorCode.GETTER_CONSTRUCTOR, 10, 3),
- expectedError(ParserErrorCode.MISSING_METHOD_PARAMETERS, 14, 1),
- ]
- : [
- expectedError(
- ParserErrorCode.STATIC_GETTER_WITHOUT_BODY, 15, 1),
- expectedError(ParserErrorCode.EXPECTED_CLASS_MEMBER, 15, 1),
- expectedError(ParserErrorCode.UNEXPECTED_TOKEN, 15, 1),
- expectedError(ParserErrorCode.EXPECTED_CLASS_MEMBER, 22, 2),
- expectedError(ParserErrorCode.EXPECTED_CLASS_MEMBER, 22, 2),
- expectedError(ParserErrorCode.UNEXPECTED_TOKEN, 22, 2),
- expectedError(ParserErrorCode.EXPECTED_CLASS_MEMBER, 25, 4),
- expectedError(ParserErrorCode.UNEXPECTED_TOKEN, 25, 4),
- expectedError(ParserErrorCode.UNEXPECTED_TOKEN, 29, 1),
- ]);
+ final unit =
+ parseCompilationUnit('class C { get C.named => null; }', errors: [
+ expectedError(ParserErrorCode.GETTER_CONSTRUCTOR, 10, 3),
+ expectedError(ParserErrorCode.MISSING_METHOD_PARAMETERS, 14, 1),
+ ]);
ClassDeclaration declaration = unit.declarations[0];
- if (usingFastaParser) {
- ConstructorDeclaration method = declaration.members[0];
- expect(method.name.name, 'named');
- expect(method.parameters, isNotNull);
- } else {
- MethodDeclaration method = declaration.members[0];
- expect(method.name.name, 'C');
- expect(method.isGetter, isTrue);
- expect(method.parameters, isNull);
- }
+ ConstructorDeclaration method = declaration.members[0];
+ expect(method.name.name, 'named');
+ expect(method.parameters, isNotNull);
}
void test_issue_34610_initializers() {
final unit = parseCompilationUnit('class C { C.named : super(); }',
- errors: usingFastaParser
- ? [expectedError(ParserErrorCode.MISSING_METHOD_PARAMETERS, 10, 1)]
- : [
- expectedError(ParserErrorCode.EXPECTED_CLASS_MEMBER, 18, 19),
- expectedError(ParserErrorCode.EXPECTED_CLASS_MEMBER, 18, 19),
- expectedError(ParserErrorCode.UNEXPECTED_TOKEN, 18, 19),
- expectedError(ParserErrorCode.EXPECTED_CLASS_MEMBER, 20, 25),
- expectedError(ParserErrorCode.UNEXPECTED_TOKEN, 20, 25),
- expectedError(ParserErrorCode.EXPECTED_CLASS_MEMBER, 25, 26),
- expectedError(ParserErrorCode.UNEXPECTED_TOKEN, 25, 26),
- expectedError(ParserErrorCode.EXPECTED_CLASS_MEMBER, 26, 27),
- expectedError(ParserErrorCode.UNEXPECTED_TOKEN, 26, 27),
- expectedError(ParserErrorCode.UNEXPECTED_TOKEN, 27, 28),
- ]);
+ errors: [
+ expectedError(ParserErrorCode.MISSING_METHOD_PARAMETERS, 10, 1)
+ ]);
ClassDeclaration declaration = unit.declarations[0];
- if (usingFastaParser) {
- ConstructorDeclaration constructor = declaration.members[0];
- expect(constructor.name.name, 'named');
- expect(constructor.parameters, isNotNull);
- expect(constructor.parameters.parameters, hasLength(0));
- } else {
- FieldDeclaration field = declaration.members[0];
- expect(field.fields.type.toSource(), 'C.named');
- }
+ ConstructorDeclaration constructor = declaration.members[0];
+ expect(constructor.name.name, 'named');
+ expect(constructor.parameters, isNotNull);
+ expect(constructor.parameters.parameters, hasLength(0));
}
void test_issue_34610_missing_param() {
- final unit = parseCompilationUnit('class C { C => null; }',
- errors: usingFastaParser
- ? [expectedError(ParserErrorCode.MISSING_METHOD_PARAMETERS, 10, 1)]
- : [
- expectedError(ParserErrorCode.EXPECTED_CLASS_MEMBER, 18, 2),
- expectedError(ParserErrorCode.EXPECTED_CLASS_MEMBER, 18, 2),
- expectedError(ParserErrorCode.UNEXPECTED_TOKEN, 18, 2),
- expectedError(ParserErrorCode.EXPECTED_CLASS_MEMBER, 21, 4),
- expectedError(ParserErrorCode.UNEXPECTED_TOKEN, 21, 4),
- expectedError(ParserErrorCode.UNEXPECTED_TOKEN, 25, 1),
- ]);
+ final unit = parseCompilationUnit('class C { C => null; }', errors: [
+ expectedError(ParserErrorCode.MISSING_METHOD_PARAMETERS, 10, 1)
+ ]);
ClassDeclaration declaration = unit.declarations[0];
- if (usingFastaParser) {
- ConstructorDeclaration constructor = declaration.members[0];
- expect(constructor.name, isNull);
- expect(constructor.parameters, isNotNull);
- expect(constructor.parameters.parameters, hasLength(0));
- } else {
- FieldDeclaration field = declaration.members[0];
- expect(field.fields.type.toSource(), 'C');
- }
+ ConstructorDeclaration constructor = declaration.members[0];
+ expect(constructor.name, isNull);
+ expect(constructor.parameters, isNotNull);
+ expect(constructor.parameters.parameters, hasLength(0));
}
void test_issue_34610_named_missing_param() {
- final unit = parseCompilationUnit('class C { C.named => null; }',
- errors: usingFastaParser
- ? [expectedError(ParserErrorCode.MISSING_METHOD_PARAMETERS, 10, 1)]
- : [
- expectedError(ParserErrorCode.EXPECTED_CLASS_MEMBER, 18, 2),
- expectedError(ParserErrorCode.EXPECTED_CLASS_MEMBER, 18, 2),
- expectedError(ParserErrorCode.UNEXPECTED_TOKEN, 18, 2),
- expectedError(ParserErrorCode.EXPECTED_CLASS_MEMBER, 21, 4),
- expectedError(ParserErrorCode.UNEXPECTED_TOKEN, 21, 4),
- expectedError(ParserErrorCode.UNEXPECTED_TOKEN, 25, 1),
- ]);
+ final unit = parseCompilationUnit('class C { C.named => null; }', errors: [
+ expectedError(ParserErrorCode.MISSING_METHOD_PARAMETERS, 10, 1)
+ ]);
ClassDeclaration declaration = unit.declarations[0];
- if (usingFastaParser) {
- ConstructorDeclaration constructor = declaration.members[0];
- expect(constructor.name.name, 'named');
- expect(constructor.parameters, isNotNull);
- expect(constructor.parameters.parameters, hasLength(0));
- } else {
- FieldDeclaration field = declaration.members[0];
- expect(field.fields.type.toSource(), 'C.named');
- }
+ ConstructorDeclaration constructor = declaration.members[0];
+ expect(constructor.name.name, 'named');
+ expect(constructor.parameters, isNotNull);
+ expect(constructor.parameters.parameters, hasLength(0));
}
void test_issue_34610_set() {
- final unit = parseCompilationUnit('class C { set C.named => null; }',
- errors: usingFastaParser
- ? [
- expectedError(ParserErrorCode.SETTER_CONSTRUCTOR, 10, 3),
- expectedError(ParserErrorCode.MISSING_METHOD_PARAMETERS, 14, 1),
- ]
- : [
- expectedError(ParserErrorCode.EXPECTED_TOKEN, 15, 1),
- expectedError(ParserErrorCode.MISSING_IDENTIFIER, 15, 1),
- expectedError(ParserErrorCode.EXPECTED_TOKEN, 15, 1),
- expectedError(
- ParserErrorCode.STATIC_SETTER_WITHOUT_BODY, 15, 1),
- expectedError(ParserErrorCode.EXPECTED_CLASS_MEMBER, 15, 1),
- expectedError(ParserErrorCode.UNEXPECTED_TOKEN, 15, 1),
- expectedError(ParserErrorCode.EXPECTED_CLASS_MEMBER, 22, 2),
- expectedError(ParserErrorCode.EXPECTED_CLASS_MEMBER, 22, 2),
- expectedError(ParserErrorCode.UNEXPECTED_TOKEN, 22, 2),
- expectedError(ParserErrorCode.EXPECTED_CLASS_MEMBER, 25, 4),
- expectedError(ParserErrorCode.UNEXPECTED_TOKEN, 25, 4),
- expectedError(ParserErrorCode.UNEXPECTED_TOKEN, 29, 1),
- ]);
+ final unit =
+ parseCompilationUnit('class C { set C.named => null; }', errors: [
+ expectedError(ParserErrorCode.SETTER_CONSTRUCTOR, 10, 3),
+ expectedError(ParserErrorCode.MISSING_METHOD_PARAMETERS, 14, 1),
+ ]);
ClassDeclaration declaration = unit.declarations[0];
- if (usingFastaParser) {
- ConstructorDeclaration method = declaration.members[0];
- expect(method.name.name, 'named');
- expect(method.parameters, isNotNull);
- expect(method.parameters.parameters, hasLength(0));
- } else {
- MethodDeclaration method = declaration.members[0];
- expect(method.name.name, 'C');
- expect(method.isSetter, isTrue);
- expect(method.parameters, isNotNull);
- expect(method.parameters.parameters, hasLength(1));
- }
+ ConstructorDeclaration method = declaration.members[0];
+ expect(method.name.name, 'named');
+ expect(method.parameters, isNotNull);
+ expect(method.parameters.parameters, hasLength(0));
}
void test_keywordInPlaceOfIdentifier() {
// TODO(brianwilkerson) We could do better with this.
parseCompilationUnit("do() {}",
- codes: usingFastaParser
- ? [ParserErrorCode.EXPECTED_IDENTIFIER_BUT_GOT_KEYWORD]
- : [
- ParserErrorCode.EXPECTED_EXECUTABLE,
- ParserErrorCode.UNEXPECTED_TOKEN
- ]);
+ codes: [ParserErrorCode.EXPECTED_IDENTIFIER_BUT_GOT_KEYWORD]);
}
void test_logicalAndExpression_missing_LHS() {
@@ -11465,12 +10613,7 @@
int length {}
void foo() {}
}''', errors: [
- expectedError(
- usingFastaParser
- ? ParserErrorCode.MISSING_METHOD_PARAMETERS
- : ParserErrorCode.MISSING_GET,
- 16,
- 6)
+ expectedError(ParserErrorCode.MISSING_METHOD_PARAMETERS, 16, 6)
]);
expect(unit, isNotNull);
ClassDeclaration classDeclaration =
@@ -11489,18 +10632,9 @@
expectNotNullIfNoErrors(member);
listener.assertErrors(
[expectedError(ParserErrorCode.EXPECTED_CLASS_MEMBER, 10, 1)]);
- if (usingFastaParser) {
- // TODO(danrubel): Consider generating a sub method so that the
- // existing annotation can be associated with a class member.
- expect(member, isNull);
- } else {
- expect(member, isMethodDeclaration);
- MethodDeclaration method = member;
- expect(method.documentationComment, isNull);
- NodeList<Annotation> metadata = method.metadata;
- expect(metadata, hasLength(1));
- expect(metadata[0].name.name, "override");
- }
+ // TODO(danrubel): Consider generating a sub method so that the
+ // existing annotation can be associated with a class member.
+ expect(member, isNull);
}
void test_missingSemicolon_varialeDeclarationList() {
@@ -11608,19 +10742,14 @@
}
void test_nonStringLiteralUri_import() {
- parseCompilationUnit("import dart:io; class C {}",
- errors: usingFastaParser
- ? [
- expectedError(ParserErrorCode.EXPECTED_STRING_LITERAL, 7, 4),
- expectedError(ParserErrorCode.EXPECTED_TOKEN, 7, 4),
- expectedError(
- ParserErrorCode.MISSING_CONST_FINAL_VAR_OR_TYPE, 7, 4),
- expectedError(ParserErrorCode.EXPECTED_TOKEN, 7, 4),
- expectedError(ParserErrorCode.EXPECTED_EXECUTABLE, 11, 1),
- expectedError(
- ParserErrorCode.MISSING_CONST_FINAL_VAR_OR_TYPE, 12, 2)
- ]
- : [expectedError(ParserErrorCode.NON_STRING_LITERAL_AS_URI, 7, 4)]);
+ parseCompilationUnit("import dart:io; class C {}", errors: [
+ expectedError(ParserErrorCode.EXPECTED_STRING_LITERAL, 7, 4),
+ expectedError(ParserErrorCode.EXPECTED_TOKEN, 7, 4),
+ expectedError(ParserErrorCode.MISSING_CONST_FINAL_VAR_OR_TYPE, 7, 4),
+ expectedError(ParserErrorCode.EXPECTED_TOKEN, 7, 4),
+ expectedError(ParserErrorCode.EXPECTED_EXECUTABLE, 11, 1),
+ expectedError(ParserErrorCode.MISSING_CONST_FINAL_VAR_OR_TYPE, 12, 2)
+ ]);
}
void test_prefixExpression_missing_operand_minus() {
@@ -11634,11 +10763,9 @@
void test_primaryExpression_argumentDefinitionTest() {
SimpleIdentifier expression = parsePrimaryExpression('?a',
expectedEndOffset: 0,
- errors: usingFastaParser
- ? [expectedError(ParserErrorCode.MISSING_IDENTIFIER, 0, 1)]
- : [expectedError(ParserErrorCode.UNEXPECTED_TOKEN, 0, 1)]);
+ errors: [expectedError(ParserErrorCode.MISSING_IDENTIFIER, 0, 1)]);
expectNotNullIfNoErrors(expression);
- expect(expression.isSynthetic, usingFastaParser);
+ expect(expression.isSynthetic, isTrue);
}
void test_propertyAccess_missing_LHS_RHS() {
@@ -11646,18 +10773,10 @@
ParserErrorCode.MISSING_IDENTIFIER,
ParserErrorCode.MISSING_IDENTIFIER
]);
- if (usingFastaParser) {
- PrefixedIdentifier expression = result;
- expect(expression.prefix.isSynthetic, isTrue);
- expect(expression.period.lexeme, '.');
- expect(expression.identifier.isSynthetic, isTrue);
- } else {
- PropertyAccess expression = result;
- SimpleIdentifier target = expression.target;
- expect(target.isSynthetic, isTrue);
- expect(expression.operator.lexeme, '.');
- expect(expression.propertyName.isSynthetic, isTrue);
- }
+ PrefixedIdentifier expression = result;
+ expect(expression.prefix.isSynthetic, isTrue);
+ expect(expression.period.lexeme, '.');
+ expect(expression.identifier.isSynthetic, isTrue);
}
void test_relationalExpression_missing_LHS() {
@@ -11768,820 +10887,12 @@
}
}
-/// Tests of the analyzer parser based on [SimpleParserTestMixin].
-@reflectiveTest
-class SimpleParserTest extends ParserTestCase with SimpleParserTestMixin {
- void test_computeStringValue_emptyInterpolationPrefix() {
- expect(_computeStringValue("'''", true, false), "");
- }
-
- void test_computeStringValue_escape_b() {
- expect(_computeStringValue("'\\b'", true, true), "\b");
- }
-
- void test_computeStringValue_escape_f() {
- expect(_computeStringValue("'\\f'", true, true), "\f");
- }
-
- void test_computeStringValue_escape_n() {
- expect(_computeStringValue("'\\n'", true, true), "\n");
- }
-
- void test_computeStringValue_escape_notSpecial() {
- expect(_computeStringValue("'\\:'", true, true), ":");
- }
-
- void test_computeStringValue_escape_r() {
- expect(_computeStringValue("'\\r'", true, true), "\r");
- }
-
- void test_computeStringValue_escape_t() {
- expect(_computeStringValue("'\\t'", true, true), "\t");
- }
-
- void test_computeStringValue_escape_u_fixed() {
- expect(_computeStringValue("'\\u4321'", true, true), "\u4321");
- }
-
- void test_computeStringValue_escape_u_variable() {
- expect(_computeStringValue("'\\u{123}'", true, true), "\u0123");
- }
-
- void test_computeStringValue_escape_v() {
- expect(_computeStringValue("'\\v'", true, true), "\u000B");
- }
-
- void test_computeStringValue_escape_x() {
- expect(_computeStringValue("'\\xFF'", true, true), "\u00FF");
- }
-
- void test_computeStringValue_noEscape_single() {
- expect(_computeStringValue("'text'", true, true), "text");
- }
-
- void test_computeStringValue_noEscape_triple() {
- expect(_computeStringValue("'''text'''", true, true), "text");
- }
-
- void test_computeStringValue_raw_single() {
- expect(_computeStringValue("r'text'", true, true), "text");
- }
-
- void test_computeStringValue_raw_triple() {
- expect(_computeStringValue("r'''text'''", true, true), "text");
- }
-
- void test_computeStringValue_raw_withEscape() {
- expect(_computeStringValue("r'two\\nlines'", true, true), "two\\nlines");
- }
-
- void test_computeStringValue_triple_internalQuote_first_empty() {
- expect(_computeStringValue("''''", true, false), "'");
- }
-
- void test_computeStringValue_triple_internalQuote_first_nonEmpty() {
- expect(_computeStringValue("''''text", true, false), "'text");
- }
-
- void test_computeStringValue_triple_internalQuote_last_empty() {
- expect(_computeStringValue("'''", false, true), "");
- }
-
- void test_computeStringValue_triple_internalQuote_last_nonEmpty() {
- expect(_computeStringValue("text'''", false, true), "text");
- }
-
- void test_createSyntheticIdentifier() {
- createParser('');
- SimpleIdentifier identifier = parser.createSyntheticIdentifier();
- expectNotNullIfNoErrors(identifier);
- expect(identifier.isSynthetic, isTrue);
- }
-
- void test_createSyntheticStringLiteral() {
- createParser('');
- SimpleStringLiteral literal = parser.createSyntheticStringLiteral();
- expectNotNullIfNoErrors(literal);
- expect(literal.isSynthetic, isTrue);
- }
-
- void test_isFunctionDeclaration_nameButNoReturn_block() {
- expect(_isFunctionDeclaration("f() {}"), isTrue);
- }
-
- void test_isFunctionDeclaration_nameButNoReturn_expression() {
- expect(_isFunctionDeclaration("f() => e"), isTrue);
- }
-
- void test_isFunctionDeclaration_nameButNoReturn_typeParameters_block() {
- expect(_isFunctionDeclaration("f<E>() {}"), isTrue);
- }
-
- void test_isFunctionDeclaration_nameButNoReturn_typeParameters_expression() {
- expect(_isFunctionDeclaration("f<E>() => e"), isTrue);
- }
-
- void test_isFunctionDeclaration_normalReturn_block() {
- expect(_isFunctionDeclaration("C f() {}"), isTrue);
- }
-
- void test_isFunctionDeclaration_normalReturn_expression() {
- expect(_isFunctionDeclaration("C f() => e"), isTrue);
- }
-
- void test_isFunctionDeclaration_normalReturn_typeParameters_block() {
- expect(_isFunctionDeclaration("C f<E>() {}"), isTrue);
- }
-
- void test_isFunctionDeclaration_normalReturn_typeParameters_expression() {
- expect(_isFunctionDeclaration("C f<E>() => e"), isTrue);
- }
-
- void test_isFunctionDeclaration_voidReturn_block() {
- expect(_isFunctionDeclaration("void f() {}"), isTrue);
- }
-
- void test_isFunctionDeclaration_voidReturn_expression() {
- expect(_isFunctionDeclaration("void f() => e"), isTrue);
- }
-
- void test_isFunctionDeclaration_voidReturn_typeParameters_block() {
- expect(_isFunctionDeclaration("void f<E>() {}"), isTrue);
- }
-
- void test_isFunctionDeclaration_voidReturn_typeParameters_expression() {
- expect(_isFunctionDeclaration("void f<E>() => e"), isTrue);
- }
-
- void test_isFunctionExpression_false_noBody() {
- expect(_isFunctionExpression("f();"), isFalse);
- }
-
- void test_isFunctionExpression_false_notParameters() {
- expect(_isFunctionExpression("(a + b) {"), isFalse);
- }
-
- void test_isFunctionExpression_noParameters_block() {
- expect(_isFunctionExpression("() {}"), isTrue);
- }
-
- void test_isFunctionExpression_noParameters_expression() {
- expect(_isFunctionExpression("() => e"), isTrue);
- }
-
- void test_isFunctionExpression_noParameters_typeParameters_block() {
- expect(_isFunctionExpression("<E>() {}"), isTrue);
- }
-
- void test_isFunctionExpression_noParameters_typeParameters_expression() {
- expect(_isFunctionExpression("<E>() => e"), isTrue);
- }
-
- void test_isFunctionExpression_parameter_final() {
- expect(_isFunctionExpression("(final a) {}"), isTrue);
- expect(_isFunctionExpression("(final a, b) {}"), isTrue);
- expect(_isFunctionExpression("(final a, final b) {}"), isTrue);
- }
-
- void test_isFunctionExpression_parameter_final_typed() {
- expect(_isFunctionExpression("(final int a) {}"), isTrue);
- expect(_isFunctionExpression("(final prefix.List a) {}"), isTrue);
- expect(_isFunctionExpression("(final List<int> a) {}"), isTrue);
- expect(_isFunctionExpression("(final prefix.List<int> a) {}"), isTrue);
- }
-
- void test_isFunctionExpression_parameter_multiple() {
- expect(_isFunctionExpression("(a, b) {}"), isTrue);
- }
-
- void test_isFunctionExpression_parameter_named() {
- expect(_isFunctionExpression("({a}) {}"), isTrue);
- }
-
- void test_isFunctionExpression_parameter_optional() {
- expect(_isFunctionExpression("([a]) {}"), isTrue);
- }
-
- void test_isFunctionExpression_parameter_single() {
- expect(_isFunctionExpression("(a) {}"), isTrue);
- }
-
- void test_isFunctionExpression_parameter_typed() {
- expect(_isFunctionExpression("(int a, int b) {}"), isTrue);
- }
-
- void test_isInitializedVariableDeclaration_assignment() {
- expect(_isInitializedVariableDeclaration("a = null;"), isFalse);
- }
-
- void test_isInitializedVariableDeclaration_comparison() {
- expect(_isInitializedVariableDeclaration("a < 0;"), isFalse);
- }
-
- void test_isInitializedVariableDeclaration_conditional() {
- expect(_isInitializedVariableDeclaration("a == null ? init() : update();"),
- isFalse);
- }
-
- void test_isInitializedVariableDeclaration_const_noType_initialized() {
- expect(_isInitializedVariableDeclaration("const a = 0;"), isTrue);
- }
-
- void test_isInitializedVariableDeclaration_const_noType_uninitialized() {
- expect(_isInitializedVariableDeclaration("const a;"), isTrue);
- }
-
- void test_isInitializedVariableDeclaration_const_simpleType_uninitialized() {
- expect(_isInitializedVariableDeclaration("const A a;"), isTrue);
- }
-
- void test_isInitializedVariableDeclaration_final_noType_initialized() {
- expect(_isInitializedVariableDeclaration("final a = 0;"), isTrue);
- }
-
- void test_isInitializedVariableDeclaration_final_noType_uninitialized() {
- expect(_isInitializedVariableDeclaration("final a;"), isTrue);
- }
-
- void test_isInitializedVariableDeclaration_final_simpleType_initialized() {
- expect(_isInitializedVariableDeclaration("final A a = 0;"), isTrue);
- }
-
- void test_isInitializedVariableDeclaration_functionDeclaration_typed() {
- expect(_isInitializedVariableDeclaration("A f() {};"), isFalse);
- }
-
- void test_isInitializedVariableDeclaration_functionDeclaration_untyped() {
- expect(_isInitializedVariableDeclaration("f() {};"), isFalse);
- }
-
- void test_isInitializedVariableDeclaration_noType_initialized() {
- expect(_isInitializedVariableDeclaration("var a = 0;"), isTrue);
- }
-
- void test_isInitializedVariableDeclaration_noType_uninitialized() {
- expect(_isInitializedVariableDeclaration("var a;"), isTrue);
- }
-
- void test_isInitializedVariableDeclaration_parameterizedType_initialized() {
- expect(_isInitializedVariableDeclaration("List<int> a = null;"), isTrue);
- }
-
- void test_isInitializedVariableDeclaration_parameterizedType_uninitialized() {
- expect(_isInitializedVariableDeclaration("List<int> a;"), isTrue);
- }
-
- void test_isInitializedVariableDeclaration_simpleType_initialized() {
- expect(_isInitializedVariableDeclaration("A a = 0;"), isTrue);
- }
-
- void test_isInitializedVariableDeclaration_simpleType_uninitialized() {
- expect(_isInitializedVariableDeclaration("A a;"), isTrue);
- }
-
- void test_isSwitchMember_case_labeled() {
- expect(_isSwitchMember("l1: l2: case"), isTrue);
- }
-
- void test_isSwitchMember_case_unlabeled() {
- expect(_isSwitchMember("case"), isTrue);
- }
-
- void test_isSwitchMember_default_labeled() {
- expect(_isSwitchMember("l1: l2: default"), isTrue);
- }
-
- void test_isSwitchMember_default_unlabeled() {
- expect(_isSwitchMember("default"), isTrue);
- }
-
- void test_isSwitchMember_false() {
- expect(_isSwitchMember("break;"), isFalse);
- }
-
- void test_parseDottedName_multiple() {
- createParser('a.b.c');
- DottedName name = parser.parseDottedName();
- expectNotNullIfNoErrors(name);
- assertNoErrors();
- expectDottedName(name, ["a", "b", "c"]);
- }
-
- void test_parseDottedName_single() {
- createParser('a');
- DottedName name = parser.parseDottedName();
- expectNotNullIfNoErrors(name);
- assertNoErrors();
- expectDottedName(name, ["a"]);
- }
-
- void test_parseFinalConstVarOrType_const_functionType() {
- createParser('const int Function(int) f');
- FinalConstVarOrType result = parser.parseFinalConstVarOrType(false);
- expectNotNullIfNoErrors(result);
- assertNoErrors();
- Token keyword = result.keyword;
- expect(keyword, isNotNull);
- expect(keyword.type.isKeyword, true);
- expect(keyword.keyword, Keyword.CONST);
- expect(result.type, isNotNull);
- }
-
- void test_parseFinalConstVarOrType_const_namedType() {
- createParser('const A a');
- FinalConstVarOrType result = parser.parseFinalConstVarOrType(false);
- expectNotNullIfNoErrors(result);
- assertNoErrors();
- Token keyword = result.keyword;
- expect(keyword, isNotNull);
- expect(keyword.type.isKeyword, true);
- expect(keyword.keyword, Keyword.CONST);
- expect(result.type, isNotNull);
- }
-
- void test_parseFinalConstVarOrType_const_noType() {
- createParser('const');
- FinalConstVarOrType result = parser.parseFinalConstVarOrType(false);
- expectNotNullIfNoErrors(result);
- assertNoErrors();
- Token keyword = result.keyword;
- expect(keyword, isNotNull);
- expect(keyword.type.isKeyword, true);
- expect(keyword.keyword, Keyword.CONST);
- expect(result.type, isNull);
- }
-
- void test_parseFinalConstVarOrType_final_functionType() {
- createParser('final int Function(int) f');
- FinalConstVarOrType result = parser.parseFinalConstVarOrType(false);
- expectNotNullIfNoErrors(result);
- assertNoErrors();
- Token keyword = result.keyword;
- expect(keyword, isNotNull);
- expect(keyword.type.isKeyword, true);
- expect(keyword.keyword, Keyword.FINAL);
- expect(result.type, isNotNull);
- }
-
- void test_parseFinalConstVarOrType_final_namedType() {
- createParser('final A a');
- FinalConstVarOrType result = parser.parseFinalConstVarOrType(false);
- expectNotNullIfNoErrors(result);
- assertNoErrors();
- Token keyword = result.keyword;
- expect(keyword, isNotNull);
- expect(keyword.type.isKeyword, true);
- expect(keyword.keyword, Keyword.FINAL);
- expect(result.type, isNotNull);
- }
-
- void test_parseFinalConstVarOrType_final_noType() {
- createParser('final');
- FinalConstVarOrType result = parser.parseFinalConstVarOrType(false);
- expectNotNullIfNoErrors(result);
- assertNoErrors();
- Token keyword = result.keyword;
- expect(keyword, isNotNull);
- expect(keyword.type.isKeyword, true);
- expect(keyword.keyword, Keyword.FINAL);
- expect(result.type, isNull);
- }
-
- void test_parseFinalConstVarOrType_final_prefixedType() {
- createParser('final p.A a');
- FinalConstVarOrType result = parser.parseFinalConstVarOrType(false);
- expectNotNullIfNoErrors(result);
- assertNoErrors();
- Token keyword = result.keyword;
- expect(keyword, isNotNull);
- expect(keyword.type.isKeyword, true);
- expect(keyword.keyword, Keyword.FINAL);
- expect(result.type, isNotNull);
- }
-
- void test_parseFinalConstVarOrType_type_function() {
- createParser('int Function(int) f');
- FinalConstVarOrType result = parser.parseFinalConstVarOrType(false);
- expectNotNullIfNoErrors(result);
- assertNoErrors();
- expect(result.keyword, isNull);
- expect(result.type, isNotNull);
- }
-
- void test_parseFinalConstVarOrType_type_parameterized() {
- createParser('A<B> a');
- FinalConstVarOrType result = parser.parseFinalConstVarOrType(false);
- expectNotNullIfNoErrors(result);
- assertNoErrors();
- expect(result.keyword, isNull);
- expect(result.type, isNotNull);
- }
-
- void test_parseFinalConstVarOrType_type_prefixed() {
- createParser('p.A a');
- FinalConstVarOrType result = parser.parseFinalConstVarOrType(false);
- expectNotNullIfNoErrors(result);
- assertNoErrors();
- expect(result.keyword, isNull);
- expect(result.type, isNotNull);
- }
-
- void test_parseFinalConstVarOrType_type_prefixed_noIdentifier() {
- createParser('p.A,');
- FinalConstVarOrType result = parser.parseFinalConstVarOrType(false);
- expectNotNullIfNoErrors(result);
- assertNoErrors();
- expect(result.keyword, isNull);
- expect(result.type, isNotNull);
- }
-
- void test_parseFinalConstVarOrType_type_prefixedAndParameterized() {
- createParser('p.A<B> a');
- FinalConstVarOrType result = parser.parseFinalConstVarOrType(false);
- expectNotNullIfNoErrors(result);
- assertNoErrors();
- expect(result.keyword, isNull);
- expect(result.type, isNotNull);
- }
-
- void test_parseFinalConstVarOrType_type_simple() {
- createParser('A a');
- FinalConstVarOrType result = parser.parseFinalConstVarOrType(false);
- expectNotNullIfNoErrors(result);
- assertNoErrors();
- expect(result.keyword, isNull);
- expect(result.type, isNotNull);
- }
-
- void test_parseFinalConstVarOrType_type_simple_noIdentifier_inFunctionType() {
- createParser('A,');
- FinalConstVarOrType result =
- parser.parseFinalConstVarOrType(false, inFunctionType: true);
- expectNotNullIfNoErrors(result);
- assertNoErrors();
- expect(result.keyword, isNull);
- expect(result.type, isNotNull);
- }
-
- void test_parseFinalConstVarOrType_var() {
- createParser('var');
- FinalConstVarOrType result = parser.parseFinalConstVarOrType(false);
- expectNotNullIfNoErrors(result);
- assertNoErrors();
- Token keyword = result.keyword;
- expect(keyword, isNotNull);
- expect(keyword.type.isKeyword, true);
- expect(keyword.keyword, Keyword.VAR);
- expect(result.type, isNull);
- }
-
- void test_parseFinalConstVarOrType_void() {
- createParser('void f()');
- FinalConstVarOrType result = parser.parseFinalConstVarOrType(false);
- expectNotNullIfNoErrors(result);
- assertNoErrors();
- expect(result.keyword, isNull);
- expect(result.type, isNotNull);
- }
-
- void test_parseFinalConstVarOrType_void_identifier() {
- createParser('void x');
- FinalConstVarOrType result = parser.parseFinalConstVarOrType(false);
- expectNotNullIfNoErrors(result);
- assertNoErrors();
- expect(result.keyword, isNull);
- expect(result.type, isNotNull);
- }
-
- void test_parseFinalConstVarOrType_void_noIdentifier() {
- createParser('void,');
- FinalConstVarOrType result = parser.parseFinalConstVarOrType(false);
- expectNotNullIfNoErrors(result);
- listener.assertErrorsWithCodes(
- [ParserErrorCode.MISSING_CONST_FINAL_VAR_OR_TYPE]);
- }
-
- void test_parseFunctionBody_skip_block() {
- ParserTestCase.parseFunctionBodies = false;
- createParser('{}');
- FunctionBody functionBody = parser.parseFunctionBody(false, null, false);
- expectNotNullIfNoErrors(functionBody);
- assertNoErrors();
- expect(functionBody, isEmptyFunctionBody);
- }
-
- void test_parseFunctionBody_skip_block_invalid() {
- ParserTestCase.parseFunctionBodies = false;
- createParser('{');
- FunctionBody functionBody = parser.parseFunctionBody(false, null, false);
- expectNotNullIfNoErrors(functionBody);
- listener.assertErrorsWithCodes([ScannerErrorCode.EXPECTED_TOKEN]);
- expect(functionBody, isEmptyFunctionBody);
- }
-
- void test_parseFunctionBody_skip_blocks() {
- ParserTestCase.parseFunctionBodies = false;
- createParser('{ {} }');
- FunctionBody functionBody = parser.parseFunctionBody(false, null, false);
- expectNotNullIfNoErrors(functionBody);
- assertNoErrors();
- expect(functionBody, isEmptyFunctionBody);
- }
-
- void test_parseFunctionBody_skip_expression() {
- ParserTestCase.parseFunctionBodies = false;
- createParser('=> y;');
- FunctionBody functionBody = parser.parseFunctionBody(false, null, false);
- expectNotNullIfNoErrors(functionBody);
- assertNoErrors();
- expect(functionBody, isEmptyFunctionBody);
- }
-
- void test_parseModifiers_abstract() {
- createParser('abstract A');
- Modifiers modifiers = parser.parseModifiers();
- expectNotNullIfNoErrors(modifiers);
- assertNoErrors();
- expect(modifiers.abstractKeyword, isNotNull);
- }
-
- void test_parseModifiers_const() {
- createParser('const A');
- Modifiers modifiers = parser.parseModifiers();
- expectNotNullIfNoErrors(modifiers);
- assertNoErrors();
- expect(modifiers.constKeyword, isNotNull);
- }
-
- void test_parseModifiers_covariant() {
- createParser('covariant A');
- Modifiers modifiers = parser.parseModifiers();
- expectNotNullIfNoErrors(modifiers);
- assertNoErrors();
- expect(modifiers.covariantKeyword, isNotNull);
- }
-
- void test_parseModifiers_external() {
- createParser('external A');
- Modifiers modifiers = parser.parseModifiers();
- expectNotNullIfNoErrors(modifiers);
- assertNoErrors();
- expect(modifiers.externalKeyword, isNotNull);
- }
-
- void test_parseModifiers_factory() {
- createParser('factory A');
- Modifiers modifiers = parser.parseModifiers();
- expectNotNullIfNoErrors(modifiers);
- assertNoErrors();
- expect(modifiers.factoryKeyword, isNotNull);
- }
-
- void test_parseModifiers_final() {
- createParser('final A');
- Modifiers modifiers = parser.parseModifiers();
- expectNotNullIfNoErrors(modifiers);
- assertNoErrors();
- expect(modifiers.finalKeyword, isNotNull);
- }
-
- void test_parseModifiers_static() {
- createParser('static A');
- Modifiers modifiers = parser.parseModifiers();
- expectNotNullIfNoErrors(modifiers);
- assertNoErrors();
- expect(modifiers.staticKeyword, isNotNull);
- }
-
- void test_parseModifiers_var() {
- createParser('var A');
- Modifiers modifiers = parser.parseModifiers();
- expectNotNullIfNoErrors(modifiers);
- assertNoErrors();
- expect(modifiers.varKeyword, isNotNull);
- }
-
- void test_Parser() {
- expect(
- Parser(
- NonExistingSource.unknown,
- null,
- featureSet: FeatureSet.forTesting(),
- ),
- isNotNull,
- );
- }
-
- void test_skipPrefixedIdentifier_invalid() {
- createParser('+');
- Token following = parser.skipPrefixedIdentifier(parser.currentToken);
- expect(following, isNull);
- }
-
- void test_skipPrefixedIdentifier_notPrefixed() {
- createParser('a +');
- Token following = parser.skipPrefixedIdentifier(parser.currentToken);
- expect(following, isNotNull);
- expect(following.type, TokenType.PLUS);
- }
-
- void test_skipPrefixedIdentifier_prefixed() {
- createParser('a.b +');
- Token following = parser.skipPrefixedIdentifier(parser.currentToken);
- expect(following, isNotNull);
- expect(following.type, TokenType.PLUS);
- }
-
- void test_skipReturnType_invalid() {
- // TODO(eernst): `skipReturnType` eliminated, delete this test?
- createParser('+');
- Token following = parser.skipTypeAnnotation(parser.currentToken);
- expect(following, isNull);
- }
-
- void test_skipReturnType_type() {
- // TODO(eernst): `skipReturnType` eliminated, delete this test?
- createParser('C +');
- Token following = parser.skipTypeAnnotation(parser.currentToken);
- expect(following, isNotNull);
- expect(following.type, TokenType.PLUS);
- }
-
- void test_skipReturnType_void() {
- // TODO(eernst): `skipReturnType` eliminated, delete this test?
- createParser('void +');
- Token following = parser.skipTypeAnnotation(parser.currentToken);
- expect(following, isNotNull);
- expect(following.type, TokenType.PLUS);
- }
-
- void test_skipSimpleIdentifier_identifier() {
- createParser('i +');
- Token following = parser.skipSimpleIdentifier(parser.currentToken);
- expect(following, isNotNull);
- expect(following.type, TokenType.PLUS);
- }
-
- void test_skipSimpleIdentifier_invalid() {
- createParser('9 +');
- Token following = parser.skipSimpleIdentifier(parser.currentToken);
- expect(following, isNull);
- }
-
- void test_skipSimpleIdentifier_pseudoKeyword() {
- createParser('as +');
- Token following = parser.skipSimpleIdentifier(parser.currentToken);
- expect(following, isNotNull);
- expect(following.type, TokenType.PLUS);
- }
-
- void test_skipStringLiteral_adjacent() {
- createParser("'a' 'b' +");
- Token following = parser.skipStringLiteral(parser.currentToken);
- expect(following, isNotNull);
- expect(following.type, TokenType.PLUS);
- }
-
- void test_skipStringLiteral_interpolated() {
- createParser("'a\${b}c' +");
- Token following = parser.skipStringLiteral(parser.currentToken);
- expect(following, isNotNull);
- expect(following.type, TokenType.PLUS);
- }
-
- void test_skipStringLiteral_invalid() {
- createParser('a');
- Token following = parser.skipStringLiteral(parser.currentToken);
- expect(following, isNull);
- }
-
- void test_skipStringLiteral_single() {
- createParser("'a' +");
- Token following = parser.skipStringLiteral(parser.currentToken);
- expect(following, isNotNull);
- expect(following.type, TokenType.PLUS);
- }
-
- void test_skipTypeArgumentList_invalid() {
- createParser('+');
- Token following = parser.skipTypeArgumentList(parser.currentToken);
- expect(following, isNull);
- }
-
- void test_skipTypeArgumentList_multiple() {
- createParser('<E, F, G> +');
- Token following = parser.skipTypeArgumentList(parser.currentToken);
- expect(following, isNotNull);
- expect(following.type, TokenType.PLUS);
- }
-
- void test_skipTypeArgumentList_single() {
- createParser('<E> +');
- Token following = parser.skipTypeArgumentList(parser.currentToken);
- expect(following, isNotNull);
- expect(following.type, TokenType.PLUS);
- }
-
- void test_skipTypeName_invalid() {
- createParser('+');
- Token following = parser.skipTypeName(parser.currentToken);
- expect(following, isNull);
- }
-
- void test_skipTypeName_parameterized() {
- createParser('C<E<F<G>>> +');
- Token following = parser.skipTypeName(parser.currentToken);
- expect(following, isNotNull);
- expect(following.type, TokenType.PLUS);
- }
-
- void test_skipTypeName_simple() {
- createParser('C +');
- Token following = parser.skipTypeName(parser.currentToken);
- expect(following, isNotNull);
- expect(following.type, TokenType.PLUS);
- }
-
- /// Invoke the method [Parser.computeStringValue] with the given argument.
- ///
- /// @param lexeme the argument to the method
- /// @param first `true` if this is the first token in a string literal
- /// @param last `true` if this is the last token in a string literal
- /// @return the result of invoking the method
- /// @throws Exception if the method could not be invoked or throws an
- /// exception
- String _computeStringValue(String lexeme, bool first, bool last) {
- createParser('');
- String value = parser.computeStringValue(lexeme, first, last);
- assertNoErrors();
- return value;
- }
-
- /// Invoke the method [Parser.isFunctionDeclaration] with the parser set to
- /// the token stream produced by scanning the given source.
- ///
- /// @param source the source to be scanned to produce the token stream being
- /// tested
- /// @return the result of invoking the method
- /// @throws Exception if the method could not be invoked or throws an
- /// exception
- bool _isFunctionDeclaration(String source) {
- createParser(source);
- bool result = parser.isFunctionDeclaration();
- expectNotNullIfNoErrors(result);
- return result;
- }
-
- /// Invoke the method [Parser.isFunctionExpression] with the parser set to the
- /// token stream produced by scanning the given source.
- ///
- /// @param source the source to be scanned to produce the token stream being
- /// tested
- /// @return the result of invoking the method
- /// @throws Exception if the method could not be invoked or throws an
- /// exception
- bool _isFunctionExpression(String source) {
- createParser(source);
- return parser.isFunctionExpression(parser.currentToken);
- }
-
- /// Invoke the method [Parser.isInitializedVariableDeclaration] with the
- /// parser set to the token stream produced by scanning the given source.
- ///
- /// @param source the source to be scanned to produce the token stream being
- /// tested
- /// @return the result of invoking the method
- /// @throws Exception if the method could not be invoked or throws an
- /// exception
- bool _isInitializedVariableDeclaration(String source) {
- createParser(source);
- bool result = parser.isInitializedVariableDeclaration();
- expectNotNullIfNoErrors(result);
- return result;
- }
-
- /// Invoke the method [Parser.isSwitchMember] with the parser set to the token
- /// stream produced by scanning the given source.
- ///
- /// @param source the source to be scanned to produce the token stream being
- /// tested
- /// @return the result of invoking the method
- /// @throws Exception if the method could not be invoked or throws an
- /// exception
- bool _isSwitchMember(String source) {
- createParser(source);
- bool result = parser.isSwitchMember();
- expectNotNullIfNoErrors(result);
- return result;
- }
-}
-
/// Parser tests that test individual parsing methods. The code fragments should
/// be as minimal as possible in order to test the method, but should not test
/// the interactions between the method under test and other methods.
///
/// More complex tests should be defined in the class [ComplexParserTest].
-mixin SimpleParserTestMixin implements AbstractParserTestCase {
+mixin SimpleParserTestMixin implements AbstractParserViaProxyTestCase {
ConstructorName parseConstructorName(String name) {
createParser('new $name();');
Statement statement = parser.parseStatement2();
@@ -13771,7 +12082,7 @@
expect(functionBody, isBlockFunctionBody);
BlockFunctionBody body = functionBody;
expect(body.keyword, isNotNull);
- expect(body.keyword.lexeme, Parser.ASYNC);
+ expect(body.keyword.lexeme, Keyword.ASYNC.lexeme);
expect(body.star, isNull);
expect(body.block, isNotNull);
expect(body.isAsynchronous, isTrue);
@@ -13787,7 +12098,7 @@
expect(functionBody, isBlockFunctionBody);
BlockFunctionBody body = functionBody;
expect(body.keyword, isNotNull);
- expect(body.keyword.lexeme, Parser.ASYNC);
+ expect(body.keyword.lexeme, Keyword.ASYNC.lexeme);
expect(body.star, isNotNull);
expect(body.block, isNotNull);
expect(body.isAsynchronous, isTrue);
@@ -13803,7 +12114,7 @@
expect(functionBody, isBlockFunctionBody);
BlockFunctionBody body = functionBody;
expect(body.keyword, isNotNull);
- expect(body.keyword.lexeme, Parser.SYNC);
+ expect(body.keyword.lexeme, Keyword.SYNC.lexeme);
expect(body.star, isNotNull);
expect(body.block, isNotNull);
expect(body.isAsynchronous, isFalse);
@@ -13845,7 +12156,7 @@
expect(functionBody, isExpressionFunctionBody);
ExpressionFunctionBody body = functionBody;
expect(body.keyword, isNotNull);
- expect(body.keyword.lexeme, Parser.ASYNC);
+ expect(body.keyword.lexeme, Keyword.ASYNC.lexeme);
expect(body.functionDefinition, isNotNull);
expect(body.expression, isNotNull);
expect(body.semicolon, isNotNull);
@@ -13900,19 +12211,16 @@
void test_parseInstanceCreation_noKeyword_33647() {
enableOptionalNewAndConst = true;
- // Old parser produces errors
- if (usingFastaParser) {
- CompilationUnit unit = parseCompilationUnit('''
+ CompilationUnit unit = parseCompilationUnit('''
var c = Future<int>.sync(() => 3).then<int>((e) => e);
''');
- expect(unit, isNotNull);
- TopLevelVariableDeclaration v = unit.declarations[0];
- MethodInvocation init = v.variables.variables[0].initializer;
- expect(init.methodName.name, 'then');
- NodeList<TypeAnnotation> typeArg = init.typeArguments.arguments;
- expect(typeArg, hasLength(1));
- expect(typeArg[0].beginToken.lexeme, 'int');
- }
+ expect(unit, isNotNull);
+ TopLevelVariableDeclaration v = unit.declarations[0];
+ MethodInvocation init = v.variables.variables[0].initializer;
+ expect(init.methodName.name, 'then');
+ NodeList<TypeAnnotation> typeArg = init.typeArguments.arguments;
+ expect(typeArg, hasLength(1));
+ expect(typeArg[0].beginToken.lexeme, 'int');
}
void test_parseInstanceCreation_noKeyword_noPrefix() {
@@ -13934,9 +12242,6 @@
}
void test_parseInstanceCreation_noKeyword_noPrefix_34403() {
- if (!usingFastaParser) {
- return;
- }
enableOptionalNewAndConst = true;
createParser('f() => C<E>.n<B>();');
CompilationUnit unit = parser.parseCompilationUnit2();
@@ -13998,14 +12303,10 @@
}
void test_parseLibraryIdentifier_invalid() {
- parseCompilationUnit('library <myLibId>;',
- errors: usingFastaParser
- ? [
- expectedError(
- ParserErrorCode.MISSING_FUNCTION_PARAMETERS, 0, 7),
- expectedError(ParserErrorCode.MISSING_FUNCTION_BODY, 17, 1),
- ]
- : [expectedError(ParserErrorCode.EXPECTED_EXECUTABLE, 8, 1)]);
+ parseCompilationUnit('library <myLibId>;', errors: [
+ expectedError(ParserErrorCode.MISSING_FUNCTION_PARAMETERS, 0, 7),
+ expectedError(ParserErrorCode.MISSING_FUNCTION_BODY, 17, 1),
+ ]);
}
void test_parseLibraryIdentifier_multiple() {
@@ -14462,18 +12763,10 @@
void test_parseTypeParameterList_single() {
createParser('<<A>', expectedEndOffset: 0);
TypeParameterList parameterList = parser.parseTypeParameterList();
- if (usingFastaParser) {
- // TODO(danrubel): Consider splitting `<<` and marking the first `<`
- // as an unexpected token.
- expect(parameterList, isNull);
- assertNoErrors();
- } else {
- expectNotNullIfNoErrors(parameterList);
- assertNoErrors();
- expect(parameterList.leftBracket, isNotNull);
- expect(parameterList.rightBracket, isNotNull);
- expect(parameterList.typeParameters, hasLength(1));
- }
+ // TODO(danrubel): Consider splitting `<<` and marking the first `<`
+ // as an unexpected token.
+ expect(parameterList, isNull);
+ assertNoErrors();
}
void test_parseTypeParameterList_withTrailingEquals() {
@@ -14521,42 +12814,23 @@
}
}
-@reflectiveTest
-class StatementParserTest extends ParserTestCase with StatementParserTestMixin {
-}
-
/// The class [FormalParameterParserTestMixin] defines parser tests that test
/// the parsing statements.
mixin StatementParserTestMixin implements AbstractParserTestCase {
void test_invalid_typeParamAnnotation() {
- parseCompilationUnit('main() { C<@Foo T> v; }',
- errors: usingFastaParser
- ? [
- expectedError(
- ParserErrorCode.ANNOTATION_ON_TYPE_ARGUMENT, 11, 4)
- ]
- : [
- expectedError(ParserErrorCode.MISSING_IDENTIFIER, 11, 1),
- expectedError(ParserErrorCode.EXPECTED_TOKEN, 11, 1)
- ]);
+ parseCompilationUnit('main() { C<@Foo T> v; }', errors: [
+ expectedError(ParserErrorCode.ANNOTATION_ON_TYPE_ARGUMENT, 11, 4)
+ ]);
}
void test_invalid_typeParamAnnotation2() {
- parseCompilationUnit('main() { C<@Foo.bar(1) T> v; }',
- errors: usingFastaParser
- ? [
- expectedError(
- ParserErrorCode.ANNOTATION_ON_TYPE_ARGUMENT, 11, 11)
- ]
- : [
- expectedError(ParserErrorCode.MISSING_IDENTIFIER, 11, 1),
- expectedError(ParserErrorCode.EXPECTED_TOKEN, 11, 1)
- ]);
+ parseCompilationUnit('main() { C<@Foo.bar(1) T> v; }', errors: [
+ expectedError(ParserErrorCode.ANNOTATION_ON_TYPE_ARGUMENT, 11, 11)
+ ]);
}
void test_invalid_typeParamAnnotation3() {
- if (usingFastaParser) {
- parseCompilationUnit('''
+ parseCompilationUnit('''
main() {
C<@Foo.bar(const [], const [1], const{"":r""}, 0xFF + 2, .3, 4.5) T,
F Function<G>(int, String, {Bar b}),
@@ -14565,9 +12839,8 @@
W<X<Y<Z>>>
> v;
}''', errors: [
- expectedError(ParserErrorCode.ANNOTATION_ON_TYPE_ARGUMENT, 13, 63)
- ]);
- }
+ expectedError(ParserErrorCode.ANNOTATION_ON_TYPE_ARGUMENT, 13, 63)
+ ]);
}
void test_parseAssertStatement() {
@@ -14705,17 +12978,11 @@
}
void test_parseElseAlone() {
- parseCompilationUnit('main() { else return 0; } ',
- errors: usingFastaParser
- ? [
- expectedError(ParserErrorCode.MISSING_IDENTIFIER, 9, 4),
- expectedError(ParserErrorCode.EXPECTED_TOKEN, 9, 4),
- expectedError(ParserErrorCode.UNEXPECTED_TOKEN, 9, 4),
- ]
- : [
- expectedError(ParserErrorCode.MISSING_STATEMENT, 9, 4),
- expectedError(ParserErrorCode.UNEXPECTED_TOKEN, 9, 4),
- ]);
+ parseCompilationUnit('main() { else return 0; } ', errors: [
+ expectedError(ParserErrorCode.MISSING_IDENTIFIER, 9, 4),
+ expectedError(ParserErrorCode.EXPECTED_TOKEN, 9, 4),
+ expectedError(ParserErrorCode.UNEXPECTED_TOKEN, 9, 4),
+ ]);
}
void test_parseEmptyStatement() {
@@ -14730,7 +12997,7 @@
String code = 'await for (element in list) {}';
var forStatement = _parseAsyncStatement(code) as ForStatement;
assertNoErrors();
- expect(forStatement.awaitKeyword, usingFastaParser ? isNotNull : isNull);
+ expect(forStatement.awaitKeyword, isNotNull);
expect(forStatement.forKeyword, isNotNull);
expect(forStatement.leftParenthesis, isNotNull);
var forEachParts = forStatement.forLoopParts as ForEachPartsWithIdentifier;
@@ -15143,9 +13410,6 @@
}
void test_parseNonLabeledStatement_const_object_named_typeParameters_34403() {
- if (!usingFastaParser) {
- return;
- }
var statement = parseStatement('const A<B>.c<C>();') as ExpressionStatement;
assertErrorsWithCodes(
[CompileTimeErrorCode.WRONG_NUMBER_OF_TYPE_ARGUMENTS_CONSTRUCTOR]);
@@ -15586,18 +13850,9 @@
}
void test_parseTryStatement_catch_error_invalidCatchParam() {
- CompilationUnit unit =
- parseCompilationUnit('main() { try {} catch (int e) { } }',
- errors: usingFastaParser
- ? [expectedError(ParserErrorCode.CATCH_SYNTAX, 27, 1)]
- : [
- expectedError(ParserErrorCode.EXPECTED_TOKEN, 27, 1),
- expectedError(ParserErrorCode.EXPECTED_TOKEN, 27, 1),
- expectedError(ParserErrorCode.EXPECTED_TOKEN, 27, 1),
- expectedError(ParserErrorCode.MISSING_IDENTIFIER, 28, 1),
- expectedError(ParserErrorCode.EXPECTED_TOKEN, 28, 1),
- expectedError(ParserErrorCode.UNEXPECTED_TOKEN, 28, 1),
- ]);
+ CompilationUnit unit = parseCompilationUnit(
+ 'main() { try {} catch (int e) { } }',
+ errors: [expectedError(ParserErrorCode.CATCH_SYNTAX, 27, 1)]);
FunctionDeclaration method = unit.declarations[0];
BlockFunctionBody body = method.functionExpression.body;
TryStatement statement = body.block.statements[0];
@@ -15609,15 +13864,9 @@
expect(clause.onKeyword, isNull);
expect(clause.exceptionType, isNull);
expect(clause.catchKeyword, isNotNull);
- if (usingFastaParser) {
- expect(clause.exceptionParameter.name, 'int');
- expect(clause.comma, isNotNull);
- expect(clause.stackTraceParameter.name, 'e');
- } else {
- expect(clause.exceptionParameter.name, 'int');
- expect(clause.comma, isNull);
- expect(clause.stackTraceParameter, isNull);
- }
+ expect(clause.exceptionParameter.name, 'int');
+ expect(clause.comma, isNotNull);
+ expect(clause.stackTraceParameter.name, 'e');
expect(clause.body, isNotNull);
expect(statement.finallyKeyword, isNull);
expect(statement.finallyBlock, isNull);
@@ -15625,11 +13874,7 @@
void test_parseTryStatement_catch_error_missingCatchParam() {
var statement = parseStatement('try {} catch () {}') as TryStatement;
- listener.assertErrors(usingFastaParser
- ? [expectedError(ParserErrorCode.CATCH_SYNTAX, 14, 1)]
- : [
- expectedError(ParserErrorCode.MISSING_IDENTIFIER, 14, 1),
- ]);
+ listener.assertErrors([expectedError(ParserErrorCode.CATCH_SYNTAX, 14, 1)]);
expect(statement.tryKeyword, isNotNull);
expect(statement.body, isNotNull);
NodeList<CatchClause> catchClauses = statement.catchClauses;
@@ -15648,13 +13893,7 @@
void test_parseTryStatement_catch_error_missingCatchParen() {
var statement = parseStatement('try {} catch {}') as TryStatement;
- listener.assertErrors(usingFastaParser
- ? [expectedError(ParserErrorCode.CATCH_SYNTAX, 13, 1)]
- : [
- expectedError(ParserErrorCode.EXPECTED_TOKEN, 13, 1),
- expectedError(ParserErrorCode.MISSING_IDENTIFIER, 13, 1),
- expectedError(ParserErrorCode.EXPECTED_TOKEN, 13, 1)
- ]);
+ listener.assertErrors([expectedError(ParserErrorCode.CATCH_SYNTAX, 13, 1)]);
expect(statement.tryKeyword, isNotNull);
expect(statement.body, isNotNull);
NodeList<CatchClause> catchClauses = statement.catchClauses;
@@ -15673,11 +13912,7 @@
void test_parseTryStatement_catch_error_missingCatchTrace() {
var statement = parseStatement('try {} catch (e,) {}') as TryStatement;
- listener.assertErrors(usingFastaParser
- ? [expectedError(ParserErrorCode.CATCH_SYNTAX, 16, 1)]
- : [
- expectedError(ParserErrorCode.MISSING_IDENTIFIER, 14, 1),
- ]);
+ listener.assertErrors([expectedError(ParserErrorCode.CATCH_SYNTAX, 16, 1)]);
expect(statement.tryKeyword, isNotNull);
expect(statement.body, isNotNull);
NodeList<CatchClause> catchClauses = statement.catchClauses;
@@ -15927,9 +14162,6 @@
}
}
-@reflectiveTest
-class TopLevelParserTest extends ParserTestCase with TopLevelParserTestMixin {}
-
/// Tests which exercise the parser using a complete compilation unit or
/// compilation unit member.
mixin TopLevelParserTestMixin implements AbstractParserTestCase {
@@ -16267,16 +14499,7 @@
void test_parseClassDeclaration_typeParameters_extends_void() {
parseCompilationUnit('class C<T extends void>{}',
- errors: usingFastaParser
- ? [expectedError(ParserErrorCode.EXPECTED_TYPE_NAME, 18, 4)]
- : [
- expectedError(ParserErrorCode.EXPECTED_TYPE_NAME, 18, 4),
- expectedError(ParserErrorCode.EXPECTED_TOKEN, 18, 4),
- expectedError(ParserErrorCode.EXPECTED_BODY, 18, 4),
- expectedError(ParserErrorCode.EXPECTED_EXECUTABLE, 22, 1),
- expectedError(ParserErrorCode.EXPECTED_EXECUTABLE, 22, 1),
- expectedError(ParserErrorCode.UNEXPECTED_TOKEN, 22, 1),
- ]);
+ errors: [expectedError(ParserErrorCode.EXPECTED_TYPE_NAME, 18, 4)]);
}
void test_parseClassDeclaration_withDocumentationComment() {
@@ -16293,11 +14516,9 @@
void test_parseCompilationUnit_abstractAsPrefix_parameterized() {
var errorCodes = <ErrorCode>[];
- if (usingFastaParser) {
- // This used to be deferred to later in the pipeline, but is now being
- // reported by the parser.
- errorCodes.add(CompileTimeErrorCode.BUILT_IN_IDENTIFIER_AS_TYPE);
- }
+ // This used to be deferred to later in the pipeline, but is now being
+ // reported by the parser.
+ errorCodes.add(CompileTimeErrorCode.BUILT_IN_IDENTIFIER_AS_TYPE);
CompilationUnit unit = parseCompilationUnit(
'abstract<dynamic> _abstract = new abstract.A();',
codes: errorCodes);
@@ -16318,16 +14539,14 @@
}
void test_parseCompilationUnit_builtIn_asFunctionName_withTypeParameter() {
- if (usingFastaParser) {
- for (Keyword keyword in Keyword.values) {
- if (keyword.isBuiltIn || keyword.isPseudo) {
- String lexeme = keyword.lexeme;
- if (lexeme == 'Function') continue;
- // The fasta type resolution phase will report an error
- // on type arguments on `dynamic` (e.g. `dynamic<int>`).
- parseCompilationUnit('$lexeme<T>(x) => 0;');
- parseCompilationUnit('class C {$lexeme<T>(x) => 0;}');
- }
+ for (Keyword keyword in Keyword.values) {
+ if (keyword.isBuiltIn || keyword.isPseudo) {
+ String lexeme = keyword.lexeme;
+ if (lexeme == 'Function') continue;
+ // The fasta type resolution phase will report an error
+ // on type arguments on `dynamic` (e.g. `dynamic<int>`).
+ parseCompilationUnit('$lexeme<T>(x) => 0;');
+ parseCompilationUnit('class C {$lexeme<T>(x) => 0;}');
}
}
}
@@ -16389,13 +14608,9 @@
createParser('export<dynamic> _export = new export.A();');
CompilationUnit unit = parser.parseCompilationUnit2();
expect(unit, isNotNull);
- if (usingFastaParser) {
- // This used to be deferred to later in the pipeline, but is now being
- // reported by the parser.
- assertErrorsWithCodes([CompileTimeErrorCode.BUILT_IN_IDENTIFIER_AS_TYPE]);
- } else {
- assertNoErrors();
- }
+ // This used to be deferred to later in the pipeline, but is now being
+ // reported by the parser.
+ assertErrorsWithCodes([CompileTimeErrorCode.BUILT_IN_IDENTIFIER_AS_TYPE]);
expect(unit.scriptTag, isNull);
expect(unit.directives, hasLength(0));
expect(unit.declarations, hasLength(1));
@@ -16405,13 +14620,9 @@
createParser('operator<dynamic> _operator = new operator.A();');
CompilationUnit unit = parser.parseCompilationUnit2();
expect(unit, isNotNull);
- if (usingFastaParser) {
- // This used to be deferred to later in the pipeline, but is now being
- // reported by the parser.
- assertErrorsWithCodes([CompileTimeErrorCode.BUILT_IN_IDENTIFIER_AS_TYPE]);
- } else {
- assertNoErrors();
- }
+ // This used to be deferred to later in the pipeline, but is now being
+ // reported by the parser.
+ assertErrorsWithCodes([CompileTimeErrorCode.BUILT_IN_IDENTIFIER_AS_TYPE]);
expect(unit.scriptTag, isNull);
expect(unit.directives, hasLength(0));
expect(unit.declarations, hasLength(1));
diff --git a/pkg/analyzer/test/generated/test_support.dart b/pkg/analyzer/test/generated/test_support.dart
index ad8cc0b..43a53ee 100644
--- a/pkg/analyzer/test/generated/test_support.dart
+++ b/pkg/analyzer/test/generated/test_support.dart
@@ -7,7 +7,6 @@
import 'package:analyzer/error/listener.dart';
import 'package:analyzer/instrumentation/instrumentation.dart';
import 'package:analyzer/src/generated/engine.dart';
-import 'package:analyzer/src/generated/parser.dart';
import 'package:analyzer/src/generated/source.dart';
import 'package:test/test.dart';
@@ -117,7 +116,7 @@
final Map<Source, LineInfo> _lineInfoMap = <Source, LineInfo>{};
/// Initialize a newly created error listener to collect errors.
- GatheringErrorListener({this.checkRanges = Parser.useFasta});
+ GatheringErrorListener({this.checkRanges = true});
/// Return the errors that were collected.
List<AnalysisError> get errors => _errors;
diff --git a/pkg/analyzer/test/src/dart/analysis/base.dart b/pkg/analyzer/test/src/dart/analysis/base.dart
index f9e47a8..166c8b9 100644
--- a/pkg/analyzer/test/src/dart/analysis/base.dart
+++ b/pkg/analyzer/test/src/dart/analysis/base.dart
@@ -16,7 +16,6 @@
import 'package:analyzer/src/dart/analysis/status.dart';
import 'package:analyzer/src/file_system/file_system.dart';
import 'package:analyzer/src/generated/engine.dart' show AnalysisOptionsImpl;
-import 'package:analyzer/src/generated/parser.dart' as analyzer;
import 'package:analyzer/src/generated/sdk.dart';
import 'package:analyzer/src/generated/source.dart';
import 'package:analyzer/src/source/package_map_resolver.dart';
@@ -125,7 +124,7 @@
}
AnalysisOptionsImpl createAnalysisOptions() => AnalysisOptionsImpl()
- ..useFastaParser = analyzer.Parser.useFasta
+ ..useFastaParser = true
..contextFeatures = FeatureSet.fromEnableFlags2(
sdkLanguageVersion: ExperimentStatus.testingSdkLanguageVersion,
flags: enabledExperiments,
diff --git a/pkg/analyzer/test/src/dart/ast/parse_base.dart b/pkg/analyzer/test/src/dart/ast/parse_base.dart
index d280721..eb662b2 100644
--- a/pkg/analyzer/test/src/dart/ast/parse_base.dart
+++ b/pkg/analyzer/test/src/dart/ast/parse_base.dart
@@ -36,12 +36,10 @@
var token = scanner.tokenize();
featureSet = scanner.featureSet;
- var useFasta = analysisOptions.useFastaParser;
var parser = Parser(
source,
errorListener,
featureSet: featureSet,
- useFasta: useFasta,
);
parser.enableOptionalNewAndConst = true;
diff --git a/pkg/compiler/lib/src/common_elements.dart b/pkg/compiler/lib/src/common_elements.dart
index 8d84fe7..0cb4190 100644
--- a/pkg/compiler/lib/src/common_elements.dart
+++ b/pkg/compiler/lib/src/common_elements.dart
@@ -449,6 +449,8 @@
FunctionEntity getInstantiateFunction(int typeArgumentCount);
+ FunctionEntity get convertMainArgumentList;
+
// From dart:_rti
FunctionEntity get setRuntimeTypeInfo;
@@ -1834,6 +1836,10 @@
cls.name.startsWith('Instantiation');
}
+ @override
+ FunctionEntity get convertMainArgumentList =>
+ _findHelperFunction('convertMainArgumentList');
+
// From dart:_rti
ClassEntity _findRtiClass(String name) => _findClass(rtiLibrary, name);
diff --git a/pkg/compiler/lib/src/js_backend/backend_impact.dart b/pkg/compiler/lib/src/js_backend/backend_impact.dart
index 5f63cfb..39c5e4f 100644
--- a/pkg/compiler/lib/src/js_backend/backend_impact.dart
+++ b/pkg/compiler/lib/src/js_backend/backend_impact.dart
@@ -117,10 +117,13 @@
BackendImpact _mainWithArguments;
BackendImpact get mainWithArguments {
- return _mainWithArguments ??= new BackendImpact(instantiatedClasses: [
- _commonElements.jsArrayClass,
- _commonElements.jsStringClass
- ]);
+ return _mainWithArguments ??= new BackendImpact(
+ globalUses: [_commonElements.convertMainArgumentList],
+ instantiatedClasses: [
+ _commonElements.jsArrayClass,
+ _commonElements.jsStringClass
+ ],
+ );
}
BackendImpact _asyncBody;
diff --git a/pkg/compiler/lib/src/js_emitter/main_call_stub_generator.dart b/pkg/compiler/lib/src/js_emitter/main_call_stub_generator.dart
index e20f889..d26bb2e 100644
--- a/pkg/compiler/lib/src/js_emitter/main_call_stub_generator.dart
+++ b/pkg/compiler/lib/src/js_emitter/main_call_stub_generator.dart
@@ -9,16 +9,58 @@
import '../elements/entities.dart';
import '../js/js.dart' as jsAst;
import '../js/js.dart' show js;
+import '../common_elements.dart';
import 'code_emitter_task.dart' show Emitter;
class MainCallStubGenerator {
static jsAst.Statement generateInvokeMain(
- Emitter emitter, FunctionEntity main) {
- jsAst.Expression mainCallClosure = emitter.staticFunctionAccess(main);
+ CommonElements commonElements, Emitter emitter, FunctionEntity main) {
+ jsAst.Expression mainAccess = emitter.staticFunctionAccess(main);
jsAst.Expression currentScriptAccess =
emitter.generateEmbeddedGlobalAccess(embeddedNames.CURRENT_SCRIPT);
+ // TODO(https://github.com/dart-lang/language/issues/1120#issuecomment-670802088):
+ // Validate constraints on `main()` in resolution for dart2js, and in DDC.
+
+ final parameterStructure = main.parameterStructure;
+
+ // The forwarding stub passes all arguments, i.e. both required and optional
+ // positional arguments. We ignore named arguments, assuming the `main()`
+ // has been validated earlier.
+ int positionalParameters = parameterStructure.positionalParameters;
+
+ jsAst.Expression mainCallClosure;
+ if (positionalParameters == 0) {
+ if (parameterStructure.namedParameters.isEmpty) {
+ // e.g. `void main()`.
+ // No parameters. The compiled Dart `main` has no parameters and will
+ // ignore any extra parameters passed in, so it can be used directly.
+ mainCallClosure = mainAccess;
+ } else {
+ // e.g. `void main({arg})`. We should not get here. Drop the named
+ // arguments as we don't know how to convert them.
+ mainCallClosure = js(r'''function() { return #(); }''', mainAccess);
+ }
+ } else {
+ jsAst.Expression convertArgumentList =
+ emitter.staticFunctionAccess(commonElements.convertMainArgumentList);
+ if (positionalParameters == 1) {
+ // e.g. `void main(List<String> args)`, `main([args])`.
+ mainCallClosure = js(
+ r'''function(args) { return #(#(args)); }''',
+ [mainAccess, convertArgumentList],
+ );
+ } else {
+ // positionalParameters == 2.
+ // e.g. `void main(List<String> args, Object? extra)`
+ mainCallClosure = js(
+ r'''function(args, extra) { return #(#(args), extra); }''',
+ [mainAccess, convertArgumentList],
+ );
+ }
+ }
+
// This code finds the currently executing script by listening to the
// onload event of all script tags and getting the first script which
// finishes. Since onload is called immediately after execution this should
@@ -48,11 +90,11 @@
}
})(function(currentScript) {
#currentScript = currentScript;
-
+ var callMain = #mainCallClosure;
if (typeof dartMainRunner === "function") {
- dartMainRunner(#mainCallClosure, []);
+ dartMainRunner(callMain, []);
} else {
- #mainCallClosure([]);
+ callMain([]);
}
})''', {
'currentScript': currentScriptAccess,
diff --git a/pkg/compiler/lib/src/js_emitter/program_builder/program_builder.dart b/pkg/compiler/lib/src/js_emitter/program_builder/program_builder.dart
index 351d6bc..99e7544 100644
--- a/pkg/compiler/lib/src/js_emitter/program_builder/program_builder.dart
+++ b/pkg/compiler/lib/src/js_emitter/program_builder/program_builder.dart
@@ -388,7 +388,7 @@
js.Statement _buildInvokeMain() {
return MainCallStubGenerator.generateInvokeMain(
- _task.emitter, _mainFunction);
+ _commonElements, _task.emitter, _mainFunction);
}
DeferredFragment _buildDeferredFragment(LibrariesMap librariesMap) {
diff --git a/pkg/dev_compiler/lib/src/compiler/module_containers.dart b/pkg/dev_compiler/lib/src/compiler/module_containers.dart
index 6c76688..267afb5 100644
--- a/pkg/dev_compiler/lib/src/compiler/module_containers.dart
+++ b/pkg/dev_compiler/lib/src/compiler/module_containers.dart
@@ -35,11 +35,11 @@
/// ...
/// };
/// ```
-class ModuleItemContainer<K> {
+abstract class ModuleItemContainer<K> {
/// Name of the container in the emitted JS.
String name;
- /// If null, this container will be automatically renamed based on [name].
+ /// Refers to the latest container if this container is sharded.
js_ast.Identifier containerId;
final Map<K, ModuleItemData> moduleItems = {};
@@ -66,43 +66,15 @@
int get length => moduleItems.keys.length;
+ bool get isEmpty => moduleItems.isEmpty;
+
js_ast.Expression operator [](K key) => moduleItems[key]?.jsValue;
- void operator []=(K key, js_ast.Expression value) {
- if (moduleItems.containsKey(key)) {
- moduleItems[key].jsValue = value;
- return;
- }
- var fieldString = '$key';
- // Avoid shadowing common JS properties.
- if (js_ast.objectProperties.contains(fieldString)) {
- fieldString += '\$';
- }
- moduleItems[key] = ModuleItemData(
- containerId, js_ast.LiteralString("'$fieldString'"), value);
- }
+ void operator []=(K key, js_ast.Expression value);
/// Returns the expression that retrieves [key]'s corresponding JS value via
/// a property access through its container.
- js_ast.Expression access(K key) {
- return js.call('#.#', [containerId, moduleItems[key].jsKey]);
- }
-
- /// Emit the container declaration/initializer.
- ///
- /// May be multiple statements if the container is automatically sharded.
- List<js_ast.Statement> emit() {
- var properties = <js_ast.Property>[];
- moduleItems.forEach((k, v) {
- if (!_noEmit.contains(k)) return;
- properties.add(js_ast.Property(v.jsKey, v.jsValue));
- });
- var containerObject =
- js_ast.ObjectInitializer(properties, multiline: properties.length > 1);
- return [
- js.statement('var # = Object.create(#)', [containerId, containerObject])
- ];
- }
+ js_ast.Expression access(K key);
bool contains(K key) => moduleItems.containsKey(key);
@@ -115,6 +87,16 @@
void setNoEmit(K key) {
_noEmit.add(key);
}
+
+ /// Emit the container declaration/initializer, using multiple statements if
+ /// necessary.
+ List<js_ast.Statement> emit();
+
+ /// Emit the container declaration/initializer incrementally.
+ ///
+ /// Used during expression evaluation. Appends all newly added types to the
+ /// most recent container.
+ List<js_ast.Statement> emitIncremental();
}
/// Associates a [K] with a container-unique JS key and arbitrary JS value.
@@ -129,9 +111,6 @@
/// var C$1 = { ... };
/// ```
class ModuleItemObjectContainer<K> extends ModuleItemContainer<K> {
- /// Holds the TemporaryId for the current container shard.
- js_ast.Identifier _currentContainerId;
-
/// Tracks how often JS emitted field names appear.
///
/// [keyToString] may resolve multiple unique keys to the same JS string.
@@ -144,7 +123,7 @@
String Function(K) keyToString;
ModuleItemObjectContainer(String name, this.keyToString)
- : super._(name, null);
+ : super._(name, js_ast.TemporaryId(name));
@override
void operator []=(K key, js_ast.Expression value) {
@@ -152,7 +131,6 @@
moduleItems[key].jsValue = value;
return;
}
- if (length % 500 == 0) _currentContainerId = js_ast.TemporaryId(name);
// Create a unique name for K when emitted as a JS field.
var fieldString = keyToString(key);
_nameFrequencies.update(fieldString, (v) {
@@ -166,7 +144,8 @@
return 0;
});
moduleItems[key] = ModuleItemData(
- _currentContainerId, js_ast.LiteralString("'$fieldString'"), value);
+ containerId, js_ast.LiteralString("'$fieldString'"), value);
+ if (length % 500 == 0) containerId = js_ast.TemporaryId(name);
}
@override
@@ -185,6 +164,14 @@
containersToProperties[v.id].add(js_ast.Property(v.jsKey, v.jsValue));
});
+ // Emit a self-reference for the next container so V8 does not optimize it
+ // away. Required for expression evaluation.
+ if (containersToProperties[containerId] == null) {
+ containersToProperties[containerId] = [
+ js_ast.Property(
+ js_ast.LiteralString('_'), js.call('() => #', [containerId]))
+ ];
+ }
var statements = <js_ast.Statement>[];
containersToProperties.forEach((containerId, properties) {
var containerObject = js_ast.ObjectInitializer(properties,
@@ -194,6 +181,18 @@
});
return statements;
}
+
+ /// Appends all newly added types to the most recent container.
+ @override
+ List<js_ast.Statement> emitIncremental() {
+ var statements = <js_ast.Statement>[];
+ moduleItems.forEach((k, v) {
+ if (_noEmit.contains(k)) return;
+ statements
+ .add(js.statement('#[#] = #', [containerId, v.jsKey, v.jsValue]));
+ });
+ return statements;
+ }
}
/// Associates a unique [K] with an arbitrary JS value.
@@ -226,7 +225,6 @@
@override
List<js_ast.Statement> emit() {
- if (moduleItems.isEmpty) return [];
var properties = List<js_ast.Expression>.filled(length, null);
// If the entire array holds just one value, generate a short initializer.
@@ -256,4 +254,15 @@
])
];
}
+
+ @override
+ List<js_ast.Statement> emitIncremental() {
+ var statements = <js_ast.Statement>[];
+ moduleItems.forEach((k, v) {
+ if (_noEmit.contains(k)) return;
+ statements
+ .add(js.statement('#[#] = #', [containerId, v.jsKey, v.jsValue]));
+ });
+ return statements;
+ }
}
diff --git a/pkg/dev_compiler/lib/src/kernel/compiler.dart b/pkg/dev_compiler/lib/src/kernel/compiler.dart
index 46ee30d..ba707e4 100644
--- a/pkg/dev_compiler/lib/src/kernel/compiler.dart
+++ b/pkg/dev_compiler/lib/src/kernel/compiler.dart
@@ -364,6 +364,17 @@
_pendingClasses.addAll(l.classes);
}
+ // Insert a circular reference so neither the constant table or its cache
+ // are optimized away by V8. Required for expression evaluation.
+ var constTableDeclaration =
+ js.statement('const # = Object.create({# : () => (#, #)});', [
+ _constTable,
+ js_ast.LiteralString('_'),
+ _constTableCache.containerId,
+ _constTable
+ ]);
+ moduleItems.add(constTableDeclaration);
+
// Record a safe index after the declaration of type generators and
// top-level symbols but before the declaration of any functions.
// Various preliminary data structures must be inserted here prior before
@@ -384,19 +395,12 @@
// Emit hoisted assert strings
moduleItems.insertAll(safeDeclarationIndex, _uriContainer.emit());
- if (_constTableCache.isNotEmpty) {
- moduleItems.insertAll(safeDeclarationIndex, _constTableCache.emit());
- }
+ moduleItems.insertAll(safeDeclarationIndex, _constTableCache.emit());
- // This can cause problems if it's ever true during the SDK build, as it's
- // emitted before dart.defineLazy.
if (_constLazyAccessors.isNotEmpty) {
- var constTableDeclaration =
- js.statement('const # = Object.create(null);', [_constTable]);
var constTableBody = runtimeStatement(
'defineLazy(#, { # }, false)', [_constTable, _constLazyAccessors]);
- moduleItems.insertAll(
- _constTableInsertionIndex, [constTableDeclaration, constTableBody]);
+ moduleItems.insert(_constTableInsertionIndex, constTableBody);
_constLazyAccessors.clear();
}
@@ -3093,8 +3097,9 @@
// Issue: https://github.com/dart-lang/sdk/issues/43288
var fun = _emitFunction(functionNode, name);
- var types = _typeTable?.dischargeFreeTypes();
+ var types = _typeTable?.dischargeBoundTypes(incremental: true);
var constants = _dischargeConstTable();
+
var body = js_ast.Block([...?types, ...?constants, ...fun.body.statements]);
return js_ast.Fun(fun.params, body);
}
diff --git a/pkg/dev_compiler/lib/src/kernel/type_table.dart b/pkg/dev_compiler/lib/src/kernel/type_table.dart
index b9b73fd..d25ae97 100644
--- a/pkg/dev_compiler/lib/src/kernel/type_table.dart
+++ b/pkg/dev_compiler/lib/src/kernel/type_table.dart
@@ -122,12 +122,20 @@
/// Emit the initializer statements for the type container, which contains
/// all named types with fully bound type parameters.
- List<js_ast.Statement> dischargeBoundTypes() {
+ ///
+ /// [incremental] is only used for expression evaluation.
+ List<js_ast.Statement> dischargeBoundTypes({bool incremental = false}) {
for (var t in typeContainer.keys) {
typeContainer[t] = js.call('() => ((# = #.constFn(#))())',
[typeContainer.access(t), _runtimeModule, typeContainer[t]]);
}
- return typeContainer.emit();
+ var boundTypes =
+ incremental ? typeContainer.emitIncremental() : typeContainer.emit();
+ // Bound types should only be emitted once (even across multiple evals).
+ for (var t in typeContainer.keys) {
+ typeContainer.setNoEmit(t);
+ }
+ return boundTypes;
}
js_ast.Statement _dischargeFreeType(DartType type) {
diff --git a/pkg/dev_compiler/test/expression_compiler/expression_compiler_test.dart b/pkg/dev_compiler/test/expression_compiler/expression_compiler_test.dart
index 1209475..bd36fbb 100644
--- a/pkg/dev_compiler/test/expression_compiler/expression_compiler_test.dart
+++ b/pkg/dev_compiler/test/expression_compiler/expression_compiler_test.dart
@@ -452,14 +452,13 @@
expression: 'main',
expectedResult: '''
(function(x, y, z) {
- var VoidTodynamic = () => (VoidTodynamic = dart.constFn(dart.fnType(dart.dynamic, [])))();
+ T.VoidTodynamic = () => (T.VoidTodynamic = dart.constFn(dart.fnType(dart.dynamic, [])))();
dart.defineLazy(CT, {
get C0() {
- return C0 = dart.fn(foo.main, VoidTodynamic());
+ return C[0] = dart.fn(foo.main, T.VoidTodynamic());
}
}, false);
- var C0;
- return C0 || CT.C0;
+ return C[0] || CT.C0;
}(
1,
2,
@@ -1342,8 +1341,8 @@
expression: 'baz(p as String)',
expectedResult: '''
(function(p) {
- var StringL = () => (StringL = dart.constFn(dart.legacy(core.String)))();
- return foo.baz(StringL().as(p));
+ T.StringL = () => (T.StringL = dart.constFn(dart.legacy(core.String)))();
+ return foo.baz(T.StringL().as(p));
}(
0
))
@@ -1358,14 +1357,13 @@
(function(p) {
dart.defineLazy(CT, {
get C0() {
- return C0 = dart.const({
+ return C[0] = dart.const({
__proto__: foo.MyClass.prototype,
[_t]: 1
});
}
}, false);
- var C0;
- return C0 || CT.C0;
+ return C[0] || CT.C0;
}(
1
))
@@ -1407,14 +1405,13 @@
(function(p) {
dart.defineLazy(CT, {
get C0() {
- return C0 = dart.const({
+ return C[0] = dart.const({
__proto__: foo.ValueKey.prototype,
[value]: "t"
});
}
}, false);
- var C0;
- return C0 || CT.C0;
+ return C[0] || CT.C0;
}(
1
))
@@ -1927,6 +1924,103 @@
expectedError: "Error: Getter not found: 'z'");
});
});
+
+ group('Expression compiler tests for interactions with module containers:',
+ () {
+ var source = '''
+ ${options.dartLangComment}
+ class A {
+ const A();
+ }
+ class B {
+ const B();
+ }
+ void foo() {
+ const a = A();
+ var check = a is int;
+ /* evaluation placeholder */
+ return;
+ }
+
+ void main() => foo();
+ ''';
+
+ TestDriver driver;
+ setUp(() {
+ driver = TestDriver(options, source);
+ });
+
+ tearDown(() {
+ driver.delete();
+ });
+
+ test('evaluation that non-destructively appends to the type container',
+ () async {
+ await driver.check(
+ scope: <String, String>{'a': 'null', 'check': 'null'},
+ expression: 'a is String',
+ expectedResult: '''
+ (function(a, check) {
+ T.StringL = () => (T.StringL = dart.constFn(dart.legacy(core.String)))();
+ return T.StringL().is(a);
+ }(
+ null,
+ null
+ ))
+ ''');
+ });
+
+ test('evaluation that reuses the type container', () async {
+ await driver.check(
+ scope: <String, String>{'a': 'null', 'check': 'null'},
+ expression: 'a is int',
+ expectedResult: '''
+ (function(a, check) {
+ return T.intL().is(a);
+ }(
+ null,
+ null
+ ))
+ ''');
+ });
+
+ test(
+ 'evaluation that non-destructively appends to the constant container',
+ () async {
+ await driver.check(
+ scope: <String, String>{'a': 'null', 'check': 'null'},
+ expression: 'const B()',
+ expectedResult: '''
+ (function(a, check) {
+ dart.defineLazy(CT, {
+ get C1() {
+ return C[1] = dart.const({
+ __proto__: foo.B.prototype
+ });
+ }
+ }, false);
+ return C[1] || CT.C1;
+ }(
+ null,
+ null
+ ))
+ ''');
+ });
+
+ test('evaluation that reuses the constant container', () async {
+ await driver.check(
+ scope: <String, String>{'a': 'null', 'check': 'null'},
+ expression: 'const A()',
+ expectedResult: '''
+ (function(a, check) {
+ return C[0] || CT.C0;
+ }(
+ null,
+ null
+ ))
+ ''');
+ });
+ });
});
group('Sound null safety:', () {
@@ -2090,14 +2184,13 @@
expression: 'main',
expectedResult: '''
(function(x, y, z) {
- var VoidTodynamic = () => (VoidTodynamic = dart.constFn(dart.fnType(dart.dynamic, [])))();
+ T.VoidTodynamic = () => (T.VoidTodynamic = dart.constFn(dart.fnType(dart.dynamic, [])))();
dart.defineLazy(CT, {
get C0() {
- return C0 = dart.fn(foo.main, VoidTodynamic());
+ return C[0] = dart.fn(foo.main, T.VoidTodynamic());
}
}, false);
- var C0;
- return C0 || CT.C0;
+ return C[0] || CT.C0;
}(
1,
2,
@@ -2995,14 +3088,13 @@
(function(p) {
dart.defineLazy(CT, {
get C0() {
- return C0 = dart.const({
+ return C[0] = dart.const({
__proto__: foo.MyClass.prototype,
[_t]: 1
});
}
}, false);
- var C0;
- return C0 || CT.C0;
+ return C[0] || CT.C0;
}(
1
))
@@ -3044,14 +3136,13 @@
(function(p) {
dart.defineLazy(CT, {
get C0() {
- return C0 = dart.const({
+ return C[0] = dart.const({
__proto__: foo.ValueKey.prototype,
[value]: "t"
});
}
}, false);
- var C0;
- return C0 || CT.C0;
+ return C[0] || CT.C0;
}(
1
))
diff --git a/pkg/scrape/example/strings.dart b/pkg/scrape/example/strings.dart
new file mode 100644
index 0000000..a89fcef
--- /dev/null
+++ b/pkg/scrape/example/strings.dart
@@ -0,0 +1,96 @@
+// Copyright (c) 2020, 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.
+import 'package:analyzer/dart/ast/ast.dart';
+import 'package:scrape/scrape.dart';
+
+final quoteRegExp = RegExp('\\\\?[\'"]');
+
+void main(List<String> arguments) {
+ Scrape()
+ ..addHistogram('Directive')
+ ..addHistogram('Expression')
+ ..addHistogram('Escapes')
+ ..addVisitor(() => StringVisitor())
+ ..runCommandLine(arguments);
+}
+
+class StringVisitor extends ScrapeVisitor {
+ @override
+ void visitSimpleStringLiteral(SimpleStringLiteral node) {
+ _record('Expression', node);
+ _recordEscapes(node);
+ super.visitSimpleStringLiteral(node);
+ }
+
+ @override
+ void visitStringInterpolation(StringInterpolation node) {
+ // Entire expression containing interpolation elements.
+ _record('Expression', node);
+
+ // TODO: Analyze escaped quotes inside strings.
+
+ // TODO: Analyze string literals nested inside interpolation.
+ super.visitStringInterpolation(node);
+ }
+
+ @override
+ void visitExportDirective(ExportDirective node) {
+ _record('Directive', node.uri);
+ // Don't recurse so that we don't treat the URI as a string expression.
+ }
+
+ @override
+ void visitImportDirective(ImportDirective node) {
+ _record('Directive', node.uri);
+ // Don't recurse so that we don't treat the URI as a string expression.
+ }
+
+ @override
+ void visitPartDirective(PartDirective node) {
+ _record('Directive', node.uri);
+ // Don't recurse so that we don't treat the URI as a string expression.
+ }
+
+ @override
+ void visitPartOfDirective(PartOfDirective node) {
+ if (node.uri != null) _record('Directive', node.uri);
+ // Don't recurse so that we don't treat the URI as a string expression.
+ }
+
+ void _record(String histogram, StringLiteral string) {
+ record(histogram, _quoteType(string.beginToken.lexeme));
+ }
+
+ void _recordEscapes(StringLiteral string) {
+ var quote = _quoteType(string.beginToken.lexeme);
+
+ // Ignore the rarer quote styles.
+ if (quote != "'" && quote != '"') return;
+
+ var contents = string.toSource();
+ contents = contents.substring(1, contents.length - 1);
+
+ var quotes = quoteRegExp
+ .allMatches(contents)
+ .map((match) => match[0])
+ .toSet()
+ .toList();
+ quotes.sort();
+
+ if (quotes.isNotEmpty) {
+ record('Escapes', '$quote containing ${quotes.join(" ")}');
+ }
+ }
+
+ String _quoteType(String lexeme) {
+ const types = ['"""', "'''", 'r"""', "r'''", '"', "'", 'r"', "r'"];
+
+ for (var type in types) {
+ if (lexeme.startsWith(type)) return type;
+ }
+
+ log('Unknown string quote in $lexeme');
+ return '';
+ }
+}
diff --git a/sdk/lib/_internal/js_runtime/lib/js_helper.dart b/sdk/lib/_internal/js_runtime/lib/js_helper.dart
index 3b1cca4..570aa15 100644
--- a/sdk/lib/_internal/js_runtime/lib/js_helper.dart
+++ b/sdk/lib/_internal/js_runtime/lib/js_helper.dart
@@ -2960,24 +2960,20 @@
return completer.future;
}
-class MainError extends Error implements NoSuchMethodError {
- final String _message;
-
- MainError(this._message);
-
- String toString() => 'NoSuchMethodError: $_message';
-}
-
-void missingMain() {
- throw new MainError("No top-level function named 'main'.");
-}
-
-void badMain() {
- throw new MainError("'main' is not a function.");
-}
-
-void mainHasTooManyParameters() {
- throw new MainError("'main' expects too many parameters.");
+/// Converts a raw JavaScript array into a `List<String>`.
+/// Called from generated code.
+List<String> convertMainArgumentList(Object? args) {
+ List<String> result = [];
+ if (args == null) return result;
+ if (args is JSArray) {
+ for (int i = 0; i < args.length; i++) {
+ JS('', '#.push(String(#[#]))', result, args, i);
+ }
+ return result;
+ }
+ // Single non-Array element. Convert to a String.
+ JS('', '#.push(String(#))', result, args);
+ return result;
}
class _AssertionError extends AssertionError {
diff --git a/sdk/lib/_internal/js_runtime/lib/preambles/d8.js b/sdk/lib/_internal/js_runtime/lib/preambles/d8.js
index 0174d95..6604c8a 100644
--- a/sdk/lib/_internal/js_runtime/lib/preambles/d8.js
+++ b/sdk/lib/_internal/js_runtime/lib/preambles/d8.js
@@ -10,7 +10,7 @@
var self = this;
if (typeof global != "undefined") self = global; // Node.js.
-(function(self) {
+(function(self, scriptArguments) {
// Using strict mode to avoid accidentally defining global variables.
"use strict"; // Should be first statement of this function.
@@ -270,9 +270,9 @@
// Global properties. "self" refers to the global object, so adding a
// property to "self" defines a global variable.
self.self = self;
- self.dartMainRunner = function(main, args) {
+ self.dartMainRunner = function(main, ignored_args) {
// Initialize.
- var action = function() { main(args); }
+ var action = function() { main(scriptArguments, null); }
eventLoop(action);
};
self.setTimeout = addTimer;
@@ -345,4 +345,4 @@
// so pretend they don't exist.
// TODO(30217): Try to use D8's worker.
delete self.Worker;
-})(self);
+})(self, arguments);
diff --git a/sdk/lib/_internal/js_runtime/lib/preambles/jsshell.js b/sdk/lib/_internal/js_runtime/lib/preambles/jsshell.js
index a6b41c4..48f60cd 100644
--- a/sdk/lib/_internal/js_runtime/lib/preambles/jsshell.js
+++ b/sdk/lib/_internal/js_runtime/lib/preambles/jsshell.js
@@ -4,7 +4,7 @@
// Javascript preamble, that lets the output of dart2js run on JSShell.
-(function(self) {
+(function(self, scriptArguments) {
// Using strict mode to avoid accidentally defining global variables.
"use strict"; // Should be first statement of this function.
@@ -262,9 +262,9 @@
}
}
- self.dartMainRunner = function(main, args) {
+ self.dartMainRunner = function(main, ignored_args) {
// Initialize.
- var action = function() { main(args); }
+ var action = function() { main(scriptArguments, null); }
eventLoop(action);
};
self.setTimeout = addTimer;
@@ -329,7 +329,7 @@
array[i] = Math.random() * 256;
}
}};
-})(this)
+})(this, typeof scriptArgs == "undefined" ? [] : scriptArgs)
var getKeys = function(obj){
var keys = [];
diff --git a/tests/language/nonfunction_type_aliases/usage_object_error_test.dart b/tests/language/nonfunction_type_aliases/usage_object_error_test.dart
index 2ea105c..cd7c78b 100644
--- a/tests/language/nonfunction_type_aliases/usage_object_error_test.dart
+++ b/tests/language/nonfunction_type_aliases/usage_object_error_test.dart
@@ -15,7 +15,12 @@
final T v12;
C(): v12 = T();
C.name1(this.v10, this.v12);
- factory C.name2(T arg1, T arg2) = C.name1;
+ factory C.name2(T arg1, T arg2) = C1.name1;
+}
+
+class C1 implements C {
+ C1.name1(T arg1, T arg2);
+ noSuchMethod(Invocation invocation) => throw 0;
}
abstract class D2 extends C with T {}
diff --git a/tools/VERSION b/tools/VERSION
index 857b325..58c42d0 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
MAJOR 2
MINOR 12
PATCH 0
-PRERELEASE 144
+PRERELEASE 145
PRERELEASE_PATCH 0
\ No newline at end of file