Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(825)

Side by Side Diff: packages/analyzer/lib/src/generated/parser.dart

Issue 2990843002: Removed fixed dependencies (Closed)
Patch Set: Created 3 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 library engine.parser; 5 library analyzer.src.generated.parser;
6 6
7 import 'dart:collection'; 7 import 'dart:collection';
8 import "dart:math" as math; 8 import "dart:math" as math;
9 9
10 import 'ast.dart'; 10 import 'package:analyzer/dart/ast/ast.dart';
11 import 'engine.dart' show AnalysisEngine, AnalysisOptionsImpl; 11 import 'package:analyzer/dart/ast/token.dart';
12 import 'error.dart'; 12 import 'package:analyzer/error/error.dart';
13 import 'java_core.dart'; 13 import 'package:analyzer/error/listener.dart';
14 import 'java_engine.dart'; 14 import 'package:analyzer/src/dart/ast/ast.dart';
15 import 'scanner.dart'; 15 import 'package:analyzer/src/dart/ast/token.dart';
16 import 'source.dart'; 16 import 'package:analyzer/src/dart/error/syntactic_errors.dart';
17 import 'utilities_collection.dart' show TokenMap; 17 import 'package:analyzer/src/dart/scanner/reader.dart';
18 import 'utilities_dart.dart'; 18 import 'package:analyzer/src/dart/scanner/scanner.dart';
19 import 'package:analyzer/src/error/codes.dart';
20 import 'package:analyzer/src/generated/engine.dart' show AnalysisEngine;
21 import 'package:analyzer/src/generated/java_core.dart';
22 import 'package:analyzer/src/generated/java_engine.dart';
23 import 'package:analyzer/src/generated/source.dart';
24 import 'package:analyzer/src/generated/utilities_dart.dart';
19 25
20 Map<String, MethodTrampoline> methodTable_Parser = <String, MethodTrampoline>{ 26 export 'package:analyzer/src/dart/ast/utilities.dart' show ResolutionCopier;
21 'parseCompilationUnit_1': new MethodTrampoline( 27 export 'package:analyzer/src/dart/error/syntactic_errors.dart';
22 1, (Parser target, arg0) => target.parseCompilationUnit(arg0)),
23 'parseDirectives_1': new MethodTrampoline(
24 1, (Parser target, arg0) => target.parseDirectives(arg0)),
25 'parseExpression_1': new MethodTrampoline(
26 1, (Parser target, arg0) => target.parseExpression(arg0)),
27 'parseStatement_1': new MethodTrampoline(
28 1, (Parser target, arg0) => target.parseStatement(arg0)),
29 'parseStatements_1': new MethodTrampoline(
30 1, (Parser target, arg0) => target.parseStatements(arg0)),
31 'parseAnnotation_0':
32 new MethodTrampoline(0, (Parser target) => target.parseAnnotation()),
33 'parseArgument_0':
34 new MethodTrampoline(0, (Parser target) => target.parseArgument()),
35 'parseArgumentList_0':
36 new MethodTrampoline(0, (Parser target) => target.parseArgumentList()),
37 'parseBitwiseOrExpression_0': new MethodTrampoline(
38 0, (Parser target) => target.parseBitwiseOrExpression()),
39 'parseBlock_0':
40 new MethodTrampoline(0, (Parser target) => target.parseBlock()),
41 'parseClassMember_1': new MethodTrampoline(
42 1, (Parser target, arg0) => target.parseClassMember(arg0)),
43 'parseCompilationUnit_0': new MethodTrampoline(
44 0, (Parser target) => target.parseCompilationUnit2()),
45 'parseConditionalExpression_0': new MethodTrampoline(
46 0, (Parser target) => target.parseConditionalExpression()),
47 'parseConstructorName_0':
48 new MethodTrampoline(0, (Parser target) => target.parseConstructorName()),
49 'parseExpression_0':
50 new MethodTrampoline(0, (Parser target) => target.parseExpression2()),
51 'parseExpressionWithoutCascade_0': new MethodTrampoline(
52 0, (Parser target) => target.parseExpressionWithoutCascade()),
53 'parseExtendsClause_0':
54 new MethodTrampoline(0, (Parser target) => target.parseExtendsClause()),
55 'parseFormalParameterList_0': new MethodTrampoline(
56 0, (Parser target) => target.parseFormalParameterList()),
57 'parseFunctionExpression_0': new MethodTrampoline(
58 0, (Parser target) => target.parseFunctionExpression()),
59 'parseImplementsClause_0': new MethodTrampoline(
60 0, (Parser target) => target.parseImplementsClause()),
61 'parseLabel_0':
62 new MethodTrampoline(0, (Parser target) => target.parseLabel()),
63 'parseLibraryIdentifier_0': new MethodTrampoline(
64 0, (Parser target) => target.parseLibraryIdentifier()),
65 'parseLogicalOrExpression_0': new MethodTrampoline(
66 0, (Parser target) => target.parseLogicalOrExpression()),
67 'parseMapLiteralEntry_0':
68 new MethodTrampoline(0, (Parser target) => target.parseMapLiteralEntry()),
69 'parseNormalFormalParameter_0': new MethodTrampoline(
70 0, (Parser target) => target.parseNormalFormalParameter()),
71 'parsePrefixedIdentifier_0': new MethodTrampoline(
72 0, (Parser target) => target.parsePrefixedIdentifier()),
73 'parseReturnType_0':
74 new MethodTrampoline(0, (Parser target) => target.parseReturnType()),
75 'parseSimpleIdentifier_0': new MethodTrampoline(
76 0, (Parser target) => target.parseSimpleIdentifier()),
77 'parseStatement_0':
78 new MethodTrampoline(0, (Parser target) => target.parseStatement2()),
79 'parseStringLiteral_0':
80 new MethodTrampoline(0, (Parser target) => target.parseStringLiteral()),
81 'parseTypeArgumentList_0': new MethodTrampoline(
82 0, (Parser target) => target.parseTypeArgumentList()),
83 'parseTypeName_0':
84 new MethodTrampoline(0, (Parser target) => target.parseTypeName()),
85 'parseTypeParameter_0':
86 new MethodTrampoline(0, (Parser target) => target.parseTypeParameter()),
87 'parseTypeParameterList_0': new MethodTrampoline(
88 0, (Parser target) => target.parseTypeParameterList()),
89 'parseWithClause_0':
90 new MethodTrampoline(0, (Parser target) => target.parseWithClause()),
91 'advance_0': new MethodTrampoline(0, (Parser target) => target._advance()),
92 'appendScalarValue_5': new MethodTrampoline(
93 5,
94 (Parser target, arg0, arg1, arg2, arg3, arg4) =>
95 target._appendScalarValue(arg0, arg1, arg2, arg3, arg4)),
96 'computeStringValue_3': new MethodTrampoline(
97 3,
98 (Parser target, arg0, arg1, arg2) =>
99 target._computeStringValue(arg0, arg1, arg2)),
100 'convertToFunctionDeclaration_1': new MethodTrampoline(
101 1, (Parser target, arg0) => target._convertToFunctionDeclaration(arg0)),
102 'couldBeStartOfCompilationUnitMember_0': new MethodTrampoline(
103 0, (Parser target) => target._couldBeStartOfCompilationUnitMember()),
104 'createSyntheticIdentifier_0': new MethodTrampoline(
105 0, (Parser target) => target._createSyntheticIdentifier()),
106 'createSyntheticKeyword_1': new MethodTrampoline(
107 1, (Parser target, arg0) => target._createSyntheticKeyword(arg0)),
108 'createSyntheticStringLiteral_0': new MethodTrampoline(
109 0, (Parser target) => target._createSyntheticStringLiteral()),
110 'createSyntheticToken_1': new MethodTrampoline(
111 1, (Parser target, arg0) => target._createSyntheticToken(arg0)),
112 'ensureAssignable_1': new MethodTrampoline(
113 1, (Parser target, arg0) => target._ensureAssignable(arg0)),
114 'expect_1':
115 new MethodTrampoline(1, (Parser target, arg0) => target._expect(arg0)),
116 'expectGt_0': new MethodTrampoline(0, (Parser target) => target._expectGt()),
117 'expectKeyword_1': new MethodTrampoline(
118 1, (Parser target, arg0) => target._expectKeyword(arg0)),
119 'expectSemicolon_0':
120 new MethodTrampoline(0, (Parser target) => target._expectSemicolon()),
121 'findRange_2': new MethodTrampoline(
122 2, (Parser target, arg0, arg1) => target._findRange(arg0, arg1)),
123 'getCodeBlockRanges_1': new MethodTrampoline(
124 1, (Parser target, arg0) => target._getCodeBlockRanges(arg0)),
125 'getEndToken_1': new MethodTrampoline(
126 1, (Parser target, arg0) => target._getEndToken(arg0)),
127 'injectToken_1': new MethodTrampoline(
128 1, (Parser target, arg0) => target._injectToken(arg0)),
129 'isFunctionDeclaration_0': new MethodTrampoline(
130 0, (Parser target) => target._isFunctionDeclaration()),
131 'isFunctionExpression_1': new MethodTrampoline(
132 1, (Parser target, arg0) => target._isFunctionExpression(arg0)),
133 'isHexDigit_1': new MethodTrampoline(
134 1, (Parser target, arg0) => target._isHexDigit(arg0)),
135 'isInitializedVariableDeclaration_0': new MethodTrampoline(
136 0, (Parser target) => target._isInitializedVariableDeclaration()),
137 'isLinkText_2': new MethodTrampoline(
138 2, (Parser target, arg0, arg1) => target._isLinkText(arg0, arg1)),
139 'isOperator_1': new MethodTrampoline(
140 1, (Parser target, arg0) => target._isOperator(arg0)),
141 'isSwitchMember_0':
142 new MethodTrampoline(0, (Parser target) => target._isSwitchMember()),
143 'isTypedIdentifier_1': new MethodTrampoline(
144 1, (Parser target, arg0) => target._isTypedIdentifier(arg0)),
145 'lockErrorListener_0':
146 new MethodTrampoline(0, (Parser target) => target._lockErrorListener()),
147 'matches_1':
148 new MethodTrampoline(1, (Parser target, arg0) => target._matches(arg0)),
149 'matchesGt_0':
150 new MethodTrampoline(0, (Parser target) => target._matchesGt()),
151 'matchesIdentifier_0':
152 new MethodTrampoline(0, (Parser target) => target._matchesIdentifier()),
153 'matchesKeyword_1': new MethodTrampoline(
154 1, (Parser target, arg0) => target._matchesKeyword(arg0)),
155 'matchesString_1': new MethodTrampoline(
156 1, (Parser target, arg0) => target._matchesString(arg0)),
157 'optional_1':
158 new MethodTrampoline(1, (Parser target, arg0) => target._optional(arg0)),
159 'parseAdditiveExpression_0': new MethodTrampoline(
160 0, (Parser target) => target._parseAdditiveExpression()),
161 'parseAssertStatement_0': new MethodTrampoline(
162 0, (Parser target) => target._parseAssertStatement()),
163 'parseAssignableExpression_1': new MethodTrampoline(
164 1, (Parser target, arg0) => target._parseAssignableExpression(arg0)),
165 'parseAssignableSelector_2': new MethodTrampoline(
166 2,
167 (Parser target, arg0, arg1) =>
168 target._parseAssignableSelector(arg0, arg1)),
169 'parseAwaitExpression_0': new MethodTrampoline(
170 0, (Parser target) => target._parseAwaitExpression()),
171 'parseBitwiseAndExpression_0': new MethodTrampoline(
172 0, (Parser target) => target._parseBitwiseAndExpression()),
173 'parseBitwiseXorExpression_0': new MethodTrampoline(
174 0, (Parser target) => target._parseBitwiseXorExpression()),
175 'parseBreakStatement_0':
176 new MethodTrampoline(0, (Parser target) => target._parseBreakStatement()),
177 'parseCascadeSection_0':
178 new MethodTrampoline(0, (Parser target) => target._parseCascadeSection()),
179 'parseClassDeclaration_2': new MethodTrampoline(2,
180 (Parser target, arg0, arg1) => target._parseClassDeclaration(arg0, arg1)),
181 'parseClassMembers_2': new MethodTrampoline(
182 2, (Parser target, arg0, arg1) => target._parseClassMembers(arg0, arg1)),
183 'parseClassTypeAlias_3': new MethodTrampoline(
184 3,
185 (Parser target, arg0, arg1, arg2) =>
186 target._parseClassTypeAlias(arg0, arg1, arg2)),
187 'parseCombinator_0':
188 new MethodTrampoline(0, (Parser target) => target.parseCombinator()),
189 'parseCombinators_0':
190 new MethodTrampoline(0, (Parser target) => target._parseCombinators()),
191 'parseCommentAndMetadata_0': new MethodTrampoline(
192 0, (Parser target) => target._parseCommentAndMetadata()),
193 'parseCommentReference_2': new MethodTrampoline(2,
194 (Parser target, arg0, arg1) => target._parseCommentReference(arg0, arg1)),
195 'parseCommentReferences_1': new MethodTrampoline(
196 1, (Parser target, arg0) => target._parseCommentReferences(arg0)),
197 'parseCompilationUnitMember_1': new MethodTrampoline(
198 1, (Parser target, arg0) => target._parseCompilationUnitMember(arg0)),
199 'parseConstExpression_0': new MethodTrampoline(
200 0, (Parser target) => target._parseConstExpression()),
201 'parseConstructor_8': new MethodTrampoline(
202 8,
203 (Parser target, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7) => target
204 ._parseConstructor(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7)),
205 'parseConstructorFieldInitializer_0': new MethodTrampoline(
206 0, (Parser target) => target._parseConstructorFieldInitializer()),
207 'parseContinueStatement_0': new MethodTrampoline(
208 0, (Parser target) => target._parseContinueStatement()),
209 'parseDirective_1': new MethodTrampoline(
210 1, (Parser target, arg0) => target._parseDirective(arg0)),
211 'parseDirectives_0':
212 new MethodTrampoline(0, (Parser target) => target._parseDirectives()),
213 'parseDocumentationComment_0': new MethodTrampoline(
214 0, (Parser target) => target._parseDocumentationComment()),
215 'parseDoStatement_0':
216 new MethodTrampoline(0, (Parser target) => target._parseDoStatement()),
217 'parseEmptyStatement_0':
218 new MethodTrampoline(0, (Parser target) => target._parseEmptyStatement()),
219 'parseEnumConstantDeclaration_0': new MethodTrampoline(
220 0, (Parser target) => target._parseEnumConstantDeclaration()),
221 'parseEnumDeclaration_1': new MethodTrampoline(
222 1, (Parser target, arg0) => target._parseEnumDeclaration(arg0)),
223 'parseEqualityExpression_0': new MethodTrampoline(
224 0, (Parser target) => target._parseEqualityExpression()),
225 'parseExportDirective_1': new MethodTrampoline(
226 1, (Parser target, arg0) => target._parseExportDirective(arg0)),
227 'parseExpressionList_0':
228 new MethodTrampoline(0, (Parser target) => target._parseExpressionList()),
229 'parseFinalConstVarOrType_1': new MethodTrampoline(
230 1, (Parser target, arg0) => target._parseFinalConstVarOrType(arg0)),
231 'parseFormalParameter_1': new MethodTrampoline(
232 1, (Parser target, arg0) => target._parseFormalParameter(arg0)),
233 'parseForStatement_0':
234 new MethodTrampoline(0, (Parser target) => target._parseForStatement()),
235 'parseFunctionBody_3': new MethodTrampoline(
236 3,
237 (Parser target, arg0, arg1, arg2) =>
238 target._parseFunctionBody(arg0, arg1, arg2)),
239 'parseFunctionDeclaration_3': new MethodTrampoline(
240 3,
241 (Parser target, arg0, arg1, arg2) =>
242 target._parseFunctionDeclaration(arg0, arg1, arg2)),
243 'parseFunctionDeclarationStatement_0': new MethodTrampoline(
244 0, (Parser target) => target._parseFunctionDeclarationStatement()),
245 'parseFunctionDeclarationStatementAfterReturnType_2': new MethodTrampoline(
246 2,
247 (Parser target, arg0, arg1) =>
248 target._parseFunctionDeclarationStatementAfterReturnType(arg0, arg1)),
249 'parseFunctionTypeAlias_2': new MethodTrampoline(
250 2,
251 (Parser target, arg0, arg1) =>
252 target._parseFunctionTypeAlias(arg0, arg1)),
253 'parseGetter_4': new MethodTrampoline(
254 4,
255 (Parser target, arg0, arg1, arg2, arg3) =>
256 target._parseGetter(arg0, arg1, arg2, arg3)),
257 'parseIdentifierList_0':
258 new MethodTrampoline(0, (Parser target) => target._parseIdentifierList()),
259 'parseIfStatement_0':
260 new MethodTrampoline(0, (Parser target) => target._parseIfStatement()),
261 'parseImportDirective_1': new MethodTrampoline(
262 1, (Parser target, arg0) => target._parseImportDirective(arg0)),
263 'parseInitializedIdentifierList_4': new MethodTrampoline(
264 4,
265 (Parser target, arg0, arg1, arg2, arg3) =>
266 target._parseInitializedIdentifierList(arg0, arg1, arg2, arg3)),
267 'parseInstanceCreationExpression_1': new MethodTrampoline(1,
268 (Parser target, arg0) => target._parseInstanceCreationExpression(arg0)),
269 'parseLibraryDirective_1': new MethodTrampoline(
270 1, (Parser target, arg0) => target._parseLibraryDirective(arg0)),
271 'parseLibraryName_2': new MethodTrampoline(
272 2, (Parser target, arg0, arg1) => target._parseLibraryName(arg0, arg1)),
273 'parseListLiteral_2': new MethodTrampoline(
274 2, (Parser target, arg0, arg1) => target._parseListLiteral(arg0, arg1)),
275 'parseListOrMapLiteral_1': new MethodTrampoline(
276 1, (Parser target, arg0) => target._parseListOrMapLiteral(arg0)),
277 'parseLogicalAndExpression_0': new MethodTrampoline(
278 0, (Parser target) => target._parseLogicalAndExpression()),
279 'parseMapLiteral_2': new MethodTrampoline(
280 2, (Parser target, arg0, arg1) => target._parseMapLiteral(arg0, arg1)),
281 'parseMethodDeclarationAfterParameters_7': new MethodTrampoline(
282 7,
283 (Parser target, arg0, arg1, arg2, arg3, arg4, arg5, arg6) =>
284 target._parseMethodDeclarationAfterParameters(
285 arg0, arg1, arg2, arg3, arg4, arg5, arg6)),
286 'parseMethodDeclarationAfterReturnType_4': new MethodTrampoline(
287 4,
288 (Parser target, arg0, arg1, arg2, arg3) => target
289 ._parseMethodDeclarationAfterReturnType(arg0, arg1, arg2, arg3)),
290 'parseModifiers_0':
291 new MethodTrampoline(0, (Parser target) => target._parseModifiers()),
292 'parseMultiplicativeExpression_0': new MethodTrampoline(
293 0, (Parser target) => target._parseMultiplicativeExpression()),
294 'parseNativeClause_0':
295 new MethodTrampoline(0, (Parser target) => target._parseNativeClause()),
296 'parseNewExpression_0':
297 new MethodTrampoline(0, (Parser target) => target._parseNewExpression()),
298 'parseNonLabeledStatement_0': new MethodTrampoline(
299 0, (Parser target) => target._parseNonLabeledStatement()),
300 'parseOperator_3': new MethodTrampoline(
301 3,
302 (Parser target, arg0, arg1, arg2) =>
303 target._parseOperator(arg0, arg1, arg2)),
304 'parseOptionalReturnType_0': new MethodTrampoline(
305 0, (Parser target) => target._parseOptionalReturnType()),
306 'parsePartDirective_1': new MethodTrampoline(
307 1, (Parser target, arg0) => target._parsePartDirective(arg0)),
308 'parsePostfixExpression_0': new MethodTrampoline(
309 0, (Parser target) => target._parsePostfixExpression()),
310 'parsePrimaryExpression_0': new MethodTrampoline(
311 0, (Parser target) => target._parsePrimaryExpression()),
312 'parseRedirectingConstructorInvocation_0': new MethodTrampoline(
313 0, (Parser target) => target._parseRedirectingConstructorInvocation()),
314 'parseRelationalExpression_0': new MethodTrampoline(
315 0, (Parser target) => target._parseRelationalExpression()),
316 'parseRethrowExpression_0': new MethodTrampoline(
317 0, (Parser target) => target._parseRethrowExpression()),
318 'parseReturnStatement_0': new MethodTrampoline(
319 0, (Parser target) => target._parseReturnStatement()),
320 'parseSetter_4': new MethodTrampoline(
321 4,
322 (Parser target, arg0, arg1, arg2, arg3) =>
323 target._parseSetter(arg0, arg1, arg2, arg3)),
324 'parseShiftExpression_0': new MethodTrampoline(
325 0, (Parser target) => target._parseShiftExpression()),
326 'parseStatementList_0':
327 new MethodTrampoline(0, (Parser target) => target._parseStatementList()),
328 'parseStringInterpolation_1': new MethodTrampoline(
329 1, (Parser target, arg0) => target._parseStringInterpolation(arg0)),
330 'parseSuperConstructorInvocation_0': new MethodTrampoline(
331 0, (Parser target) => target._parseSuperConstructorInvocation()),
332 'parseSwitchStatement_0': new MethodTrampoline(
333 0, (Parser target) => target._parseSwitchStatement()),
334 'parseSymbolLiteral_0':
335 new MethodTrampoline(0, (Parser target) => target._parseSymbolLiteral()),
336 'parseThrowExpression_0': new MethodTrampoline(
337 0, (Parser target) => target._parseThrowExpression()),
338 'parseThrowExpressionWithoutCascade_0': new MethodTrampoline(
339 0, (Parser target) => target._parseThrowExpressionWithoutCascade()),
340 'parseTryStatement_0':
341 new MethodTrampoline(0, (Parser target) => target._parseTryStatement()),
342 'parseTypeAlias_1': new MethodTrampoline(
343 1, (Parser target, arg0) => target._parseTypeAlias(arg0)),
344 'parseUnaryExpression_0': new MethodTrampoline(
345 0, (Parser target) => target._parseUnaryExpression()),
346 'parseVariableDeclaration_0': new MethodTrampoline(
347 0, (Parser target) => target._parseVariableDeclaration()),
348 'parseVariableDeclarationListAfterMetadata_1': new MethodTrampoline(
349 1,
350 (Parser target, arg0) =>
351 target._parseVariableDeclarationListAfterMetadata(arg0)),
352 'parseVariableDeclarationListAfterType_3': new MethodTrampoline(
353 3,
354 (Parser target, arg0, arg1, arg2) =>
355 target._parseVariableDeclarationListAfterType(arg0, arg1, arg2)),
356 'parseVariableDeclarationStatementAfterMetadata_1': new MethodTrampoline(
357 1,
358 (Parser target, arg0) =>
359 target._parseVariableDeclarationStatementAfterMetadata(arg0)),
360 'parseVariableDeclarationStatementAfterType_3': new MethodTrampoline(
361 3,
362 (Parser target, arg0, arg1, arg2) =>
363 target._parseVariableDeclarationStatementAfterType(arg0, arg1, arg2)),
364 'parseWhileStatement_0':
365 new MethodTrampoline(0, (Parser target) => target._parseWhileStatement()),
366 'parseYieldStatement_0':
367 new MethodTrampoline(0, (Parser target) => target._parseYieldStatement()),
368 'peek_0': new MethodTrampoline(0, (Parser target) => target._peek()),
369 'peekAt_1':
370 new MethodTrampoline(1, (Parser target, arg0) => target._peekAt(arg0)),
371 'reportError_1': new MethodTrampoline(
372 1, (Parser target, arg0) => target._reportError(arg0)),
373 'reportErrorForCurrentToken_2': new MethodTrampoline(
374 2,
375 (Parser target, arg0, arg1) =>
376 target._reportErrorForCurrentToken(arg0, arg1)),
377 'reportErrorForNode_3': new MethodTrampoline(
378 3,
379 (Parser target, arg0, arg1, arg2) =>
380 target._reportErrorForNode(arg0, arg1, arg2)),
381 'reportErrorForToken_3': new MethodTrampoline(
382 3,
383 (Parser target, arg0, arg1, arg2) =>
384 target._reportErrorForToken(arg0, arg1, arg2)),
385 'skipBlock_0':
386 new MethodTrampoline(0, (Parser target) => target._skipBlock()),
387 'skipFinalConstVarOrType_1': new MethodTrampoline(
388 1, (Parser target, arg0) => target._skipFinalConstVarOrType(arg0)),
389 'skipFormalParameterList_1': new MethodTrampoline(
390 1, (Parser target, arg0) => target._skipFormalParameterList(arg0)),
391 'skipPastMatchingToken_1': new MethodTrampoline(
392 1, (Parser target, arg0) => target._skipPastMatchingToken(arg0)),
393 'skipPrefixedIdentifier_1': new MethodTrampoline(
394 1, (Parser target, arg0) => target._skipPrefixedIdentifier(arg0)),
395 'skipReturnType_1': new MethodTrampoline(
396 1, (Parser target, arg0) => target._skipReturnType(arg0)),
397 'skipSimpleIdentifier_1': new MethodTrampoline(
398 1, (Parser target, arg0) => target._skipSimpleIdentifier(arg0)),
399 'skipStringInterpolation_1': new MethodTrampoline(
400 1, (Parser target, arg0) => target._skipStringInterpolation(arg0)),
401 'skipStringLiteral_1': new MethodTrampoline(
402 1, (Parser target, arg0) => target._skipStringLiteral(arg0)),
403 'skipTypeArgumentList_1': new MethodTrampoline(
404 1, (Parser target, arg0) => target._skipTypeArgumentList(arg0)),
405 'skipTypeName_1': new MethodTrampoline(
406 1, (Parser target, arg0) => target._skipTypeName(arg0)),
407 'skipTypeParameterList_1': new MethodTrampoline(
408 1, (Parser target, arg0) => target._skipTypeParameterList(arg0)),
409 'tokenMatches_2': new MethodTrampoline(
410 2, (Parser target, arg0, arg1) => target._tokenMatches(arg0, arg1)),
411 'tokenMatchesIdentifier_1': new MethodTrampoline(
412 1, (Parser target, arg0) => target._tokenMatchesIdentifier(arg0)),
413 'tokenMatchesKeyword_2': new MethodTrampoline(2,
414 (Parser target, arg0, arg1) => target._tokenMatchesKeyword(arg0, arg1)),
415 'tokenMatchesString_2': new MethodTrampoline(
416 2, (Parser target, arg0, arg1) => target._tokenMatchesString(arg0, arg1)),
417 'translateCharacter_3': new MethodTrampoline(
418 3,
419 (Parser target, arg0, arg1, arg2) =>
420 target._translateCharacter(arg0, arg1, arg2)),
421 'unlockErrorListener_0':
422 new MethodTrampoline(0, (Parser target) => target._unlockErrorListener()),
423 'validateFormalParameterList_1': new MethodTrampoline(
424 1, (Parser target, arg0) => target._validateFormalParameterList(arg0)),
425 'validateModifiersForClass_1': new MethodTrampoline(
426 1, (Parser target, arg0) => target._validateModifiersForClass(arg0)),
427 'validateModifiersForConstructor_1': new MethodTrampoline(1,
428 (Parser target, arg0) => target._validateModifiersForConstructor(arg0)),
429 'validateModifiersForEnum_1': new MethodTrampoline(
430 1, (Parser target, arg0) => target._validateModifiersForEnum(arg0)),
431 'validateModifiersForField_1': new MethodTrampoline(
432 1, (Parser target, arg0) => target._validateModifiersForField(arg0)),
433 'validateModifiersForFunctionDeclarationStatement_1': new MethodTrampoline(
434 1,
435 (Parser target, arg0) =>
436 target._validateModifiersForFunctionDeclarationStatement(arg0)),
437 'validateModifiersForGetterOrSetterOrMethod_1': new MethodTrampoline(
438 1,
439 (Parser target, arg0) =>
440 target._validateModifiersForGetterOrSetterOrMethod(arg0)),
441 'validateModifiersForOperator_1': new MethodTrampoline(
442 1, (Parser target, arg0) => target._validateModifiersForOperator(arg0)),
443 'validateModifiersForTopLevelDeclaration_1': new MethodTrampoline(
444 1,
445 (Parser target, arg0) =>
446 target._validateModifiersForTopLevelDeclaration(arg0)),
447 'validateModifiersForTopLevelFunction_1': new MethodTrampoline(
448 1,
449 (Parser target, arg0) =>
450 target._validateModifiersForTopLevelFunction(arg0)),
451 'validateModifiersForTopLevelVariable_1': new MethodTrampoline(
452 1,
453 (Parser target, arg0) =>
454 target._validateModifiersForTopLevelVariable(arg0)),
455 'validateModifiersForTypedef_1': new MethodTrampoline(
456 1, (Parser target, arg0) => target._validateModifiersForTypedef(arg0)),
457 };
458
459 Object invokeParserMethodImpl(
460 Parser parser, String methodName, List<Object> objects, Token tokenStream) {
461 parser.currentToken = tokenStream;
462 MethodTrampoline method =
463 methodTable_Parser['${methodName}_${objects.length}'];
464 if (method == null) {
465 throw new IllegalArgumentException('There is no method named $methodName');
466 }
467 return method.invoke(parser, objects);
468 }
469 28
470 /** 29 /**
471 * A simple data-holder for a method that needs to return multiple values. 30 * A simple data-holder for a method that needs to return multiple values.
472 */ 31 */
473 class CommentAndMetadata { 32 class CommentAndMetadata {
474 /** 33 /**
475 * The documentation comment that was parsed, or `null` if none was given. 34 * The documentation comment that was parsed, or `null` if none was given.
476 */ 35 */
477 final Comment comment; 36 final Comment comment;
478 37
479 /** 38 /**
480 * The metadata that was parsed. 39 * The metadata that was parsed, or `null` if none was given.
481 */ 40 */
482 final List<Annotation> metadata; 41 final List<Annotation> metadata;
483 42
484 /** 43 /**
485 * Initialize a newly created holder with the given [comment] and [metadata]. 44 * Initialize a newly created holder with the given [comment] and [metadata].
486 */ 45 */
487 CommentAndMetadata(this.comment, this.metadata); 46 CommentAndMetadata(this.comment, this.metadata);
47
48 /**
49 * Return `true` if some metadata was parsed.
50 */
51 bool get hasMetadata => metadata != null && metadata.isNotEmpty;
488 } 52 }
489 53
490 /** 54 /**
491 * A simple data-holder for a method that needs to return multiple values. 55 * A simple data-holder for a method that needs to return multiple values.
492 */ 56 */
493 class FinalConstVarOrType { 57 class FinalConstVarOrType {
494 /** 58 /**
495 * The 'final', 'const' or 'var' keyword, or `null` if none was given. 59 * The 'final', 'const' or 'var' keyword, or `null` if none was given.
496 */ 60 */
497 final Token keyword; 61 final Token keyword;
498 62
499 /** 63 /**
500 * The type, of `null` if no type was specified. 64 * The type, of `null` if no type was specified.
501 */ 65 */
502 final TypeName type; 66 final TypeName type;
503 67
504 /** 68 /**
505 * Initialize a newly created holder with the given [keyword] and [type]. 69 * Initialize a newly created holder with the given [keyword] and [type].
506 */ 70 */
507 FinalConstVarOrType(this.keyword, this.type); 71 FinalConstVarOrType(this.keyword, this.type);
508 } 72 }
509 73
510 /** 74 /**
511 * A dispatcher that will invoke the right parse method when re-parsing a
512 * specified child of the visited node. All of the methods in this class assume
513 * that the parser is positioned to parse the replacement for the node. All of
514 * the methods will throw an [IncrementalParseException] if the node could not
515 * be parsed for some reason.
516 */
517 class IncrementalParseDispatcher implements AstVisitor<AstNode> {
518 /**
519 * The parser used to parse the replacement for the node.
520 */
521 final Parser _parser;
522
523 /**
524 * The node that is to be replaced.
525 */
526 final AstNode _oldNode;
527
528 /**
529 * Initialize a newly created dispatcher to parse a single node that will
530 * use the [_parser] to replace the [_oldNode].
531 */
532 IncrementalParseDispatcher(this._parser, this._oldNode);
533
534 @override
535 AstNode visitAdjacentStrings(AdjacentStrings node) {
536 if (node.strings.contains(_oldNode)) {
537 return _parser.parseStringLiteral();
538 }
539 return _notAChild(node);
540 }
541
542 @override
543 AstNode visitAnnotation(Annotation node) {
544 if (identical(_oldNode, node.name)) {
545 throw new InsufficientContextException();
546 } else if (identical(_oldNode, node.constructorName)) {
547 throw new InsufficientContextException();
548 } else if (identical(_oldNode, node.arguments)) {
549 return _parser.parseArgumentList();
550 }
551 return _notAChild(node);
552 }
553
554 @override
555 AstNode visitArgumentList(ArgumentList node) {
556 if (node.arguments.contains(_oldNode)) {
557 return _parser.parseArgument();
558 }
559 return _notAChild(node);
560 }
561
562 @override
563 AstNode visitAsExpression(AsExpression node) {
564 if (identical(_oldNode, node.expression)) {
565 return _parser.parseBitwiseOrExpression();
566 } else if (identical(_oldNode, node.type)) {
567 return _parser.parseTypeName();
568 }
569 return _notAChild(node);
570 }
571
572 @override
573 AstNode visitAssertStatement(AssertStatement node) {
574 if (identical(_oldNode, node.condition)) {
575 return _parser.parseExpression2();
576 }
577 return _notAChild(node);
578 }
579
580 @override
581 AstNode visitAssignmentExpression(AssignmentExpression node) {
582 if (identical(_oldNode, node.leftHandSide)) {
583 // TODO(brianwilkerson) If the assignment is part of a cascade section,
584 // then we don't have a single parse method that will work.
585 // Otherwise, we can parse a conditional expression, but need to ensure
586 // that the resulting expression is assignable.
587 // return parser.parseConditionalExpression();
588 throw new InsufficientContextException();
589 } else if (identical(_oldNode, node.rightHandSide)) {
590 if (_isCascadeAllowedInAssignment(node)) {
591 return _parser.parseExpression2();
592 }
593 return _parser.parseExpressionWithoutCascade();
594 }
595 return _notAChild(node);
596 }
597
598 @override
599 AstNode visitAwaitExpression(AwaitExpression node) {
600 if (identical(_oldNode, node.expression)) {
601 // TODO(brianwilkerson) Depending on precedence,
602 // this might not be sufficient.
603 return _parser.parseExpression2();
604 }
605 return _notAChild(node);
606 }
607
608 @override
609 AstNode visitBinaryExpression(BinaryExpression node) {
610 if (identical(_oldNode, node.leftOperand)) {
611 throw new InsufficientContextException();
612 } else if (identical(_oldNode, node.rightOperand)) {
613 throw new InsufficientContextException();
614 }
615 return _notAChild(node);
616 }
617
618 @override
619 AstNode visitBlock(Block node) {
620 if (node.statements.contains(_oldNode)) {
621 return _parser.parseStatement2();
622 }
623 return _notAChild(node);
624 }
625
626 @override
627 AstNode visitBlockFunctionBody(BlockFunctionBody node) {
628 if (identical(_oldNode, node.block)) {
629 return _parser.parseBlock();
630 }
631 return _notAChild(node);
632 }
633
634 @override
635 AstNode visitBooleanLiteral(BooleanLiteral node) => _notAChild(node);
636
637 @override
638 AstNode visitBreakStatement(BreakStatement node) {
639 if (identical(_oldNode, node.label)) {
640 return _parser.parseSimpleIdentifier();
641 }
642 return _notAChild(node);
643 }
644
645 @override
646 AstNode visitCascadeExpression(CascadeExpression node) {
647 if (identical(_oldNode, node.target)) {
648 return _parser.parseConditionalExpression();
649 } else if (node.cascadeSections.contains(_oldNode)) {
650 throw new InsufficientContextException();
651 }
652 return _notAChild(node);
653 }
654
655 @override
656 AstNode visitCatchClause(CatchClause node) {
657 if (identical(_oldNode, node.exceptionType)) {
658 return _parser.parseTypeName();
659 } else if (identical(_oldNode, node.exceptionParameter)) {
660 return _parser.parseSimpleIdentifier();
661 } else if (identical(_oldNode, node.stackTraceParameter)) {
662 return _parser.parseSimpleIdentifier();
663 } else if (identical(_oldNode, node.body)) {
664 return _parser.parseBlock();
665 }
666 return _notAChild(node);
667 }
668
669 @override
670 AstNode visitClassDeclaration(ClassDeclaration node) {
671 if (identical(_oldNode, node.documentationComment)) {
672 throw new InsufficientContextException();
673 } else if (node.metadata.contains(_oldNode)) {
674 return _parser.parseAnnotation();
675 } else if (identical(_oldNode, node.name)) {
676 // Changing the class name changes whether a member is interpreted as a
677 // constructor or not, so we'll just have to re-parse the entire class.
678 throw new InsufficientContextException();
679 } else if (identical(_oldNode, node.typeParameters)) {
680 return _parser.parseTypeParameterList();
681 } else if (identical(_oldNode, node.extendsClause)) {
682 return _parser.parseExtendsClause();
683 } else if (identical(_oldNode, node.withClause)) {
684 return _parser.parseWithClause();
685 } else if (identical(_oldNode, node.implementsClause)) {
686 return _parser.parseImplementsClause();
687 } else if (node.members.contains(_oldNode)) {
688 ClassMember member = _parser.parseClassMember(node.name.name);
689 if (member == null) {
690 throw new InsufficientContextException();
691 }
692 return member;
693 }
694 return _notAChild(node);
695 }
696
697 @override
698 AstNode visitClassTypeAlias(ClassTypeAlias node) {
699 if (identical(_oldNode, node.documentationComment)) {
700 throw new InsufficientContextException();
701 } else if (node.metadata.contains(_oldNode)) {
702 return _parser.parseAnnotation();
703 } else if (identical(_oldNode, node.name)) {
704 return _parser.parseSimpleIdentifier();
705 } else if (identical(_oldNode, node.typeParameters)) {
706 return _parser.parseTypeParameterList();
707 } else if (identical(_oldNode, node.superclass)) {
708 return _parser.parseTypeName();
709 } else if (identical(_oldNode, node.withClause)) {
710 return _parser.parseWithClause();
711 } else if (identical(_oldNode, node.implementsClause)) {
712 return _parser.parseImplementsClause();
713 }
714 return _notAChild(node);
715 }
716
717 @override
718 AstNode visitComment(Comment node) {
719 throw new InsufficientContextException();
720 }
721
722 @override
723 AstNode visitCommentReference(CommentReference node) {
724 if (identical(_oldNode, node.identifier)) {
725 return _parser.parsePrefixedIdentifier();
726 }
727 return _notAChild(node);
728 }
729
730 @override
731 AstNode visitCompilationUnit(CompilationUnit node) {
732 throw new InsufficientContextException();
733 }
734
735 @override
736 AstNode visitConditionalExpression(ConditionalExpression node) {
737 if (identical(_oldNode, node.condition)) {
738 return _parser.parseIfNullExpression();
739 } else if (identical(_oldNode, node.thenExpression)) {
740 return _parser.parseExpressionWithoutCascade();
741 } else if (identical(_oldNode, node.elseExpression)) {
742 return _parser.parseExpressionWithoutCascade();
743 }
744 return _notAChild(node);
745 }
746
747 @override
748 AstNode visitConstructorDeclaration(ConstructorDeclaration node) {
749 if (identical(_oldNode, node.documentationComment)) {
750 throw new InsufficientContextException();
751 } else if (node.metadata.contains(_oldNode)) {
752 return _parser.parseAnnotation();
753 } else if (identical(_oldNode, node.returnType)) {
754 throw new InsufficientContextException();
755 } else if (identical(_oldNode, node.name)) {
756 throw new InsufficientContextException();
757 } else if (identical(_oldNode, node.parameters)) {
758 return _parser.parseFormalParameterList();
759 } else if (identical(_oldNode, node.redirectedConstructor)) {
760 throw new InsufficientContextException();
761 } else if (node.initializers.contains(_oldNode)) {
762 throw new InsufficientContextException();
763 } else if (identical(_oldNode, node.body)) {
764 throw new InsufficientContextException();
765 }
766 return _notAChild(node);
767 }
768
769 @override
770 AstNode visitConstructorFieldInitializer(ConstructorFieldInitializer node) {
771 if (identical(_oldNode, node.fieldName)) {
772 return _parser.parseSimpleIdentifier();
773 } else if (identical(_oldNode, node.expression)) {
774 throw new InsufficientContextException();
775 }
776 return _notAChild(node);
777 }
778
779 @override
780 AstNode visitConstructorName(ConstructorName node) {
781 if (identical(_oldNode, node.type)) {
782 return _parser.parseTypeName();
783 } else if (identical(_oldNode, node.name)) {
784 return _parser.parseSimpleIdentifier();
785 }
786 return _notAChild(node);
787 }
788
789 @override
790 AstNode visitContinueStatement(ContinueStatement node) {
791 if (identical(_oldNode, node.label)) {
792 return _parser.parseSimpleIdentifier();
793 }
794 return _notAChild(node);
795 }
796
797 @override
798 AstNode visitDeclaredIdentifier(DeclaredIdentifier node) {
799 if (identical(_oldNode, node.documentationComment)) {
800 throw new InsufficientContextException();
801 } else if (node.metadata.contains(_oldNode)) {
802 return _parser.parseAnnotation();
803 } else if (identical(_oldNode, node.type)) {
804 throw new InsufficientContextException();
805 } else if (identical(_oldNode, node.identifier)) {
806 return _parser.parseSimpleIdentifier();
807 }
808 return _notAChild(node);
809 }
810
811 @override
812 AstNode visitDefaultFormalParameter(DefaultFormalParameter node) {
813 if (identical(_oldNode, node.parameter)) {
814 return _parser.parseNormalFormalParameter();
815 } else if (identical(_oldNode, node.defaultValue)) {
816 return _parser.parseExpression2();
817 }
818 return _notAChild(node);
819 }
820
821 @override
822 AstNode visitDoStatement(DoStatement node) {
823 if (identical(_oldNode, node.body)) {
824 return _parser.parseStatement2();
825 } else if (identical(_oldNode, node.condition)) {
826 return _parser.parseExpression2();
827 }
828 return _notAChild(node);
829 }
830
831 @override
832 AstNode visitDoubleLiteral(DoubleLiteral node) => _notAChild(node);
833
834 @override
835 AstNode visitEmptyFunctionBody(EmptyFunctionBody node) => _notAChild(node);
836
837 @override
838 AstNode visitEmptyStatement(EmptyStatement node) => _notAChild(node);
839
840 @override
841 AstNode visitEnumConstantDeclaration(EnumConstantDeclaration node) {
842 if (identical(_oldNode, node.documentationComment)) {
843 throw new InsufficientContextException();
844 } else if (node.metadata.contains(_oldNode)) {
845 return _parser.parseAnnotation();
846 } else if (identical(_oldNode, node.name)) {
847 return _parser.parseSimpleIdentifier();
848 }
849 return _notAChild(node);
850 }
851
852 @override
853 AstNode visitEnumDeclaration(EnumDeclaration node) {
854 if (identical(_oldNode, node.documentationComment)) {
855 throw new InsufficientContextException();
856 } else if (node.metadata.contains(_oldNode)) {
857 return _parser.parseAnnotation();
858 } else if (identical(_oldNode, node.name)) {
859 return _parser.parseSimpleIdentifier();
860 } else if (node.constants.contains(_oldNode)) {
861 throw new InsufficientContextException();
862 }
863 return _notAChild(node);
864 }
865
866 @override
867 AstNode visitExportDirective(ExportDirective node) {
868 if (identical(_oldNode, node.documentationComment)) {
869 throw new InsufficientContextException();
870 } else if (node.metadata.contains(_oldNode)) {
871 return _parser.parseAnnotation();
872 } else if (identical(_oldNode, node.uri)) {
873 return _parser.parseStringLiteral();
874 } else if (node.combinators.contains(_oldNode)) {
875 throw new IncrementalParseException();
876 //return parser.parseCombinator();
877 }
878 return _notAChild(node);
879 }
880
881 @override
882 AstNode visitExpressionFunctionBody(ExpressionFunctionBody node) {
883 if (identical(_oldNode, node.expression)) {
884 return _parser.parseExpression2();
885 }
886 return _notAChild(node);
887 }
888
889 @override
890 AstNode visitExpressionStatement(ExpressionStatement node) {
891 if (identical(_oldNode, node.expression)) {
892 return _parser.parseExpression2();
893 }
894 return _notAChild(node);
895 }
896
897 @override
898 AstNode visitExtendsClause(ExtendsClause node) {
899 if (identical(_oldNode, node.superclass)) {
900 return _parser.parseTypeName();
901 }
902 return _notAChild(node);
903 }
904
905 @override
906 AstNode visitFieldDeclaration(FieldDeclaration node) {
907 if (identical(_oldNode, node.documentationComment)) {
908 throw new InsufficientContextException();
909 } else if (node.metadata.contains(_oldNode)) {
910 return _parser.parseAnnotation();
911 } else if (identical(_oldNode, node.fields)) {
912 throw new InsufficientContextException();
913 }
914 return _notAChild(node);
915 }
916
917 @override
918 AstNode visitFieldFormalParameter(FieldFormalParameter node) {
919 if (identical(_oldNode, node.documentationComment)) {
920 throw new InsufficientContextException();
921 } else if (node.metadata.contains(_oldNode)) {
922 return _parser.parseAnnotation();
923 } else if (identical(_oldNode, node.type)) {
924 return _parser.parseTypeName();
925 } else if (identical(_oldNode, node.identifier)) {
926 return _parser.parseSimpleIdentifier();
927 } else if (identical(_oldNode, node.parameters)) {
928 return _parser.parseFormalParameterList();
929 }
930 return _notAChild(node);
931 }
932
933 @override
934 AstNode visitForEachStatement(ForEachStatement node) {
935 if (identical(_oldNode, node.loopVariable)) {
936 throw new InsufficientContextException();
937 //return parser.parseDeclaredIdentifier();
938 } else if (identical(_oldNode, node.identifier)) {
939 return _parser.parseSimpleIdentifier();
940 } else if (identical(_oldNode, node.body)) {
941 return _parser.parseStatement2();
942 }
943 return _notAChild(node);
944 }
945
946 @override
947 AstNode visitFormalParameterList(FormalParameterList node) {
948 // We don't know which kind of parameter to parse.
949 throw new InsufficientContextException();
950 }
951
952 @override
953 AstNode visitForStatement(ForStatement node) {
954 if (identical(_oldNode, node.variables)) {
955 throw new InsufficientContextException();
956 } else if (identical(_oldNode, node.initialization)) {
957 throw new InsufficientContextException();
958 } else if (identical(_oldNode, node.condition)) {
959 return _parser.parseExpression2();
960 } else if (node.updaters.contains(_oldNode)) {
961 return _parser.parseExpression2();
962 } else if (identical(_oldNode, node.body)) {
963 return _parser.parseStatement2();
964 }
965 return _notAChild(node);
966 }
967
968 @override
969 AstNode visitFunctionDeclaration(FunctionDeclaration node) {
970 if (identical(_oldNode, node.documentationComment)) {
971 throw new InsufficientContextException();
972 } else if (node.metadata.contains(_oldNode)) {
973 return _parser.parseAnnotation();
974 } else if (identical(_oldNode, node.returnType)) {
975 return _parser.parseReturnType();
976 } else if (identical(_oldNode, node.name)) {
977 return _parser.parseSimpleIdentifier();
978 } else if (identical(_oldNode, node.functionExpression)) {
979 throw new InsufficientContextException();
980 }
981 return _notAChild(node);
982 }
983
984 @override
985 AstNode visitFunctionDeclarationStatement(FunctionDeclarationStatement node) {
986 if (identical(_oldNode, node.functionDeclaration)) {
987 throw new InsufficientContextException();
988 }
989 return _notAChild(node);
990 }
991
992 @override
993 AstNode visitFunctionExpression(FunctionExpression node) {
994 if (identical(_oldNode, node.parameters)) {
995 return _parser.parseFormalParameterList();
996 } else if (identical(_oldNode, node.body)) {
997 throw new InsufficientContextException();
998 }
999 return _notAChild(node);
1000 }
1001
1002 @override
1003 AstNode visitFunctionExpressionInvocation(FunctionExpressionInvocation node) {
1004 if (identical(_oldNode, node.function)) {
1005 throw new InsufficientContextException();
1006 } else if (identical(_oldNode, node.argumentList)) {
1007 return _parser.parseArgumentList();
1008 }
1009 return _notAChild(node);
1010 }
1011
1012 @override
1013 AstNode visitFunctionTypeAlias(FunctionTypeAlias node) {
1014 if (identical(_oldNode, node.documentationComment)) {
1015 throw new InsufficientContextException();
1016 } else if (node.metadata.contains(_oldNode)) {
1017 return _parser.parseAnnotation();
1018 } else if (identical(_oldNode, node.returnType)) {
1019 return _parser.parseReturnType();
1020 } else if (identical(_oldNode, node.name)) {
1021 return _parser.parseSimpleIdentifier();
1022 } else if (identical(_oldNode, node.typeParameters)) {
1023 return _parser.parseTypeParameterList();
1024 } else if (identical(_oldNode, node.parameters)) {
1025 return _parser.parseFormalParameterList();
1026 }
1027 return _notAChild(node);
1028 }
1029
1030 @override
1031 AstNode visitFunctionTypedFormalParameter(FunctionTypedFormalParameter node) {
1032 if (identical(_oldNode, node.documentationComment)) {
1033 throw new InsufficientContextException();
1034 } else if (node.metadata.contains(_oldNode)) {
1035 return _parser.parseAnnotation();
1036 } else if (identical(_oldNode, node.returnType)) {
1037 return _parser.parseReturnType();
1038 } else if (identical(_oldNode, node.identifier)) {
1039 return _parser.parseSimpleIdentifier();
1040 } else if (identical(_oldNode, node.parameters)) {
1041 return _parser.parseFormalParameterList();
1042 }
1043 return _notAChild(node);
1044 }
1045
1046 @override
1047 AstNode visitHideCombinator(HideCombinator node) {
1048 if (node.hiddenNames.contains(_oldNode)) {
1049 return _parser.parseSimpleIdentifier();
1050 }
1051 return _notAChild(node);
1052 }
1053
1054 @override
1055 AstNode visitIfStatement(IfStatement node) {
1056 if (identical(_oldNode, node.condition)) {
1057 return _parser.parseExpression2();
1058 } else if (identical(_oldNode, node.thenStatement)) {
1059 return _parser.parseStatement2();
1060 } else if (identical(_oldNode, node.elseStatement)) {
1061 return _parser.parseStatement2();
1062 }
1063 return _notAChild(node);
1064 }
1065
1066 @override
1067 AstNode visitImplementsClause(ImplementsClause node) {
1068 if (node.interfaces.contains(node)) {
1069 return _parser.parseTypeName();
1070 }
1071 return _notAChild(node);
1072 }
1073
1074 @override
1075 AstNode visitImportDirective(ImportDirective node) {
1076 if (identical(_oldNode, node.documentationComment)) {
1077 throw new InsufficientContextException();
1078 } else if (node.metadata.contains(_oldNode)) {
1079 return _parser.parseAnnotation();
1080 } else if (identical(_oldNode, node.uri)) {
1081 return _parser.parseStringLiteral();
1082 } else if (identical(_oldNode, node.prefix)) {
1083 return _parser.parseSimpleIdentifier();
1084 } else if (node.combinators.contains(_oldNode)) {
1085 return _parser.parseCombinator();
1086 }
1087 return _notAChild(node);
1088 }
1089
1090 @override
1091 AstNode visitIndexExpression(IndexExpression node) {
1092 if (identical(_oldNode, node.target)) {
1093 throw new InsufficientContextException();
1094 } else if (identical(_oldNode, node.index)) {
1095 return _parser.parseExpression2();
1096 }
1097 return _notAChild(node);
1098 }
1099
1100 @override
1101 AstNode visitInstanceCreationExpression(InstanceCreationExpression node) {
1102 if (identical(_oldNode, node.constructorName)) {
1103 return _parser.parseConstructorName();
1104 } else if (identical(_oldNode, node.argumentList)) {
1105 return _parser.parseArgumentList();
1106 }
1107 return _notAChild(node);
1108 }
1109
1110 @override
1111 AstNode visitIntegerLiteral(IntegerLiteral node) => _notAChild(node);
1112
1113 @override
1114 AstNode visitInterpolationExpression(InterpolationExpression node) {
1115 if (identical(_oldNode, node.expression)) {
1116 if (node.leftBracket == null) {
1117 throw new InsufficientContextException();
1118 //return parser.parseThisOrSimpleIdentifier();
1119 }
1120 return _parser.parseExpression2();
1121 }
1122 return _notAChild(node);
1123 }
1124
1125 @override
1126 AstNode visitInterpolationString(InterpolationString node) {
1127 throw new InsufficientContextException();
1128 }
1129
1130 @override
1131 AstNode visitIsExpression(IsExpression node) {
1132 if (identical(_oldNode, node.expression)) {
1133 return _parser.parseBitwiseOrExpression();
1134 } else if (identical(_oldNode, node.type)) {
1135 return _parser.parseTypeName();
1136 }
1137 return _notAChild(node);
1138 }
1139
1140 @override
1141 AstNode visitLabel(Label node) {
1142 if (identical(_oldNode, node.label)) {
1143 return _parser.parseSimpleIdentifier();
1144 }
1145 return _notAChild(node);
1146 }
1147
1148 @override
1149 AstNode visitLabeledStatement(LabeledStatement node) {
1150 if (node.labels.contains(_oldNode)) {
1151 return _parser.parseLabel();
1152 } else if (identical(_oldNode, node.statement)) {
1153 return _parser.parseStatement2();
1154 }
1155 return _notAChild(node);
1156 }
1157
1158 @override
1159 AstNode visitLibraryDirective(LibraryDirective node) {
1160 if (identical(_oldNode, node.documentationComment)) {
1161 throw new InsufficientContextException();
1162 } else if (node.metadata.contains(_oldNode)) {
1163 return _parser.parseAnnotation();
1164 } else if (identical(_oldNode, node.name)) {
1165 return _parser.parseLibraryIdentifier();
1166 }
1167 return _notAChild(node);
1168 }
1169
1170 @override
1171 AstNode visitLibraryIdentifier(LibraryIdentifier node) {
1172 if (node.components.contains(_oldNode)) {
1173 return _parser.parseSimpleIdentifier();
1174 }
1175 return _notAChild(node);
1176 }
1177
1178 @override
1179 AstNode visitListLiteral(ListLiteral node) {
1180 if (identical(_oldNode, node.typeArguments)) {
1181 return _parser.parseTypeArgumentList();
1182 } else if (node.elements.contains(_oldNode)) {
1183 return _parser.parseExpression2();
1184 }
1185 return _notAChild(node);
1186 }
1187
1188 @override
1189 AstNode visitMapLiteral(MapLiteral node) {
1190 if (identical(_oldNode, node.typeArguments)) {
1191 return _parser.parseTypeArgumentList();
1192 } else if (node.entries.contains(_oldNode)) {
1193 return _parser.parseMapLiteralEntry();
1194 }
1195 return _notAChild(node);
1196 }
1197
1198 @override
1199 AstNode visitMapLiteralEntry(MapLiteralEntry node) {
1200 if (identical(_oldNode, node.key)) {
1201 return _parser.parseExpression2();
1202 } else if (identical(_oldNode, node.value)) {
1203 return _parser.parseExpression2();
1204 }
1205 return _notAChild(node);
1206 }
1207
1208 @override
1209 AstNode visitMethodDeclaration(MethodDeclaration node) {
1210 if (identical(_oldNode, node.documentationComment)) {
1211 throw new InsufficientContextException();
1212 } else if (node.metadata.contains(_oldNode)) {
1213 return _parser.parseAnnotation();
1214 } else if (identical(_oldNode, node.returnType)) {
1215 throw new InsufficientContextException();
1216 //return parser.parseTypeName();
1217 //return parser.parseReturnType();
1218 } else if (identical(_oldNode, node.name)) {
1219 if (node.operatorKeyword != null) {
1220 throw new InsufficientContextException();
1221 }
1222 return _parser.parseSimpleIdentifier();
1223 } else if (identical(_oldNode, node.body)) {
1224 //return parser.parseFunctionBody();
1225 throw new InsufficientContextException();
1226 } else if (identical(_oldNode, node.parameters)) {
1227 // TODO(paulberry): if we want errors to be correct, we'll need to also
1228 // call _validateFormalParameterList, and sometimes
1229 // _validateModifiersForGetterOrSetterOrMethod.
1230 return _parser.parseFormalParameterList();
1231 }
1232 return _notAChild(node);
1233 }
1234
1235 @override
1236 AstNode visitMethodInvocation(MethodInvocation node) {
1237 if (identical(_oldNode, node.target)) {
1238 throw new IncrementalParseException();
1239 } else if (identical(_oldNode, node.methodName)) {
1240 return _parser.parseSimpleIdentifier();
1241 } else if (identical(_oldNode, node.argumentList)) {
1242 return _parser.parseArgumentList();
1243 }
1244 return _notAChild(node);
1245 }
1246
1247 @override
1248 AstNode visitNamedExpression(NamedExpression node) {
1249 if (identical(_oldNode, node.name)) {
1250 return _parser.parseLabel();
1251 } else if (identical(_oldNode, node.expression)) {
1252 return _parser.parseExpression2();
1253 }
1254 return _notAChild(node);
1255 }
1256
1257 @override
1258 AstNode visitNativeClause(NativeClause node) {
1259 if (identical(_oldNode, node.name)) {
1260 return _parser.parseStringLiteral();
1261 }
1262 return _notAChild(node);
1263 }
1264
1265 @override
1266 AstNode visitNativeFunctionBody(NativeFunctionBody node) {
1267 if (identical(_oldNode, node.stringLiteral)) {
1268 return _parser.parseStringLiteral();
1269 }
1270 return _notAChild(node);
1271 }
1272
1273 @override
1274 AstNode visitNullLiteral(NullLiteral node) => _notAChild(node);
1275
1276 @override
1277 AstNode visitParenthesizedExpression(ParenthesizedExpression node) {
1278 if (identical(_oldNode, node.expression)) {
1279 return _parser.parseExpression2();
1280 }
1281 return _notAChild(node);
1282 }
1283
1284 @override
1285 AstNode visitPartDirective(PartDirective node) {
1286 if (identical(_oldNode, node.documentationComment)) {
1287 throw new InsufficientContextException();
1288 } else if (node.metadata.contains(_oldNode)) {
1289 return _parser.parseAnnotation();
1290 } else if (identical(_oldNode, node.uri)) {
1291 return _parser.parseStringLiteral();
1292 }
1293 return _notAChild(node);
1294 }
1295
1296 @override
1297 AstNode visitPartOfDirective(PartOfDirective node) {
1298 if (identical(_oldNode, node.documentationComment)) {
1299 throw new InsufficientContextException();
1300 } else if (node.metadata.contains(_oldNode)) {
1301 return _parser.parseAnnotation();
1302 } else if (identical(_oldNode, node.libraryName)) {
1303 return _parser.parseLibraryIdentifier();
1304 }
1305 return _notAChild(node);
1306 }
1307
1308 @override
1309 AstNode visitPostfixExpression(PostfixExpression node) {
1310 if (identical(_oldNode, node.operand)) {
1311 throw new InsufficientContextException();
1312 }
1313 return _notAChild(node);
1314 }
1315
1316 @override
1317 AstNode visitPrefixedIdentifier(PrefixedIdentifier node) {
1318 if (identical(_oldNode, node.prefix)) {
1319 return _parser.parseSimpleIdentifier();
1320 } else if (identical(_oldNode, node.identifier)) {
1321 return _parser.parseSimpleIdentifier();
1322 }
1323 return _notAChild(node);
1324 }
1325
1326 @override
1327 AstNode visitPrefixExpression(PrefixExpression node) {
1328 if (identical(_oldNode, node.operand)) {
1329 throw new InsufficientContextException();
1330 }
1331 return _notAChild(node);
1332 }
1333
1334 @override
1335 AstNode visitPropertyAccess(PropertyAccess node) {
1336 if (identical(_oldNode, node.target)) {
1337 throw new InsufficientContextException();
1338 } else if (identical(_oldNode, node.propertyName)) {
1339 return _parser.parseSimpleIdentifier();
1340 }
1341 return _notAChild(node);
1342 }
1343
1344 @override
1345 AstNode visitRedirectingConstructorInvocation(
1346 RedirectingConstructorInvocation node) {
1347 if (identical(_oldNode, node.constructorName)) {
1348 return _parser.parseSimpleIdentifier();
1349 } else if (identical(_oldNode, node.argumentList)) {
1350 return _parser.parseArgumentList();
1351 }
1352 return _notAChild(node);
1353 }
1354
1355 @override
1356 AstNode visitRethrowExpression(RethrowExpression node) => _notAChild(node);
1357
1358 @override
1359 AstNode visitReturnStatement(ReturnStatement node) {
1360 if (identical(_oldNode, node.expression)) {
1361 return _parser.parseExpression2();
1362 }
1363 return _notAChild(node);
1364 }
1365
1366 @override
1367 AstNode visitScriptTag(ScriptTag node) => _notAChild(node);
1368
1369 @override
1370 AstNode visitShowCombinator(ShowCombinator node) {
1371 if (node.shownNames.contains(_oldNode)) {
1372 return _parser.parseSimpleIdentifier();
1373 }
1374 return _notAChild(node);
1375 }
1376
1377 @override
1378 AstNode visitSimpleFormalParameter(SimpleFormalParameter node) {
1379 if (identical(_oldNode, node.documentationComment)) {
1380 throw new InsufficientContextException();
1381 } else if (node.metadata.contains(_oldNode)) {
1382 return _parser.parseAnnotation();
1383 } else if (identical(_oldNode, node.type)) {
1384 throw new InsufficientContextException();
1385 } else if (identical(_oldNode, node.identifier)) {
1386 throw new InsufficientContextException();
1387 }
1388 return _notAChild(node);
1389 }
1390
1391 @override
1392 AstNode visitSimpleIdentifier(SimpleIdentifier node) => _notAChild(node);
1393
1394 @override
1395 AstNode visitSimpleStringLiteral(SimpleStringLiteral node) =>
1396 _notAChild(node);
1397
1398 @override
1399 AstNode visitStringInterpolation(StringInterpolation node) {
1400 if (node.elements.contains(_oldNode)) {
1401 throw new InsufficientContextException();
1402 }
1403 return _notAChild(node);
1404 }
1405
1406 @override
1407 AstNode visitSuperConstructorInvocation(SuperConstructorInvocation node) {
1408 if (identical(_oldNode, node.constructorName)) {
1409 return _parser.parseSimpleIdentifier();
1410 } else if (identical(_oldNode, node.argumentList)) {
1411 return _parser.parseArgumentList();
1412 }
1413 return _notAChild(node);
1414 }
1415
1416 @override
1417 AstNode visitSuperExpression(SuperExpression node) => _notAChild(node);
1418
1419 @override
1420 AstNode visitSwitchCase(SwitchCase node) {
1421 if (node.labels.contains(_oldNode)) {
1422 return _parser.parseLabel();
1423 } else if (identical(_oldNode, node.expression)) {
1424 return _parser.parseExpression2();
1425 } else if (node.statements.contains(_oldNode)) {
1426 return _parser.parseStatement2();
1427 }
1428 return _notAChild(node);
1429 }
1430
1431 @override
1432 AstNode visitSwitchDefault(SwitchDefault node) {
1433 if (node.labels.contains(_oldNode)) {
1434 return _parser.parseLabel();
1435 } else if (node.statements.contains(_oldNode)) {
1436 return _parser.parseStatement2();
1437 }
1438 return _notAChild(node);
1439 }
1440
1441 @override
1442 AstNode visitSwitchStatement(SwitchStatement node) {
1443 if (identical(_oldNode, node.expression)) {
1444 return _parser.parseExpression2();
1445 } else if (node.members.contains(_oldNode)) {
1446 throw new InsufficientContextException();
1447 }
1448 return _notAChild(node);
1449 }
1450
1451 @override
1452 AstNode visitSymbolLiteral(SymbolLiteral node) => _notAChild(node);
1453
1454 @override
1455 AstNode visitThisExpression(ThisExpression node) => _notAChild(node);
1456
1457 @override
1458 AstNode visitThrowExpression(ThrowExpression node) {
1459 if (identical(_oldNode, node.expression)) {
1460 if (_isCascadeAllowedInThrow(node)) {
1461 return _parser.parseExpression2();
1462 }
1463 return _parser.parseExpressionWithoutCascade();
1464 }
1465 return _notAChild(node);
1466 }
1467
1468 @override
1469 AstNode visitTopLevelVariableDeclaration(TopLevelVariableDeclaration node) {
1470 if (identical(_oldNode, node.documentationComment)) {
1471 throw new InsufficientContextException();
1472 } else if (node.metadata.contains(_oldNode)) {
1473 return _parser.parseAnnotation();
1474 } else if (identical(_oldNode, node.variables)) {
1475 throw new InsufficientContextException();
1476 }
1477 return _notAChild(node);
1478 }
1479
1480 @override
1481 AstNode visitTryStatement(TryStatement node) {
1482 if (identical(_oldNode, node.body)) {
1483 return _parser.parseBlock();
1484 } else if (node.catchClauses.contains(_oldNode)) {
1485 throw new InsufficientContextException();
1486 } else if (identical(_oldNode, node.finallyBlock)) {
1487 throw new InsufficientContextException();
1488 }
1489 return _notAChild(node);
1490 }
1491
1492 @override
1493 AstNode visitTypeArgumentList(TypeArgumentList node) {
1494 if (node.arguments.contains(_oldNode)) {
1495 return _parser.parseTypeName();
1496 }
1497 return _notAChild(node);
1498 }
1499
1500 @override
1501 AstNode visitTypeName(TypeName node) {
1502 if (identical(_oldNode, node.name)) {
1503 return _parser.parsePrefixedIdentifier();
1504 } else if (identical(_oldNode, node.typeArguments)) {
1505 return _parser.parseTypeArgumentList();
1506 }
1507 return _notAChild(node);
1508 }
1509
1510 @override
1511 AstNode visitTypeParameter(TypeParameter node) {
1512 if (identical(_oldNode, node.documentationComment)) {
1513 throw new InsufficientContextException();
1514 } else if (node.metadata.contains(_oldNode)) {
1515 return _parser.parseAnnotation();
1516 } else if (identical(_oldNode, node.name)) {
1517 return _parser.parseSimpleIdentifier();
1518 } else if (identical(_oldNode, node.bound)) {
1519 return _parser.parseTypeName();
1520 }
1521 return _notAChild(node);
1522 }
1523
1524 @override
1525 AstNode visitTypeParameterList(TypeParameterList node) {
1526 if (node.typeParameters.contains(node)) {
1527 return _parser.parseTypeParameter();
1528 }
1529 return _notAChild(node);
1530 }
1531
1532 @override
1533 AstNode visitVariableDeclaration(VariableDeclaration node) {
1534 if (identical(_oldNode, node.documentationComment)) {
1535 throw new InsufficientContextException();
1536 } else if (node.metadata.contains(_oldNode)) {
1537 return _parser.parseAnnotation();
1538 } else if (identical(_oldNode, node.name)) {
1539 throw new InsufficientContextException();
1540 } else if (identical(_oldNode, node.initializer)) {
1541 throw new InsufficientContextException();
1542 }
1543 return _notAChild(node);
1544 }
1545
1546 @override
1547 AstNode visitVariableDeclarationList(VariableDeclarationList node) {
1548 if (identical(_oldNode, node.documentationComment)) {
1549 throw new InsufficientContextException();
1550 } else if (node.metadata.contains(_oldNode)) {
1551 return _parser.parseAnnotation();
1552 } else if (identical(_oldNode, node.type)) {
1553 // There is not enough context to know whether we should reparse the type
1554 // using parseReturnType() (which allows 'void') or parseTypeName()
1555 // (which doesn't). Note that even though the language disallows
1556 // variables of type 'void', the parser sometimes accepts them in the
1557 // course of error recovery (e.g. "class C { void v; }"
1558 throw new InsufficientContextException();
1559 } else if (node.variables.contains(_oldNode)) {
1560 throw new InsufficientContextException();
1561 }
1562 return _notAChild(node);
1563 }
1564
1565 @override
1566 AstNode visitVariableDeclarationStatement(VariableDeclarationStatement node) {
1567 if (identical(_oldNode, node.variables)) {
1568 throw new InsufficientContextException();
1569 }
1570 return _notAChild(node);
1571 }
1572
1573 @override
1574 AstNode visitWhileStatement(WhileStatement node) {
1575 if (identical(_oldNode, node.condition)) {
1576 return _parser.parseExpression2();
1577 } else if (identical(_oldNode, node.body)) {
1578 return _parser.parseStatement2();
1579 }
1580 return _notAChild(node);
1581 }
1582
1583 @override
1584 AstNode visitWithClause(WithClause node) {
1585 if (node.mixinTypes.contains(node)) {
1586 return _parser.parseTypeName();
1587 }
1588 return _notAChild(node);
1589 }
1590
1591 @override
1592 AstNode visitYieldStatement(YieldStatement node) {
1593 if (identical(_oldNode, node.expression)) {
1594 return _parser.parseExpression2();
1595 }
1596 return _notAChild(node);
1597 }
1598
1599 /**
1600 * Return `true` if the given assignment [expression] can have a cascade
1601 * expression on the right-hand side.
1602 */
1603 bool _isCascadeAllowedInAssignment(AssignmentExpression expression) {
1604 // TODO(brianwilkerson) Implement this method.
1605 throw new InsufficientContextException();
1606 }
1607
1608 /**
1609 * Return `true` if the given throw [expression] can have a cascade
1610 * expression.
1611 */
1612 bool _isCascadeAllowedInThrow(ThrowExpression expression) {
1613 // TODO(brianwilkerson) Implement this method.
1614 throw new InsufficientContextException();
1615 }
1616
1617 /**
1618 * Throw an exception indicating that the visited [node] was not the parent of
1619 * the node to be replaced.
1620 */
1621 AstNode _notAChild(AstNode node) {
1622 throw new IncrementalParseException.con1(
1623 "Internal error: the visited node (a ${node.runtimeType}) was not the pa rent of the node to be replaced (a ${_oldNode.runtimeType})");
1624 }
1625 }
1626
1627 /**
1628 * An exception that occurred while attempting to parse a replacement for a
1629 * specified node in an existing AST structure.
1630 */
1631 class IncrementalParseException extends RuntimeException {
1632 /**
1633 * Initialize a newly created exception to have no message and to be its own
1634 * cause.
1635 */
1636 IncrementalParseException() : super();
1637
1638 /**
1639 * Initialize a newly created exception to have the given [message] and to be
1640 * its own cause.
1641 */
1642 IncrementalParseException.con1(String message) : super(message: message);
1643
1644 /**
1645 * Initialize a newly created exception to have no message and to have the
1646 * given [cause].
1647 */
1648 IncrementalParseException.con2(Exception cause) : super(cause: cause);
1649 }
1650
1651 /**
1652 * An object used to re-parse a single AST structure within a larger AST
1653 * structure.
1654 */
1655 class IncrementalParser {
1656 /**
1657 * The source being parsed.
1658 */
1659 final Source _source;
1660
1661 /**
1662 * A map from old tokens to new tokens used during the cloning process.
1663 */
1664 final TokenMap _tokenMap;
1665
1666 /**
1667 * The error listener that will be informed of any errors that are found
1668 * during the parse.
1669 */
1670 final AnalysisErrorListener _errorListener;
1671
1672 /**
1673 * The node in the AST structure that contains the revised content.
1674 */
1675 AstNode _updatedNode;
1676
1677 /**
1678 * Initialize a newly created incremental parser to parse a portion of the
1679 * content of the given [_source]. The [_tokenMap] is a map from old tokens to
1680 * new tokens that is used during the cloning process. The [_errorListener]
1681 * will be informed of any errors that are found during the parse.
1682 */
1683 IncrementalParser(this._source, this._tokenMap, this._errorListener);
1684
1685 /**
1686 * Return the node in the AST structure that contains the revised content.
1687 */
1688 AstNode get updatedNode => _updatedNode;
1689
1690 /**
1691 * Given a range of tokens that were re-scanned, re-parse the minimum number
1692 * of tokens to produce a consistent AST structure. The range is represented
1693 * by the first and last tokens in the range.
1694 *
1695 * More specifically, the [leftToken] is the token in the new token stream
1696 * immediately to the left of the range of tokens that were inserted and the
1697 * [rightToken] is the token in the new token stream immediately to the right
1698 * of the range of tokens that were inserted. The [originalStart] and
1699 * [originalEnd] are the offsets in the original source of the first and last
1700 * characters that were modified.
1701 *
1702 * The tokens are assumed to be contained in the same token stream.
1703 */
1704 AstNode reparse(AstNode originalStructure, Token leftToken, Token rightToken,
1705 int originalStart, int originalEnd) {
1706 AstNode oldNode = null;
1707 AstNode newNode = null;
1708 //
1709 // Find the first token that needs to be re-parsed.
1710 //
1711 Token firstToken = leftToken.next;
1712 if (identical(firstToken, rightToken)) {
1713 // If there are no new tokens, then we need to include at least one copied
1714 // node in the range.
1715 firstToken = leftToken;
1716 }
1717 //
1718 // Find the smallest AST node that encompasses the range of re-scanned
1719 // tokens.
1720 //
1721 if (originalEnd < originalStart) {
1722 oldNode = new NodeLocator(originalStart).searchWithin(originalStructure);
1723 } else {
1724 oldNode = new NodeLocator(originalStart, originalEnd)
1725 .searchWithin(originalStructure);
1726 }
1727 //
1728 // Find the token at which parsing is to begin.
1729 //
1730 int originalOffset = oldNode.offset;
1731 Token parseToken = _findTokenAt(firstToken, originalOffset);
1732 if (parseToken == null) {
1733 return null;
1734 }
1735 //
1736 // Parse the appropriate AST structure starting at the appropriate place.
1737 //
1738 Parser parser = new Parser(_source, _errorListener);
1739 parser.currentToken = parseToken;
1740 while (newNode == null) {
1741 AstNode parent = oldNode.parent;
1742 if (parent == null) {
1743 parseToken = _findFirstToken(parseToken);
1744 parser.currentToken = parseToken;
1745 return parser.parseCompilationUnit2();
1746 }
1747 bool advanceToParent = false;
1748 try {
1749 IncrementalParseDispatcher dispatcher =
1750 new IncrementalParseDispatcher(parser, oldNode);
1751 IncrementalParseStateBuilder contextBuilder =
1752 new IncrementalParseStateBuilder(parser);
1753 contextBuilder.buildState(oldNode);
1754 newNode = parent.accept(dispatcher);
1755 //
1756 // Validate that the new node can replace the old node.
1757 //
1758 Token mappedToken = _tokenMap.get(oldNode.endToken.next);
1759 if (mappedToken == null ||
1760 newNode == null ||
1761 mappedToken.offset != newNode.endToken.next.offset ||
1762 newNode.offset != oldNode.offset) {
1763 advanceToParent = true;
1764 }
1765 } on InsufficientContextException {
1766 advanceToParent = true;
1767 } catch (exception) {
1768 return null;
1769 }
1770 if (advanceToParent) {
1771 newNode = null;
1772 oldNode = parent;
1773 originalOffset = oldNode.offset;
1774 parseToken = _findTokenAt(parseToken, originalOffset);
1775 parser.currentToken = parseToken;
1776 }
1777 }
1778 _updatedNode = newNode;
1779 //
1780 // Replace the old node with the new node in a copy of the original AST
1781 // structure.
1782 //
1783 if (identical(oldNode, originalStructure)) {
1784 // We ended up re-parsing the whole structure, so there's no need for a
1785 // copy.
1786 ResolutionCopier.copyResolutionData(oldNode, newNode);
1787 return newNode;
1788 }
1789 ResolutionCopier.copyResolutionData(oldNode, newNode);
1790 IncrementalAstCloner cloner =
1791 new IncrementalAstCloner(oldNode, newNode, _tokenMap);
1792 return originalStructure.accept(cloner) as AstNode;
1793 }
1794
1795 /**
1796 * Return the first (non-EOF) token in the token stream containing the
1797 * [firstToken].
1798 */
1799 Token _findFirstToken(Token firstToken) {
1800 while (firstToken.type != TokenType.EOF) {
1801 firstToken = firstToken.previous;
1802 }
1803 return firstToken.next;
1804 }
1805
1806 /**
1807 * Find the token at or before the [firstToken] with the given [offset], or
1808 * `null` if there is no such token.
1809 */
1810 Token _findTokenAt(Token firstToken, int offset) {
1811 while (firstToken.offset > offset && firstToken.type != TokenType.EOF) {
1812 firstToken = firstToken.previous;
1813 }
1814 return firstToken;
1815 }
1816 }
1817
1818 /**
1819 * A visitor capable of inferring the correct parser state for incremental
1820 * parsing. This visitor visits each parent/child relationship in the chain of
1821 * ancestors of the node to be replaced (starting with the root of the parse
1822 * tree), updating the parser to the correct state for parsing the child of the
1823 * given parent. Once it has visited all of these relationships, the parser
1824 * will be in the correct state for reparsing the node to be replaced.
1825 */
1826 class IncrementalParseStateBuilder extends SimpleAstVisitor {
1827 // TODO(paulberry): add support for other pieces of parser state (_inAsync,
1828 // _inGenerator, _inLoop, and _inSwitch). Note that _inLoop and _inSwitch
1829 // only affect error message generation.
1830
1831 /**
1832 * The parser whose state should be built.
1833 */
1834 final Parser _parser;
1835
1836 /**
1837 * The child node in the parent/child relationship currently being visited.
1838 * (The corresponding parent is the node passed to the visit...() function.)
1839 */
1840 AstNode _childNode;
1841
1842 /**
1843 * Create an IncrementalParseStateBuilder which will build the correct state
1844 * for [_parser].
1845 */
1846 IncrementalParseStateBuilder(this._parser);
1847
1848 /**
1849 * Build the correct parser state for parsing a replacement for [node].
1850 */
1851 void buildState(AstNode node) {
1852 List<AstNode> ancestors = <AstNode>[];
1853 while (node != null) {
1854 ancestors.add(node);
1855 node = node.parent;
1856 }
1857 _parser._inInitializer = false;
1858 for (int i = ancestors.length - 2; i >= 0; i--) {
1859 _childNode = ancestors[i];
1860 ancestors[i + 1].accept(this);
1861 }
1862 }
1863
1864 @override
1865 void visitArgumentList(ArgumentList node) {
1866 _parser._inInitializer = false;
1867 }
1868
1869 @override
1870 void visitConstructorFieldInitializer(ConstructorFieldInitializer node) {
1871 if (identical(_childNode, node.expression)) {
1872 _parser._inInitializer = true;
1873 }
1874 }
1875
1876 @override
1877 void visitIndexExpression(IndexExpression node) {
1878 if (identical(_childNode, node.index)) {
1879 _parser._inInitializer = false;
1880 }
1881 }
1882
1883 @override
1884 void visitInterpolationExpression(InterpolationExpression node) {
1885 if (identical(_childNode, node.expression)) {
1886 _parser._inInitializer = false;
1887 }
1888 }
1889
1890 @override
1891 void visitListLiteral(ListLiteral node) {
1892 if (node.elements.contains(_childNode)) {
1893 _parser._inInitializer = false;
1894 }
1895 }
1896
1897 @override
1898 void visitMapLiteral(MapLiteral node) {
1899 if (node.entries.contains(_childNode)) {
1900 _parser._inInitializer = false;
1901 }
1902 }
1903
1904 @override
1905 void visitParenthesizedExpression(ParenthesizedExpression node) {
1906 if (identical(_childNode, node.expression)) {
1907 _parser._inInitializer = false;
1908 }
1909 }
1910 }
1911
1912 /**
1913 * An exception indicating that an AST node cannot be re-parsed because there is
1914 * not enough context to know how to re-parse the node. Clients can attempt to
1915 * re-parse the parent of the node.
1916 */
1917 class InsufficientContextException extends IncrementalParseException {
1918 /**
1919 * Initialize a newly created exception to have no message and to be its own
1920 * cause.
1921 */
1922 InsufficientContextException() : super();
1923
1924 /**
1925 * Initialize a newly created exception to have the given [message] and to be
1926 * its own cause.
1927 */
1928 InsufficientContextException.con1(String message) : super.con1(message);
1929
1930 /**
1931 * Initialize a newly created exception to have no message and to have the
1932 * given [cause].
1933 */
1934 InsufficientContextException.con2(Exception cause) : super.con2(cause);
1935 }
1936
1937 /**
1938 * Wrapper around [Function] which should be called with "target" and
1939 * "arguments".
1940 */
1941 class MethodTrampoline {
1942 int parameterCount;
1943 Function trampoline;
1944 MethodTrampoline(this.parameterCount, this.trampoline);
1945 Object invoke(target, List arguments) {
1946 if (arguments.length != parameterCount) {
1947 throw new IllegalArgumentException(
1948 "${arguments.length} != $parameterCount");
1949 }
1950 switch (parameterCount) {
1951 case 0:
1952 return trampoline(target);
1953 case 1:
1954 return trampoline(target, arguments[0]);
1955 case 2:
1956 return trampoline(target, arguments[0], arguments[1]);
1957 case 3:
1958 return trampoline(target, arguments[0], arguments[1], arguments[2]);
1959 case 4:
1960 return trampoline(
1961 target, arguments[0], arguments[1], arguments[2], arguments[3]);
1962 default:
1963 throw new IllegalArgumentException("Not implemented for > 4 arguments");
1964 }
1965 }
1966 }
1967
1968 /**
1969 * A simple data-holder for a method that needs to return multiple values. 75 * A simple data-holder for a method that needs to return multiple values.
1970 */ 76 */
1971 class Modifiers { 77 class Modifiers {
1972 /** 78 /**
1973 * The token representing the keyword 'abstract', or `null` if the keyword was 79 * The token representing the keyword 'abstract', or `null` if the keyword was
1974 * not found. 80 * not found.
1975 */ 81 */
1976 Token abstractKeyword; 82 Token abstractKeyword;
1977 83
1978 /** 84 /**
(...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after
2068 */ 174 */
2069 final Source _source; 175 final Source _source;
2070 176
2071 /** 177 /**
2072 * The error listener that will be informed of any errors that are found 178 * The error listener that will be informed of any errors that are found
2073 * during the parse. 179 * during the parse.
2074 */ 180 */
2075 final AnalysisErrorListener _errorListener; 181 final AnalysisErrorListener _errorListener;
2076 182
2077 /** 183 /**
2078 * An [errorListener] lock, if more than `0`, then errors are not reported. 184 * An [_errorListener] lock, if more than `0`, then errors are not reported.
2079 */ 185 */
2080 int _errorListenerLock = 0; 186 int _errorListenerLock = 0;
2081 187
2082 /** 188 /**
189 * A flag indicating whether the parser is to parse asserts in the initializer
190 * list of a constructor.
191 */
192 bool _enableAssertInitializer = false;
193
194 /**
195 * A flag indicating whether the parser is to parse the non-nullable modifier
196 * in type names.
197 */
198 bool _enableNnbd = false;
199
200 /**
2083 * A flag indicating whether parser is to parse function bodies. 201 * A flag indicating whether parser is to parse function bodies.
2084 */ 202 */
2085 bool _parseFunctionBodies = true; 203 bool _parseFunctionBodies = true;
2086 204
2087 /** 205 /**
2088 * The next token to be parsed. 206 * The next token to be parsed.
2089 */ 207 */
2090 Token _currentToken; 208 Token _currentToken;
2091 209
2092 /** 210 /**
2093 * A flag indicating whether the parser is currently in a function body marked 211 * A flag indicating whether the parser is currently in a function body marked
2094 * as being 'async'. 212 * as being 'async'.
2095 */ 213 */
2096 bool _inAsync = false; 214 bool _inAsync = false;
2097 215
2098 /** 216 /**
2099 * A flag indicating whether the parser is currently in a function body marked 217 * A flag indicating whether the parser is currently in a function body marked
2100 * as being 'async'. 218 * (by a star) as being a generator.
2101 */ 219 */
2102 bool _inGenerator = false; 220 bool _inGenerator = false;
2103 221
2104 /** 222 /**
2105 * A flag indicating whether the parser is currently in the body of a loop. 223 * A flag indicating whether the parser is currently in the body of a loop.
2106 */ 224 */
2107 bool _inLoop = false; 225 bool _inLoop = false;
2108 226
2109 /** 227 /**
2110 * A flag indicating whether the parser is currently in a switch statement. 228 * A flag indicating whether the parser is currently in a switch statement.
2111 */ 229 */
2112 bool _inSwitch = false; 230 bool _inSwitch = false;
2113 231
2114 /** 232 /**
2115 * A flag indicating whether the parser is currently in a constructor field 233 * A flag indicating whether the parser is currently in a constructor field
2116 * initializer, with no intervening parens, braces, or brackets. 234 * initializer, with no intervening parentheses, braces, or brackets.
2117 */ 235 */
2118 bool _inInitializer = false; 236 bool _inInitializer = false;
2119 237
2120 /** 238 /**
2121 * A flag indicating whether the parser is to parse generic method syntax. 239 * A flag indicating whether the parser is to parse generic method syntax.
2122 */ 240 */
2123 bool parseGenericMethods = false; 241 bool parseGenericMethods = false;
2124 242
2125 /** 243 /**
2126 * Initialize a newly created parser to parse the content of the given 244 * A flag indicating whether to parse generic method comments, of the form
2127 * [_source] and to report any errors that are found to the given 245 * `/*=T*/` and `/*<T>*/`.
2128 * [_errorListener]. 246 */
247 bool parseGenericMethodComments = false;
248
249 /**
250 * Initialize a newly created parser to parse tokens in the given [_source]
251 * and to report any errors that are found to the given [_errorListener].
2129 */ 252 */
2130 Parser(this._source, this._errorListener); 253 Parser(this._source, this._errorListener);
2131 254
2132 void set currentToken(Token currentToken) { 255 /**
2133 this._currentToken = currentToken; 256 * Return the current token.
257 */
258 Token get currentToken => _currentToken;
259
260 /**
261 * Set the token with which the parse is to begin to the given [token].
262 */
263 void set currentToken(Token token) {
264 this._currentToken = token;
265 }
266
267 /**
268 * Return `true` if the parser is to parse asserts in the initializer list of
269 * a constructor.
270 */
271 bool get enableAssertInitializer => _enableAssertInitializer;
272
273 /**
274 * Set whether the parser is to parse asserts in the initializer list of a
275 * constructor to match the given [enable] flag.
276 */
277 void set enableAssertInitializer(bool enable) {
278 _enableAssertInitializer = enable;
279 }
280
281 /**
282 * Return `true` if the parser is to parse the non-nullable modifier in type
283 * names.
284 */
285 bool get enableNnbd => _enableNnbd;
286
287 /**
288 * Set whether the parser is to parse the non-nullable modifier in type names
289 * to match the given [enable] flag.
290 */
291 void set enableNnbd(bool enable) {
292 _enableNnbd = enable;
2134 } 293 }
2135 294
2136 /** 295 /**
2137 * Return `true` if the current token is the first token of a return type that 296 * Return `true` if the current token is the first token of a return type that
2138 * is followed by an identifier, possibly followed by a list of type 297 * is followed by an identifier, possibly followed by a list of type
2139 * parameters, followed by a left-parenthesis. This is used by 298 * parameters, followed by a left-parenthesis. This is used by
2140 * [_parseTypeAlias] to determine whether or not to parse a return type. 299 * [parseTypeAlias] to determine whether or not to parse a return type.
2141 */ 300 */
301 @deprecated
2142 bool get hasReturnTypeInTypeAlias { 302 bool get hasReturnTypeInTypeAlias {
2143 Token next = _skipReturnType(_currentToken); 303 Token next = skipReturnType(_currentToken);
2144 if (next == null) { 304 if (next == null) {
2145 return false; 305 return false;
2146 } 306 }
2147 return _tokenMatchesIdentifier(next); 307 return _tokenMatchesIdentifier(next);
2148 } 308 }
2149 309
2150 /** 310 /**
2151 * Set whether the parser is to parse the async support. 311 * Set whether the parser is to parse the async support.
312 *
313 * Support for removing the 'async' library has been removed.
2152 */ 314 */
2153 @deprecated 315 @deprecated
2154 void set parseAsync(bool parseAsync) { 316 void set parseAsync(bool parseAsync) {}
2155 // Async support cannot be disabled 317
2156 }
2157
2158 /**
2159 * Set whether the parser is to parse deferred libraries.
2160 */
2161 @deprecated 318 @deprecated
2162 void set parseDeferredLibraries(bool parseDeferredLibraries) { 319 bool get parseConditionalDirectives => true;
2163 // Deferred libraries support cannot be disabled 320
2164 }
2165
2166 /**
2167 * Set whether the parser is to parse enum declarations.
2168 */
2169 @deprecated 321 @deprecated
2170 void set parseEnum(bool parseEnum) { 322 void set parseConditionalDirectives(bool value) {}
2171 // Enum support cannot be disabled
2172 }
2173 323
2174 /** 324 /**
2175 * Set whether parser is to parse function bodies. 325 * Set whether parser is to parse function bodies.
2176 */ 326 */
2177 void set parseFunctionBodies(bool parseFunctionBodies) { 327 void set parseFunctionBodies(bool parseFunctionBodies) {
2178 this._parseFunctionBodies = parseFunctionBodies; 328 this._parseFunctionBodies = parseFunctionBodies;
2179 } 329 }
2180 330
2181 /** 331 /**
2182 * Advance to the next token in the token stream, making it the new current
2183 * token and return the token that was current before this method was invoked.
2184 */
2185 Token getAndAdvance() {
2186 Token token = _currentToken;
2187 _advance();
2188 return token;
2189 }
2190
2191 /**
2192 * Parse an annotation. Return the annotation that was parsed.
2193 *
2194 * annotation ::=
2195 * '@' qualified ('.' identifier)? arguments?
2196 *
2197 */
2198 Annotation parseAnnotation() {
2199 Token atSign = _expect(TokenType.AT);
2200 Identifier name = parsePrefixedIdentifier();
2201 Token period = null;
2202 SimpleIdentifier constructorName = null;
2203 if (_matches(TokenType.PERIOD)) {
2204 period = getAndAdvance();
2205 constructorName = parseSimpleIdentifier();
2206 }
2207 ArgumentList arguments = null;
2208 if (_matches(TokenType.OPEN_PAREN)) {
2209 arguments = parseArgumentList();
2210 }
2211 return new Annotation(atSign, name, period, constructorName, arguments);
2212 }
2213
2214 /**
2215 * Parse an argument. Return the argument that was parsed.
2216 *
2217 * argument ::=
2218 * namedArgument
2219 * | expression
2220 *
2221 * namedArgument ::=
2222 * label expression
2223 */
2224 Expression parseArgument() {
2225 //
2226 // Both namedArgument and expression can start with an identifier, but only
2227 // namedArgument can have an identifier followed by a colon.
2228 //
2229 if (_matchesIdentifier() && _tokenMatches(_peek(), TokenType.COLON)) {
2230 return new NamedExpression(parseLabel(), parseExpression2());
2231 } else {
2232 return parseExpression2();
2233 }
2234 }
2235
2236 /**
2237 * Parse a list of arguments. Return the argument list that was parsed.
2238 *
2239 * arguments ::=
2240 * '(' argumentList? ')'
2241 *
2242 * argumentList ::=
2243 * namedArgument (',' namedArgument)*
2244 * | expressionList (',' namedArgument)*
2245 */
2246 ArgumentList parseArgumentList() {
2247 Token leftParenthesis = _expect(TokenType.OPEN_PAREN);
2248 List<Expression> arguments = new List<Expression>();
2249 if (_matches(TokenType.CLOSE_PAREN)) {
2250 return new ArgumentList(leftParenthesis, arguments, getAndAdvance());
2251 }
2252 //
2253 // Even though unnamed arguments must all appear before any named arguments,
2254 // we allow them to appear in any order so that we can recover faster.
2255 //
2256 bool wasInInitializer = _inInitializer;
2257 _inInitializer = false;
2258 try {
2259 Expression argument = parseArgument();
2260 arguments.add(argument);
2261 bool foundNamedArgument = argument is NamedExpression;
2262 bool generatedError = false;
2263 while (_optional(TokenType.COMMA)) {
2264 argument = parseArgument();
2265 arguments.add(argument);
2266 if (foundNamedArgument) {
2267 bool blankArgument =
2268 argument is SimpleIdentifier && argument.name.isEmpty;
2269 if (!generatedError &&
2270 !(argument is NamedExpression && !blankArgument)) {
2271 // Report the error, once, but allow the arguments to be in any
2272 // order in the AST.
2273 _reportErrorForCurrentToken(
2274 ParserErrorCode.POSITIONAL_AFTER_NAMED_ARGUMENT);
2275 generatedError = true;
2276 }
2277 } else if (argument is NamedExpression) {
2278 foundNamedArgument = true;
2279 }
2280 }
2281 // TODO(brianwilkerson) Recovery: Look at the left parenthesis to see
2282 // whether there is a matching right parenthesis. If there is, then we're
2283 // more likely missing a comma and should go back to parsing arguments.
2284 Token rightParenthesis = _expect(TokenType.CLOSE_PAREN);
2285 return new ArgumentList(leftParenthesis, arguments, rightParenthesis);
2286 } finally {
2287 _inInitializer = wasInInitializer;
2288 }
2289 }
2290
2291 /**
2292 * Parse a bitwise or expression. Return the bitwise or expression that was
2293 * parsed.
2294 *
2295 * bitwiseOrExpression ::=
2296 * bitwiseXorExpression ('|' bitwiseXorExpression)*
2297 * | 'super' ('|' bitwiseXorExpression)+
2298 */
2299 Expression parseBitwiseOrExpression() {
2300 Expression expression;
2301 if (_matchesKeyword(Keyword.SUPER) &&
2302 _tokenMatches(_peek(), TokenType.BAR)) {
2303 expression = new SuperExpression(getAndAdvance());
2304 } else {
2305 expression = _parseBitwiseXorExpression();
2306 }
2307 while (_matches(TokenType.BAR)) {
2308 Token operator = getAndAdvance();
2309 expression = new BinaryExpression(
2310 expression, operator, _parseBitwiseXorExpression());
2311 }
2312 return expression;
2313 }
2314
2315 /**
2316 * Parse a block. Return the block that was parsed.
2317 *
2318 * block ::=
2319 * '{' statements '}'
2320 */
2321 Block parseBlock() {
2322 Token leftBracket = _expect(TokenType.OPEN_CURLY_BRACKET);
2323 List<Statement> statements = new List<Statement>();
2324 Token statementStart = _currentToken;
2325 while (
2326 !_matches(TokenType.EOF) && !_matches(TokenType.CLOSE_CURLY_BRACKET)) {
2327 Statement statement = parseStatement2();
2328 if (statement != null) {
2329 statements.add(statement);
2330 }
2331 if (identical(_currentToken, statementStart)) {
2332 // Ensure that we are making progress and report an error if we're not.
2333 _reportErrorForToken(ParserErrorCode.UNEXPECTED_TOKEN, _currentToken,
2334 [_currentToken.lexeme]);
2335 _advance();
2336 }
2337 statementStart = _currentToken;
2338 }
2339 Token rightBracket = _expect(TokenType.CLOSE_CURLY_BRACKET);
2340 return new Block(leftBracket, statements, rightBracket);
2341 }
2342
2343 /**
2344 * Parse a class member. The [className] is the name of the class containing
2345 * the member being parsed. Return the class member that was parsed, or `null`
2346 * if what was found was not a valid class member.
2347 *
2348 * classMemberDefinition ::=
2349 * declaration ';'
2350 * | methodSignature functionBody
2351 */
2352 ClassMember parseClassMember(String className) {
2353 CommentAndMetadata commentAndMetadata = _parseCommentAndMetadata();
2354 Modifiers modifiers = _parseModifiers();
2355 if (_matchesKeyword(Keyword.VOID)) {
2356 TypeName returnType = parseReturnType();
2357 if (_matchesKeyword(Keyword.GET) && _tokenMatchesIdentifier(_peek())) {
2358 _validateModifiersForGetterOrSetterOrMethod(modifiers);
2359 return _parseGetter(commentAndMetadata, modifiers.externalKeyword,
2360 modifiers.staticKeyword, returnType);
2361 } else if (_matchesKeyword(Keyword.SET) &&
2362 _tokenMatchesIdentifier(_peek())) {
2363 _validateModifiersForGetterOrSetterOrMethod(modifiers);
2364 return _parseSetter(commentAndMetadata, modifiers.externalKeyword,
2365 modifiers.staticKeyword, returnType);
2366 } else if (_matchesKeyword(Keyword.OPERATOR) && _isOperator(_peek())) {
2367 _validateModifiersForOperator(modifiers);
2368 return _parseOperator(
2369 commentAndMetadata, modifiers.externalKeyword, returnType);
2370 } else if (_matchesIdentifier() &&
2371 _peek().matchesAny([
2372 TokenType.OPEN_PAREN,
2373 TokenType.OPEN_CURLY_BRACKET,
2374 TokenType.FUNCTION,
2375 TokenType.LT
2376 ])) {
2377 _validateModifiersForGetterOrSetterOrMethod(modifiers);
2378 return _parseMethodDeclarationAfterReturnType(commentAndMetadata,
2379 modifiers.externalKeyword, modifiers.staticKeyword, returnType);
2380 } else {
2381 //
2382 // We have found an error of some kind. Try to recover.
2383 //
2384 if (_matchesIdentifier()) {
2385 if (_peek().matchesAny(
2386 [TokenType.EQ, TokenType.COMMA, TokenType.SEMICOLON])) {
2387 //
2388 // We appear to have a variable declaration with a type of "void".
2389 //
2390 _reportErrorForNode(ParserErrorCode.VOID_VARIABLE, returnType);
2391 return _parseInitializedIdentifierList(
2392 commentAndMetadata,
2393 modifiers.staticKeyword,
2394 _validateModifiersForField(modifiers),
2395 returnType);
2396 }
2397 }
2398 if (_isOperator(_currentToken)) {
2399 //
2400 // We appear to have found an operator declaration without the
2401 // 'operator' keyword.
2402 //
2403 _validateModifiersForOperator(modifiers);
2404 return _parseOperator(
2405 commentAndMetadata, modifiers.externalKeyword, returnType);
2406 }
2407 _reportErrorForToken(
2408 ParserErrorCode.EXPECTED_EXECUTABLE, _currentToken);
2409 return null;
2410 }
2411 } else if (_matchesKeyword(Keyword.GET) &&
2412 _tokenMatchesIdentifier(_peek())) {
2413 _validateModifiersForGetterOrSetterOrMethod(modifiers);
2414 return _parseGetter(commentAndMetadata, modifiers.externalKeyword,
2415 modifiers.staticKeyword, null);
2416 } else if (_matchesKeyword(Keyword.SET) &&
2417 _tokenMatchesIdentifier(_peek())) {
2418 _validateModifiersForGetterOrSetterOrMethod(modifiers);
2419 return _parseSetter(commentAndMetadata, modifiers.externalKeyword,
2420 modifiers.staticKeyword, null);
2421 } else if (_matchesKeyword(Keyword.OPERATOR) && _isOperator(_peek())) {
2422 _validateModifiersForOperator(modifiers);
2423 return _parseOperator(
2424 commentAndMetadata, modifiers.externalKeyword, null);
2425 } else if (!_matchesIdentifier()) {
2426 //
2427 // Recover from an error.
2428 //
2429 if (_matchesKeyword(Keyword.CLASS)) {
2430 _reportErrorForCurrentToken(ParserErrorCode.CLASS_IN_CLASS);
2431 // TODO(brianwilkerson) We don't currently have any way to capture the
2432 // class that was parsed.
2433 _parseClassDeclaration(commentAndMetadata, null);
2434 return null;
2435 } else if (_matchesKeyword(Keyword.ABSTRACT) &&
2436 _tokenMatchesKeyword(_peek(), Keyword.CLASS)) {
2437 _reportErrorForToken(ParserErrorCode.CLASS_IN_CLASS, _peek());
2438 // TODO(brianwilkerson) We don't currently have any way to capture the
2439 // class that was parsed.
2440 _parseClassDeclaration(commentAndMetadata, getAndAdvance());
2441 return null;
2442 } else if (_matchesKeyword(Keyword.ENUM)) {
2443 _reportErrorForToken(ParserErrorCode.ENUM_IN_CLASS, _peek());
2444 // TODO(brianwilkerson) We don't currently have any way to capture the
2445 // enum that was parsed.
2446 _parseEnumDeclaration(commentAndMetadata);
2447 return null;
2448 } else if (_isOperator(_currentToken)) {
2449 //
2450 // We appear to have found an operator declaration without the
2451 // 'operator' keyword.
2452 //
2453 _validateModifiersForOperator(modifiers);
2454 return _parseOperator(
2455 commentAndMetadata, modifiers.externalKeyword, null);
2456 }
2457 Token keyword = modifiers.varKeyword;
2458 if (keyword == null) {
2459 keyword = modifiers.finalKeyword;
2460 }
2461 if (keyword == null) {
2462 keyword = modifiers.constKeyword;
2463 }
2464 if (keyword != null) {
2465 //
2466 // We appear to have found an incomplete field declaration.
2467 //
2468 _reportErrorForCurrentToken(ParserErrorCode.MISSING_IDENTIFIER);
2469 List<VariableDeclaration> variables = new List<VariableDeclaration>();
2470 variables.add(
2471 new VariableDeclaration(_createSyntheticIdentifier(), null, null));
2472 return new FieldDeclaration(
2473 commentAndMetadata.comment,
2474 commentAndMetadata.metadata,
2475 null,
2476 new VariableDeclarationList(null, null, keyword, null, variables),
2477 _expectSemicolon());
2478 }
2479 _reportErrorForToken(
2480 ParserErrorCode.EXPECTED_CLASS_MEMBER, _currentToken);
2481 if (commentAndMetadata.comment != null ||
2482 !commentAndMetadata.metadata.isEmpty) {
2483 //
2484 // We appear to have found an incomplete declaration at the end of the
2485 // class. At this point it consists of a metadata, which we don't want
2486 // to loose, so we'll treat it as a method declaration with a missing
2487 // name, parameters and empty body.
2488 //
2489 return new MethodDeclaration(
2490 commentAndMetadata.comment,
2491 commentAndMetadata.metadata,
2492 null,
2493 null,
2494 null,
2495 null,
2496 null,
2497 _createSyntheticIdentifier(),
2498 null,
2499 new FormalParameterList(
2500 null, new List<FormalParameter>(), null, null, null),
2501 new EmptyFunctionBody(_createSyntheticToken(TokenType.SEMICOLON)));
2502 }
2503 return null;
2504 } else if (_tokenMatches(_peek(), TokenType.PERIOD) &&
2505 _tokenMatchesIdentifier(_peekAt(2)) &&
2506 _tokenMatches(_peekAt(3), TokenType.OPEN_PAREN)) {
2507 return _parseConstructor(
2508 commentAndMetadata,
2509 modifiers.externalKeyword,
2510 _validateModifiersForConstructor(modifiers),
2511 modifiers.factoryKeyword,
2512 parseSimpleIdentifier(),
2513 getAndAdvance(),
2514 parseSimpleIdentifier(),
2515 parseFormalParameterList());
2516 } else if (_tokenMatches(_peek(), TokenType.OPEN_PAREN)) {
2517 SimpleIdentifier methodName = parseSimpleIdentifier();
2518 FormalParameterList parameters = parseFormalParameterList();
2519 if (_matches(TokenType.COLON) ||
2520 modifiers.factoryKeyword != null ||
2521 methodName.name == className) {
2522 return _parseConstructor(
2523 commentAndMetadata,
2524 modifiers.externalKeyword,
2525 _validateModifiersForConstructor(modifiers),
2526 modifiers.factoryKeyword,
2527 methodName,
2528 null,
2529 null,
2530 parameters);
2531 }
2532 _validateModifiersForGetterOrSetterOrMethod(modifiers);
2533 _validateFormalParameterList(parameters);
2534 return _parseMethodDeclarationAfterParameters(
2535 commentAndMetadata,
2536 modifiers.externalKeyword,
2537 modifiers.staticKeyword,
2538 null,
2539 methodName,
2540 null,
2541 parameters);
2542 } else if (_peek()
2543 .matchesAny([TokenType.EQ, TokenType.COMMA, TokenType.SEMICOLON])) {
2544 if (modifiers.constKeyword == null &&
2545 modifiers.finalKeyword == null &&
2546 modifiers.varKeyword == null) {
2547 _reportErrorForCurrentToken(
2548 ParserErrorCode.MISSING_CONST_FINAL_VAR_OR_TYPE);
2549 }
2550 return _parseInitializedIdentifierList(commentAndMetadata,
2551 modifiers.staticKeyword, _validateModifiersForField(modifiers), null);
2552 } else if (_matchesKeyword(Keyword.TYPEDEF)) {
2553 _reportErrorForCurrentToken(ParserErrorCode.TYPEDEF_IN_CLASS);
2554 // TODO(brianwilkerson) We don't currently have any way to capture the
2555 // function type alias that was parsed.
2556 _parseFunctionTypeAlias(commentAndMetadata, getAndAdvance());
2557 return null;
2558 } else if (parseGenericMethods) {
2559 Token token = _skipTypeParameterList(_peek());
2560 if (token != null && _tokenMatches(token, TokenType.OPEN_PAREN)) {
2561 return _parseMethodDeclarationAfterReturnType(commentAndMetadata,
2562 modifiers.externalKeyword, modifiers.staticKeyword, null);
2563 }
2564 }
2565 TypeName type = parseTypeName();
2566 if (_matchesKeyword(Keyword.GET) && _tokenMatchesIdentifier(_peek())) {
2567 _validateModifiersForGetterOrSetterOrMethod(modifiers);
2568 return _parseGetter(commentAndMetadata, modifiers.externalKeyword,
2569 modifiers.staticKeyword, type);
2570 } else if (_matchesKeyword(Keyword.SET) &&
2571 _tokenMatchesIdentifier(_peek())) {
2572 _validateModifiersForGetterOrSetterOrMethod(modifiers);
2573 return _parseSetter(commentAndMetadata, modifiers.externalKeyword,
2574 modifiers.staticKeyword, type);
2575 } else if (_matchesKeyword(Keyword.OPERATOR) && _isOperator(_peek())) {
2576 _validateModifiersForOperator(modifiers);
2577 return _parseOperator(
2578 commentAndMetadata, modifiers.externalKeyword, type);
2579 } else if (!_matchesIdentifier()) {
2580 if (_matches(TokenType.CLOSE_CURLY_BRACKET)) {
2581 //
2582 // We appear to have found an incomplete declaration at the end of the
2583 // class. At this point it consists of a type name, so we'll treat it as
2584 // a field declaration with a missing field name and semicolon.
2585 //
2586 return _parseInitializedIdentifierList(
2587 commentAndMetadata,
2588 modifiers.staticKeyword,
2589 _validateModifiersForField(modifiers),
2590 type);
2591 }
2592 if (_isOperator(_currentToken)) {
2593 //
2594 // We appear to have found an operator declaration without the
2595 // 'operator' keyword.
2596 //
2597 _validateModifiersForOperator(modifiers);
2598 return _parseOperator(
2599 commentAndMetadata, modifiers.externalKeyword, type);
2600 }
2601 //
2602 // We appear to have found an incomplete declaration before another
2603 // declaration. At this point it consists of a type name, so we'll treat
2604 // it as a field declaration with a missing field name and semicolon.
2605 //
2606 _reportErrorForToken(
2607 ParserErrorCode.EXPECTED_CLASS_MEMBER, _currentToken);
2608 try {
2609 _lockErrorListener();
2610 return _parseInitializedIdentifierList(
2611 commentAndMetadata,
2612 modifiers.staticKeyword,
2613 _validateModifiersForField(modifiers),
2614 type);
2615 } finally {
2616 _unlockErrorListener();
2617 }
2618 } else if (_tokenMatches(_peek(), TokenType.OPEN_PAREN)) {
2619 SimpleIdentifier methodName = parseSimpleIdentifier();
2620 FormalParameterList parameters = parseFormalParameterList();
2621 if (methodName.name == className) {
2622 _reportErrorForNode(ParserErrorCode.CONSTRUCTOR_WITH_RETURN_TYPE, type);
2623 return _parseConstructor(
2624 commentAndMetadata,
2625 modifiers.externalKeyword,
2626 _validateModifiersForConstructor(modifiers),
2627 modifiers.factoryKeyword,
2628 methodName,
2629 null,
2630 null,
2631 parameters);
2632 }
2633 _validateModifiersForGetterOrSetterOrMethod(modifiers);
2634 _validateFormalParameterList(parameters);
2635 return _parseMethodDeclarationAfterParameters(
2636 commentAndMetadata,
2637 modifiers.externalKeyword,
2638 modifiers.staticKeyword,
2639 type,
2640 methodName,
2641 null,
2642 parameters);
2643 } else if (parseGenericMethods && _tokenMatches(_peek(), TokenType.LT)) {
2644 return _parseMethodDeclarationAfterReturnType(commentAndMetadata,
2645 modifiers.externalKeyword, modifiers.staticKeyword, type);
2646 } else if (_tokenMatches(_peek(), TokenType.OPEN_CURLY_BRACKET)) {
2647 // We have found "TypeName identifier {", and are guessing that this is a
2648 // getter without the keyword 'get'.
2649 _validateModifiersForGetterOrSetterOrMethod(modifiers);
2650 _reportErrorForCurrentToken(ParserErrorCode.MISSING_GET);
2651 _currentToken = _injectToken(
2652 new Parser_SyntheticKeywordToken(Keyword.GET, _currentToken.offset));
2653 return _parseGetter(commentAndMetadata, modifiers.externalKeyword,
2654 modifiers.staticKeyword, type);
2655 }
2656 return _parseInitializedIdentifierList(commentAndMetadata,
2657 modifiers.staticKeyword, _validateModifiersForField(modifiers), type);
2658 }
2659
2660 /**
2661 * Parse a single combinator. Return the combinator that was parsed, or `null`
2662 * if no combinator is found.
2663 *
2664 * combinator ::=
2665 * 'show' identifier (',' identifier)*
2666 * | 'hide' identifier (',' identifier)*
2667 */
2668 Combinator parseCombinator() {
2669 if (_matchesString(_SHOW) || _matchesString(_HIDE)) {
2670 Token keyword = getAndAdvance();
2671 List<SimpleIdentifier> names = _parseIdentifierList();
2672 if (keyword.lexeme == _SHOW) {
2673 return new ShowCombinator(keyword, names);
2674 } else {
2675 return new HideCombinator(keyword, names);
2676 }
2677 }
2678 return null;
2679 }
2680
2681 /**
2682 * Parse a compilation unit, starting with the given [token]. Return the
2683 * compilation unit that was parsed.
2684 */
2685 CompilationUnit parseCompilationUnit(Token token) {
2686 _currentToken = token;
2687 return parseCompilationUnit2();
2688 }
2689
2690 /**
2691 * Parse a compilation unit. Return the compilation unit that was parsed.
2692 *
2693 * Specified:
2694 *
2695 * compilationUnit ::=
2696 * scriptTag? directive* topLevelDeclaration*
2697 *
2698 * Actual:
2699 *
2700 * compilationUnit ::=
2701 * scriptTag? topLevelElement*
2702 *
2703 * topLevelElement ::=
2704 * directive
2705 * | topLevelDeclaration
2706 */
2707 CompilationUnit parseCompilationUnit2() {
2708 Token firstToken = _currentToken;
2709 ScriptTag scriptTag = null;
2710 if (_matches(TokenType.SCRIPT_TAG)) {
2711 scriptTag = new ScriptTag(getAndAdvance());
2712 }
2713 //
2714 // Even though all directives must appear before declarations and must occur
2715 // in a given order, we allow directives and declarations to occur in any
2716 // order so that we can recover better.
2717 //
2718 bool libraryDirectiveFound = false;
2719 bool partOfDirectiveFound = false;
2720 bool partDirectiveFound = false;
2721 bool directiveFoundAfterDeclaration = false;
2722 List<Directive> directives = new List<Directive>();
2723 List<CompilationUnitMember> declarations =
2724 new List<CompilationUnitMember>();
2725 Token memberStart = _currentToken;
2726 while (!_matches(TokenType.EOF)) {
2727 CommentAndMetadata commentAndMetadata = _parseCommentAndMetadata();
2728 if ((_matchesKeyword(Keyword.IMPORT) ||
2729 _matchesKeyword(Keyword.EXPORT) ||
2730 _matchesKeyword(Keyword.LIBRARY) ||
2731 _matchesKeyword(Keyword.PART)) &&
2732 !_tokenMatches(_peek(), TokenType.PERIOD) &&
2733 !_tokenMatches(_peek(), TokenType.LT) &&
2734 !_tokenMatches(_peek(), TokenType.OPEN_PAREN)) {
2735 Directive directive = _parseDirective(commentAndMetadata);
2736 if (declarations.length > 0 && !directiveFoundAfterDeclaration) {
2737 _reportErrorForToken(ParserErrorCode.DIRECTIVE_AFTER_DECLARATION,
2738 directive.beginToken);
2739 directiveFoundAfterDeclaration = true;
2740 }
2741 if (directive is LibraryDirective) {
2742 if (libraryDirectiveFound) {
2743 _reportErrorForCurrentToken(
2744 ParserErrorCode.MULTIPLE_LIBRARY_DIRECTIVES);
2745 } else {
2746 if (directives.length > 0) {
2747 _reportErrorForToken(ParserErrorCode.LIBRARY_DIRECTIVE_NOT_FIRST,
2748 directive.libraryKeyword);
2749 }
2750 libraryDirectiveFound = true;
2751 }
2752 } else if (directive is PartDirective) {
2753 partDirectiveFound = true;
2754 } else if (partDirectiveFound) {
2755 if (directive is ExportDirective) {
2756 _reportErrorForToken(
2757 ParserErrorCode.EXPORT_DIRECTIVE_AFTER_PART_DIRECTIVE,
2758 directive.keyword);
2759 } else if (directive is ImportDirective) {
2760 _reportErrorForToken(
2761 ParserErrorCode.IMPORT_DIRECTIVE_AFTER_PART_DIRECTIVE,
2762 directive.keyword);
2763 }
2764 }
2765 if (directive is PartOfDirective) {
2766 if (partOfDirectiveFound) {
2767 _reportErrorForCurrentToken(
2768 ParserErrorCode.MULTIPLE_PART_OF_DIRECTIVES);
2769 } else {
2770 int directiveCount = directives.length;
2771 for (int i = 0; i < directiveCount; i++) {
2772 _reportErrorForToken(
2773 ParserErrorCode.NON_PART_OF_DIRECTIVE_IN_PART,
2774 directives[i].keyword);
2775 }
2776 partOfDirectiveFound = true;
2777 }
2778 } else {
2779 if (partOfDirectiveFound) {
2780 _reportErrorForToken(ParserErrorCode.NON_PART_OF_DIRECTIVE_IN_PART,
2781 directive.keyword);
2782 }
2783 }
2784 directives.add(directive);
2785 } else if (_matches(TokenType.SEMICOLON)) {
2786 _reportErrorForToken(ParserErrorCode.UNEXPECTED_TOKEN, _currentToken,
2787 [_currentToken.lexeme]);
2788 _advance();
2789 } else {
2790 CompilationUnitMember member =
2791 _parseCompilationUnitMember(commentAndMetadata);
2792 if (member != null) {
2793 declarations.add(member);
2794 }
2795 }
2796 if (identical(_currentToken, memberStart)) {
2797 _reportErrorForToken(ParserErrorCode.UNEXPECTED_TOKEN, _currentToken,
2798 [_currentToken.lexeme]);
2799 _advance();
2800 while (!_matches(TokenType.EOF) &&
2801 !_couldBeStartOfCompilationUnitMember()) {
2802 _advance();
2803 }
2804 }
2805 memberStart = _currentToken;
2806 }
2807 return new CompilationUnit(
2808 firstToken, scriptTag, directives, declarations, _currentToken);
2809 }
2810
2811 /**
2812 * Parse a conditional expression. Return the conditional expression that was
2813 * parsed.
2814 *
2815 * conditionalExpression ::=
2816 * ifNullExpression ('?' expressionWithoutCascade ':' expressionWithou tCascade)?
2817 */
2818 Expression parseConditionalExpression() {
2819 Expression condition = parseIfNullExpression();
2820 if (!_matches(TokenType.QUESTION)) {
2821 return condition;
2822 }
2823 Token question = getAndAdvance();
2824 Expression thenExpression = parseExpressionWithoutCascade();
2825 Token colon = _expect(TokenType.COLON);
2826 Expression elseExpression = parseExpressionWithoutCascade();
2827 return new ConditionalExpression(
2828 condition, question, thenExpression, colon, elseExpression);
2829 }
2830
2831 /**
2832 * Parse the name of a constructor. Return the constructor name that was
2833 * parsed.
2834 *
2835 * constructorName:
2836 * type ('.' identifier)?
2837 */
2838 ConstructorName parseConstructorName() {
2839 TypeName type = parseTypeName();
2840 Token period = null;
2841 SimpleIdentifier name = null;
2842 if (_matches(TokenType.PERIOD)) {
2843 period = getAndAdvance();
2844 name = parseSimpleIdentifier();
2845 }
2846 return new ConstructorName(type, period, name);
2847 }
2848
2849 /**
2850 * Parse the script tag and directives in a compilation unit, starting with
2851 * the given [token], until the first non-directive is encountered. The
2852 * remainder of the compilation unit will not be parsed. Specifically, if
2853 * there are directives later in the file, they will not be parsed. Return the
2854 * compilation unit that was parsed.
2855 */
2856 CompilationUnit parseDirectives(Token token) {
2857 _currentToken = token;
2858 return _parseDirectives();
2859 }
2860
2861 /**
2862 * Parse an expression, starting with the given [token]. Return the expression
2863 * that was parsed, or `null` if the tokens do not represent a recognizable
2864 * expression.
2865 */
2866 Expression parseExpression(Token token) {
2867 _currentToken = token;
2868 return parseExpression2();
2869 }
2870
2871 /**
2872 * Parse an expression that might contain a cascade. Return the expression
2873 * that was parsed.
2874 *
2875 * expression ::=
2876 * assignableExpression assignmentOperator expression
2877 * | conditionalExpression cascadeSection*
2878 * | throwExpression
2879 */
2880 Expression parseExpression2() {
2881 if (_matchesKeyword(Keyword.THROW)) {
2882 return _parseThrowExpression();
2883 } else if (_matchesKeyword(Keyword.RETHROW)) {
2884 // TODO(brianwilkerson) Rethrow is a statement again.
2885 return _parseRethrowExpression();
2886 }
2887 //
2888 // assignableExpression is a subset of conditionalExpression, so we can
2889 // parse a conditional expression and then determine whether it is followed
2890 // by an assignmentOperator, checking for conformance to the restricted
2891 // grammar after making that determination.
2892 //
2893 Expression expression = parseConditionalExpression();
2894 TokenType tokenType = _currentToken.type;
2895 if (tokenType == TokenType.PERIOD_PERIOD) {
2896 List<Expression> cascadeSections = new List<Expression>();
2897 while (tokenType == TokenType.PERIOD_PERIOD) {
2898 Expression section = _parseCascadeSection();
2899 if (section != null) {
2900 cascadeSections.add(section);
2901 }
2902 tokenType = _currentToken.type;
2903 }
2904 return new CascadeExpression(expression, cascadeSections);
2905 } else if (tokenType.isAssignmentOperator) {
2906 Token operator = getAndAdvance();
2907 _ensureAssignable(expression);
2908 return new AssignmentExpression(expression, operator, parseExpression2());
2909 }
2910 return expression;
2911 }
2912
2913 /**
2914 * Parse an expression that does not contain any cascades. Return the
2915 * expression that was parsed.
2916 *
2917 * expressionWithoutCascade ::=
2918 * assignableExpression assignmentOperator expressionWithoutCascade
2919 * | conditionalExpression
2920 * | throwExpressionWithoutCascade
2921 */
2922 Expression parseExpressionWithoutCascade() {
2923 if (_matchesKeyword(Keyword.THROW)) {
2924 return _parseThrowExpressionWithoutCascade();
2925 } else if (_matchesKeyword(Keyword.RETHROW)) {
2926 return _parseRethrowExpression();
2927 }
2928 //
2929 // assignableExpression is a subset of conditionalExpression, so we can
2930 // parse a conditional expression and then determine whether it is followed
2931 // by an assignmentOperator, checking for conformance to the restricted
2932 // grammar after making that determination.
2933 //
2934 Expression expression = parseConditionalExpression();
2935 if (_currentToken.type.isAssignmentOperator) {
2936 Token operator = getAndAdvance();
2937 _ensureAssignable(expression);
2938 expression = new AssignmentExpression(
2939 expression, operator, parseExpressionWithoutCascade());
2940 }
2941 return expression;
2942 }
2943
2944 /**
2945 * Parse a class extends clause. Return the class extends clause that was
2946 * parsed.
2947 *
2948 * classExtendsClause ::=
2949 * 'extends' type
2950 */
2951 ExtendsClause parseExtendsClause() {
2952 Token keyword = _expectKeyword(Keyword.EXTENDS);
2953 TypeName superclass = parseTypeName();
2954 return new ExtendsClause(keyword, superclass);
2955 }
2956
2957 /**
2958 * Parse a list of formal parameters. Return the formal parameters that were
2959 * parsed.
2960 *
2961 * formalParameterList ::=
2962 * '(' ')'
2963 * | '(' normalFormalParameters (',' optionalFormalParameters)? ')'
2964 * | '(' optionalFormalParameters ')'
2965 *
2966 * normalFormalParameters ::=
2967 * normalFormalParameter (',' normalFormalParameter)*
2968 *
2969 * optionalFormalParameters ::=
2970 * optionalPositionalFormalParameters
2971 * | namedFormalParameters
2972 *
2973 * optionalPositionalFormalParameters ::=
2974 * '[' defaultFormalParameter (',' defaultFormalParameter)* ']'
2975 *
2976 * namedFormalParameters ::=
2977 * '{' defaultNamedParameter (',' defaultNamedParameter)* '}'
2978 */
2979 FormalParameterList parseFormalParameterList() {
2980 Token leftParenthesis = _expect(TokenType.OPEN_PAREN);
2981 if (_matches(TokenType.CLOSE_PAREN)) {
2982 return new FormalParameterList(
2983 leftParenthesis, null, null, null, getAndAdvance());
2984 }
2985 //
2986 // Even though it is invalid to have default parameters outside of brackets,
2987 // required parameters inside of brackets, or multiple groups of default and
2988 // named parameters, we allow all of these cases so that we can recover
2989 // better.
2990 //
2991 List<FormalParameter> parameters = new List<FormalParameter>();
2992 List<FormalParameter> normalParameters = new List<FormalParameter>();
2993 List<FormalParameter> positionalParameters = new List<FormalParameter>();
2994 List<FormalParameter> namedParameters = new List<FormalParameter>();
2995 List<FormalParameter> currentParameters = normalParameters;
2996 Token leftSquareBracket = null;
2997 Token rightSquareBracket = null;
2998 Token leftCurlyBracket = null;
2999 Token rightCurlyBracket = null;
3000 ParameterKind kind = ParameterKind.REQUIRED;
3001 bool firstParameter = true;
3002 bool reportedMuliplePositionalGroups = false;
3003 bool reportedMulipleNamedGroups = false;
3004 bool reportedMixedGroups = false;
3005 bool wasOptionalParameter = false;
3006 Token initialToken = null;
3007 do {
3008 if (firstParameter) {
3009 firstParameter = false;
3010 } else if (!_optional(TokenType.COMMA)) {
3011 // TODO(brianwilkerson) The token is wrong, we need to recover from this
3012 // case.
3013 if (_getEndToken(leftParenthesis) != null) {
3014 _reportErrorForCurrentToken(
3015 ParserErrorCode.EXPECTED_TOKEN, [TokenType.COMMA.lexeme]);
3016 } else {
3017 _reportErrorForToken(ParserErrorCode.MISSING_CLOSING_PARENTHESIS,
3018 _currentToken.previous);
3019 break;
3020 }
3021 }
3022 initialToken = _currentToken;
3023 //
3024 // Handle the beginning of parameter groups.
3025 //
3026 if (_matches(TokenType.OPEN_SQUARE_BRACKET)) {
3027 wasOptionalParameter = true;
3028 if (leftSquareBracket != null && !reportedMuliplePositionalGroups) {
3029 _reportErrorForCurrentToken(
3030 ParserErrorCode.MULTIPLE_POSITIONAL_PARAMETER_GROUPS);
3031 reportedMuliplePositionalGroups = true;
3032 }
3033 if (leftCurlyBracket != null && !reportedMixedGroups) {
3034 _reportErrorForCurrentToken(ParserErrorCode.MIXED_PARAMETER_GROUPS);
3035 reportedMixedGroups = true;
3036 }
3037 leftSquareBracket = getAndAdvance();
3038 currentParameters = positionalParameters;
3039 kind = ParameterKind.POSITIONAL;
3040 } else if (_matches(TokenType.OPEN_CURLY_BRACKET)) {
3041 wasOptionalParameter = true;
3042 if (leftCurlyBracket != null && !reportedMulipleNamedGroups) {
3043 _reportErrorForCurrentToken(
3044 ParserErrorCode.MULTIPLE_NAMED_PARAMETER_GROUPS);
3045 reportedMulipleNamedGroups = true;
3046 }
3047 if (leftSquareBracket != null && !reportedMixedGroups) {
3048 _reportErrorForCurrentToken(ParserErrorCode.MIXED_PARAMETER_GROUPS);
3049 reportedMixedGroups = true;
3050 }
3051 leftCurlyBracket = getAndAdvance();
3052 currentParameters = namedParameters;
3053 kind = ParameterKind.NAMED;
3054 }
3055 //
3056 // Parse and record the parameter.
3057 //
3058 FormalParameter parameter = _parseFormalParameter(kind);
3059 parameters.add(parameter);
3060 currentParameters.add(parameter);
3061 if (kind == ParameterKind.REQUIRED && wasOptionalParameter) {
3062 _reportErrorForNode(
3063 ParserErrorCode.NORMAL_BEFORE_OPTIONAL_PARAMETERS, parameter);
3064 }
3065 //
3066 // Handle the end of parameter groups.
3067 //
3068 // TODO(brianwilkerson) Improve the detection and reporting of missing and
3069 // mismatched delimiters.
3070 if (_matches(TokenType.CLOSE_SQUARE_BRACKET)) {
3071 rightSquareBracket = getAndAdvance();
3072 currentParameters = normalParameters;
3073 if (leftSquareBracket == null) {
3074 if (leftCurlyBracket != null) {
3075 _reportErrorForCurrentToken(
3076 ParserErrorCode.WRONG_TERMINATOR_FOR_PARAMETER_GROUP, ["}"]);
3077 rightCurlyBracket = rightSquareBracket;
3078 rightSquareBracket = null;
3079 } else {
3080 _reportErrorForCurrentToken(
3081 ParserErrorCode.UNEXPECTED_TERMINATOR_FOR_PARAMETER_GROUP,
3082 ["["]);
3083 }
3084 }
3085 kind = ParameterKind.REQUIRED;
3086 } else if (_matches(TokenType.CLOSE_CURLY_BRACKET)) {
3087 rightCurlyBracket = getAndAdvance();
3088 currentParameters = normalParameters;
3089 if (leftCurlyBracket == null) {
3090 if (leftSquareBracket != null) {
3091 _reportErrorForCurrentToken(
3092 ParserErrorCode.WRONG_TERMINATOR_FOR_PARAMETER_GROUP, ["]"]);
3093 rightSquareBracket = rightCurlyBracket;
3094 rightCurlyBracket = null;
3095 } else {
3096 _reportErrorForCurrentToken(
3097 ParserErrorCode.UNEXPECTED_TERMINATOR_FOR_PARAMETER_GROUP,
3098 ["{"]);
3099 }
3100 }
3101 kind = ParameterKind.REQUIRED;
3102 }
3103 } while (!_matches(TokenType.CLOSE_PAREN) &&
3104 !identical(initialToken, _currentToken));
3105 Token rightParenthesis = _expect(TokenType.CLOSE_PAREN);
3106 //
3107 // Check that the groups were closed correctly.
3108 //
3109 if (leftSquareBracket != null && rightSquareBracket == null) {
3110 _reportErrorForCurrentToken(
3111 ParserErrorCode.MISSING_TERMINATOR_FOR_PARAMETER_GROUP, ["]"]);
3112 }
3113 if (leftCurlyBracket != null && rightCurlyBracket == null) {
3114 _reportErrorForCurrentToken(
3115 ParserErrorCode.MISSING_TERMINATOR_FOR_PARAMETER_GROUP, ["}"]);
3116 }
3117 //
3118 // Build the parameter list.
3119 //
3120 if (leftSquareBracket == null) {
3121 leftSquareBracket = leftCurlyBracket;
3122 }
3123 if (rightSquareBracket == null) {
3124 rightSquareBracket = rightCurlyBracket;
3125 }
3126 return new FormalParameterList(leftParenthesis, parameters,
3127 leftSquareBracket, rightSquareBracket, rightParenthesis);
3128 }
3129
3130 /**
3131 * Parse a function expression. Return the function expression that was
3132 * parsed.
3133 *
3134 * functionExpression ::=
3135 * typeParameters? formalParameterList functionExpressionBody
3136 */
3137 FunctionExpression parseFunctionExpression() {
3138 TypeParameterList typeParameters = null;
3139 if (parseGenericMethods && _matches(TokenType.LT)) {
3140 typeParameters = parseTypeParameterList();
3141 }
3142 FormalParameterList parameters = parseFormalParameterList();
3143 _validateFormalParameterList(parameters);
3144 FunctionBody body =
3145 _parseFunctionBody(false, ParserErrorCode.MISSING_FUNCTION_BODY, true);
3146 return new FunctionExpression(typeParameters, parameters, body);
3147 }
3148
3149 /**
3150 * Parse an if-null expression. Return the if-null expression that was
3151 * parsed.
3152 *
3153 * ifNullExpression ::= logicalOrExpression ('??' logicalOrExpression)*
3154 */
3155 Expression parseIfNullExpression() {
3156 Expression expression = parseLogicalOrExpression();
3157 while (_matches(TokenType.QUESTION_QUESTION)) {
3158 Token operator = getAndAdvance();
3159 expression = new BinaryExpression(
3160 expression, operator, parseLogicalOrExpression());
3161 }
3162 return expression;
3163 }
3164
3165 /**
3166 * Parse an implements clause. Return the implements clause that was parsed.
3167 *
3168 * implementsClause ::=
3169 * 'implements' type (',' type)*
3170 */
3171 ImplementsClause parseImplementsClause() {
3172 Token keyword = _expectKeyword(Keyword.IMPLEMENTS);
3173 List<TypeName> interfaces = new List<TypeName>();
3174 interfaces.add(parseTypeName());
3175 while (_optional(TokenType.COMMA)) {
3176 interfaces.add(parseTypeName());
3177 }
3178 return new ImplementsClause(keyword, interfaces);
3179 }
3180
3181 /**
3182 * Parse a label. Return the label that was parsed.
3183 *
3184 * label ::=
3185 * identifier ':'
3186 */
3187 Label parseLabel() {
3188 SimpleIdentifier label = parseSimpleIdentifier();
3189 Token colon = _expect(TokenType.COLON);
3190 return new Label(label, colon);
3191 }
3192
3193 /**
3194 * Parse a library identifier. Return the library identifier that was parsed.
3195 *
3196 * libraryIdentifier ::=
3197 * identifier ('.' identifier)*
3198 */
3199 LibraryIdentifier parseLibraryIdentifier() {
3200 List<SimpleIdentifier> components = new List<SimpleIdentifier>();
3201 components.add(parseSimpleIdentifier());
3202 while (_matches(TokenType.PERIOD)) {
3203 _advance();
3204 components.add(parseSimpleIdentifier());
3205 }
3206 return new LibraryIdentifier(components);
3207 }
3208
3209 /**
3210 * Parse a logical or expression. Return the logical or expression that was
3211 * parsed.
3212 *
3213 * logicalOrExpression ::=
3214 * logicalAndExpression ('||' logicalAndExpression)*
3215 */
3216 Expression parseLogicalOrExpression() {
3217 Expression expression = _parseLogicalAndExpression();
3218 while (_matches(TokenType.BAR_BAR)) {
3219 Token operator = getAndAdvance();
3220 expression = new BinaryExpression(
3221 expression, operator, _parseLogicalAndExpression());
3222 }
3223 return expression;
3224 }
3225
3226 /**
3227 * Parse a map literal entry. Return the map literal entry that was parsed.
3228 *
3229 * mapLiteralEntry ::=
3230 * expression ':' expression
3231 */
3232 MapLiteralEntry parseMapLiteralEntry() {
3233 Expression key = parseExpression2();
3234 Token separator = _expect(TokenType.COLON);
3235 Expression value = parseExpression2();
3236 return new MapLiteralEntry(key, separator, value);
3237 }
3238
3239 /**
3240 * Parse a normal formal parameter. Return the normal formal parameter that
3241 * was parsed.
3242 *
3243 * normalFormalParameter ::=
3244 * functionSignature
3245 * | fieldFormalParameter
3246 * | simpleFormalParameter
3247 *
3248 * functionSignature:
3249 * metadata returnType? identifier typeParameters? formalParameterList
3250 *
3251 * fieldFormalParameter ::=
3252 * metadata finalConstVarOrType? 'this' '.' identifier
3253 *
3254 * simpleFormalParameter ::=
3255 * declaredIdentifier
3256 * | metadata identifier
3257 */
3258 NormalFormalParameter parseNormalFormalParameter() {
3259 CommentAndMetadata commentAndMetadata = _parseCommentAndMetadata();
3260 FinalConstVarOrType holder = _parseFinalConstVarOrType(true);
3261 Token thisKeyword = null;
3262 Token period = null;
3263 if (_matchesKeyword(Keyword.THIS)) {
3264 thisKeyword = getAndAdvance();
3265 period = _expect(TokenType.PERIOD);
3266 }
3267 SimpleIdentifier identifier = parseSimpleIdentifier();
3268 TypeParameterList typeParameters = null;
3269 if (parseGenericMethods && _matches(TokenType.LT)) {
3270 typeParameters = parseTypeParameterList();
3271 }
3272 if (_matches(TokenType.OPEN_PAREN)) {
3273 FormalParameterList parameters = parseFormalParameterList();
3274 if (thisKeyword == null) {
3275 if (holder.keyword != null) {
3276 _reportErrorForToken(
3277 ParserErrorCode.FUNCTION_TYPED_PARAMETER_VAR, holder.keyword);
3278 }
3279 return new FunctionTypedFormalParameter(
3280 commentAndMetadata.comment,
3281 commentAndMetadata.metadata,
3282 holder.type,
3283 identifier,
3284 typeParameters,
3285 parameters);
3286 } else {
3287 return new FieldFormalParameter(
3288 commentAndMetadata.comment,
3289 commentAndMetadata.metadata,
3290 holder.keyword,
3291 holder.type,
3292 thisKeyword,
3293 period,
3294 identifier,
3295 typeParameters,
3296 parameters);
3297 }
3298 } else if (typeParameters != null) {
3299 // TODO(brianwilkerson) Report an error. It looks like a function-typed
3300 // parameter with no parameter list.
3301 //_reportErrorForToken(ParserErrorCode.MISSING_PARAMETERS, typeParameters. endToken);
3302 }
3303 TypeName type = holder.type;
3304 if (type != null) {
3305 if (_tokenMatchesKeyword(type.name.beginToken, Keyword.VOID)) {
3306 _reportErrorForToken(
3307 ParserErrorCode.VOID_PARAMETER, type.name.beginToken);
3308 } else if (holder.keyword != null &&
3309 _tokenMatchesKeyword(holder.keyword, Keyword.VAR)) {
3310 _reportErrorForToken(ParserErrorCode.VAR_AND_TYPE, holder.keyword);
3311 }
3312 }
3313 if (thisKeyword != null) {
3314 // TODO(brianwilkerson) If there are type parameters but no parameters,
3315 // should we create a synthetic empty parameter list here so we can
3316 // capture the type parameters?
3317 return new FieldFormalParameter(
3318 commentAndMetadata.comment,
3319 commentAndMetadata.metadata,
3320 holder.keyword,
3321 holder.type,
3322 thisKeyword,
3323 period,
3324 identifier,
3325 null,
3326 null);
3327 }
3328 return new SimpleFormalParameter(commentAndMetadata.comment,
3329 commentAndMetadata.metadata, holder.keyword, holder.type, identifier);
3330 }
3331
3332 /**
3333 * Parse a prefixed identifier. Return the prefixed identifier that was
3334 * parsed.
3335 *
3336 * prefixedIdentifier ::=
3337 * identifier ('.' identifier)?
3338 */
3339 Identifier parsePrefixedIdentifier() {
3340 SimpleIdentifier qualifier = parseSimpleIdentifier();
3341 if (!_matches(TokenType.PERIOD)) {
3342 return qualifier;
3343 }
3344 Token period = getAndAdvance();
3345 SimpleIdentifier qualified = parseSimpleIdentifier();
3346 return new PrefixedIdentifier(qualifier, period, qualified);
3347 }
3348
3349 /**
3350 * Parse a return type. Return the return type that was parsed.
3351 *
3352 * returnType ::=
3353 * 'void'
3354 * | type
3355 */
3356 TypeName parseReturnType() {
3357 if (_matchesKeyword(Keyword.VOID)) {
3358 return new TypeName(new SimpleIdentifier(getAndAdvance()), null);
3359 } else {
3360 return parseTypeName();
3361 }
3362 }
3363
3364 /**
3365 * Parse a simple identifier. Return the simple identifier that was parsed.
3366 *
3367 * identifier ::=
3368 * IDENTIFIER
3369 */
3370 SimpleIdentifier parseSimpleIdentifier() {
3371 if (_matchesIdentifier()) {
3372 String lexeme = _currentToken.lexeme;
3373 if ((_inAsync || _inGenerator) &&
3374 (lexeme == 'async' || lexeme == 'await' || lexeme == 'yield')) {
3375 _reportErrorForCurrentToken(
3376 ParserErrorCode.ASYNC_KEYWORD_USED_AS_IDENTIFIER);
3377 }
3378 return new SimpleIdentifier(getAndAdvance());
3379 }
3380 _reportErrorForCurrentToken(ParserErrorCode.MISSING_IDENTIFIER);
3381 return _createSyntheticIdentifier();
3382 }
3383
3384 /**
3385 * Parse a statement, starting with the given [token]. Return the statement
3386 * that was parsed, or `null` if the tokens do not represent a recognizable
3387 * statement.
3388 */
3389 Statement parseStatement(Token token) {
3390 _currentToken = token;
3391 return parseStatement2();
3392 }
3393
3394 /**
3395 * Parse a statement. Return the statement that was parsed.
3396 *
3397 * statement ::=
3398 * label* nonLabeledStatement
3399 */
3400 Statement parseStatement2() {
3401 List<Label> labels = new List<Label>();
3402 while (_matchesIdentifier() && _tokenMatches(_peek(), TokenType.COLON)) {
3403 labels.add(parseLabel());
3404 }
3405 Statement statement = _parseNonLabeledStatement();
3406 if (labels.isEmpty) {
3407 return statement;
3408 }
3409 return new LabeledStatement(labels, statement);
3410 }
3411
3412 /**
3413 * Parse a sequence of statements, starting with the given [token]. Return the
3414 * statements that were parsed, or `null` if the tokens do not represent a
3415 * recognizable sequence of statements.
3416 */
3417 List<Statement> parseStatements(Token token) {
3418 _currentToken = token;
3419 return _parseStatementList();
3420 }
3421
3422 /**
3423 * Parse a string literal. Return the string literal that was parsed.
3424 *
3425 * stringLiteral ::=
3426 * MULTI_LINE_STRING+
3427 * | SINGLE_LINE_STRING+
3428 */
3429 StringLiteral parseStringLiteral() {
3430 List<StringLiteral> strings = new List<StringLiteral>();
3431 while (_matches(TokenType.STRING)) {
3432 Token string = getAndAdvance();
3433 if (_matches(TokenType.STRING_INTERPOLATION_EXPRESSION) ||
3434 _matches(TokenType.STRING_INTERPOLATION_IDENTIFIER)) {
3435 strings.add(_parseStringInterpolation(string));
3436 } else {
3437 strings.add(new SimpleStringLiteral(
3438 string, _computeStringValue(string.lexeme, true, true)));
3439 }
3440 }
3441 if (strings.length < 1) {
3442 _reportErrorForCurrentToken(ParserErrorCode.EXPECTED_STRING_LITERAL);
3443 return _createSyntheticStringLiteral();
3444 } else if (strings.length == 1) {
3445 return strings[0];
3446 } else {
3447 return new AdjacentStrings(strings);
3448 }
3449 }
3450
3451 /**
3452 * Parse a list of type arguments. Return the type argument list that was
3453 * parsed.
3454 *
3455 * typeArguments ::=
3456 * '<' typeList '>'
3457 *
3458 * typeList ::=
3459 * type (',' type)*
3460 */
3461 TypeArgumentList parseTypeArgumentList() {
3462 Token leftBracket = _expect(TokenType.LT);
3463 List<TypeName> arguments = new List<TypeName>();
3464 arguments.add(parseTypeName());
3465 while (_optional(TokenType.COMMA)) {
3466 arguments.add(parseTypeName());
3467 }
3468 Token rightBracket = _expectGt();
3469 return new TypeArgumentList(leftBracket, arguments, rightBracket);
3470 }
3471
3472 /**
3473 * Parse a type name. Return the type name that was parsed.
3474 *
3475 * type ::=
3476 * qualified typeArguments?
3477 */
3478 TypeName parseTypeName() {
3479 Identifier typeName;
3480 if (_matchesKeyword(Keyword.VAR)) {
3481 _reportErrorForCurrentToken(ParserErrorCode.VAR_AS_TYPE_NAME);
3482 typeName = new SimpleIdentifier(getAndAdvance());
3483 } else if (_matchesIdentifier()) {
3484 typeName = parsePrefixedIdentifier();
3485 } else {
3486 typeName = _createSyntheticIdentifier();
3487 _reportErrorForCurrentToken(ParserErrorCode.EXPECTED_TYPE_NAME);
3488 }
3489 TypeArgumentList typeArguments = null;
3490 if (_matches(TokenType.LT)) {
3491 typeArguments = parseTypeArgumentList();
3492 }
3493 return new TypeName(typeName, typeArguments);
3494 }
3495
3496 /**
3497 * Parse a type parameter. Return the type parameter that was parsed.
3498 *
3499 * typeParameter ::=
3500 * metadata name ('extends' bound)?
3501 */
3502 TypeParameter parseTypeParameter() {
3503 CommentAndMetadata commentAndMetadata = _parseCommentAndMetadata();
3504 SimpleIdentifier name = parseSimpleIdentifier();
3505 if (_matchesKeyword(Keyword.EXTENDS)) {
3506 Token keyword = getAndAdvance();
3507 TypeName bound = parseTypeName();
3508 return new TypeParameter(commentAndMetadata.comment,
3509 commentAndMetadata.metadata, name, keyword, bound);
3510 }
3511 return new TypeParameter(commentAndMetadata.comment,
3512 commentAndMetadata.metadata, name, null, null);
3513 }
3514
3515 /**
3516 * Parse a list of type parameters. Return the list of type parameters that
3517 * were parsed.
3518 *
3519 * typeParameterList ::=
3520 * '<' typeParameter (',' typeParameter)* '>'
3521 */
3522 TypeParameterList parseTypeParameterList() {
3523 Token leftBracket = _expect(TokenType.LT);
3524 List<TypeParameter> typeParameters = new List<TypeParameter>();
3525 typeParameters.add(parseTypeParameter());
3526 while (_optional(TokenType.COMMA)) {
3527 typeParameters.add(parseTypeParameter());
3528 }
3529 Token rightBracket = _expectGt();
3530 return new TypeParameterList(leftBracket, typeParameters, rightBracket);
3531 }
3532
3533 /**
3534 * Parse a with clause. Return the with clause that was parsed.
3535 *
3536 * withClause ::=
3537 * 'with' typeName (',' typeName)*
3538 */
3539 WithClause parseWithClause() {
3540 Token with2 = _expectKeyword(Keyword.WITH);
3541 List<TypeName> types = new List<TypeName>();
3542 types.add(parseTypeName());
3543 while (_optional(TokenType.COMMA)) {
3544 types.add(parseTypeName());
3545 }
3546 return new WithClause(with2, types);
3547 }
3548
3549 /**
3550 * Advance to the next token in the token stream.
3551 */
3552 void _advance() {
3553 _currentToken = _currentToken.next;
3554 }
3555
3556 /**
3557 * Append the character equivalent of the given [scalarValue] to the given
3558 * [builder]. Use the [startIndex] and [endIndex] to report an error, and
3559 * don't append anything to the builder, if the scalar value is invalid. The
3560 * [escapeSequence] is the escape sequence that was parsed to produce the
3561 * scalar value (used for error reporting).
3562 */
3563 void _appendScalarValue(StringBuffer buffer, String escapeSequence,
3564 int scalarValue, int startIndex, int endIndex) {
3565 if (scalarValue < 0 ||
3566 scalarValue > Character.MAX_CODE_POINT ||
3567 (scalarValue >= 0xD800 && scalarValue <= 0xDFFF)) {
3568 _reportErrorForCurrentToken(
3569 ParserErrorCode.INVALID_CODE_POINT, [escapeSequence]);
3570 return;
3571 }
3572 if (scalarValue < Character.MAX_VALUE) {
3573 buffer.writeCharCode(scalarValue);
3574 } else {
3575 buffer.write(Character.toChars(scalarValue));
3576 }
3577 }
3578
3579 /**
3580 * Return the content of a string with the given literal representation. The 332 * Return the content of a string with the given literal representation. The
3581 * [lexeme] is the literal representation of the string. The flag [isFirst] is 333 * [lexeme] is the literal representation of the string. The flag [isFirst] is
3582 * `true` if this is the first token in a string literal. The flag [isLast] is 334 * `true` if this is the first token in a string literal. The flag [isLast] is
3583 * `true` if this is the last token in a string literal. 335 * `true` if this is the last token in a string literal.
3584 */ 336 */
3585 String _computeStringValue(String lexeme, bool isFirst, bool isLast) { 337 String computeStringValue(String lexeme, bool isFirst, bool isLast) {
3586 StringLexemeHelper helper = new StringLexemeHelper(lexeme, isFirst, isLast); 338 StringLexemeHelper helper = new StringLexemeHelper(lexeme, isFirst, isLast);
3587 int start = helper.start; 339 int start = helper.start;
3588 int end = helper.end; 340 int end = helper.end;
3589 bool stringEndsAfterStart = end >= start; 341 bool stringEndsAfterStart = end >= start;
3590 assert(stringEndsAfterStart); 342 assert(stringEndsAfterStart);
3591 if (!stringEndsAfterStart) { 343 if (!stringEndsAfterStart) {
3592 AnalysisEngine.instance.logger.logError( 344 AnalysisEngine.instance.logger.logError(
3593 "Internal error: computeStringValue($lexeme, $isFirst, $isLast)"); 345 "Internal error: computeStringValue($lexeme, $isFirst, $isLast)");
3594 return ""; 346 return "";
3595 } 347 }
3596 if (helper.isRaw) { 348 if (helper.isRaw) {
3597 return lexeme.substring(start, end); 349 return lexeme.substring(start, end);
3598 } 350 }
3599 StringBuffer buffer = new StringBuffer(); 351 StringBuffer buffer = new StringBuffer();
3600 int index = start; 352 int index = start;
3601 while (index < end) { 353 while (index < end) {
3602 index = _translateCharacter(buffer, lexeme, index); 354 index = _translateCharacter(buffer, lexeme, index);
3603 } 355 }
3604 return buffer.toString(); 356 return buffer.toString();
3605 } 357 }
3606 358
3607 /** 359 /**
3608 * Convert the given [method] declaration into the nearest valid top-level
3609 * function declaration (that is, the function declaration that most closely
3610 * captures the components of the given method declaration).
3611 */
3612 FunctionDeclaration _convertToFunctionDeclaration(MethodDeclaration method) =>
3613 new FunctionDeclaration(
3614 method.documentationComment,
3615 method.metadata,
3616 method.externalKeyword,
3617 method.returnType,
3618 method.propertyKeyword,
3619 method.name,
3620 new FunctionExpression(
3621 method.typeParameters, method.parameters, method.body));
3622
3623 /**
3624 * Return `true` if the current token could be the start of a compilation unit
3625 * member. This method is used for recovery purposes to decide when to stop
3626 * skipping tokens after finding an error while parsing a compilation unit
3627 * member.
3628 */
3629 bool _couldBeStartOfCompilationUnitMember() {
3630 if ((_matchesKeyword(Keyword.IMPORT) ||
3631 _matchesKeyword(Keyword.EXPORT) ||
3632 _matchesKeyword(Keyword.LIBRARY) ||
3633 _matchesKeyword(Keyword.PART)) &&
3634 !_tokenMatches(_peek(), TokenType.PERIOD) &&
3635 !_tokenMatches(_peek(), TokenType.LT)) {
3636 // This looks like the start of a directive
3637 return true;
3638 } else if (_matchesKeyword(Keyword.CLASS)) {
3639 // This looks like the start of a class definition
3640 return true;
3641 } else if (_matchesKeyword(Keyword.TYPEDEF) &&
3642 !_tokenMatches(_peek(), TokenType.PERIOD) &&
3643 !_tokenMatches(_peek(), TokenType.LT)) {
3644 // This looks like the start of a typedef
3645 return true;
3646 } else if (_matchesKeyword(Keyword.VOID) ||
3647 ((_matchesKeyword(Keyword.GET) || _matchesKeyword(Keyword.SET)) &&
3648 _tokenMatchesIdentifier(_peek())) ||
3649 (_matchesKeyword(Keyword.OPERATOR) && _isOperator(_peek()))) {
3650 // This looks like the start of a function
3651 return true;
3652 } else if (_matchesIdentifier()) {
3653 if (_tokenMatches(_peek(), TokenType.OPEN_PAREN)) {
3654 // This looks like the start of a function
3655 return true;
3656 }
3657 Token token = _skipReturnType(_currentToken);
3658 if (token == null) {
3659 return false;
3660 }
3661 if (_matchesKeyword(Keyword.GET) ||
3662 _matchesKeyword(Keyword.SET) ||
3663 (_matchesKeyword(Keyword.OPERATOR) && _isOperator(_peek())) ||
3664 _matchesIdentifier()) {
3665 return true;
3666 }
3667 }
3668 return false;
3669 }
3670
3671 /**
3672 * Return a synthetic identifier. 360 * Return a synthetic identifier.
3673 */ 361 */
3674 SimpleIdentifier _createSyntheticIdentifier() { 362 SimpleIdentifier createSyntheticIdentifier({bool isDeclaration: false}) {
3675 Token syntheticToken; 363 Token syntheticToken;
3676 if (_currentToken.type == TokenType.KEYWORD) { 364 if (_currentToken.type == TokenType.KEYWORD) {
3677 // Consider current keyword token as an identifier. 365 // Consider current keyword token as an identifier.
3678 // It is not always true, e.g. "^is T" where "^" is place the place for 366 // It is not always true, e.g. "^is T" where "^" is place the place for
3679 // synthetic identifier. By creating SyntheticStringToken we can 367 // synthetic identifier. By creating SyntheticStringToken we can
3680 // distinguish a real identifier from synthetic. In the code completion 368 // distinguish a real identifier from synthetic. In the code completion
3681 // behavior will depend on a cursor position - before or on "is". 369 // behavior will depend on a cursor position - before or on "is".
3682 syntheticToken = _injectToken(new SyntheticStringToken( 370 syntheticToken = _injectToken(new SyntheticStringToken(
3683 TokenType.IDENTIFIER, _currentToken.lexeme, _currentToken.offset)); 371 TokenType.IDENTIFIER, _currentToken.lexeme, _currentToken.offset));
3684 } else { 372 } else {
3685 syntheticToken = _createSyntheticToken(TokenType.IDENTIFIER); 373 syntheticToken = _createSyntheticToken(TokenType.IDENTIFIER);
3686 } 374 }
3687 return new SimpleIdentifier(syntheticToken); 375 return new SimpleIdentifier(syntheticToken, isDeclaration: isDeclaration);
3688 } 376 }
3689
3690 /**
3691 * Return a synthetic token representing the given [keyword].
3692 */
3693 Token _createSyntheticKeyword(Keyword keyword) => _injectToken(
3694 new Parser_SyntheticKeywordToken(keyword, _currentToken.offset));
3695 377
3696 /** 378 /**
3697 * Return a synthetic string literal. 379 * Return a synthetic string literal.
3698 */ 380 */
3699 SimpleStringLiteral _createSyntheticStringLiteral() => 381 SimpleStringLiteral createSyntheticStringLiteral() =>
3700 new SimpleStringLiteral(_createSyntheticToken(TokenType.STRING), ""); 382 new SimpleStringLiteral(_createSyntheticToken(TokenType.STRING), "");
3701 383
3702 /** 384 /**
3703 * Return a synthetic token with the given [type]. 385 * Advance to the next token in the token stream, making it the new current
3704 */ 386 * token and return the token that was current before this method was invoked.
3705 Token _createSyntheticToken(TokenType type) => 387 */
3706 _injectToken(new StringToken(type, "", _currentToken.offset)); 388 Token getAndAdvance() {
3707 389 Token token = _currentToken;
3708 /** 390 _currentToken = _currentToken.next;
3709 * Create and return a new token with the given [type]. The token will replace
3710 * the first portion of the given [token], so it will have the same offset and
3711 * will have any comments that might have preceeded the token.
3712 */
3713 Token _createToken(Token token, TokenType type, {bool isBegin: false}) {
3714 CommentToken comments = token.precedingComments;
3715 if (comments == null) {
3716 if (isBegin) {
3717 return new BeginToken(type, token.offset);
3718 }
3719 return new Token(type, token.offset);
3720 } else if (isBegin) {
3721 return new BeginTokenWithComment(type, token.offset, comments);
3722 }
3723 return new TokenWithComment(type, token.offset, comments);
3724 }
3725
3726 /**
3727 * Check that the given [expression] is assignable and report an error if it
3728 * isn't.
3729 *
3730 * assignableExpression ::=
3731 * primary (arguments* assignableSelector)+
3732 * | 'super' unconditionalAssignableSelector
3733 * | identifier
3734 *
3735 * unconditionalAssignableSelector ::=
3736 * '[' expression ']'
3737 * | '.' identifier
3738 *
3739 * assignableSelector ::=
3740 * unconditionalAssignableSelector
3741 * | '?.' identifier
3742 */
3743 void _ensureAssignable(Expression expression) {
3744 if (expression != null && !expression.isAssignable) {
3745 _reportErrorForCurrentToken(
3746 ParserErrorCode.ILLEGAL_ASSIGNMENT_TO_NON_ASSIGNABLE);
3747 }
3748 }
3749
3750 /**
3751 * If the current token has the expected type, return it after advancing to
3752 * the next token. Otherwise report an error and return the current token
3753 * without advancing.
3754 *
3755 * Note that the method [_expectGt] should be used if the argument to this
3756 * method would be [TokenType.GT].
3757 *
3758 * The [type] is the type of token that is expected.
3759 */
3760 Token _expect(TokenType type) {
3761 if (_matches(type)) {
3762 return getAndAdvance();
3763 }
3764 // Remove uses of this method in favor of matches?
3765 // Pass in the error code to use to report the error?
3766 if (type == TokenType.SEMICOLON) {
3767 if (_tokenMatches(_currentToken.next, TokenType.SEMICOLON)) {
3768 _reportErrorForCurrentToken(
3769 ParserErrorCode.UNEXPECTED_TOKEN, [_currentToken.lexeme]);
3770 _advance();
3771 return getAndAdvance();
3772 }
3773 _reportErrorForToken(ParserErrorCode.EXPECTED_TOKEN,
3774 _currentToken.previous, [type.lexeme]);
3775 } else {
3776 _reportErrorForCurrentToken(
3777 ParserErrorCode.EXPECTED_TOKEN, [type.lexeme]);
3778 }
3779 return _currentToken;
3780 }
3781
3782 /**
3783 * If the current token has the type [TokenType.GT], return it after advancing
3784 * to the next token. Otherwise report an error and return the current token
3785 * without advancing.
3786 */
3787 Token _expectGt() {
3788 if (_matchesGt()) {
3789 return getAndAdvance();
3790 }
3791 _reportErrorForCurrentToken(
3792 ParserErrorCode.EXPECTED_TOKEN, [TokenType.GT.lexeme]);
3793 return _currentToken;
3794 }
3795
3796 /**
3797 * If the current token is a keyword matching the given [keyword], return it
3798 * after advancing to the next token. Otherwise report an error and return the
3799 * current token without advancing.
3800 */
3801 Token _expectKeyword(Keyword keyword) {
3802 if (_matchesKeyword(keyword)) {
3803 return getAndAdvance();
3804 }
3805 // Remove uses of this method in favor of matches?
3806 // Pass in the error code to use to report the error?
3807 _reportErrorForCurrentToken(
3808 ParserErrorCode.EXPECTED_TOKEN, [keyword.syntax]);
3809 return _currentToken;
3810 }
3811
3812 /**
3813 * If the current token is a semicolon, return it after advancing to the next
3814 * token. Otherwise report an error and create a synthetic semicolon.
3815 */
3816 Token _expectSemicolon() {
3817 // TODO(scheglov) consider pushing this behavior into [_expect]
3818 if (_matches(TokenType.SEMICOLON)) {
3819 return getAndAdvance();
3820 } else {
3821 _reportErrorForToken(
3822 ParserErrorCode.EXPECTED_TOKEN, _currentToken.previous, [";"]);
3823 return _createSyntheticToken(TokenType.SEMICOLON);
3824 }
3825 }
3826
3827 /**
3828 * Search the given list of [ranges] for a range that contains the given
3829 * [index]. Return the range that was found, or `null` if none of the ranges
3830 * contain the index.
3831 */
3832 List<int> _findRange(List<List<int>> ranges, int index) {
3833 int rangeCount = ranges.length;
3834 for (int i = 0; i < rangeCount; i++) {
3835 List<int> range = ranges[i];
3836 if (range[0] <= index && index <= range[1]) {
3837 return range;
3838 } else if (index < range[0]) {
3839 return null;
3840 }
3841 }
3842 return null;
3843 }
3844
3845 /**
3846 * Return a list of the ranges of characters in the given [comment] that
3847 * should be treated as code blocks.
3848 */
3849 List<List<int>> _getCodeBlockRanges(String comment) {
3850 List<List<int>> ranges = new List<List<int>>();
3851 int length = comment.length;
3852 if (length < 3) {
3853 return ranges;
3854 }
3855 int index = 0;
3856 int firstChar = comment.codeUnitAt(0);
3857 if (firstChar == 0x2F) {
3858 int secondChar = comment.codeUnitAt(1);
3859 int thirdChar = comment.codeUnitAt(2);
3860 if ((secondChar == 0x2A && thirdChar == 0x2A) ||
3861 (secondChar == 0x2F && thirdChar == 0x2F)) {
3862 index = 3;
3863 }
3864 }
3865 while (index < length) {
3866 int currentChar = comment.codeUnitAt(index);
3867 if (currentChar == 0xD || currentChar == 0xA) {
3868 index = index + 1;
3869 while (index < length &&
3870 Character.isWhitespace(comment.codeUnitAt(index))) {
3871 index = index + 1;
3872 }
3873 if (StringUtilities.startsWith6(
3874 comment, index, 0x2A, 0x20, 0x20, 0x20, 0x20, 0x20)) {
3875 int end = index + 6;
3876 while (end < length &&
3877 comment.codeUnitAt(end) != 0xD &&
3878 comment.codeUnitAt(end) != 0xA) {
3879 end = end + 1;
3880 }
3881 ranges.add(<int>[index, end]);
3882 index = end;
3883 }
3884 } else if (index + 1 < length &&
3885 currentChar == 0x5B &&
3886 comment.codeUnitAt(index + 1) == 0x3A) {
3887 int end = StringUtilities.indexOf2(comment, index + 2, 0x3A, 0x5D);
3888 if (end < 0) {
3889 end = length;
3890 }
3891 ranges.add(<int>[index, end]);
3892 index = end + 1;
3893 } else {
3894 index = index + 1;
3895 }
3896 }
3897 return ranges;
3898 }
3899
3900 /**
3901 * Return the end token associated with the given [beginToken], or `null` if
3902 * either the given token is not a begin token or it does not have an end
3903 * token associated with it.
3904 */
3905 Token _getEndToken(Token beginToken) {
3906 if (beginToken is BeginToken) {
3907 return beginToken.endToken;
3908 }
3909 return null;
3910 }
3911
3912 /**
3913 * Inject the given [token] into the token stream immediately before the
3914 * current token.
3915 */
3916 Token _injectToken(Token token) {
3917 Token previous = _currentToken.previous;
3918 token.setNext(_currentToken);
3919 previous.setNext(token);
3920 return token; 391 return token;
3921 } 392 }
3922 393
3923 /** 394 /**
3924 * Return `true` if the current token appears to be the beginning of a 395 * Return `true` if the current token appears to be the beginning of a
3925 * function declaration. 396 * function declaration.
3926 */ 397 */
3927 bool _isFunctionDeclaration() { 398 bool isFunctionDeclaration() {
3928 if (_matchesKeyword(Keyword.VOID)) { 399 Keyword keyword = _currentToken.keyword;
400 if (keyword == Keyword.VOID) {
3929 return true; 401 return true;
3930 } 402 }
3931 Token afterReturnType = _skipTypeName(_currentToken); 403 Token afterReturnType = skipTypeName(_currentToken);
3932 if (afterReturnType == null) { 404 if (afterReturnType == null) {
3933 // There was no return type, but it is optional, so go back to where we 405 // There was no return type, but it is optional, so go back to where we
3934 // started. 406 // started.
3935 afterReturnType = _currentToken; 407 afterReturnType = _currentToken;
3936 } 408 }
3937 Token afterIdentifier = _skipSimpleIdentifier(afterReturnType); 409 Token afterIdentifier = skipSimpleIdentifier(afterReturnType);
3938 if (afterIdentifier == null) { 410 if (afterIdentifier == null) {
3939 // It's possible that we parsed the function name as if it were a type 411 // It's possible that we parsed the function name as if it were a type
3940 // name, so see whether it makes sense if we assume that there is no type. 412 // name, so see whether it makes sense if we assume that there is no type.
3941 afterIdentifier = _skipSimpleIdentifier(_currentToken); 413 afterIdentifier = skipSimpleIdentifier(_currentToken);
3942 } 414 }
3943 if (afterIdentifier == null) { 415 if (afterIdentifier == null) {
3944 return false; 416 return false;
3945 } 417 }
3946 if (_isFunctionExpression(afterIdentifier)) { 418 if (isFunctionExpression(afterIdentifier)) {
3947 return true; 419 return true;
3948 } 420 }
3949 // It's possible that we have found a getter. While this isn't valid at this 421 // It's possible that we have found a getter. While this isn't valid at this
3950 // point we test for it in order to recover better. 422 // point we test for it in order to recover better.
3951 if (_matchesKeyword(Keyword.GET)) { 423 if (keyword == Keyword.GET) {
3952 Token afterName = _skipSimpleIdentifier(_currentToken.next); 424 Token afterName = skipSimpleIdentifier(_currentToken.next);
3953 if (afterName == null) { 425 if (afterName == null) {
3954 return false; 426 return false;
3955 } 427 }
3956 return _tokenMatches(afterName, TokenType.FUNCTION) || 428 TokenType type = afterName.type;
3957 _tokenMatches(afterName, TokenType.OPEN_CURLY_BRACKET); 429 return type == TokenType.FUNCTION || type == TokenType.OPEN_CURLY_BRACKET;
3958 } else if (_tokenMatchesKeyword(afterReturnType, Keyword.GET)) { 430 } else if (_tokenMatchesKeyword(afterReturnType, Keyword.GET)) {
3959 Token afterName = _skipSimpleIdentifier(afterReturnType.next); 431 Token afterName = skipSimpleIdentifier(afterReturnType.next);
3960 if (afterName == null) { 432 if (afterName == null) {
3961 return false; 433 return false;
3962 } 434 }
3963 return _tokenMatches(afterName, TokenType.FUNCTION) || 435 TokenType type = afterName.type;
3964 _tokenMatches(afterName, TokenType.OPEN_CURLY_BRACKET); 436 return type == TokenType.FUNCTION || type == TokenType.OPEN_CURLY_BRACKET;
3965 } 437 }
3966 return false; 438 return false;
3967 } 439 }
3968 440
3969 /** 441 /**
3970 * Return `true` if the given [token] appears to be the beginning of a 442 * Return `true` if the given [token] appears to be the beginning of a
3971 * function expression. 443 * function expression.
3972 */ 444 */
3973 bool _isFunctionExpression(Token token) { 445 bool isFunctionExpression(Token token) {
3974 // Function expressions aren't allowed in initializer lists. 446 // Function expressions aren't allowed in initializer lists.
3975 if (_inInitializer) { 447 if (_inInitializer) {
3976 return false; 448 return false;
3977 } 449 }
3978 Token afterTypeParameters = _skipTypeParameterList(token); 450 Token afterTypeParameters = _skipTypeParameterList(token);
3979 if (afterTypeParameters == null) { 451 if (afterTypeParameters == null) {
3980 afterTypeParameters = token; 452 afterTypeParameters = token;
3981 } 453 }
3982 Token afterParameters = _skipFormalParameterList(afterTypeParameters); 454 Token afterParameters = _skipFormalParameterList(afterTypeParameters);
3983 if (afterParameters == null) { 455 if (afterParameters == null) {
3984 return false; 456 return false;
3985 } 457 }
3986 if (afterParameters 458 if (afterParameters.matchesAny(
3987 .matchesAny([TokenType.OPEN_CURLY_BRACKET, TokenType.FUNCTION])) { 459 const <TokenType>[TokenType.OPEN_CURLY_BRACKET, TokenType.FUNCTION])) {
3988 return true; 460 return true;
3989 } 461 }
3990 String lexeme = afterParameters.lexeme; 462 String lexeme = afterParameters.lexeme;
3991 return lexeme == ASYNC || lexeme == SYNC; 463 return lexeme == ASYNC || lexeme == SYNC;
3992 } 464 }
3993 465
3994 /** 466 /**
3995 * Return `true` if the given [character] is a valid hexadecimal digit.
3996 */
3997 bool _isHexDigit(int character) => (0x30 <= character && character <= 0x39) ||
3998 (0x41 <= character && character <= 0x46) ||
3999 (0x61 <= character && character <= 0x66);
4000
4001 /**
4002 * Return `true` if the current token is the first token in an initialized 467 * Return `true` if the current token is the first token in an initialized
4003 * variable declaration rather than an expression. This method assumes that we 468 * variable declaration rather than an expression. This method assumes that we
4004 * have already skipped past any metadata that might be associated with the 469 * have already skipped past any metadata that might be associated with the
4005 * declaration. 470 * declaration.
4006 * 471 *
4007 * initializedVariableDeclaration ::= 472 * initializedVariableDeclaration ::=
4008 * declaredIdentifier ('=' expression)? (',' initializedIdentifier)* 473 * declaredIdentifier ('=' expression)? (',' initializedIdentifier)*
4009 * 474 *
4010 * declaredIdentifier ::= 475 * declaredIdentifier ::=
4011 * metadata finalConstVarOrType identifier 476 * metadata finalConstVarOrType identifier
4012 * 477 *
4013 * finalConstVarOrType ::= 478 * finalConstVarOrType ::=
4014 * 'final' type? 479 * 'final' type?
4015 * | 'const' type? 480 * | 'const' type?
4016 * | 'var' 481 * | 'var'
4017 * | type 482 * | type
4018 * 483 *
4019 * type ::= 484 * type ::=
4020 * qualified typeArguments? 485 * qualified typeArguments?
4021 * 486 *
4022 * initializedIdentifier ::= 487 * initializedIdentifier ::=
4023 * identifier ('=' expression)? 488 * identifier ('=' expression)?
4024 */ 489 */
4025 bool _isInitializedVariableDeclaration() { 490 bool isInitializedVariableDeclaration() {
4026 if (_matchesKeyword(Keyword.FINAL) || _matchesKeyword(Keyword.VAR)) { 491 Keyword keyword = _currentToken.keyword;
492 if (keyword == Keyword.FINAL || keyword == Keyword.VAR) {
4027 // An expression cannot start with a keyword other than 'const', 493 // An expression cannot start with a keyword other than 'const',
4028 // 'rethrow', or 'throw'. 494 // 'rethrow', or 'throw'.
4029 return true; 495 return true;
4030 } 496 }
4031 if (_matchesKeyword(Keyword.CONST)) { 497 if (keyword == Keyword.CONST) {
4032 // Look to see whether we might be at the start of a list or map literal, 498 // Look to see whether we might be at the start of a list or map literal,
4033 // otherwise this should be the start of a variable declaration. 499 // otherwise this should be the start of a variable declaration.
4034 return !_peek().matchesAny([ 500 return !_peek().matchesAny(const <TokenType>[
4035 TokenType.LT, 501 TokenType.LT,
4036 TokenType.OPEN_CURLY_BRACKET, 502 TokenType.OPEN_CURLY_BRACKET,
4037 TokenType.OPEN_SQUARE_BRACKET, 503 TokenType.OPEN_SQUARE_BRACKET,
4038 TokenType.INDEX 504 TokenType.INDEX
4039 ]); 505 ]);
4040 } 506 }
4041 bool allowAdditionalTokens = true; 507 bool allowAdditionalTokens = true;
4042 // We know that we have an identifier, and need to see whether it might be 508 // We know that we have an identifier, and need to see whether it might be
4043 // a type name. 509 // a type name.
4044 if (_currentToken.type != TokenType.IDENTIFIER) { 510 if (_currentToken.type != TokenType.IDENTIFIER) {
4045 allowAdditionalTokens = false; 511 allowAdditionalTokens = false;
4046 } 512 }
4047 Token token = _skipTypeName(_currentToken); 513 Token token = skipTypeName(_currentToken);
4048 if (token == null) { 514 if (token == null) {
4049 // There was no type name, so this can't be a declaration. 515 // There was no type name, so this can't be a declaration.
4050 return false; 516 return false;
4051 } 517 }
4052 if (token.type != TokenType.IDENTIFIER) { 518 if (token.type != TokenType.IDENTIFIER) {
4053 allowAdditionalTokens = false; 519 allowAdditionalTokens = false;
4054 } 520 }
4055 token = _skipSimpleIdentifier(token); 521 token = skipSimpleIdentifier(token);
4056 if (token == null) { 522 if (token == null) {
4057 return false; 523 return false;
4058 } 524 }
4059 TokenType type = token.type; 525 TokenType type = token.type;
4060 // Usual cases in valid code: 526 // Usual cases in valid code:
4061 // String v = ''; 527 // String v = '';
4062 // String v, v2; 528 // String v, v2;
4063 // String v; 529 // String v;
4064 // for (String item in items) {} 530 // for (String item in items) {}
4065 if (type == TokenType.EQ || 531 if (type == TokenType.EQ ||
4066 type == TokenType.COMMA || 532 type == TokenType.COMMA ||
4067 type == TokenType.SEMICOLON || 533 type == TokenType.SEMICOLON ||
4068 _tokenMatchesKeyword(token, Keyword.IN)) { 534 token.keyword == Keyword.IN) {
4069 return true; 535 return true;
4070 } 536 }
4071 // It is OK to parse as a variable declaration in these cases: 537 // It is OK to parse as a variable declaration in these cases:
4072 // String v } 538 // String v }
4073 // String v if (true) print('OK'); 539 // String v if (true) print('OK');
4074 // String v { print(42); } 540 // String v { print(42); }
4075 // ...but not in these cases: 541 // ...but not in these cases:
4076 // get getterName { 542 // get getterName {
4077 // String get getterName 543 // String get getterName
4078 if (allowAdditionalTokens) { 544 if (allowAdditionalTokens) {
4079 if (type == TokenType.CLOSE_CURLY_BRACKET || 545 if (type == TokenType.CLOSE_CURLY_BRACKET ||
4080 type == TokenType.KEYWORD || 546 type == TokenType.KEYWORD ||
4081 type == TokenType.IDENTIFIER || 547 type == TokenType.IDENTIFIER ||
4082 type == TokenType.OPEN_CURLY_BRACKET) { 548 type == TokenType.OPEN_CURLY_BRACKET) {
4083 return true; 549 return true;
4084 } 550 }
4085 } 551 }
4086 return false; 552 return false;
4087 } 553 }
4088 554
4089 bool _isLikelyParameterList() {
4090 if (_matches(TokenType.OPEN_PAREN)) {
4091 return true;
4092 }
4093 if (!parseGenericMethods) {
4094 return false;
4095 }
4096 Token token = _skipTypeArgumentList(_currentToken);
4097 return token != null && _tokenMatches(token, TokenType.OPEN_PAREN);
4098 }
4099
4100 /**
4101 * Given that we have just found bracketed text within the given [comment],
4102 * look to see whether that text is (a) followed by a parenthesized link
4103 * address, (b) followed by a colon, or (c) followed by optional whitespace
4104 * and another square bracket. The [rightIndex] is the index of the right
4105 * bracket. Return `true` if the bracketed text is followed by a link address.
4106 *
4107 * This method uses the syntax described by the
4108 * <a href="http://daringfireball.net/projects/markdown/syntax">markdown</a>
4109 * project.
4110 */
4111 bool _isLinkText(String comment, int rightIndex) {
4112 int length = comment.length;
4113 int index = rightIndex + 1;
4114 if (index >= length) {
4115 return false;
4116 }
4117 int nextChar = comment.codeUnitAt(index);
4118 if (nextChar == 0x28 || nextChar == 0x3A) {
4119 return true;
4120 }
4121 while (Character.isWhitespace(nextChar)) {
4122 index = index + 1;
4123 if (index >= length) {
4124 return false;
4125 }
4126 nextChar = comment.codeUnitAt(index);
4127 }
4128 return nextChar == 0x5B;
4129 }
4130
4131 /**
4132 * Return `true` if the given [startToken] appears to be the beginning of an
4133 * operator declaration.
4134 */
4135 bool _isOperator(Token startToken) {
4136 // Accept any operator here, even if it is not user definable.
4137 if (!startToken.isOperator) {
4138 return false;
4139 }
4140 // Token "=" means that it is actually field initializer.
4141 if (startToken.type == TokenType.EQ) {
4142 return false;
4143 }
4144 // Consume all operator tokens.
4145 Token token = startToken.next;
4146 while (token.isOperator) {
4147 token = token.next;
4148 }
4149 // Formal parameter list is expect now.
4150 return _tokenMatches(token, TokenType.OPEN_PAREN);
4151 }
4152
4153 /** 555 /**
4154 * Return `true` if the current token appears to be the beginning of a switch 556 * Return `true` if the current token appears to be the beginning of a switch
4155 * member. 557 * member.
4156 */ 558 */
4157 bool _isSwitchMember() { 559 bool isSwitchMember() {
4158 Token token = _currentToken; 560 Token token = _currentToken;
4159 while (_tokenMatches(token, TokenType.IDENTIFIER) && 561 while (_tokenMatches(token, TokenType.IDENTIFIER) &&
4160 _tokenMatches(token.next, TokenType.COLON)) { 562 _tokenMatches(token.next, TokenType.COLON)) {
4161 token = token.next.next; 563 token = token.next.next;
4162 } 564 }
4163 if (token.type == TokenType.KEYWORD) { 565 Keyword keyword = token.keyword;
4164 Keyword keyword = (token as KeywordToken).keyword; 566 return keyword == Keyword.CASE || keyword == Keyword.DEFAULT;
4165 return keyword == Keyword.CASE || keyword == Keyword.DEFAULT;
4166 }
4167 return false;
4168 }
4169
4170 /**
4171 * Return `true` if the [startToken] appears to be the first token of a type
4172 * name that is followed by a variable or field formal parameter.
4173 */
4174 bool _isTypedIdentifier(Token startToken) {
4175 Token token = _skipReturnType(startToken);
4176 if (token == null) {
4177 return false;
4178 } else if (_tokenMatchesIdentifier(token)) {
4179 return true;
4180 } else if (_tokenMatchesKeyword(token, Keyword.THIS) &&
4181 _tokenMatches(token.next, TokenType.PERIOD) &&
4182 _tokenMatchesIdentifier(token.next.next)) {
4183 return true;
4184 } else if (_tokenMatchesKeyword(startToken, Keyword.VOID)) {
4185 // The keyword 'void' isn't a valid identifier, so it should be assumed to
4186 // be a type name.
4187 return true;
4188 } else if (startToken.next != token &&
4189 !_tokenMatches(token, TokenType.OPEN_PAREN)) {
4190 // The type is more than a simple identifier, so it should be assumed to
4191 // be a type name.
4192 return true;
4193 }
4194 return false;
4195 }
4196
4197 /**
4198 * Increments the error reporting lock level. If level is more than `0`, then
4199 * [reportError] wont report any error.
4200 */
4201 void _lockErrorListener() {
4202 _errorListenerLock++;
4203 }
4204
4205 /**
4206 * Return `true` if the current token has the given [type]. Note that the
4207 * method [_matchesGt] should be used if the argument to this method would be
4208 * [TokenType.GT].
4209 */
4210 bool _matches(TokenType type) => _currentToken.type == type;
4211
4212 /**
4213 * Return `true` if the current token has a type of [TokenType.GT]. Note that
4214 * this method, unlike other variants, will modify the token stream if
4215 * possible to match desired type. In particular, if the next token is either
4216 * a '>>' or '>>>', the token stream will be re-written and `true` will be
4217 * returned.
4218 */
4219 bool _matchesGt() {
4220 TokenType currentType = _currentToken.type;
4221 if (currentType == TokenType.GT) {
4222 return true;
4223 } else if (currentType == TokenType.GT_GT) {
4224 Token first = _createToken(_currentToken, TokenType.GT);
4225 Token second = new Token(TokenType.GT, _currentToken.offset + 1);
4226 second.setNext(_currentToken.next);
4227 first.setNext(second);
4228 _currentToken.previous.setNext(first);
4229 _currentToken = first;
4230 return true;
4231 } else if (currentType == TokenType.GT_EQ) {
4232 Token first = _createToken(_currentToken, TokenType.GT);
4233 Token second = new Token(TokenType.EQ, _currentToken.offset + 1);
4234 second.setNext(_currentToken.next);
4235 first.setNext(second);
4236 _currentToken.previous.setNext(first);
4237 _currentToken = first;
4238 return true;
4239 } else if (currentType == TokenType.GT_GT_EQ) {
4240 int offset = _currentToken.offset;
4241 Token first = _createToken(_currentToken, TokenType.GT);
4242 Token second = new Token(TokenType.GT, offset + 1);
4243 Token third = new Token(TokenType.EQ, offset + 2);
4244 third.setNext(_currentToken.next);
4245 second.setNext(third);
4246 first.setNext(second);
4247 _currentToken.previous.setNext(first);
4248 _currentToken = first;
4249 return true;
4250 }
4251 return false;
4252 }
4253
4254 /**
4255 * Return `true` if the current token is a valid identifier. Valid identifiers
4256 * include built-in identifiers (pseudo-keywords).
4257 */
4258 bool _matchesIdentifier() => _tokenMatchesIdentifier(_currentToken);
4259
4260 /**
4261 * Return `true` if the current token matches the given [keyword].
4262 */
4263 bool _matchesKeyword(Keyword keyword) =>
4264 _tokenMatchesKeyword(_currentToken, keyword);
4265
4266 /**
4267 * Return `true` if the current token matches the given [identifier].
4268 */
4269 bool _matchesString(String identifier) =>
4270 _currentToken.type == TokenType.IDENTIFIER &&
4271 _currentToken.lexeme == identifier;
4272
4273 /**
4274 * If the current token has the given [type], then advance to the next token
4275 * and return `true`. Otherwise, return `false` without advancing. This method
4276 * should not be invoked with an argument value of [TokenType.GT].
4277 */
4278 bool _optional(TokenType type) {
4279 if (_matches(type)) {
4280 _advance();
4281 return true;
4282 }
4283 return false;
4284 } 567 }
4285 568
4286 /** 569 /**
4287 * Parse an additive expression. Return the additive expression that was 570 * Parse an additive expression. Return the additive expression that was
4288 * parsed. 571 * parsed.
4289 * 572 *
4290 * additiveExpression ::= 573 * additiveExpression ::=
4291 * multiplicativeExpression (additiveOperator multiplicativeExpression )* 574 * multiplicativeExpression (additiveOperator multiplicativeExpression )*
4292 * | 'super' (additiveOperator multiplicativeExpression)+ 575 * | 'super' (additiveOperator multiplicativeExpression)+
4293 */ 576 */
4294 Expression _parseAdditiveExpression() { 577 Expression parseAdditiveExpression() {
4295 Expression expression; 578 Expression expression;
4296 if (_matchesKeyword(Keyword.SUPER) && 579 if (_currentToken.keyword == Keyword.SUPER &&
4297 _currentToken.next.type.isAdditiveOperator) { 580 _currentToken.next.type.isAdditiveOperator) {
4298 expression = new SuperExpression(getAndAdvance()); 581 expression = new SuperExpression(getAndAdvance());
4299 } else { 582 } else {
4300 expression = _parseMultiplicativeExpression(); 583 expression = parseMultiplicativeExpression();
4301 } 584 }
4302 while (_currentToken.type.isAdditiveOperator) { 585 while (_currentToken.type.isAdditiveOperator) {
4303 Token operator = getAndAdvance();
4304 expression = new BinaryExpression( 586 expression = new BinaryExpression(
4305 expression, operator, _parseMultiplicativeExpression()); 587 expression, getAndAdvance(), parseMultiplicativeExpression());
4306 } 588 }
4307 return expression; 589 return expression;
4308 } 590 }
4309 591
4310 /** 592 /**
593 * Parse an annotation. Return the annotation that was parsed.
594 *
595 * This method assumes that the current token matches [TokenType.AT].
596 *
597 * annotation ::=
598 * '@' qualified ('.' identifier)? arguments?
599 */
600 Annotation parseAnnotation() {
601 Token atSign = getAndAdvance();
602 Identifier name = parsePrefixedIdentifier();
603 Token period = null;
604 SimpleIdentifier constructorName = null;
605 if (_matches(TokenType.PERIOD)) {
606 period = getAndAdvance();
607 constructorName = parseSimpleIdentifier();
608 }
609 ArgumentList arguments = null;
610 if (_matches(TokenType.OPEN_PAREN)) {
611 arguments = parseArgumentList();
612 }
613 return new Annotation(atSign, name, period, constructorName, arguments);
614 }
615
616 /**
617 * Parse an argument. Return the argument that was parsed.
618 *
619 * argument ::=
620 * namedArgument
621 * | expression
622 *
623 * namedArgument ::=
624 * label expression
625 */
626 Expression parseArgument() {
627 // TODO(brianwilkerson) Consider returning a wrapper indicating whether the
628 // expression is a named expression in order to remove the 'is' check in
629 // 'parseArgumentList'.
630 //
631 // Both namedArgument and expression can start with an identifier, but only
632 // namedArgument can have an identifier followed by a colon.
633 //
634 if (_matchesIdentifier() && _tokenMatches(_peek(), TokenType.COLON)) {
635 return new NamedExpression(parseLabel(), parseExpression2());
636 } else {
637 return parseExpression2();
638 }
639 }
640
641 /**
642 * Parse a list of arguments. Return the argument list that was parsed.
643 *
644 * This method assumes that the current token matches [TokenType.OPEN_PAREN].
645 *
646 * arguments ::=
647 * '(' argumentList? ')'
648 *
649 * argumentList ::=
650 * namedArgument (',' namedArgument)*
651 * | expressionList (',' namedArgument)*
652 */
653 ArgumentList parseArgumentList() {
654 Token leftParenthesis = getAndAdvance();
655 if (_matches(TokenType.CLOSE_PAREN)) {
656 return new ArgumentList(leftParenthesis, null, getAndAdvance());
657 }
658 //
659 // Even though unnamed arguments must all appear before any named arguments,
660 // we allow them to appear in any order so that we can recover faster.
661 //
662 bool wasInInitializer = _inInitializer;
663 _inInitializer = false;
664 try {
665 Expression argument = parseArgument();
666 List<Expression> arguments = <Expression>[argument];
667 bool foundNamedArgument = argument is NamedExpression;
668 bool generatedError = false;
669 while (_optional(TokenType.COMMA)) {
670 if (_matches(TokenType.CLOSE_PAREN)) {
671 break;
672 }
673 argument = parseArgument();
674 arguments.add(argument);
675 if (argument is NamedExpression) {
676 foundNamedArgument = true;
677 } else if (foundNamedArgument) {
678 if (!generatedError) {
679 if (!argument.isSynthetic) {
680 // Report the error, once, but allow the arguments to be in any
681 // order in the AST.
682 _reportErrorForCurrentToken(
683 ParserErrorCode.POSITIONAL_AFTER_NAMED_ARGUMENT);
684 generatedError = true;
685 }
686 }
687 }
688 }
689 // Recovery: If the next token is not a right parenthesis, look at the
690 // left parenthesis to see whether there is a matching right parenthesis.
691 // If there is, then we're more likely missing a comma and should go back
692 // to parsing arguments.
693 Token rightParenthesis = _expect(TokenType.CLOSE_PAREN);
694 return new ArgumentList(leftParenthesis, arguments, rightParenthesis);
695 } finally {
696 _inInitializer = wasInInitializer;
697 }
698 }
699
700 /**
4311 * Parse an assert statement. Return the assert statement. 701 * Parse an assert statement. Return the assert statement.
4312 * 702 *
703 * This method assumes that the current token matches `Keyword.ASSERT`.
704 *
4313 * assertStatement ::= 705 * assertStatement ::=
4314 * 'assert' '(' conditionalExpression ')' ';' 706 * 'assert' '(' expression [',' expression] ')' ';'
4315 */ 707 */
4316 AssertStatement _parseAssertStatement() { 708 AssertStatement parseAssertStatement() {
4317 Token keyword = _expectKeyword(Keyword.ASSERT); 709 Token keyword = getAndAdvance();
4318 Token leftParen = _expect(TokenType.OPEN_PAREN); 710 Token leftParen = _expect(TokenType.OPEN_PAREN);
4319 Expression expression = parseExpression2(); 711 Expression expression = parseExpression2();
4320 if (expression is AssignmentExpression) { 712 Token comma;
4321 _reportErrorForNode( 713 Expression message;
4322 ParserErrorCode.ASSERT_DOES_NOT_TAKE_ASSIGNMENT, expression); 714 if (_matches(TokenType.COMMA)) {
4323 } else if (expression is CascadeExpression) { 715 comma = getAndAdvance();
4324 _reportErrorForNode( 716 message = parseExpression2();
4325 ParserErrorCode.ASSERT_DOES_NOT_TAKE_CASCADE, expression);
4326 } else if (expression is ThrowExpression) {
4327 _reportErrorForNode(
4328 ParserErrorCode.ASSERT_DOES_NOT_TAKE_THROW, expression);
4329 } else if (expression is RethrowExpression) {
4330 _reportErrorForNode(
4331 ParserErrorCode.ASSERT_DOES_NOT_TAKE_RETHROW, expression);
4332 } 717 }
4333 Token rightParen = _expect(TokenType.CLOSE_PAREN); 718 Token rightParen = _expect(TokenType.CLOSE_PAREN);
4334 Token semicolon = _expect(TokenType.SEMICOLON); 719 Token semicolon = _expect(TokenType.SEMICOLON);
4335 return new AssertStatement( 720 return new AssertStatement(
4336 keyword, leftParen, expression, rightParen, semicolon); 721 keyword, leftParen, expression, comma, message, rightParen, semicolon);
4337 } 722 }
4338 723
4339 /** 724 /**
4340 * Parse an assignable expression. The [primaryAllowed] is `true` if the 725 * Parse an assignable expression. The [primaryAllowed] is `true` if the
4341 * expression is allowed to be a primary without any assignable selector. 726 * expression is allowed to be a primary without any assignable selector.
4342 * Return the assignable expression that was parsed. 727 * Return the assignable expression that was parsed.
4343 * 728 *
4344 * assignableExpression ::= 729 * assignableExpression ::=
4345 * primary (arguments* assignableSelector)+ 730 * primary (arguments* assignableSelector)+
4346 * | 'super' unconditionalAssignableSelector 731 * | 'super' unconditionalAssignableSelector
4347 * | identifier 732 * | identifier
4348 */ 733 */
4349 Expression _parseAssignableExpression(bool primaryAllowed) { 734 Expression parseAssignableExpression(bool primaryAllowed) {
4350 if (_matchesKeyword(Keyword.SUPER)) { 735 if (_matchesKeyword(Keyword.SUPER)) {
4351 return _parseAssignableSelector( 736 return parseAssignableSelector(
4352 new SuperExpression(getAndAdvance()), false, 737 new SuperExpression(getAndAdvance()), false,
4353 allowConditional: false); 738 allowConditional: false);
4354 } 739 }
4355 // 740 return _parseAssignableExpressionNotStartingWithSuper(primaryAllowed);
4356 // A primary expression can start with an identifier. We resolve the
4357 // ambiguity by determining whether the primary consists of anything other
4358 // than an identifier and/or is followed by an assignableSelector.
4359 //
4360 Expression expression = _parsePrimaryExpression();
4361 bool isOptional = primaryAllowed || expression is SimpleIdentifier;
4362 while (true) {
4363 while (_isLikelyParameterList()) {
4364 TypeArgumentList typeArguments = null;
4365 if (_matches(TokenType.LT)) {
4366 typeArguments = parseTypeArgumentList();
4367 }
4368 ArgumentList argumentList = parseArgumentList();
4369 if (expression is SimpleIdentifier) {
4370 expression = new MethodInvocation(null, null,
4371 expression as SimpleIdentifier, typeArguments, argumentList);
4372 } else if (expression is PrefixedIdentifier) {
4373 PrefixedIdentifier identifier = expression as PrefixedIdentifier;
4374 expression = new MethodInvocation(
4375 identifier.prefix,
4376 identifier.period,
4377 identifier.identifier,
4378 typeArguments,
4379 argumentList);
4380 } else if (expression is PropertyAccess) {
4381 PropertyAccess access = expression as PropertyAccess;
4382 expression = new MethodInvocation(access.target, access.operator,
4383 access.propertyName, typeArguments, argumentList);
4384 } else {
4385 expression = new FunctionExpressionInvocation(
4386 expression, typeArguments, argumentList);
4387 }
4388 if (!primaryAllowed) {
4389 isOptional = false;
4390 }
4391 }
4392 Expression selectorExpression = _parseAssignableSelector(
4393 expression, isOptional || (expression is PrefixedIdentifier));
4394 if (identical(selectorExpression, expression)) {
4395 if (!isOptional && (expression is PrefixedIdentifier)) {
4396 PrefixedIdentifier identifier = expression as PrefixedIdentifier;
4397 expression = new PropertyAccess(
4398 identifier.prefix, identifier.period, identifier.identifier);
4399 }
4400 return expression;
4401 }
4402 expression = selectorExpression;
4403 isOptional = true;
4404 }
4405 } 741 }
4406 742
4407 /** 743 /**
4408 * Parse an assignable selector. The [prefix] is the expression preceding the 744 * Parse an assignable selector. The [prefix] is the expression preceding the
4409 * selector. The [optional] is `true` if the selector is optional. Return the 745 * selector. The [optional] is `true` if the selector is optional. Return the
4410 * assignable selector that was parsed, or the original prefix if there was no 746 * assignable selector that was parsed, or the original prefix if there was no
4411 * assignable selector. If [allowConditional] is false, then the '?.' 747 * assignable selector. If [allowConditional] is false, then the '?.'
4412 * operator will still be parsed, but a parse error will be generated. 748 * operator will still be parsed, but a parse error will be generated.
4413 * 749 *
4414 * unconditionalAssignableSelector ::= 750 * unconditionalAssignableSelector ::=
4415 * '[' expression ']' 751 * '[' expression ']'
4416 * | '.' identifier 752 * | '.' identifier
4417 * 753 *
4418 * assignableSelector ::= 754 * assignableSelector ::=
4419 * unconditionalAssignableSelector 755 * unconditionalAssignableSelector
4420 * | '?.' identifier 756 * | '?.' identifier
4421 */ 757 */
4422 Expression _parseAssignableSelector(Expression prefix, bool optional, 758 Expression parseAssignableSelector(Expression prefix, bool optional,
4423 {bool allowConditional: true}) { 759 {bool allowConditional: true}) {
4424 if (_matches(TokenType.OPEN_SQUARE_BRACKET)) { 760 TokenType type = _currentToken.type;
761 if (type == TokenType.OPEN_SQUARE_BRACKET) {
4425 Token leftBracket = getAndAdvance(); 762 Token leftBracket = getAndAdvance();
4426 bool wasInInitializer = _inInitializer; 763 bool wasInInitializer = _inInitializer;
4427 _inInitializer = false; 764 _inInitializer = false;
4428 try { 765 try {
4429 Expression index = parseExpression2(); 766 Expression index = parseExpression2();
4430 Token rightBracket = _expect(TokenType.CLOSE_SQUARE_BRACKET); 767 Token rightBracket = _expect(TokenType.CLOSE_SQUARE_BRACKET);
4431 return new IndexExpression.forTarget( 768 return new IndexExpression.forTarget(
4432 prefix, leftBracket, index, rightBracket); 769 prefix, leftBracket, index, rightBracket);
4433 } finally { 770 } finally {
4434 _inInitializer = wasInInitializer; 771 _inInitializer = wasInInitializer;
4435 } 772 }
4436 } else if (_matches(TokenType.PERIOD) ||
4437 _matches(TokenType.QUESTION_PERIOD)) {
4438 if (_matches(TokenType.QUESTION_PERIOD) && !allowConditional) {
4439 _reportErrorForCurrentToken(
4440 ParserErrorCode.INVALID_OPERATOR_FOR_SUPER, [_currentToken.lexeme]);
4441 }
4442 Token operator = getAndAdvance();
4443 return new PropertyAccess(prefix, operator, parseSimpleIdentifier());
4444 } else { 773 } else {
4445 if (!optional) { 774 bool isQuestionPeriod = type == TokenType.QUESTION_PERIOD;
4446 // Report the missing selector. 775 if (type == TokenType.PERIOD || isQuestionPeriod) {
4447 _reportErrorForCurrentToken( 776 if (isQuestionPeriod && !allowConditional) {
4448 ParserErrorCode.MISSING_ASSIGNABLE_SELECTOR); 777 _reportErrorForCurrentToken(
4449 } 778 ParserErrorCode.INVALID_OPERATOR_FOR_SUPER,
4450 return prefix; 779 [_currentToken.lexeme]);
780 }
781 Token operator = getAndAdvance();
782 return new PropertyAccess(prefix, operator, parseSimpleIdentifier());
783 } else {
784 if (!optional) {
785 // Report the missing selector.
786 _reportErrorForCurrentToken(
787 ParserErrorCode.MISSING_ASSIGNABLE_SELECTOR);
788 }
789 return prefix;
790 }
4451 } 791 }
4452 } 792 }
4453 793
4454 /** 794 /**
4455 * Parse a await expression. Return the await expression that was parsed. 795 * Parse a await expression. Return the await expression that was parsed.
4456 * 796 *
797 * This method assumes that the current token matches `_AWAIT`.
798 *
4457 * awaitExpression ::= 799 * awaitExpression ::=
4458 * 'await' unaryExpression 800 * 'await' unaryExpression
4459 */ 801 */
4460 AwaitExpression _parseAwaitExpression() { 802 AwaitExpression parseAwaitExpression() {
4461 Token awaitToken = getAndAdvance(); 803 Token awaitToken = getAndAdvance();
4462 Expression expression = _parseUnaryExpression(); 804 Expression expression = parseUnaryExpression();
4463 return new AwaitExpression(awaitToken, expression); 805 return new AwaitExpression(awaitToken, expression);
4464 } 806 }
4465 807
4466 /** 808 /**
4467 * Parse a bitwise and expression. Return the bitwise and expression that was 809 * Parse a bitwise and expression. Return the bitwise and expression that was
4468 * parsed. 810 * parsed.
4469 * 811 *
4470 * bitwiseAndExpression ::= 812 * bitwiseAndExpression ::=
4471 * shiftExpression ('&' shiftExpression)* 813 * shiftExpression ('&' shiftExpression)*
4472 * | 'super' ('&' shiftExpression)+ 814 * | 'super' ('&' shiftExpression)+
4473 */ 815 */
4474 Expression _parseBitwiseAndExpression() { 816 Expression parseBitwiseAndExpression() {
4475 Expression expression; 817 Expression expression;
4476 if (_matchesKeyword(Keyword.SUPER) && 818 if (_currentToken.keyword == Keyword.SUPER &&
4477 _tokenMatches(_peek(), TokenType.AMPERSAND)) { 819 _currentToken.next.type == TokenType.AMPERSAND) {
4478 expression = new SuperExpression(getAndAdvance()); 820 expression = new SuperExpression(getAndAdvance());
4479 } else { 821 } else {
4480 expression = _parseShiftExpression(); 822 expression = parseShiftExpression();
4481 } 823 }
4482 while (_matches(TokenType.AMPERSAND)) { 824 while (_currentToken.type == TokenType.AMPERSAND) {
4483 Token operator = getAndAdvance(); 825 expression = new BinaryExpression(
4484 expression = 826 expression, getAndAdvance(), parseShiftExpression());
4485 new BinaryExpression(expression, operator, _parseShiftExpression()); 827 }
828 return expression;
829 }
830
831 /**
832 * Parse a bitwise or expression. Return the bitwise or expression that was
833 * parsed.
834 *
835 * bitwiseOrExpression ::=
836 * bitwiseXorExpression ('|' bitwiseXorExpression)*
837 * | 'super' ('|' bitwiseXorExpression)+
838 */
839 Expression parseBitwiseOrExpression() {
840 Expression expression;
841 if (_currentToken.keyword == Keyword.SUPER &&
842 _currentToken.next.type == TokenType.BAR) {
843 expression = new SuperExpression(getAndAdvance());
844 } else {
845 expression = parseBitwiseXorExpression();
846 }
847 while (_currentToken.type == TokenType.BAR) {
848 expression = new BinaryExpression(
849 expression, getAndAdvance(), parseBitwiseXorExpression());
4486 } 850 }
4487 return expression; 851 return expression;
4488 } 852 }
4489 853
4490 /** 854 /**
4491 * Parse a bitwise exclusive-or expression. Return the bitwise exclusive-or 855 * Parse a bitwise exclusive-or expression. Return the bitwise exclusive-or
4492 * expression that was parsed. 856 * expression that was parsed.
4493 * 857 *
4494 * bitwiseXorExpression ::= 858 * bitwiseXorExpression ::=
4495 * bitwiseAndExpression ('^' bitwiseAndExpression)* 859 * bitwiseAndExpression ('^' bitwiseAndExpression)*
4496 * | 'super' ('^' bitwiseAndExpression)+ 860 * | 'super' ('^' bitwiseAndExpression)+
4497 */ 861 */
4498 Expression _parseBitwiseXorExpression() { 862 Expression parseBitwiseXorExpression() {
4499 Expression expression; 863 Expression expression;
4500 if (_matchesKeyword(Keyword.SUPER) && 864 if (_currentToken.keyword == Keyword.SUPER &&
4501 _tokenMatches(_peek(), TokenType.CARET)) { 865 _currentToken.next.type == TokenType.CARET) {
4502 expression = new SuperExpression(getAndAdvance()); 866 expression = new SuperExpression(getAndAdvance());
4503 } else { 867 } else {
4504 expression = _parseBitwiseAndExpression(); 868 expression = parseBitwiseAndExpression();
4505 } 869 }
4506 while (_matches(TokenType.CARET)) { 870 while (_currentToken.type == TokenType.CARET) {
4507 Token operator = getAndAdvance();
4508 expression = new BinaryExpression( 871 expression = new BinaryExpression(
4509 expression, operator, _parseBitwiseAndExpression()); 872 expression, getAndAdvance(), parseBitwiseAndExpression());
4510 } 873 }
4511 return expression; 874 return expression;
4512 } 875 }
4513 876
4514 /** 877 /**
878 * Parse a block. Return the block that was parsed.
879 *
880 * This method assumes that the current token matches
881 * [TokenType.OPEN_CURLY_BRACKET].
882 *
883 * block ::=
884 * '{' statements '}'
885 */
886 Block parseBlock() {
887 bool isEndOfBlock() {
888 TokenType type = _currentToken.type;
889 return type == TokenType.EOF || type == TokenType.CLOSE_CURLY_BRACKET;
890 }
891
892 Token leftBracket = getAndAdvance();
893 List<Statement> statements = <Statement>[];
894 Token statementStart = _currentToken;
895 while (!isEndOfBlock()) {
896 Statement statement = parseStatement2();
897 if (identical(_currentToken, statementStart)) {
898 // Ensure that we are making progress and report an error if we're not.
899 _reportErrorForToken(ParserErrorCode.UNEXPECTED_TOKEN, _currentToken,
900 [_currentToken.lexeme]);
901 _advance();
902 } else if (statement != null) {
903 statements.add(statement);
904 }
905 statementStart = _currentToken;
906 }
907 // Recovery: If the next token is not a right curly bracket, look at the
908 // left curly bracket to see whether there is a matching right bracket. If
909 // there is, then we're more likely missing a semi-colon and should go back
910 // to parsing statements.
911 Token rightBracket = _expect(TokenType.CLOSE_CURLY_BRACKET);
912 return new Block(leftBracket, statements, rightBracket);
913 }
914
915 /**
4515 * Parse a break statement. Return the break statement that was parsed. 916 * Parse a break statement. Return the break statement that was parsed.
4516 * 917 *
918 * This method assumes that the current token matches `Keyword.BREAK`.
919 *
4517 * breakStatement ::= 920 * breakStatement ::=
4518 * 'break' identifier? ';' 921 * 'break' identifier? ';'
4519 */ 922 */
4520 Statement _parseBreakStatement() { 923 Statement parseBreakStatement() {
4521 Token breakKeyword = _expectKeyword(Keyword.BREAK); 924 Token breakKeyword = getAndAdvance();
4522 SimpleIdentifier label = null; 925 SimpleIdentifier label = null;
4523 if (_matchesIdentifier()) { 926 if (_matchesIdentifier()) {
4524 label = parseSimpleIdentifier(); 927 label = _parseSimpleIdentifierUnchecked();
4525 } 928 }
4526 if (!_inLoop && !_inSwitch && label == null) { 929 if (!_inLoop && !_inSwitch && label == null) {
4527 _reportErrorForToken(ParserErrorCode.BREAK_OUTSIDE_OF_LOOP, breakKeyword); 930 _reportErrorForToken(ParserErrorCode.BREAK_OUTSIDE_OF_LOOP, breakKeyword);
4528 } 931 }
4529 Token semicolon = _expect(TokenType.SEMICOLON); 932 Token semicolon = _expect(TokenType.SEMICOLON);
4530 return new BreakStatement(breakKeyword, label, semicolon); 933 return new BreakStatement(breakKeyword, label, semicolon);
4531 } 934 }
4532 935
4533 /** 936 /**
4534 * Parse a cascade section. Return the expression representing the cascaded 937 * Parse a cascade section. Return the expression representing the cascaded
4535 * method invocation. 938 * method invocation.
4536 * 939 *
940 * This method assumes that the current token matches
941 * `TokenType.PERIOD_PERIOD`.
942 *
4537 * cascadeSection ::= 943 * cascadeSection ::=
4538 * '..' (cascadeSelector typeArguments? arguments*) 944 * '..' (cascadeSelector typeArguments? arguments*)
4539 * (assignableSelector typeArguments? arguments*)* cascadeAssignment? 945 * (assignableSelector typeArguments? arguments*)* cascadeAssignment?
4540 * 946 *
4541 * cascadeSelector ::= 947 * cascadeSelector ::=
4542 * '[' expression ']' 948 * '[' expression ']'
4543 * | identifier 949 * | identifier
4544 * 950 *
4545 * cascadeAssignment ::= 951 * cascadeAssignment ::=
4546 * assignmentOperator expressionWithoutCascade 952 * assignmentOperator expressionWithoutCascade
4547 */ 953 */
4548 Expression _parseCascadeSection() { 954 Expression parseCascadeSection() {
4549 Token period = _expect(TokenType.PERIOD_PERIOD); 955 Token period = getAndAdvance();
4550 Expression expression = null; 956 Expression expression = null;
4551 SimpleIdentifier functionName = null; 957 SimpleIdentifier functionName = null;
4552 if (_matchesIdentifier()) { 958 if (_matchesIdentifier()) {
4553 functionName = parseSimpleIdentifier(); 959 functionName = _parseSimpleIdentifierUnchecked();
4554 } else if (_currentToken.type == TokenType.OPEN_SQUARE_BRACKET) { 960 } else if (_currentToken.type == TokenType.OPEN_SQUARE_BRACKET) {
4555 Token leftBracket = getAndAdvance(); 961 Token leftBracket = getAndAdvance();
4556 bool wasInInitializer = _inInitializer; 962 bool wasInInitializer = _inInitializer;
4557 _inInitializer = false; 963 _inInitializer = false;
4558 try { 964 try {
4559 Expression index = parseExpression2(); 965 Expression index = parseExpression2();
4560 Token rightBracket = _expect(TokenType.CLOSE_SQUARE_BRACKET); 966 Token rightBracket = _expect(TokenType.CLOSE_SQUARE_BRACKET);
4561 expression = new IndexExpression.forCascade( 967 expression = new IndexExpression.forCascade(
4562 period, leftBracket, index, rightBracket); 968 period, leftBracket, index, rightBracket);
4563 period = null; 969 period = null;
4564 } finally { 970 } finally {
4565 _inInitializer = wasInInitializer; 971 _inInitializer = wasInInitializer;
4566 } 972 }
4567 } else { 973 } else {
4568 _reportErrorForToken(ParserErrorCode.MISSING_IDENTIFIER, _currentToken, 974 _reportErrorForToken(ParserErrorCode.MISSING_IDENTIFIER, _currentToken,
4569 [_currentToken.lexeme]); 975 [_currentToken.lexeme]);
4570 functionName = _createSyntheticIdentifier(); 976 functionName = createSyntheticIdentifier();
4571 } 977 }
4572 assert((expression == null && functionName != null) || 978 assert((expression == null && functionName != null) ||
4573 (expression != null && functionName == null)); 979 (expression != null && functionName == null));
4574 if (_isLikelyParameterList()) { 980 if (_isLikelyArgumentList()) {
4575 while (_isLikelyParameterList()) { 981 do {
4576 TypeArgumentList typeArguments = null; 982 TypeArgumentList typeArguments = _parseOptionalTypeArguments();
4577 if (_matches(TokenType.LT)) {
4578 typeArguments = parseTypeArgumentList();
4579 }
4580 if (functionName != null) { 983 if (functionName != null) {
4581 expression = new MethodInvocation(expression, period, functionName, 984 expression = new MethodInvocation(expression, period, functionName,
4582 typeArguments, parseArgumentList()); 985 typeArguments, parseArgumentList());
4583 period = null; 986 period = null;
4584 functionName = null; 987 functionName = null;
4585 } else if (expression == null) { 988 } else if (expression == null) {
4586 // It should not be possible to get here. 989 // It should not be possible to get here.
4587 expression = new MethodInvocation(expression, period, 990 expression = new MethodInvocation(expression, period,
4588 _createSyntheticIdentifier(), typeArguments, parseArgumentList()); 991 createSyntheticIdentifier(), typeArguments, parseArgumentList());
4589 } else { 992 } else {
4590 expression = new FunctionExpressionInvocation( 993 expression = new FunctionExpressionInvocation(
4591 expression, typeArguments, parseArgumentList()); 994 expression, typeArguments, parseArgumentList());
4592 } 995 }
4593 } 996 } while (_isLikelyArgumentList());
4594 } else if (functionName != null) { 997 } else if (functionName != null) {
4595 expression = new PropertyAccess(expression, period, functionName); 998 expression = new PropertyAccess(expression, period, functionName);
4596 period = null; 999 period = null;
4597 } 1000 }
4598 assert(expression != null); 1001 assert(expression != null);
4599 bool progress = true; 1002 bool progress = true;
4600 while (progress) { 1003 while (progress) {
4601 progress = false; 1004 progress = false;
4602 Expression selector = _parseAssignableSelector(expression, true); 1005 Expression selector = parseAssignableSelector(expression, true);
4603 if (!identical(selector, expression)) { 1006 if (!identical(selector, expression)) {
4604 expression = selector; 1007 expression = selector;
4605 progress = true; 1008 progress = true;
4606 while (_isLikelyParameterList()) { 1009 while (_isLikelyArgumentList()) {
4607 TypeArgumentList typeArguments = null; 1010 TypeArgumentList typeArguments = _parseOptionalTypeArguments();
4608 if (_matches(TokenType.LT)) { 1011 Expression currentExpression = expression;
4609 typeArguments = parseTypeArgumentList(); 1012 if (currentExpression is PropertyAccess) {
4610 }
4611 if (expression is PropertyAccess) {
4612 PropertyAccess propertyAccess = expression as PropertyAccess;
4613 expression = new MethodInvocation( 1013 expression = new MethodInvocation(
4614 propertyAccess.target, 1014 currentExpression.target,
4615 propertyAccess.operator, 1015 currentExpression.operator,
4616 propertyAccess.propertyName, 1016 currentExpression.propertyName,
4617 typeArguments, 1017 typeArguments,
4618 parseArgumentList()); 1018 parseArgumentList());
4619 } else { 1019 } else {
4620 expression = new FunctionExpressionInvocation( 1020 expression = new FunctionExpressionInvocation(
4621 expression, typeArguments, parseArgumentList()); 1021 expression, typeArguments, parseArgumentList());
4622 } 1022 }
4623 } 1023 }
4624 } 1024 }
4625 } 1025 }
4626 if (_currentToken.type.isAssignmentOperator) { 1026 if (_currentToken.type.isAssignmentOperator) {
4627 Token operator = getAndAdvance(); 1027 Token operator = getAndAdvance();
4628 _ensureAssignable(expression); 1028 _ensureAssignable(expression);
4629 expression = new AssignmentExpression( 1029 expression = new AssignmentExpression(
4630 expression, operator, parseExpressionWithoutCascade()); 1030 expression, operator, parseExpressionWithoutCascade());
4631 } 1031 }
4632 return expression; 1032 return expression;
4633 } 1033 }
4634 1034
4635 /** 1035 /**
4636 * Parse a class declaration. The [commentAndMetadata] is the metadata to be 1036 * Parse a class declaration. The [commentAndMetadata] is the metadata to be
4637 * associated with the member. The [abstractKeyword] is the token for the 1037 * associated with the member. The [abstractKeyword] is the token for the
4638 * keyword 'abstract', or `null` if the keyword was not given. Return the 1038 * keyword 'abstract', or `null` if the keyword was not given. Return the
4639 * class declaration that was parsed. 1039 * class declaration that was parsed.
4640 * 1040 *
1041 * This method assumes that the current token matches `Keyword.CLASS`.
1042 *
4641 * classDeclaration ::= 1043 * classDeclaration ::=
4642 * metadata 'abstract'? 'class' name typeParameterList? (extendsClause withClause?)? implementsClause? '{' classMembers '}' | 1044 * metadata 'abstract'? 'class' name typeParameterList? (extendsClause withClause?)? implementsClause? '{' classMembers '}' |
4643 * metadata 'abstract'? 'class' mixinApplicationClass 1045 * metadata 'abstract'? 'class' mixinApplicationClass
4644 */ 1046 */
4645 CompilationUnitMember _parseClassDeclaration( 1047 CompilationUnitMember parseClassDeclaration(
4646 CommentAndMetadata commentAndMetadata, Token abstractKeyword) { 1048 CommentAndMetadata commentAndMetadata, Token abstractKeyword) {
4647 Token keyword = _expectKeyword(Keyword.CLASS); 1049 //
4648 if (_matchesIdentifier()) { 1050 // Parse the name and type parameters.
4649 Token next = _peek(); 1051 //
4650 if (_tokenMatches(next, TokenType.LT)) { 1052 Token keyword = getAndAdvance();
4651 next = _skipTypeParameterList(next); 1053 SimpleIdentifier name = parseSimpleIdentifier(isDeclaration: true);
4652 if (next != null && _tokenMatches(next, TokenType.EQ)) {
4653 return _parseClassTypeAlias(
4654 commentAndMetadata, abstractKeyword, keyword);
4655 }
4656 } else if (_tokenMatches(next, TokenType.EQ)) {
4657 return _parseClassTypeAlias(
4658 commentAndMetadata, abstractKeyword, keyword);
4659 }
4660 }
4661 SimpleIdentifier name = parseSimpleIdentifier();
4662 String className = name.name; 1054 String className = name.name;
4663 TypeParameterList typeParameters = null; 1055 TypeParameterList typeParameters = null;
4664 if (_matches(TokenType.LT)) { 1056 TokenType type = _currentToken.type;
1057 if (type == TokenType.LT) {
4665 typeParameters = parseTypeParameterList(); 1058 typeParameters = parseTypeParameterList();
1059 type = _currentToken.type;
1060 }
1061 //
1062 // Check to see whether this might be a class type alias rather than a class
1063 // declaration.
1064 //
1065 if (type == TokenType.EQ) {
1066 return _parseClassTypeAliasAfterName(
1067 commentAndMetadata, abstractKeyword, keyword, name, typeParameters);
4666 } 1068 }
4667 // 1069 //
4668 // Parse the clauses. The parser accepts clauses in any order, but will 1070 // Parse the clauses. The parser accepts clauses in any order, but will
4669 // generate errors if they are not in the order required by the 1071 // generate errors if they are not in the order required by the
4670 // specification. 1072 // specification.
4671 // 1073 //
4672 ExtendsClause extendsClause = null; 1074 ExtendsClause extendsClause = null;
4673 WithClause withClause = null; 1075 WithClause withClause = null;
4674 ImplementsClause implementsClause = null; 1076 ImplementsClause implementsClause = null;
4675 bool foundClause = true; 1077 bool foundClause = true;
4676 while (foundClause) { 1078 while (foundClause) {
4677 if (_matchesKeyword(Keyword.EXTENDS)) { 1079 Keyword keyword = _currentToken.keyword;
1080 if (keyword == Keyword.EXTENDS) {
4678 if (extendsClause == null) { 1081 if (extendsClause == null) {
4679 extendsClause = parseExtendsClause(); 1082 extendsClause = parseExtendsClause();
4680 if (withClause != null) { 1083 if (withClause != null) {
4681 _reportErrorForToken( 1084 _reportErrorForToken(
4682 ParserErrorCode.WITH_BEFORE_EXTENDS, withClause.withKeyword); 1085 ParserErrorCode.WITH_BEFORE_EXTENDS, withClause.withKeyword);
4683 } else if (implementsClause != null) { 1086 } else if (implementsClause != null) {
4684 _reportErrorForToken(ParserErrorCode.IMPLEMENTS_BEFORE_EXTENDS, 1087 _reportErrorForToken(ParserErrorCode.IMPLEMENTS_BEFORE_EXTENDS,
4685 implementsClause.implementsKeyword); 1088 implementsClause.implementsKeyword);
4686 } 1089 }
4687 } else { 1090 } else {
4688 _reportErrorForToken(ParserErrorCode.MULTIPLE_EXTENDS_CLAUSES, 1091 _reportErrorForToken(ParserErrorCode.MULTIPLE_EXTENDS_CLAUSES,
4689 extendsClause.extendsKeyword); 1092 extendsClause.extendsKeyword);
4690 parseExtendsClause(); 1093 parseExtendsClause();
4691 } 1094 }
4692 } else if (_matchesKeyword(Keyword.WITH)) { 1095 } else if (keyword == Keyword.WITH) {
4693 if (withClause == null) { 1096 if (withClause == null) {
4694 withClause = parseWithClause(); 1097 withClause = parseWithClause();
4695 if (implementsClause != null) { 1098 if (implementsClause != null) {
4696 _reportErrorForToken(ParserErrorCode.IMPLEMENTS_BEFORE_WITH, 1099 _reportErrorForToken(ParserErrorCode.IMPLEMENTS_BEFORE_WITH,
4697 implementsClause.implementsKeyword); 1100 implementsClause.implementsKeyword);
4698 } 1101 }
4699 } else { 1102 } else {
4700 _reportErrorForToken( 1103 _reportErrorForToken(
4701 ParserErrorCode.MULTIPLE_WITH_CLAUSES, withClause.withKeyword); 1104 ParserErrorCode.MULTIPLE_WITH_CLAUSES, withClause.withKeyword);
4702 parseWithClause(); 1105 parseWithClause();
4703 // TODO(brianwilkerson) Should we merge the list of applied mixins 1106 // TODO(brianwilkerson) Should we merge the list of applied mixins
4704 // into a single list? 1107 // into a single list?
4705 } 1108 }
4706 } else if (_matchesKeyword(Keyword.IMPLEMENTS)) { 1109 } else if (keyword == Keyword.IMPLEMENTS) {
4707 if (implementsClause == null) { 1110 if (implementsClause == null) {
4708 implementsClause = parseImplementsClause(); 1111 implementsClause = parseImplementsClause();
4709 } else { 1112 } else {
4710 _reportErrorForToken(ParserErrorCode.MULTIPLE_IMPLEMENTS_CLAUSES, 1113 _reportErrorForToken(ParserErrorCode.MULTIPLE_IMPLEMENTS_CLAUSES,
4711 implementsClause.implementsKeyword); 1114 implementsClause.implementsKeyword);
4712 parseImplementsClause(); 1115 parseImplementsClause();
4713 // TODO(brianwilkerson) Should we merge the list of implemented 1116 // TODO(brianwilkerson) Should we merge the list of implemented
4714 // classes into a single list? 1117 // classes into a single list?
4715 } 1118 }
4716 } else { 1119 } else {
(...skipping 11 matching lines...) Expand all
4728 if (_matchesString(_NATIVE) && _tokenMatches(_peek(), TokenType.STRING)) { 1131 if (_matchesString(_NATIVE) && _tokenMatches(_peek(), TokenType.STRING)) {
4729 nativeClause = _parseNativeClause(); 1132 nativeClause = _parseNativeClause();
4730 } 1133 }
4731 // 1134 //
4732 // Parse the body of the class. 1135 // Parse the body of the class.
4733 // 1136 //
4734 Token leftBracket = null; 1137 Token leftBracket = null;
4735 List<ClassMember> members = null; 1138 List<ClassMember> members = null;
4736 Token rightBracket = null; 1139 Token rightBracket = null;
4737 if (_matches(TokenType.OPEN_CURLY_BRACKET)) { 1140 if (_matches(TokenType.OPEN_CURLY_BRACKET)) {
4738 leftBracket = _expect(TokenType.OPEN_CURLY_BRACKET); 1141 leftBracket = getAndAdvance();
4739 members = _parseClassMembers(className, _getEndToken(leftBracket)); 1142 members = _parseClassMembers(className, _getEndToken(leftBracket));
4740 rightBracket = _expect(TokenType.CLOSE_CURLY_BRACKET); 1143 rightBracket = _expect(TokenType.CLOSE_CURLY_BRACKET);
4741 } else { 1144 } else {
1145 // Recovery: Check for an unmatched closing curly bracket and parse
1146 // members until it is reached.
4742 leftBracket = _createSyntheticToken(TokenType.OPEN_CURLY_BRACKET); 1147 leftBracket = _createSyntheticToken(TokenType.OPEN_CURLY_BRACKET);
4743 rightBracket = _createSyntheticToken(TokenType.CLOSE_CURLY_BRACKET); 1148 rightBracket = _createSyntheticToken(TokenType.CLOSE_CURLY_BRACKET);
4744 _reportErrorForCurrentToken(ParserErrorCode.MISSING_CLASS_BODY); 1149 _reportErrorForCurrentToken(ParserErrorCode.MISSING_CLASS_BODY);
4745 } 1150 }
4746 ClassDeclaration classDeclaration = new ClassDeclaration( 1151 ClassDeclaration classDeclaration = new ClassDeclaration(
4747 commentAndMetadata.comment, 1152 commentAndMetadata.comment,
4748 commentAndMetadata.metadata, 1153 commentAndMetadata.metadata,
4749 abstractKeyword, 1154 abstractKeyword,
4750 keyword, 1155 keyword,
4751 name, 1156 name,
4752 typeParameters, 1157 typeParameters,
4753 extendsClause, 1158 extendsClause,
4754 withClause, 1159 withClause,
4755 implementsClause, 1160 implementsClause,
4756 leftBracket, 1161 leftBracket,
4757 members, 1162 members,
4758 rightBracket); 1163 rightBracket);
4759 classDeclaration.nativeClause = nativeClause; 1164 classDeclaration.nativeClause = nativeClause;
4760 return classDeclaration; 1165 return classDeclaration;
4761 } 1166 }
4762 1167
4763 /** 1168 /**
4764 * Parse a list of class members. The [className] is the name of the class 1169 * Parse a class member. The [className] is the name of the class containing
4765 * whose members are being parsed. The [closingBracket] is the closing bracket 1170 * the member being parsed. Return the class member that was parsed, or `null`
4766 * for the class, or `null` if the closing bracket is missing. Return the list 1171 * if what was found was not a valid class member.
4767 * of class members that were parsed. 1172 *
4768 * 1173 * classMemberDefinition ::=
4769 * classMembers ::= 1174 * declaration ';'
4770 * (metadata memberDefinition)* 1175 * | methodSignature functionBody
4771 */ 1176 */
4772 List<ClassMember> _parseClassMembers(String className, Token closingBracket) { 1177 ClassMember parseClassMember(String className) {
4773 List<ClassMember> members = new List<ClassMember>(); 1178 CommentAndMetadata commentAndMetadata = parseCommentAndMetadata();
4774 Token memberStart = _currentToken; 1179 Modifiers modifiers = parseModifiers();
4775 while (!_matches(TokenType.EOF) && 1180 Keyword keyword = _currentToken.keyword;
4776 !_matches(TokenType.CLOSE_CURLY_BRACKET) && 1181 if (keyword == Keyword.VOID) {
4777 (closingBracket != null || 1182 TypeName returnType =
4778 (!_matchesKeyword(Keyword.CLASS) && 1183 new TypeName(new SimpleIdentifier(getAndAdvance()), null);
4779 !_matchesKeyword(Keyword.TYPEDEF)))) { 1184 keyword = _currentToken.keyword;
4780 if (_matches(TokenType.SEMICOLON)) { 1185 Token next = _peek();
4781 _reportErrorForToken(ParserErrorCode.UNEXPECTED_TOKEN, _currentToken, 1186 bool isFollowedByIdentifier = _tokenMatchesIdentifier(next);
4782 [_currentToken.lexeme]); 1187 if (keyword == Keyword.GET && isFollowedByIdentifier) {
4783 _advance(); 1188 _validateModifiersForGetterOrSetterOrMethod(modifiers);
1189 return parseGetter(commentAndMetadata, modifiers.externalKeyword,
1190 modifiers.staticKeyword, returnType);
1191 } else if (keyword == Keyword.SET && isFollowedByIdentifier) {
1192 _validateModifiersForGetterOrSetterOrMethod(modifiers);
1193 return parseSetter(commentAndMetadata, modifiers.externalKeyword,
1194 modifiers.staticKeyword, returnType);
1195 } else if (keyword == Keyword.OPERATOR && _isOperator(next)) {
1196 _validateModifiersForOperator(modifiers);
1197 return _parseOperatorAfterKeyword(commentAndMetadata,
1198 modifiers.externalKeyword, returnType, getAndAdvance());
1199 } else if (_matchesIdentifier() &&
1200 _peek().matchesAny(const <TokenType>[
1201 TokenType.OPEN_PAREN,
1202 TokenType.OPEN_CURLY_BRACKET,
1203 TokenType.FUNCTION,
1204 TokenType.LT
1205 ])) {
1206 _validateModifiersForGetterOrSetterOrMethod(modifiers);
1207 return _parseMethodDeclarationAfterReturnType(commentAndMetadata,
1208 modifiers.externalKeyword, modifiers.staticKeyword, returnType);
4784 } else { 1209 } else {
4785 ClassMember member = parseClassMember(className); 1210 //
4786 if (member != null) { 1211 // We have found an error of some kind. Try to recover.
4787 members.add(member); 1212 //
1213 if (_matchesIdentifier()) {
1214 if (_peek().matchesAny(const <TokenType>[
1215 TokenType.EQ,
1216 TokenType.COMMA,
1217 TokenType.SEMICOLON
1218 ])) {
1219 //
1220 // We appear to have a variable declaration with a type of "void".
1221 //
1222 _reportErrorForNode(ParserErrorCode.VOID_VARIABLE, returnType);
1223 return parseInitializedIdentifierList(
1224 commentAndMetadata,
1225 modifiers.staticKeyword,
1226 _validateModifiersForField(modifiers),
1227 returnType);
1228 }
4788 } 1229 }
4789 } 1230 if (_isOperator(_currentToken)) {
4790 if (identical(_currentToken, memberStart)) { 1231 //
4791 _reportErrorForToken(ParserErrorCode.UNEXPECTED_TOKEN, _currentToken, 1232 // We appear to have found an operator declaration without the
4792 [_currentToken.lexeme]); 1233 // 'operator' keyword.
4793 _advance(); 1234 //
4794 } 1235 _validateModifiersForOperator(modifiers);
4795 memberStart = _currentToken; 1236 return parseOperator(
4796 } 1237 commentAndMetadata, modifiers.externalKeyword, returnType);
4797 return members; 1238 }
4798 } 1239 _reportErrorForToken(
4799 1240 ParserErrorCode.EXPECTED_EXECUTABLE, _currentToken);
4800 /** 1241 return null;
1242 }
1243 }
1244 Token next = _peek();
1245 bool isFollowedByIdentifier = _tokenMatchesIdentifier(next);
1246 if (keyword == Keyword.GET && isFollowedByIdentifier) {
1247 _validateModifiersForGetterOrSetterOrMethod(modifiers);
1248 return parseGetter(commentAndMetadata, modifiers.externalKeyword,
1249 modifiers.staticKeyword, null);
1250 } else if (keyword == Keyword.SET && isFollowedByIdentifier) {
1251 _validateModifiersForGetterOrSetterOrMethod(modifiers);
1252 return parseSetter(commentAndMetadata, modifiers.externalKeyword,
1253 modifiers.staticKeyword, null);
1254 } else if (keyword == Keyword.OPERATOR && _isOperator(next)) {
1255 _validateModifiersForOperator(modifiers);
1256 return _parseOperatorAfterKeyword(
1257 commentAndMetadata, modifiers.externalKeyword, null, getAndAdvance());
1258 } else if (!_matchesIdentifier()) {
1259 //
1260 // Recover from an error.
1261 //
1262 if (_matchesKeyword(Keyword.CLASS)) {
1263 _reportErrorForCurrentToken(ParserErrorCode.CLASS_IN_CLASS);
1264 // TODO(brianwilkerson) We don't currently have any way to capture the
1265 // class that was parsed.
1266 parseClassDeclaration(commentAndMetadata, null);
1267 return null;
1268 } else if (_matchesKeyword(Keyword.ABSTRACT) &&
1269 _tokenMatchesKeyword(_peek(), Keyword.CLASS)) {
1270 _reportErrorForToken(ParserErrorCode.CLASS_IN_CLASS, _peek());
1271 // TODO(brianwilkerson) We don't currently have any way to capture the
1272 // class that was parsed.
1273 parseClassDeclaration(commentAndMetadata, getAndAdvance());
1274 return null;
1275 } else if (_matchesKeyword(Keyword.ENUM)) {
1276 _reportErrorForToken(ParserErrorCode.ENUM_IN_CLASS, _peek());
1277 // TODO(brianwilkerson) We don't currently have any way to capture the
1278 // enum that was parsed.
1279 parseEnumDeclaration(commentAndMetadata);
1280 return null;
1281 } else if (_isOperator(_currentToken)) {
1282 //
1283 // We appear to have found an operator declaration without the
1284 // 'operator' keyword.
1285 //
1286 _validateModifiersForOperator(modifiers);
1287 return parseOperator(
1288 commentAndMetadata, modifiers.externalKeyword, null);
1289 }
1290 Token keyword = modifiers.varKeyword;
1291 if (keyword == null) {
1292 keyword = modifiers.finalKeyword;
1293 }
1294 if (keyword == null) {
1295 keyword = modifiers.constKeyword;
1296 }
1297 if (keyword != null) {
1298 //
1299 // We appear to have found an incomplete field declaration.
1300 //
1301 _reportErrorForCurrentToken(ParserErrorCode.MISSING_IDENTIFIER);
1302 VariableDeclaration variable =
1303 new VariableDeclaration(createSyntheticIdentifier(), null, null);
1304 List<VariableDeclaration> variables = <VariableDeclaration>[variable];
1305 return new FieldDeclaration(
1306 commentAndMetadata.comment,
1307 commentAndMetadata.metadata,
1308 null,
1309 new VariableDeclarationList(null, null, keyword, null, variables),
1310 _expect(TokenType.SEMICOLON));
1311 }
1312 _reportErrorForToken(
1313 ParserErrorCode.EXPECTED_CLASS_MEMBER, _currentToken);
1314 if (commentAndMetadata.comment != null ||
1315 commentAndMetadata.hasMetadata) {
1316 //
1317 // We appear to have found an incomplete declaration at the end of the
1318 // class. At this point it consists of a metadata, which we don't want
1319 // to loose, so we'll treat it as a method declaration with a missing
1320 // name, parameters and empty body.
1321 //
1322 return new MethodDeclaration(
1323 commentAndMetadata.comment,
1324 commentAndMetadata.metadata,
1325 null,
1326 null,
1327 null,
1328 null,
1329 null,
1330 createSyntheticIdentifier(isDeclaration: true),
1331 null,
1332 new FormalParameterList(
1333 null, <FormalParameter>[], null, null, null),
1334 new EmptyFunctionBody(_createSyntheticToken(TokenType.SEMICOLON)));
1335 }
1336 return null;
1337 } else if (_tokenMatches(next, TokenType.PERIOD) &&
1338 _tokenMatchesIdentifier(_peekAt(2)) &&
1339 _tokenMatches(_peekAt(3), TokenType.OPEN_PAREN)) {
1340 return _parseConstructor(
1341 commentAndMetadata,
1342 modifiers.externalKeyword,
1343 _validateModifiersForConstructor(modifiers),
1344 modifiers.factoryKeyword,
1345 parseSimpleIdentifier(),
1346 getAndAdvance(),
1347 parseSimpleIdentifier(isDeclaration: true),
1348 parseFormalParameterList());
1349 } else if (_tokenMatches(next, TokenType.OPEN_PAREN)) {
1350 TypeName returnType = _parseOptionalTypeNameComment();
1351 SimpleIdentifier methodName = parseSimpleIdentifier(isDeclaration: true);
1352 TypeParameterList typeParameters = _parseGenericCommentTypeParameters();
1353 FormalParameterList parameters = parseFormalParameterList();
1354 if (_matches(TokenType.COLON) ||
1355 modifiers.factoryKeyword != null ||
1356 methodName.name == className) {
1357 return _parseConstructor(
1358 commentAndMetadata,
1359 modifiers.externalKeyword,
1360 _validateModifiersForConstructor(modifiers),
1361 modifiers.factoryKeyword,
1362 new SimpleIdentifier(methodName.token, isDeclaration: false),
1363 null,
1364 null,
1365 parameters);
1366 }
1367 _validateModifiersForGetterOrSetterOrMethod(modifiers);
1368 _validateFormalParameterList(parameters);
1369 return _parseMethodDeclarationAfterParameters(
1370 commentAndMetadata,
1371 modifiers.externalKeyword,
1372 modifiers.staticKeyword,
1373 returnType,
1374 methodName,
1375 typeParameters,
1376 parameters);
1377 } else if (next.matchesAny(const <TokenType>[
1378 TokenType.EQ,
1379 TokenType.COMMA,
1380 TokenType.SEMICOLON
1381 ])) {
1382 if (modifiers.constKeyword == null &&
1383 modifiers.finalKeyword == null &&
1384 modifiers.varKeyword == null) {
1385 _reportErrorForCurrentToken(
1386 ParserErrorCode.MISSING_CONST_FINAL_VAR_OR_TYPE);
1387 }
1388 return parseInitializedIdentifierList(commentAndMetadata,
1389 modifiers.staticKeyword, _validateModifiersForField(modifiers), null);
1390 } else if (keyword == Keyword.TYPEDEF) {
1391 _reportErrorForCurrentToken(ParserErrorCode.TYPEDEF_IN_CLASS);
1392 // TODO(brianwilkerson) We don't currently have any way to capture the
1393 // function type alias that was parsed.
1394 _parseFunctionTypeAlias(commentAndMetadata, getAndAdvance());
1395 return null;
1396 } else if (parseGenericMethods) {
1397 Token token = _skipTypeParameterList(_peek());
1398 if (token != null && _tokenMatches(token, TokenType.OPEN_PAREN)) {
1399 return _parseMethodDeclarationAfterReturnType(commentAndMetadata,
1400 modifiers.externalKeyword, modifiers.staticKeyword, null);
1401 }
1402 }
1403 TypeName type = _parseTypeNameAfterIdentifier();
1404 keyword = _currentToken.keyword;
1405 next = _peek();
1406 isFollowedByIdentifier = _tokenMatchesIdentifier(next);
1407 if (keyword == Keyword.GET && isFollowedByIdentifier) {
1408 _validateModifiersForGetterOrSetterOrMethod(modifiers);
1409 return parseGetter(commentAndMetadata, modifiers.externalKeyword,
1410 modifiers.staticKeyword, type);
1411 } else if (keyword == Keyword.SET && isFollowedByIdentifier) {
1412 _validateModifiersForGetterOrSetterOrMethod(modifiers);
1413 return parseSetter(commentAndMetadata, modifiers.externalKeyword,
1414 modifiers.staticKeyword, type);
1415 } else if (keyword == Keyword.OPERATOR && _isOperator(next)) {
1416 _validateModifiersForOperator(modifiers);
1417 return _parseOperatorAfterKeyword(
1418 commentAndMetadata, modifiers.externalKeyword, type, getAndAdvance());
1419 } else if (!_matchesIdentifier()) {
1420 if (_matches(TokenType.CLOSE_CURLY_BRACKET)) {
1421 //
1422 // We appear to have found an incomplete declaration at the end of the
1423 // class. At this point it consists of a type name, so we'll treat it as
1424 // a field declaration with a missing field name and semicolon.
1425 //
1426 return parseInitializedIdentifierList(
1427 commentAndMetadata,
1428 modifiers.staticKeyword,
1429 _validateModifiersForField(modifiers),
1430 type);
1431 }
1432 if (_isOperator(_currentToken)) {
1433 //
1434 // We appear to have found an operator declaration without the
1435 // 'operator' keyword.
1436 //
1437 _validateModifiersForOperator(modifiers);
1438 return parseOperator(
1439 commentAndMetadata, modifiers.externalKeyword, type);
1440 }
1441 //
1442 // We appear to have found an incomplete declaration before another
1443 // declaration. At this point it consists of a type name, so we'll treat
1444 // it as a field declaration with a missing field name and semicolon.
1445 //
1446 _reportErrorForToken(
1447 ParserErrorCode.EXPECTED_CLASS_MEMBER, _currentToken);
1448 try {
1449 _lockErrorListener();
1450 return parseInitializedIdentifierList(
1451 commentAndMetadata,
1452 modifiers.staticKeyword,
1453 _validateModifiersForField(modifiers),
1454 type);
1455 } finally {
1456 _unlockErrorListener();
1457 }
1458 } else if (_tokenMatches(next, TokenType.OPEN_PAREN)) {
1459 SimpleIdentifier methodName =
1460 _parseSimpleIdentifierUnchecked(isDeclaration: true);
1461 TypeParameterList typeParameters = _parseGenericCommentTypeParameters();
1462 FormalParameterList parameters = parseFormalParameterList();
1463 if (methodName.name == className) {
1464 _reportErrorForNode(ParserErrorCode.CONSTRUCTOR_WITH_RETURN_TYPE, type);
1465 return _parseConstructor(
1466 commentAndMetadata,
1467 modifiers.externalKeyword,
1468 _validateModifiersForConstructor(modifiers),
1469 modifiers.factoryKeyword,
1470 new SimpleIdentifier(methodName.token, isDeclaration: true),
1471 null,
1472 null,
1473 parameters);
1474 }
1475 _validateModifiersForGetterOrSetterOrMethod(modifiers);
1476 _validateFormalParameterList(parameters);
1477 return _parseMethodDeclarationAfterParameters(
1478 commentAndMetadata,
1479 modifiers.externalKeyword,
1480 modifiers.staticKeyword,
1481 type,
1482 methodName,
1483 typeParameters,
1484 parameters);
1485 } else if (parseGenericMethods && _tokenMatches(next, TokenType.LT)) {
1486 return _parseMethodDeclarationAfterReturnType(commentAndMetadata,
1487 modifiers.externalKeyword, modifiers.staticKeyword, type);
1488 } else if (_tokenMatches(next, TokenType.OPEN_CURLY_BRACKET)) {
1489 // We have found "TypeName identifier {", and are guessing that this is a
1490 // getter without the keyword 'get'.
1491 _validateModifiersForGetterOrSetterOrMethod(modifiers);
1492 _reportErrorForCurrentToken(ParserErrorCode.MISSING_GET);
1493 _currentToken = _injectToken(
1494 new Parser_SyntheticKeywordToken(Keyword.GET, _currentToken.offset));
1495 return parseGetter(commentAndMetadata, modifiers.externalKeyword,
1496 modifiers.staticKeyword, type);
1497 }
1498 return parseInitializedIdentifierList(commentAndMetadata,
1499 modifiers.staticKeyword, _validateModifiersForField(modifiers), type);
1500 }
1501
1502 /**
4801 * Parse a class type alias. The [commentAndMetadata] is the metadata to be 1503 * Parse a class type alias. The [commentAndMetadata] is the metadata to be
4802 * associated with the member. The [abstractKeyword] is the token representing 1504 * associated with the member. The [abstractKeyword] is the token representing
4803 * the 'abstract' keyword. The [classKeyword] is the token representing the 1505 * the 'abstract' keyword. The [classKeyword] is the token representing the
4804 * 'class' keyword. Return the class type alias that was parsed. 1506 * 'class' keyword. Return the class type alias that was parsed.
4805 * 1507 *
1508 * This method assumes that the current token matches an identifier.
1509 *
4806 * classTypeAlias ::= 1510 * classTypeAlias ::=
4807 * identifier typeParameters? '=' 'abstract'? mixinApplication 1511 * identifier typeParameters? '=' 'abstract'? mixinApplication
4808 * 1512 *
4809 * mixinApplication ::= 1513 * mixinApplication ::=
4810 * type withClause implementsClause? ';' 1514 * type withClause implementsClause? ';'
4811 */ 1515 */
4812 ClassTypeAlias _parseClassTypeAlias(CommentAndMetadata commentAndMetadata, 1516 ClassTypeAlias parseClassTypeAlias(CommentAndMetadata commentAndMetadata,
4813 Token abstractKeyword, Token classKeyword) { 1517 Token abstractKeyword, Token classKeyword) {
4814 SimpleIdentifier className = parseSimpleIdentifier(); 1518 SimpleIdentifier className =
1519 _parseSimpleIdentifierUnchecked(isDeclaration: true);
4815 TypeParameterList typeParameters = null; 1520 TypeParameterList typeParameters = null;
4816 if (_matches(TokenType.LT)) { 1521 if (_matches(TokenType.LT)) {
4817 typeParameters = parseTypeParameterList(); 1522 typeParameters = parseTypeParameterList();
4818 } 1523 }
4819 Token equals = _expect(TokenType.EQ); 1524 return _parseClassTypeAliasAfterName(commentAndMetadata, abstractKeyword,
4820 TypeName superclass = parseTypeName(); 1525 classKeyword, className, typeParameters);
4821 WithClause withClause = null;
4822 if (_matchesKeyword(Keyword.WITH)) {
4823 withClause = parseWithClause();
4824 } else {
4825 _reportErrorForCurrentToken(
4826 ParserErrorCode.EXPECTED_TOKEN, [Keyword.WITH.syntax]);
4827 }
4828 ImplementsClause implementsClause = null;
4829 if (_matchesKeyword(Keyword.IMPLEMENTS)) {
4830 implementsClause = parseImplementsClause();
4831 }
4832 Token semicolon;
4833 if (_matches(TokenType.SEMICOLON)) {
4834 semicolon = getAndAdvance();
4835 } else {
4836 if (_matches(TokenType.OPEN_CURLY_BRACKET)) {
4837 _reportErrorForCurrentToken(
4838 ParserErrorCode.EXPECTED_TOKEN, [TokenType.SEMICOLON.lexeme]);
4839 Token leftBracket = getAndAdvance();
4840 _parseClassMembers(className.name, _getEndToken(leftBracket));
4841 _expect(TokenType.CLOSE_CURLY_BRACKET);
4842 } else {
4843 _reportErrorForToken(ParserErrorCode.EXPECTED_TOKEN,
4844 _currentToken.previous, [TokenType.SEMICOLON.lexeme]);
4845 }
4846 semicolon = _createSyntheticToken(TokenType.SEMICOLON);
4847 }
4848 return new ClassTypeAlias(
4849 commentAndMetadata.comment,
4850 commentAndMetadata.metadata,
4851 classKeyword,
4852 className,
4853 typeParameters,
4854 equals,
4855 abstractKeyword,
4856 superclass,
4857 withClause,
4858 implementsClause,
4859 semicolon);
4860 } 1526 }
4861 1527
4862 /** 1528 /**
4863 * Parse a list of combinators in a directive. Return the combinators that 1529 * Parse a single combinator. Return the combinator that was parsed, or `null`
4864 * were parsed. 1530 * if no combinator is found.
4865 * 1531 *
4866 * combinator ::= 1532 * combinator ::=
4867 * 'show' identifier (',' identifier)* 1533 * 'show' identifier (',' identifier)*
4868 * | 'hide' identifier (',' identifier)* 1534 * | 'hide' identifier (',' identifier)*
4869 */ 1535 */
4870 List<Combinator> _parseCombinators() { 1536 Combinator parseCombinator() {
4871 List<Combinator> combinators = new List<Combinator>(); 1537 if (_matchesString(_SHOW)) {
1538 return new ShowCombinator(getAndAdvance(), parseIdentifierList());
1539 } else if (_matchesString(_HIDE)) {
1540 return new HideCombinator(getAndAdvance(), parseIdentifierList());
1541 }
1542 return null;
1543 }
1544
1545 /**
1546 * Parse a list of combinators in a directive. Return the combinators that
1547 * were parsed, or `null` if there are no combinators.
1548 *
1549 * combinator ::=
1550 * 'show' identifier (',' identifier)*
1551 * | 'hide' identifier (',' identifier)*
1552 */
1553 List<Combinator> parseCombinators() {
1554 List<Combinator> combinators = null;
4872 while (true) { 1555 while (true) {
4873 Combinator combinator = parseCombinator(); 1556 Combinator combinator = parseCombinator();
4874 if (combinator == null) { 1557 if (combinator == null) {
4875 break; 1558 break;
4876 } 1559 }
1560 combinators ??= <Combinator>[];
4877 combinators.add(combinator); 1561 combinators.add(combinator);
4878 } 1562 }
4879 return combinators; 1563 return combinators;
4880 } 1564 }
4881 1565
4882 /** 1566 /**
4883 * Parse the documentation comment and metadata preceding a declaration. This 1567 * Parse the documentation comment and metadata preceding a declaration. This
4884 * method allows any number of documentation comments to occur before, after 1568 * method allows any number of documentation comments to occur before, after
4885 * or between the metadata, but only returns the last (right-most) 1569 * or between the metadata, but only returns the last (right-most)
4886 * documentation comment that is found. Return the documentation comment and 1570 * documentation comment that is found. Return the documentation comment and
4887 * metadata that were parsed. 1571 * metadata that were parsed.
4888 * 1572 *
4889 * metadata ::= 1573 * metadata ::=
4890 * annotation* 1574 * annotation*
4891 */ 1575 */
4892 CommentAndMetadata _parseCommentAndMetadata() { 1576 CommentAndMetadata parseCommentAndMetadata() {
4893 Comment comment = _parseDocumentationComment(); 1577 // TODO(brianwilkerson) Consider making the creation of documentation
4894 List<Annotation> metadata = new List<Annotation>(); 1578 // comments be lazy.
1579 List<DocumentationCommentToken> tokens = parseDocumentationCommentTokens();
1580 List<Annotation> metadata = null;
4895 while (_matches(TokenType.AT)) { 1581 while (_matches(TokenType.AT)) {
1582 metadata ??= <Annotation>[];
4896 metadata.add(parseAnnotation()); 1583 metadata.add(parseAnnotation());
4897 Comment optionalComment = _parseDocumentationComment(); 1584 List<DocumentationCommentToken> optionalTokens =
4898 if (optionalComment != null) { 1585 parseDocumentationCommentTokens();
4899 comment = optionalComment; 1586 if (optionalTokens != null) {
1587 tokens = optionalTokens;
4900 } 1588 }
4901 } 1589 }
4902 return new CommentAndMetadata(comment, metadata); 1590 return new CommentAndMetadata(parseDocumentationComment(tokens), metadata);
4903 } 1591 }
4904 1592
4905 /** 1593 /**
4906 * Parse a comment reference from the source between square brackets. The 1594 * Parse a comment reference from the source between square brackets. The
4907 * [referenceSource] is the source occurring between the square brackets 1595 * [referenceSource] is the source occurring between the square brackets
4908 * within a documentation comment. The [sourceOffset] is the offset of the 1596 * within a documentation comment. The [sourceOffset] is the offset of the
4909 * first character of the reference source. Return the comment reference that 1597 * first character of the reference source. Return the comment reference that
4910 * was parsed, or `null` if no reference could be found. 1598 * was parsed, or `null` if no reference could be found.
4911 * 1599 *
4912 * commentReference ::= 1600 * commentReference ::=
4913 * 'new'? prefixedIdentifier 1601 * 'new'? prefixedIdentifier
4914 */ 1602 */
4915 CommentReference _parseCommentReference( 1603 CommentReference parseCommentReference(
4916 String referenceSource, int sourceOffset) { 1604 String referenceSource, int sourceOffset) {
4917 // TODO(brianwilkerson) The errors are not getting the right offset/length 1605 // TODO(brianwilkerson) The errors are not getting the right offset/length
4918 // and are being duplicated. 1606 // and are being duplicated.
4919 if (referenceSource.length == 0) {
4920 Token syntheticToken =
4921 new SyntheticStringToken(TokenType.IDENTIFIER, "", sourceOffset);
4922 return new CommentReference(null, new SimpleIdentifier(syntheticToken));
4923 }
4924 try { 1607 try {
4925 BooleanErrorListener listener = new BooleanErrorListener(); 1608 BooleanErrorListener listener = new BooleanErrorListener();
4926 Scanner scanner = new Scanner( 1609 Scanner scanner = new Scanner(
4927 null, new SubSequenceReader(referenceSource, sourceOffset), listener); 1610 null, new SubSequenceReader(referenceSource, sourceOffset), listener);
4928 scanner.setSourceStart(1, 1); 1611 scanner.setSourceStart(1, 1);
4929 Token firstToken = scanner.tokenize(); 1612 Token firstToken = scanner.tokenize();
4930 if (listener.errorReported) { 1613 if (listener.errorReported) {
4931 return null; 1614 return null;
4932 } 1615 }
1616 if (firstToken.type == TokenType.EOF) {
1617 Token syntheticToken =
1618 new SyntheticStringToken(TokenType.IDENTIFIER, "", sourceOffset);
1619 syntheticToken.setNext(firstToken);
1620 return new CommentReference(null, new SimpleIdentifier(syntheticToken));
1621 }
4933 Token newKeyword = null; 1622 Token newKeyword = null;
4934 if (_tokenMatchesKeyword(firstToken, Keyword.NEW)) { 1623 if (_tokenMatchesKeyword(firstToken, Keyword.NEW)) {
4935 newKeyword = firstToken; 1624 newKeyword = firstToken;
4936 firstToken = firstToken.next; 1625 firstToken = firstToken.next;
4937 } 1626 }
4938 if (_tokenMatchesIdentifier(firstToken)) { 1627 if (firstToken.isUserDefinableOperator) {
1628 if (firstToken.next.type != TokenType.EOF) {
1629 return null;
1630 }
1631 Identifier identifier = new SimpleIdentifier(firstToken);
1632 return new CommentReference(null, identifier);
1633 } else if (_tokenMatchesKeyword(firstToken, Keyword.OPERATOR)) {
1634 Token secondToken = firstToken.next;
1635 if (secondToken.isUserDefinableOperator) {
1636 if (secondToken.next.type != TokenType.EOF) {
1637 return null;
1638 }
1639 Identifier identifier = new SimpleIdentifier(secondToken);
1640 return new CommentReference(null, identifier);
1641 }
1642 return null;
1643 } else if (_tokenMatchesIdentifier(firstToken)) {
4939 Token secondToken = firstToken.next; 1644 Token secondToken = firstToken.next;
4940 Token thirdToken = secondToken.next; 1645 Token thirdToken = secondToken.next;
4941 Token nextToken; 1646 Token nextToken;
4942 Identifier identifier; 1647 Identifier identifier;
4943 if (_tokenMatches(secondToken, TokenType.PERIOD) && 1648 if (_tokenMatches(secondToken, TokenType.PERIOD)) {
4944 _tokenMatchesIdentifier(thirdToken)) { 1649 if (thirdToken.isUserDefinableOperator) {
4945 identifier = new PrefixedIdentifier(new SimpleIdentifier(firstToken), 1650 identifier = new PrefixedIdentifier(
4946 secondToken, new SimpleIdentifier(thirdToken)); 1651 new SimpleIdentifier(firstToken),
4947 nextToken = thirdToken.next; 1652 secondToken,
1653 new SimpleIdentifier(thirdToken));
1654 nextToken = thirdToken.next;
1655 } else if (_tokenMatchesKeyword(thirdToken, Keyword.OPERATOR)) {
1656 Token fourthToken = thirdToken.next;
1657 if (fourthToken.isUserDefinableOperator) {
1658 identifier = new PrefixedIdentifier(
1659 new SimpleIdentifier(firstToken),
1660 secondToken,
1661 new SimpleIdentifier(fourthToken));
1662 nextToken = fourthToken.next;
1663 } else {
1664 return null;
1665 }
1666 } else if (_tokenMatchesIdentifier(thirdToken)) {
1667 identifier = new PrefixedIdentifier(
1668 new SimpleIdentifier(firstToken),
1669 secondToken,
1670 new SimpleIdentifier(thirdToken));
1671 nextToken = thirdToken.next;
1672 }
4948 } else { 1673 } else {
4949 identifier = new SimpleIdentifier(firstToken); 1674 identifier = new SimpleIdentifier(firstToken);
4950 nextToken = firstToken.next; 1675 nextToken = firstToken.next;
4951 } 1676 }
4952 if (nextToken.type != TokenType.EOF) { 1677 if (nextToken.type != TokenType.EOF) {
4953 return null; 1678 return null;
4954 } 1679 }
4955 return new CommentReference(newKeyword, identifier); 1680 return new CommentReference(newKeyword, identifier);
4956 } else if (_tokenMatchesKeyword(firstToken, Keyword.THIS) || 1681 } else {
4957 _tokenMatchesKeyword(firstToken, Keyword.NULL) || 1682 Keyword keyword = firstToken.keyword;
4958 _tokenMatchesKeyword(firstToken, Keyword.TRUE) || 1683 if (keyword == Keyword.THIS ||
4959 _tokenMatchesKeyword(firstToken, Keyword.FALSE)) { 1684 keyword == Keyword.NULL ||
4960 // TODO(brianwilkerson) If we want to support this we will need to 1685 keyword == Keyword.TRUE ||
4961 // extend the definition of CommentReference to take an expression 1686 keyword == Keyword.FALSE) {
4962 // rather than an identifier. For now we just ignore it to reduce the 1687 // TODO(brianwilkerson) If we want to support this we will need to
4963 // number of errors produced, but that's probably not a valid long term 1688 // extend the definition of CommentReference to take an expression
4964 // approach. 1689 // rather than an identifier. For now we just ignore it to reduce the
4965 return null; 1690 // number of errors produced, but that's probably not a valid long ter m
1691 // approach.
1692 return null;
1693 }
4966 } 1694 }
4967 } catch (exception) { 1695 } catch (exception) {
4968 // Ignored because we assume that it wasn't a real comment reference. 1696 // Ignored because we assume that it wasn't a real comment reference.
4969 } 1697 }
4970 return null; 1698 return null;
4971 } 1699 }
4972 1700
4973 /** 1701 /**
4974 * Parse all of the comment references occurring in the given array of 1702 * Parse all of the comment references occurring in the given array of
4975 * documentation comments. The [tokens] are the comment tokens representing 1703 * documentation comments. The [tokens] are the comment tokens representing
4976 * the documentation comments to be parsed. Return the comment references that 1704 * the documentation comments to be parsed. Return the comment references that
4977 * were parsed. 1705 * were parsed.
4978 * 1706 *
4979 * commentReference ::= 1707 * commentReference ::=
4980 * '[' 'new'? qualified ']' libraryReference? 1708 * '[' 'new'? qualified ']' libraryReference?
4981 * 1709 *
4982 * libraryReference ::= 1710 * libraryReference ::=
4983 * '(' stringLiteral ')' 1711 * '(' stringLiteral ')'
4984 */ 1712 */
4985 List<CommentReference> _parseCommentReferences( 1713 List<CommentReference> parseCommentReferences(
4986 List<DocumentationCommentToken> tokens) { 1714 List<DocumentationCommentToken> tokens) {
4987 List<CommentReference> references = new List<CommentReference>(); 1715 List<CommentReference> references = <CommentReference>[];
1716 bool isInGitHubCodeBlock = false;
4988 for (DocumentationCommentToken token in tokens) { 1717 for (DocumentationCommentToken token in tokens) {
4989 String comment = token.lexeme; 1718 String comment = token.lexeme;
1719 // Skip GitHub code blocks.
1720 // https://help.github.com/articles/creating-and-highlighting-code-blocks/
1721 if (tokens.length != 1) {
1722 if (comment.indexOf('```') != -1) {
1723 isInGitHubCodeBlock = !isInGitHubCodeBlock;
1724 }
1725 if (isInGitHubCodeBlock) {
1726 continue;
1727 }
1728 }
1729 // Remove GitHub include code.
1730 comment = _removeGitHubInlineCode(comment);
1731 // Find references.
4990 int length = comment.length; 1732 int length = comment.length;
4991 List<List<int>> codeBlockRanges = _getCodeBlockRanges(comment); 1733 List<List<int>> codeBlockRanges = _getCodeBlockRanges(comment);
4992 int leftIndex = comment.indexOf('['); 1734 int leftIndex = comment.indexOf('[');
4993 while (leftIndex >= 0 && leftIndex + 1 < length) { 1735 while (leftIndex >= 0 && leftIndex + 1 < length) {
4994 List<int> range = _findRange(codeBlockRanges, leftIndex); 1736 List<int> range = _findRange(codeBlockRanges, leftIndex);
4995 if (range == null) { 1737 if (range == null) {
4996 int nameOffset = token.offset + leftIndex + 1; 1738 int nameOffset = token.offset + leftIndex + 1;
4997 int rightIndex = JavaString.indexOf(comment, ']', leftIndex); 1739 int rightIndex = comment.indexOf(']', leftIndex);
4998 if (rightIndex >= 0) { 1740 if (rightIndex >= 0) {
4999 int firstChar = comment.codeUnitAt(leftIndex + 1); 1741 int firstChar = comment.codeUnitAt(leftIndex + 1);
5000 if (firstChar != 0x27 && firstChar != 0x22) { 1742 if (firstChar != 0x27 && firstChar != 0x22) {
5001 if (_isLinkText(comment, rightIndex)) { 1743 if (_isLinkText(comment, rightIndex)) {
5002 // TODO(brianwilkerson) Handle the case where there's a library 1744 // TODO(brianwilkerson) Handle the case where there's a library
5003 // URI in the link text. 1745 // URI in the link text.
5004 } else { 1746 } else {
5005 CommentReference reference = _parseCommentReference( 1747 CommentReference reference = parseCommentReference(
5006 comment.substring(leftIndex + 1, rightIndex), nameOffset); 1748 comment.substring(leftIndex + 1, rightIndex), nameOffset);
5007 if (reference != null) { 1749 if (reference != null) {
5008 references.add(reference); 1750 references.add(reference);
5009 token.references.add(reference.beginToken); 1751 token.references.add(reference.beginToken);
5010 } 1752 }
5011 } 1753 }
5012 } 1754 }
5013 } else { 1755 } else {
5014 // terminating ']' is not typed yet 1756 // terminating ']' is not typed yet
5015 int charAfterLeft = comment.codeUnitAt(leftIndex + 1); 1757 int charAfterLeft = comment.codeUnitAt(leftIndex + 1);
1758 Token nameToken;
5016 if (Character.isLetterOrDigit(charAfterLeft)) { 1759 if (Character.isLetterOrDigit(charAfterLeft)) {
5017 int nameEnd = StringUtilities.indexOfFirstNotLetterDigit( 1760 int nameEnd = StringUtilities.indexOfFirstNotLetterDigit(
5018 comment, leftIndex + 1); 1761 comment, leftIndex + 1);
5019 String name = comment.substring(leftIndex + 1, nameEnd); 1762 String name = comment.substring(leftIndex + 1, nameEnd);
5020 Token nameToken = 1763 nameToken =
5021 new StringToken(TokenType.IDENTIFIER, name, nameOffset); 1764 new StringToken(TokenType.IDENTIFIER, name, nameOffset);
5022 references.add(
5023 new CommentReference(null, new SimpleIdentifier(nameToken)));
5024 } else { 1765 } else {
5025 Token nameToken = new SyntheticStringToken( 1766 nameToken = new SyntheticStringToken(
5026 TokenType.IDENTIFIER, "", nameOffset); 1767 TokenType.IDENTIFIER, '', nameOffset);
5027 references.add(
5028 new CommentReference(null, new SimpleIdentifier(nameToken)));
5029 } 1768 }
1769 nameToken.setNext(new SimpleToken(TokenType.EOF, nameToken.end));
1770 references.add(
1771 new CommentReference(null, new SimpleIdentifier(nameToken)));
1772 token.references.add(nameToken);
5030 // next character 1773 // next character
5031 rightIndex = leftIndex + 1; 1774 rightIndex = leftIndex + 1;
5032 } 1775 }
5033 leftIndex = JavaString.indexOf(comment, '[', rightIndex); 1776 leftIndex = comment.indexOf('[', rightIndex);
5034 } else { 1777 } else {
5035 leftIndex = JavaString.indexOf(comment, '[', range[1] + 1); 1778 leftIndex = comment.indexOf('[', range[1]);
5036 } 1779 }
5037 } 1780 }
5038 } 1781 }
5039 return references; 1782 return references;
5040 } 1783 }
5041 1784
5042 /** 1785 /**
1786 * Parse a compilation unit, starting with the given [token]. Return the
1787 * compilation unit that was parsed.
1788 */
1789 CompilationUnit parseCompilationUnit(Token token) {
1790 _currentToken = token;
1791 return parseCompilationUnit2();
1792 }
1793
1794 /**
1795 * Parse a compilation unit. Return the compilation unit that was parsed.
1796 *
1797 * Specified:
1798 *
1799 * compilationUnit ::=
1800 * scriptTag? directive* topLevelDeclaration*
1801 *
1802 * Actual:
1803 *
1804 * compilationUnit ::=
1805 * scriptTag? topLevelElement*
1806 *
1807 * topLevelElement ::=
1808 * directive
1809 * | topLevelDeclaration
1810 */
1811 CompilationUnit parseCompilationUnit2() {
1812 Token firstToken = _currentToken;
1813 ScriptTag scriptTag = null;
1814 if (_matches(TokenType.SCRIPT_TAG)) {
1815 scriptTag = new ScriptTag(getAndAdvance());
1816 }
1817 //
1818 // Even though all directives must appear before declarations and must occur
1819 // in a given order, we allow directives and declarations to occur in any
1820 // order so that we can recover better.
1821 //
1822 bool libraryDirectiveFound = false;
1823 bool partOfDirectiveFound = false;
1824 bool partDirectiveFound = false;
1825 bool directiveFoundAfterDeclaration = false;
1826 List<Directive> directives = <Directive>[];
1827 List<CompilationUnitMember> declarations = <CompilationUnitMember>[];
1828 Token memberStart = _currentToken;
1829 TokenType type = _currentToken.type;
1830 while (type != TokenType.EOF) {
1831 CommentAndMetadata commentAndMetadata = parseCommentAndMetadata();
1832 Keyword keyword = _currentToken.keyword;
1833 TokenType nextType = _currentToken.next.type;
1834 if ((keyword == Keyword.IMPORT ||
1835 keyword == Keyword.EXPORT ||
1836 keyword == Keyword.LIBRARY ||
1837 keyword == Keyword.PART) &&
1838 nextType != TokenType.PERIOD &&
1839 nextType != TokenType.LT &&
1840 nextType != TokenType.OPEN_PAREN) {
1841 Directive parseDirective() {
1842 if (keyword == Keyword.IMPORT) {
1843 if (partDirectiveFound) {
1844 _reportErrorForCurrentToken(
1845 ParserErrorCode.IMPORT_DIRECTIVE_AFTER_PART_DIRECTIVE);
1846 }
1847 return parseImportDirective(commentAndMetadata);
1848 } else if (keyword == Keyword.EXPORT) {
1849 if (partDirectiveFound) {
1850 _reportErrorForCurrentToken(
1851 ParserErrorCode.EXPORT_DIRECTIVE_AFTER_PART_DIRECTIVE);
1852 }
1853 return parseExportDirective(commentAndMetadata);
1854 } else if (keyword == Keyword.LIBRARY) {
1855 if (libraryDirectiveFound) {
1856 _reportErrorForCurrentToken(
1857 ParserErrorCode.MULTIPLE_LIBRARY_DIRECTIVES);
1858 } else {
1859 if (directives.length > 0) {
1860 _reportErrorForCurrentToken(
1861 ParserErrorCode.LIBRARY_DIRECTIVE_NOT_FIRST);
1862 }
1863 libraryDirectiveFound = true;
1864 }
1865 return parseLibraryDirective(commentAndMetadata);
1866 } else if (keyword == Keyword.PART) {
1867 if (_tokenMatchesString(_peek(), _OF)) {
1868 partOfDirectiveFound = true;
1869 return _parsePartOfDirective(commentAndMetadata);
1870 } else {
1871 partDirectiveFound = true;
1872 return _parsePartDirective(commentAndMetadata);
1873 }
1874 } else {
1875 // Internal error: this method should not have been invoked if the
1876 // current token was something other than one of the above.
1877 throw new StateError(
1878 "parseDirective invoked in an invalid state (currentToken = $_cu rrentToken)");
1879 }
1880 }
1881
1882 Directive directive = parseDirective();
1883 if (declarations.length > 0 && !directiveFoundAfterDeclaration) {
1884 _reportErrorForToken(ParserErrorCode.DIRECTIVE_AFTER_DECLARATION,
1885 directive.beginToken);
1886 directiveFoundAfterDeclaration = true;
1887 }
1888 directives.add(directive);
1889 } else if (type == TokenType.SEMICOLON) {
1890 // TODO(brianwilkerson) Consider moving this error detection into
1891 // _parseCompilationUnitMember (in the places where EXPECTED_EXECUTABLE
1892 // is being generated).
1893 _reportErrorForToken(ParserErrorCode.UNEXPECTED_TOKEN, _currentToken,
1894 [_currentToken.lexeme]);
1895 _advance();
1896 } else {
1897 CompilationUnitMember member =
1898 parseCompilationUnitMember(commentAndMetadata);
1899 if (member != null) {
1900 declarations.add(member);
1901 }
1902 }
1903 if (identical(_currentToken, memberStart)) {
1904 _reportErrorForToken(ParserErrorCode.UNEXPECTED_TOKEN, _currentToken,
1905 [_currentToken.lexeme]);
1906 _advance();
1907 while (!_matches(TokenType.EOF) &&
1908 !_couldBeStartOfCompilationUnitMember()) {
1909 _advance();
1910 }
1911 }
1912 memberStart = _currentToken;
1913 type = _currentToken.type;
1914 }
1915 if (partOfDirectiveFound && directives.length > 1) {
1916 // TODO(brianwilkerson) Improve error reporting when both a library and
1917 // part-of directive are found.
1918 // if (libraryDirectiveFound) {
1919 // int directiveCount = directives.length;
1920 // for (int i = 0; i < directiveCount; i++) {
1921 // Directive directive = directives[i];
1922 // if (directive is PartOfDirective) {
1923 // _reportErrorForToken(
1924 // ParserErrorCode.PART_OF_IN_LIBRARY, directive.partKeyword);
1925 // }
1926 // }
1927 // } else {
1928 bool firstPartOf = true;
1929 int directiveCount = directives.length;
1930 for (int i = 0; i < directiveCount; i++) {
1931 Directive directive = directives[i];
1932 if (directive is PartOfDirective) {
1933 if (firstPartOf) {
1934 firstPartOf = false;
1935 } else {
1936 _reportErrorForToken(ParserErrorCode.MULTIPLE_PART_OF_DIRECTIVES,
1937 directive.partKeyword);
1938 }
1939 } else {
1940 _reportErrorForToken(ParserErrorCode.NON_PART_OF_DIRECTIVE_IN_PART,
1941 directives[i].keyword);
1942 }
1943 // }
1944 }
1945 }
1946 return new CompilationUnit(
1947 firstToken, scriptTag, directives, declarations, _currentToken);
1948 }
1949
1950 /**
5043 * Parse a compilation unit member. The [commentAndMetadata] is the metadata 1951 * Parse a compilation unit member. The [commentAndMetadata] is the metadata
5044 * to be associated with the member. Return the compilation unit member that 1952 * to be associated with the member. Return the compilation unit member that
5045 * was parsed, or `null` if what was parsed could not be represented as a 1953 * was parsed, or `null` if what was parsed could not be represented as a
5046 * compilation unit member. 1954 * compilation unit member.
5047 * 1955 *
5048 * compilationUnitMember ::= 1956 * compilationUnitMember ::=
5049 * classDefinition 1957 * classDefinition
5050 * | functionTypeAlias 1958 * | functionTypeAlias
5051 * | external functionSignature 1959 * | external functionSignature
5052 * | external getterSignature 1960 * | external getterSignature
5053 * | external setterSignature 1961 * | external setterSignature
5054 * | functionSignature functionBody 1962 * | functionSignature functionBody
5055 * | returnType? getOrSet identifier formalParameterList functionBody 1963 * | returnType? getOrSet identifier formalParameterList functionBody
5056 * | (final | const) type? staticFinalDeclarationList ';' 1964 * | (final | const) type? staticFinalDeclarationList ';'
5057 * | variableDeclaration ';' 1965 * | variableDeclaration ';'
5058 */ 1966 */
5059 CompilationUnitMember _parseCompilationUnitMember( 1967 CompilationUnitMember parseCompilationUnitMember(
5060 CommentAndMetadata commentAndMetadata) { 1968 CommentAndMetadata commentAndMetadata) {
5061 Modifiers modifiers = _parseModifiers(); 1969 Modifiers modifiers = parseModifiers();
5062 if (_matchesKeyword(Keyword.CLASS)) { 1970 Keyword keyword = _currentToken.keyword;
5063 return _parseClassDeclaration( 1971 if (keyword == Keyword.CLASS) {
1972 return parseClassDeclaration(
5064 commentAndMetadata, _validateModifiersForClass(modifiers)); 1973 commentAndMetadata, _validateModifiersForClass(modifiers));
5065 } else if (_matchesKeyword(Keyword.TYPEDEF) && 1974 }
5066 !_tokenMatches(_peek(), TokenType.PERIOD) && 1975 Token next = _peek();
5067 !_tokenMatches(_peek(), TokenType.LT) && 1976 TokenType nextType = next.type;
5068 !_tokenMatches(_peek(), TokenType.OPEN_PAREN)) { 1977 if (keyword == Keyword.TYPEDEF &&
1978 nextType != TokenType.PERIOD &&
1979 nextType != TokenType.LT &&
1980 nextType != TokenType.OPEN_PAREN) {
5069 _validateModifiersForTypedef(modifiers); 1981 _validateModifiersForTypedef(modifiers);
5070 return _parseTypeAlias(commentAndMetadata); 1982 return parseTypeAlias(commentAndMetadata);
5071 } else if (_matchesKeyword(Keyword.ENUM)) { 1983 } else if (keyword == Keyword.ENUM) {
5072 _validateModifiersForEnum(modifiers); 1984 _validateModifiersForEnum(modifiers);
5073 return _parseEnumDeclaration(commentAndMetadata); 1985 return parseEnumDeclaration(commentAndMetadata);
5074 } 1986 } else if (keyword == Keyword.VOID) {
5075 if (_matchesKeyword(Keyword.VOID)) { 1987 TypeName returnType =
5076 TypeName returnType = parseReturnType(); 1988 new TypeName(new SimpleIdentifier(getAndAdvance()), null);
5077 if ((_matchesKeyword(Keyword.GET) || _matchesKeyword(Keyword.SET)) && 1989 keyword = _currentToken.keyword;
5078 _tokenMatchesIdentifier(_peek())) { 1990 next = _peek();
1991 if ((keyword == Keyword.GET || keyword == Keyword.SET) &&
1992 _tokenMatchesIdentifier(next)) {
5079 _validateModifiersForTopLevelFunction(modifiers); 1993 _validateModifiersForTopLevelFunction(modifiers);
5080 return _parseFunctionDeclaration( 1994 return parseFunctionDeclaration(
5081 commentAndMetadata, modifiers.externalKeyword, returnType); 1995 commentAndMetadata, modifiers.externalKeyword, returnType);
5082 } else if (_matchesKeyword(Keyword.OPERATOR) && _isOperator(_peek())) { 1996 } else if (keyword == Keyword.OPERATOR && _isOperator(next)) {
5083 _reportErrorForToken(ParserErrorCode.TOP_LEVEL_OPERATOR, _currentToken); 1997 _reportErrorForToken(ParserErrorCode.TOP_LEVEL_OPERATOR, _currentToken);
5084 return _convertToFunctionDeclaration(_parseOperator( 1998 return _convertToFunctionDeclaration(_parseOperatorAfterKeyword(
5085 commentAndMetadata, modifiers.externalKeyword, returnType)); 1999 commentAndMetadata,
2000 modifiers.externalKeyword,
2001 returnType,
2002 getAndAdvance()));
5086 } else if (_matchesIdentifier() && 2003 } else if (_matchesIdentifier() &&
5087 _peek().matchesAny([ 2004 next.matchesAny(const <TokenType>[
5088 TokenType.OPEN_PAREN, 2005 TokenType.OPEN_PAREN,
5089 TokenType.OPEN_CURLY_BRACKET, 2006 TokenType.OPEN_CURLY_BRACKET,
5090 TokenType.FUNCTION 2007 TokenType.FUNCTION,
2008 TokenType.LT
5091 ])) { 2009 ])) {
5092 _validateModifiersForTopLevelFunction(modifiers); 2010 _validateModifiersForTopLevelFunction(modifiers);
5093 return _parseFunctionDeclaration( 2011 return parseFunctionDeclaration(
5094 commentAndMetadata, modifiers.externalKeyword, returnType); 2012 commentAndMetadata, modifiers.externalKeyword, returnType);
5095 } else { 2013 } else {
5096 // 2014 //
5097 // We have found an error of some kind. Try to recover. 2015 // We have found an error of some kind. Try to recover.
5098 // 2016 //
5099 if (_matchesIdentifier()) { 2017 if (_matchesIdentifier()) {
5100 if (_peek().matchesAny( 2018 if (next.matchesAny(const <TokenType>[
5101 [TokenType.EQ, TokenType.COMMA, TokenType.SEMICOLON])) { 2019 TokenType.EQ,
2020 TokenType.COMMA,
2021 TokenType.SEMICOLON
2022 ])) {
5102 // 2023 //
5103 // We appear to have a variable declaration with a type of "void". 2024 // We appear to have a variable declaration with a type of "void".
5104 // 2025 //
5105 _reportErrorForNode(ParserErrorCode.VOID_VARIABLE, returnType); 2026 _reportErrorForNode(ParserErrorCode.VOID_VARIABLE, returnType);
5106 return new TopLevelVariableDeclaration( 2027 return new TopLevelVariableDeclaration(
5107 commentAndMetadata.comment, 2028 commentAndMetadata.comment,
5108 commentAndMetadata.metadata, 2029 commentAndMetadata.metadata,
5109 _parseVariableDeclarationListAfterType(null, 2030 parseVariableDeclarationListAfterType(null,
5110 _validateModifiersForTopLevelVariable(modifiers), null), 2031 _validateModifiersForTopLevelVariable(modifiers), null),
5111 _expect(TokenType.SEMICOLON)); 2032 _expect(TokenType.SEMICOLON));
5112 } 2033 }
5113 } 2034 }
5114 _reportErrorForToken( 2035 _reportErrorForToken(
5115 ParserErrorCode.EXPECTED_EXECUTABLE, _currentToken); 2036 ParserErrorCode.EXPECTED_EXECUTABLE, _currentToken);
5116 return null; 2037 return null;
5117 } 2038 }
5118 } else if ((_matchesKeyword(Keyword.GET) || _matchesKeyword(Keyword.SET)) && 2039 } else if ((keyword == Keyword.GET || keyword == Keyword.SET) &&
5119 _tokenMatchesIdentifier(_peek())) { 2040 _tokenMatchesIdentifier(next)) {
5120 _validateModifiersForTopLevelFunction(modifiers); 2041 _validateModifiersForTopLevelFunction(modifiers);
5121 return _parseFunctionDeclaration( 2042 return parseFunctionDeclaration(
5122 commentAndMetadata, modifiers.externalKeyword, null); 2043 commentAndMetadata, modifiers.externalKeyword, null);
5123 } else if (_matchesKeyword(Keyword.OPERATOR) && _isOperator(_peek())) { 2044 } else if (keyword == Keyword.OPERATOR && _isOperator(next)) {
5124 _reportErrorForToken(ParserErrorCode.TOP_LEVEL_OPERATOR, _currentToken); 2045 _reportErrorForToken(ParserErrorCode.TOP_LEVEL_OPERATOR, _currentToken);
5125 return _convertToFunctionDeclaration( 2046 return _convertToFunctionDeclaration(_parseOperatorAfterKeyword(
5126 _parseOperator(commentAndMetadata, modifiers.externalKeyword, null)); 2047 commentAndMetadata,
2048 modifiers.externalKeyword,
2049 null,
2050 getAndAdvance()));
5127 } else if (!_matchesIdentifier()) { 2051 } else if (!_matchesIdentifier()) {
5128 Token keyword = modifiers.varKeyword; 2052 Token keyword = modifiers.varKeyword;
5129 if (keyword == null) { 2053 if (keyword == null) {
5130 keyword = modifiers.finalKeyword; 2054 keyword = modifiers.finalKeyword;
5131 } 2055 }
5132 if (keyword == null) { 2056 if (keyword == null) {
5133 keyword = modifiers.constKeyword; 2057 keyword = modifiers.constKeyword;
5134 } 2058 }
5135 if (keyword != null) { 2059 if (keyword != null) {
5136 // 2060 //
5137 // We appear to have found an incomplete top-level variable declaration. 2061 // We appear to have found an incomplete top-level variable declaration.
5138 // 2062 //
5139 _reportErrorForCurrentToken(ParserErrorCode.MISSING_IDENTIFIER); 2063 _reportErrorForCurrentToken(ParserErrorCode.MISSING_IDENTIFIER);
5140 List<VariableDeclaration> variables = new List<VariableDeclaration>(); 2064 VariableDeclaration variable =
5141 variables.add( 2065 new VariableDeclaration(createSyntheticIdentifier(), null, null);
5142 new VariableDeclaration(_createSyntheticIdentifier(), null, null)); 2066 List<VariableDeclaration> variables = <VariableDeclaration>[variable];
5143 return new TopLevelVariableDeclaration( 2067 return new TopLevelVariableDeclaration(
5144 commentAndMetadata.comment, 2068 commentAndMetadata.comment,
5145 commentAndMetadata.metadata, 2069 commentAndMetadata.metadata,
5146 new VariableDeclarationList(null, null, keyword, null, variables), 2070 new VariableDeclarationList(null, null, keyword, null, variables),
5147 _expectSemicolon()); 2071 _expect(TokenType.SEMICOLON));
5148 } 2072 }
5149 _reportErrorForToken(ParserErrorCode.EXPECTED_EXECUTABLE, _currentToken); 2073 _reportErrorForToken(ParserErrorCode.EXPECTED_EXECUTABLE, _currentToken);
5150 return null; 2074 return null;
5151 } else if (_tokenMatches(_peek(), TokenType.OPEN_PAREN)) { 2075 } else if (_isPeekGenericTypeParametersAndOpenParen()) {
2076 return parseFunctionDeclaration(
2077 commentAndMetadata, modifiers.externalKeyword, null);
2078 } else if (_tokenMatches(next, TokenType.OPEN_PAREN)) {
2079 TypeName returnType = _parseOptionalTypeNameComment();
5152 _validateModifiersForTopLevelFunction(modifiers); 2080 _validateModifiersForTopLevelFunction(modifiers);
5153 return _parseFunctionDeclaration( 2081 return parseFunctionDeclaration(
5154 commentAndMetadata, modifiers.externalKeyword, null); 2082 commentAndMetadata, modifiers.externalKeyword, returnType);
5155 } else if (_peek() 2083 } else if (next.matchesAny(const <TokenType>[
5156 .matchesAny([TokenType.EQ, TokenType.COMMA, TokenType.SEMICOLON])) { 2084 TokenType.EQ,
2085 TokenType.COMMA,
2086 TokenType.SEMICOLON
2087 ])) {
5157 if (modifiers.constKeyword == null && 2088 if (modifiers.constKeyword == null &&
5158 modifiers.finalKeyword == null && 2089 modifiers.finalKeyword == null &&
5159 modifiers.varKeyword == null) { 2090 modifiers.varKeyword == null) {
5160 _reportErrorForCurrentToken( 2091 _reportErrorForCurrentToken(
5161 ParserErrorCode.MISSING_CONST_FINAL_VAR_OR_TYPE); 2092 ParserErrorCode.MISSING_CONST_FINAL_VAR_OR_TYPE);
5162 } 2093 }
5163 return new TopLevelVariableDeclaration( 2094 return new TopLevelVariableDeclaration(
5164 commentAndMetadata.comment, 2095 commentAndMetadata.comment,
5165 commentAndMetadata.metadata, 2096 commentAndMetadata.metadata,
5166 _parseVariableDeclarationListAfterType( 2097 parseVariableDeclarationListAfterType(
5167 null, _validateModifiersForTopLevelVariable(modifiers), null), 2098 null, _validateModifiersForTopLevelVariable(modifiers), null),
5168 _expect(TokenType.SEMICOLON)); 2099 _expect(TokenType.SEMICOLON));
5169 } 2100 }
5170 TypeName returnType = parseReturnType(); 2101 TypeName returnType = parseReturnType();
5171 if ((_matchesKeyword(Keyword.GET) || _matchesKeyword(Keyword.SET)) && 2102 keyword = _currentToken.keyword;
5172 _tokenMatchesIdentifier(_peek())) { 2103 next = _peek();
2104 if ((keyword == Keyword.GET || keyword == Keyword.SET) &&
2105 _tokenMatchesIdentifier(next)) {
5173 _validateModifiersForTopLevelFunction(modifiers); 2106 _validateModifiersForTopLevelFunction(modifiers);
5174 return _parseFunctionDeclaration( 2107 return parseFunctionDeclaration(
5175 commentAndMetadata, modifiers.externalKeyword, returnType); 2108 commentAndMetadata, modifiers.externalKeyword, returnType);
5176 } else if (_matchesKeyword(Keyword.OPERATOR) && _isOperator(_peek())) { 2109 } else if (keyword == Keyword.OPERATOR && _isOperator(next)) {
5177 _reportErrorForToken(ParserErrorCode.TOP_LEVEL_OPERATOR, _currentToken); 2110 _reportErrorForToken(ParserErrorCode.TOP_LEVEL_OPERATOR, _currentToken);
5178 return _convertToFunctionDeclaration(_parseOperator( 2111 return _convertToFunctionDeclaration(_parseOperatorAfterKeyword(
5179 commentAndMetadata, modifiers.externalKeyword, returnType)); 2112 commentAndMetadata,
2113 modifiers.externalKeyword,
2114 returnType,
2115 getAndAdvance()));
5180 } else if (_matches(TokenType.AT)) { 2116 } else if (_matches(TokenType.AT)) {
5181 return new TopLevelVariableDeclaration( 2117 return new TopLevelVariableDeclaration(
5182 commentAndMetadata.comment, 2118 commentAndMetadata.comment,
5183 commentAndMetadata.metadata, 2119 commentAndMetadata.metadata,
5184 _parseVariableDeclarationListAfterType(null, 2120 parseVariableDeclarationListAfterType(null,
5185 _validateModifiersForTopLevelVariable(modifiers), returnType), 2121 _validateModifiersForTopLevelVariable(modifiers), returnType),
5186 _expect(TokenType.SEMICOLON)); 2122 _expect(TokenType.SEMICOLON));
5187 } else if (!_matchesIdentifier()) { 2123 } else if (!_matchesIdentifier()) {
5188 // TODO(brianwilkerson) Generalize this error. We could also be parsing a 2124 // TODO(brianwilkerson) Generalize this error. We could also be parsing a
5189 // top-level variable at this point. 2125 // top-level variable at this point.
5190 _reportErrorForToken(ParserErrorCode.EXPECTED_EXECUTABLE, _currentToken); 2126 _reportErrorForToken(ParserErrorCode.EXPECTED_EXECUTABLE, _currentToken);
5191 Token semicolon; 2127 Token semicolon;
5192 if (_matches(TokenType.SEMICOLON)) { 2128 if (_matches(TokenType.SEMICOLON)) {
5193 semicolon = getAndAdvance(); 2129 semicolon = getAndAdvance();
5194 } else { 2130 } else {
5195 semicolon = _createSyntheticToken(TokenType.SEMICOLON); 2131 semicolon = _createSyntheticToken(TokenType.SEMICOLON);
5196 } 2132 }
5197 List<VariableDeclaration> variables = new List<VariableDeclaration>(); 2133 VariableDeclaration variable =
5198 variables.add( 2134 new VariableDeclaration(createSyntheticIdentifier(), null, null);
5199 new VariableDeclaration(_createSyntheticIdentifier(), null, null)); 2135 List<VariableDeclaration> variables = <VariableDeclaration>[variable];
5200 return new TopLevelVariableDeclaration( 2136 return new TopLevelVariableDeclaration(
5201 commentAndMetadata.comment, 2137 commentAndMetadata.comment,
5202 commentAndMetadata.metadata, 2138 commentAndMetadata.metadata,
5203 new VariableDeclarationList(null, null, null, returnType, variables), 2139 new VariableDeclarationList(null, null, null, returnType, variables),
5204 semicolon); 2140 semicolon);
5205 } 2141 } else if (next.matchesAny(const <TokenType>[
5206 if (_peek().matchesAny([
5207 TokenType.OPEN_PAREN, 2142 TokenType.OPEN_PAREN,
5208 TokenType.FUNCTION, 2143 TokenType.FUNCTION,
5209 TokenType.OPEN_CURLY_BRACKET 2144 TokenType.OPEN_CURLY_BRACKET,
2145 TokenType.LT
5210 ])) { 2146 ])) {
5211 _validateModifiersForTopLevelFunction(modifiers); 2147 _validateModifiersForTopLevelFunction(modifiers);
5212 return _parseFunctionDeclaration( 2148 return parseFunctionDeclaration(
5213 commentAndMetadata, modifiers.externalKeyword, returnType); 2149 commentAndMetadata, modifiers.externalKeyword, returnType);
5214 } 2150 }
5215 return new TopLevelVariableDeclaration( 2151 return new TopLevelVariableDeclaration(
5216 commentAndMetadata.comment, 2152 commentAndMetadata.comment,
5217 commentAndMetadata.metadata, 2153 commentAndMetadata.metadata,
5218 _parseVariableDeclarationListAfterType( 2154 parseVariableDeclarationListAfterType(
5219 null, _validateModifiersForTopLevelVariable(modifiers), returnType), 2155 null, _validateModifiersForTopLevelVariable(modifiers), returnType),
5220 _expect(TokenType.SEMICOLON)); 2156 _expect(TokenType.SEMICOLON));
5221 } 2157 }
5222 2158
5223 /** 2159 /**
2160 * Parse a conditional expression. Return the conditional expression that was
2161 * parsed.
2162 *
2163 * conditionalExpression ::=
2164 * ifNullExpression ('?' expressionWithoutCascade ':' expressionWithou tCascade)?
2165 */
2166 Expression parseConditionalExpression() {
2167 Expression condition = parseIfNullExpression();
2168 if (_currentToken.type != TokenType.QUESTION) {
2169 return condition;
2170 }
2171 Token question = getAndAdvance();
2172 Expression thenExpression = parseExpressionWithoutCascade();
2173 Token colon = _expect(TokenType.COLON);
2174 Expression elseExpression = parseExpressionWithoutCascade();
2175 return new ConditionalExpression(
2176 condition, question, thenExpression, colon, elseExpression);
2177 }
2178
2179 /**
2180 * Parse a configuration in either an import or export directive.
2181 *
2182 * This method assumes that the current token matches `Keyword.IF`.
2183 *
2184 * configuration ::=
2185 * 'if' '(' test ')' uri
2186 *
2187 * test ::=
2188 * dottedName ('==' stringLiteral)?
2189 *
2190 * dottedName ::=
2191 * identifier ('.' identifier)*
2192 */
2193 Configuration parseConfiguration() {
2194 Token ifKeyword = getAndAdvance();
2195 Token leftParenthesis = _expect(TokenType.OPEN_PAREN);
2196 DottedName name = parseDottedName();
2197 Token equalToken = null;
2198 StringLiteral value = null;
2199 if (_matches(TokenType.EQ_EQ)) {
2200 equalToken = getAndAdvance();
2201 value = parseStringLiteral();
2202 if (value is StringInterpolation) {
2203 _reportErrorForNode(
2204 ParserErrorCode.INVALID_LITERAL_IN_CONFIGURATION, value);
2205 }
2206 }
2207 Token rightParenthesis = _expect(TokenType.CLOSE_PAREN);
2208 StringLiteral libraryUri = _parseUri();
2209 return new Configuration(ifKeyword, leftParenthesis, name, equalToken,
2210 value, rightParenthesis, libraryUri);
2211 }
2212
2213 /**
5224 * Parse a const expression. Return the const expression that was parsed. 2214 * Parse a const expression. Return the const expression that was parsed.
5225 * 2215 *
2216 * This method assumes that the current token matches `Keyword.CONST`.
2217 *
5226 * constExpression ::= 2218 * constExpression ::=
5227 * instanceCreationExpression 2219 * instanceCreationExpression
5228 * | listLiteral 2220 * | listLiteral
5229 * | mapLiteral 2221 * | mapLiteral
5230 */ 2222 */
5231 Expression _parseConstExpression() { 2223 Expression parseConstExpression() {
5232 Token keyword = _expectKeyword(Keyword.CONST); 2224 Token keyword = getAndAdvance();
5233 if (_matches(TokenType.OPEN_SQUARE_BRACKET) || _matches(TokenType.INDEX)) { 2225 TokenType type = _currentToken.type;
5234 return _parseListLiteral(keyword, null); 2226 if (type == TokenType.LT || _injectGenericCommentTypeList()) {
5235 } else if (_matches(TokenType.OPEN_CURLY_BRACKET)) { 2227 return parseListOrMapLiteral(keyword);
5236 return _parseMapLiteral(keyword, null); 2228 } else if (type == TokenType.OPEN_SQUARE_BRACKET ||
5237 } else if (_matches(TokenType.LT)) { 2229 type == TokenType.INDEX) {
5238 return _parseListOrMapLiteral(keyword); 2230 return parseListLiteral(keyword, null);
5239 } 2231 } else if (type == TokenType.OPEN_CURLY_BRACKET) {
5240 return _parseInstanceCreationExpression(keyword); 2232 return parseMapLiteral(keyword, null);
5241 } 2233 }
5242 2234 return parseInstanceCreationExpression(keyword);
5243 ConstructorDeclaration _parseConstructor( 2235 }
5244 CommentAndMetadata commentAndMetadata, 2236
5245 Token externalKeyword, 2237 /**
5246 Token constKeyword, 2238 * Parse a field initializer within a constructor. The flag [hasThis] should
5247 Token factoryKeyword, 2239 * be true if the current token is `this`. Return the field initializer that
5248 SimpleIdentifier returnType, 2240 * was parsed.
5249 Token period,
5250 SimpleIdentifier name,
5251 FormalParameterList parameters) {
5252 bool bodyAllowed = externalKeyword == null;
5253 Token separator = null;
5254 List<ConstructorInitializer> initializers = null;
5255 if (_matches(TokenType.COLON)) {
5256 separator = getAndAdvance();
5257 initializers = new List<ConstructorInitializer>();
5258 do {
5259 if (_matchesKeyword(Keyword.THIS)) {
5260 if (_tokenMatches(_peek(), TokenType.OPEN_PAREN)) {
5261 bodyAllowed = false;
5262 initializers.add(_parseRedirectingConstructorInvocation());
5263 } else if (_tokenMatches(_peek(), TokenType.PERIOD) &&
5264 _tokenMatches(_peekAt(3), TokenType.OPEN_PAREN)) {
5265 bodyAllowed = false;
5266 initializers.add(_parseRedirectingConstructorInvocation());
5267 } else {
5268 initializers.add(_parseConstructorFieldInitializer());
5269 }
5270 } else if (_matchesKeyword(Keyword.SUPER)) {
5271 initializers.add(_parseSuperConstructorInvocation());
5272 } else if (_matches(TokenType.OPEN_CURLY_BRACKET) ||
5273 _matches(TokenType.FUNCTION)) {
5274 _reportErrorForCurrentToken(ParserErrorCode.MISSING_INITIALIZER);
5275 } else {
5276 initializers.add(_parseConstructorFieldInitializer());
5277 }
5278 } while (_optional(TokenType.COMMA));
5279 if (factoryKeyword != null) {
5280 _reportErrorForToken(
5281 ParserErrorCode.FACTORY_WITH_INITIALIZERS, factoryKeyword);
5282 }
5283 }
5284 ConstructorName redirectedConstructor = null;
5285 FunctionBody body;
5286 if (_matches(TokenType.EQ)) {
5287 separator = getAndAdvance();
5288 redirectedConstructor = parseConstructorName();
5289 body = new EmptyFunctionBody(_expect(TokenType.SEMICOLON));
5290 if (factoryKeyword == null) {
5291 _reportErrorForNode(
5292 ParserErrorCode.REDIRECTION_IN_NON_FACTORY_CONSTRUCTOR,
5293 redirectedConstructor);
5294 }
5295 } else {
5296 body = _parseFunctionBody(
5297 true, ParserErrorCode.MISSING_FUNCTION_BODY, false);
5298 if (constKeyword != null &&
5299 factoryKeyword != null &&
5300 externalKeyword == null) {
5301 _reportErrorForToken(ParserErrorCode.CONST_FACTORY, factoryKeyword);
5302 } else if (body is EmptyFunctionBody) {
5303 if (factoryKeyword != null &&
5304 externalKeyword == null &&
5305 _parseFunctionBodies) {
5306 _reportErrorForToken(
5307 ParserErrorCode.FACTORY_WITHOUT_BODY, factoryKeyword);
5308 }
5309 } else {
5310 if (constKeyword != null) {
5311 _reportErrorForNode(
5312 ParserErrorCode.CONST_CONSTRUCTOR_WITH_BODY, body);
5313 } else if (!bodyAllowed) {
5314 _reportErrorForNode(
5315 ParserErrorCode.EXTERNAL_CONSTRUCTOR_WITH_BODY, body);
5316 }
5317 }
5318 }
5319 return new ConstructorDeclaration(
5320 commentAndMetadata.comment,
5321 commentAndMetadata.metadata,
5322 externalKeyword,
5323 constKeyword,
5324 factoryKeyword,
5325 returnType,
5326 period,
5327 name,
5328 parameters,
5329 separator,
5330 initializers,
5331 redirectedConstructor,
5332 body);
5333 }
5334
5335 /**
5336 * Parse a field initializer within a constructor. Return the field
5337 * initializer that was parsed.
5338 * 2241 *
5339 * fieldInitializer: 2242 * fieldInitializer:
5340 * ('this' '.')? identifier '=' conditionalExpression cascadeSection* 2243 * ('this' '.')? identifier '=' conditionalExpression cascadeSection*
5341 */ 2244 */
5342 ConstructorFieldInitializer _parseConstructorFieldInitializer() { 2245 ConstructorFieldInitializer parseConstructorFieldInitializer(bool hasThis) {
5343 Token keyword = null; 2246 Token keywordToken = null;
5344 Token period = null; 2247 Token period = null;
5345 if (_matchesKeyword(Keyword.THIS)) { 2248 if (hasThis) {
5346 keyword = getAndAdvance(); 2249 keywordToken = getAndAdvance();
5347 period = _expect(TokenType.PERIOD); 2250 period = _expect(TokenType.PERIOD);
5348 } 2251 }
5349 SimpleIdentifier fieldName = parseSimpleIdentifier(); 2252 SimpleIdentifier fieldName = parseSimpleIdentifier();
5350 Token equals = null; 2253 Token equals = null;
5351 if (_matches(TokenType.EQ)) { 2254 TokenType type = _currentToken.type;
2255 if (type == TokenType.EQ) {
5352 equals = getAndAdvance(); 2256 equals = getAndAdvance();
5353 } else if (!_matchesKeyword(Keyword.THIS) &&
5354 !_matchesKeyword(Keyword.SUPER) &&
5355 !_matches(TokenType.OPEN_CURLY_BRACKET) &&
5356 !_matches(TokenType.FUNCTION)) {
5357 _reportErrorForCurrentToken(
5358 ParserErrorCode.MISSING_ASSIGNMENT_IN_INITIALIZER);
5359 equals = _createSyntheticToken(TokenType.EQ);
5360 } else { 2257 } else {
5361 _reportErrorForCurrentToken( 2258 _reportErrorForCurrentToken(
5362 ParserErrorCode.MISSING_ASSIGNMENT_IN_INITIALIZER); 2259 ParserErrorCode.MISSING_ASSIGNMENT_IN_INITIALIZER);
5363 return new ConstructorFieldInitializer(keyword, period, fieldName, 2260 Keyword keyword = _currentToken.keyword;
5364 _createSyntheticToken(TokenType.EQ), _createSyntheticIdentifier()); 2261 if (keyword != Keyword.THIS &&
2262 keyword != Keyword.SUPER &&
2263 type != TokenType.OPEN_CURLY_BRACKET &&
2264 type != TokenType.FUNCTION) {
2265 equals = _createSyntheticToken(TokenType.EQ);
2266 } else {
2267 return new ConstructorFieldInitializer(keywordToken, period, fieldName,
2268 _createSyntheticToken(TokenType.EQ), createSyntheticIdentifier());
2269 }
5365 } 2270 }
5366 bool wasInInitializer = _inInitializer; 2271 bool wasInInitializer = _inInitializer;
5367 _inInitializer = true; 2272 _inInitializer = true;
5368 try { 2273 try {
5369 Expression expression = parseConditionalExpression(); 2274 Expression expression = parseConditionalExpression();
5370 TokenType tokenType = _currentToken.type; 2275 if (_matches(TokenType.PERIOD_PERIOD)) {
5371 if (tokenType == TokenType.PERIOD_PERIOD) { 2276 List<Expression> cascadeSections = <Expression>[];
5372 List<Expression> cascadeSections = new List<Expression>(); 2277 do {
5373 while (tokenType == TokenType.PERIOD_PERIOD) { 2278 Expression section = parseCascadeSection();
5374 Expression section = _parseCascadeSection();
5375 if (section != null) { 2279 if (section != null) {
5376 cascadeSections.add(section); 2280 cascadeSections.add(section);
5377 } 2281 }
5378 tokenType = _currentToken.type; 2282 } while (_matches(TokenType.PERIOD_PERIOD));
5379 }
5380 expression = new CascadeExpression(expression, cascadeSections); 2283 expression = new CascadeExpression(expression, cascadeSections);
5381 } 2284 }
5382 return new ConstructorFieldInitializer( 2285 return new ConstructorFieldInitializer(
5383 keyword, period, fieldName, equals, expression); 2286 keywordToken, period, fieldName, equals, expression);
5384 } finally { 2287 } finally {
5385 _inInitializer = wasInInitializer; 2288 _inInitializer = wasInInitializer;
5386 } 2289 }
5387 } 2290 }
5388 2291
5389 /** 2292 /**
2293 * Parse the name of a constructor. Return the constructor name that was
2294 * parsed.
2295 *
2296 * constructorName:
2297 * type ('.' identifier)?
2298 */
2299 ConstructorName parseConstructorName() {
2300 TypeName type = parseTypeName(false);
2301 Token period = null;
2302 SimpleIdentifier name = null;
2303 if (_matches(TokenType.PERIOD)) {
2304 period = getAndAdvance();
2305 name = parseSimpleIdentifier();
2306 }
2307 return new ConstructorName(type, period, name);
2308 }
2309
2310 /**
5390 * Parse a continue statement. Return the continue statement that was parsed. 2311 * Parse a continue statement. Return the continue statement that was parsed.
5391 * 2312 *
2313 * This method assumes that the current token matches `Keyword.CONTINUE`.
2314 *
5392 * continueStatement ::= 2315 * continueStatement ::=
5393 * 'continue' identifier? ';' 2316 * 'continue' identifier? ';'
5394 */ 2317 */
5395 Statement _parseContinueStatement() { 2318 Statement parseContinueStatement() {
5396 Token continueKeyword = _expectKeyword(Keyword.CONTINUE); 2319 Token continueKeyword = getAndAdvance();
5397 if (!_inLoop && !_inSwitch) { 2320 if (!_inLoop && !_inSwitch) {
5398 _reportErrorForToken( 2321 _reportErrorForToken(
5399 ParserErrorCode.CONTINUE_OUTSIDE_OF_LOOP, continueKeyword); 2322 ParserErrorCode.CONTINUE_OUTSIDE_OF_LOOP, continueKeyword);
5400 } 2323 }
5401 SimpleIdentifier label = null; 2324 SimpleIdentifier label = null;
5402 if (_matchesIdentifier()) { 2325 if (_matchesIdentifier()) {
5403 label = parseSimpleIdentifier(); 2326 label = _parseSimpleIdentifierUnchecked();
5404 } 2327 }
5405 if (_inSwitch && !_inLoop && label == null) { 2328 if (_inSwitch && !_inLoop && label == null) {
5406 _reportErrorForToken( 2329 _reportErrorForToken(
5407 ParserErrorCode.CONTINUE_WITHOUT_LABEL_IN_CASE, continueKeyword); 2330 ParserErrorCode.CONTINUE_WITHOUT_LABEL_IN_CASE, continueKeyword);
5408 } 2331 }
5409 Token semicolon = _expect(TokenType.SEMICOLON); 2332 Token semicolon = _expect(TokenType.SEMICOLON);
5410 return new ContinueStatement(continueKeyword, label, semicolon); 2333 return new ContinueStatement(continueKeyword, label, semicolon);
5411 } 2334 }
5412 2335
5413 /** 2336 /**
5414 * Parse a directive. The [commentAndMetadata] is the metadata to be 2337 * Parse a directive. The [commentAndMetadata] is the metadata to be
5415 * associated with the directive. Return the directive that was parsed. 2338 * associated with the directive. Return the directive that was parsed.
5416 * 2339 *
5417 * directive ::= 2340 * directive ::=
5418 * exportDirective 2341 * exportDirective
5419 * | libraryDirective 2342 * | libraryDirective
5420 * | importDirective 2343 * | importDirective
5421 * | partDirective 2344 * | partDirective
5422 */ 2345 */
5423 Directive _parseDirective(CommentAndMetadata commentAndMetadata) { 2346 Directive parseDirective(CommentAndMetadata commentAndMetadata) {
5424 if (_matchesKeyword(Keyword.IMPORT)) { 2347 if (_matchesKeyword(Keyword.IMPORT)) {
5425 return _parseImportDirective(commentAndMetadata); 2348 return parseImportDirective(commentAndMetadata);
5426 } else if (_matchesKeyword(Keyword.EXPORT)) { 2349 } else if (_matchesKeyword(Keyword.EXPORT)) {
5427 return _parseExportDirective(commentAndMetadata); 2350 return parseExportDirective(commentAndMetadata);
5428 } else if (_matchesKeyword(Keyword.LIBRARY)) { 2351 } else if (_matchesKeyword(Keyword.LIBRARY)) {
5429 return _parseLibraryDirective(commentAndMetadata); 2352 return parseLibraryDirective(commentAndMetadata);
5430 } else if (_matchesKeyword(Keyword.PART)) { 2353 } else if (_matchesKeyword(Keyword.PART)) {
5431 return _parsePartDirective(commentAndMetadata); 2354 return parsePartOrPartOfDirective(commentAndMetadata);
5432 } else { 2355 } else {
5433 // Internal error: this method should not have been invoked if the current 2356 // Internal error: this method should not have been invoked if the current
5434 // token was something other than one of the above. 2357 // token was something other than one of the above.
5435 throw new IllegalStateException( 2358 throw new StateError(
5436 "parseDirective invoked in an invalid state; currentToken = $_currentT oken"); 2359 "parseDirective invoked in an invalid state; currentToken = $_currentT oken");
5437 } 2360 }
5438 } 2361 }
5439 2362
5440 /** 2363 /**
2364 * Parse the script tag and directives in a compilation unit, starting with
2365 * the given [token], until the first non-directive is encountered. The
2366 * remainder of the compilation unit will not be parsed. Specifically, if
2367 * there are directives later in the file, they will not be parsed. Return the
2368 * compilation unit that was parsed.
2369 */
2370 CompilationUnit parseDirectives(Token token) {
2371 _currentToken = token;
2372 return parseDirectives2();
2373 }
2374
2375 /**
5441 * Parse the script tag and directives in a compilation unit until the first 2376 * Parse the script tag and directives in a compilation unit until the first
5442 * non-directive is encountered. Return the compilation unit that was parsed. 2377 * non-directive is encountered. Return the compilation unit that was parsed.
5443 * 2378 *
5444 * compilationUnit ::= 2379 * compilationUnit ::=
5445 * scriptTag? directive* 2380 * scriptTag? directive*
5446 */ 2381 */
5447 CompilationUnit _parseDirectives() { 2382 CompilationUnit parseDirectives2() {
5448 Token firstToken = _currentToken; 2383 Token firstToken = _currentToken;
5449 ScriptTag scriptTag = null; 2384 ScriptTag scriptTag = null;
5450 if (_matches(TokenType.SCRIPT_TAG)) { 2385 if (_matches(TokenType.SCRIPT_TAG)) {
5451 scriptTag = new ScriptTag(getAndAdvance()); 2386 scriptTag = new ScriptTag(getAndAdvance());
5452 } 2387 }
5453 List<Directive> directives = new List<Directive>(); 2388 List<Directive> directives = <Directive>[];
5454 while (!_matches(TokenType.EOF)) { 2389 while (!_matches(TokenType.EOF)) {
5455 CommentAndMetadata commentAndMetadata = _parseCommentAndMetadata(); 2390 CommentAndMetadata commentAndMetadata = parseCommentAndMetadata();
5456 if ((_matchesKeyword(Keyword.IMPORT) || 2391 Keyword keyword = _currentToken.keyword;
5457 _matchesKeyword(Keyword.EXPORT) || 2392 TokenType type = _peek().type;
5458 _matchesKeyword(Keyword.LIBRARY) || 2393 if ((keyword == Keyword.IMPORT ||
5459 _matchesKeyword(Keyword.PART)) && 2394 keyword == Keyword.EXPORT ||
5460 !_tokenMatches(_peek(), TokenType.PERIOD) && 2395 keyword == Keyword.LIBRARY ||
5461 !_tokenMatches(_peek(), TokenType.LT) && 2396 keyword == Keyword.PART) &&
5462 !_tokenMatches(_peek(), TokenType.OPEN_PAREN)) { 2397 type != TokenType.PERIOD &&
5463 directives.add(_parseDirective(commentAndMetadata)); 2398 type != TokenType.LT &&
2399 type != TokenType.OPEN_PAREN) {
2400 directives.add(parseDirective(commentAndMetadata));
5464 } else if (_matches(TokenType.SEMICOLON)) { 2401 } else if (_matches(TokenType.SEMICOLON)) {
5465 _advance(); 2402 _advance();
5466 } else { 2403 } else {
5467 while (!_matches(TokenType.EOF)) { 2404 while (!_matches(TokenType.EOF)) {
5468 _advance(); 2405 _advance();
5469 } 2406 }
5470 return new CompilationUnit(firstToken, scriptTag, directives, 2407 return new CompilationUnit(
5471 new List<CompilationUnitMember>(), _currentToken); 2408 firstToken, scriptTag, directives, null, _currentToken);
5472 } 2409 }
5473 } 2410 }
5474 return new CompilationUnit(firstToken, scriptTag, directives, 2411 return new CompilationUnit(
5475 new List<CompilationUnitMember>(), _currentToken); 2412 firstToken, scriptTag, directives, null, _currentToken);
5476 } 2413 }
5477 2414
5478 /** 2415 /**
2416 * Parse a documentation comment based on the given list of documentation
2417 * comment tokens. Return the documentation comment that was parsed, or `null`
2418 * if there was no comment.
2419 *
2420 * documentationComment ::=
2421 * multiLineComment?
2422 * | singleLineComment*
2423 */
2424 Comment parseDocumentationComment(List<DocumentationCommentToken> tokens) {
2425 if (tokens == null) {
2426 return null;
2427 }
2428 List<CommentReference> references = parseCommentReferences(tokens);
2429 return Comment.createDocumentationCommentWithReferences(tokens, references);
2430 }
2431
2432 /**
5479 * Parse a documentation comment. Return the documentation comment that was 2433 * Parse a documentation comment. Return the documentation comment that was
5480 * parsed, or `null` if there was no comment. 2434 * parsed, or `null` if there was no comment.
5481 * 2435 *
5482 * documentationComment ::= 2436 * documentationComment ::=
5483 * multiLineComment? 2437 * multiLineComment?
5484 * | singleLineComment* 2438 * | singleLineComment*
5485 */ 2439 */
5486 Comment _parseDocumentationComment() { 2440 List<DocumentationCommentToken> parseDocumentationCommentTokens() {
5487 List<DocumentationCommentToken> documentationTokens = 2441 List<DocumentationCommentToken> tokens = <DocumentationCommentToken>[];
5488 <DocumentationCommentToken>[];
5489 CommentToken commentToken = _currentToken.precedingComments; 2442 CommentToken commentToken = _currentToken.precedingComments;
5490 while (commentToken != null) { 2443 while (commentToken != null) {
5491 if (commentToken is DocumentationCommentToken) { 2444 if (commentToken is DocumentationCommentToken) {
5492 if (documentationTokens.isNotEmpty) { 2445 if (tokens.isNotEmpty) {
5493 if (commentToken.type == TokenType.SINGLE_LINE_COMMENT) { 2446 if (commentToken.type == TokenType.SINGLE_LINE_COMMENT) {
5494 if (documentationTokens[0].type != TokenType.SINGLE_LINE_COMMENT) { 2447 if (tokens[0].type != TokenType.SINGLE_LINE_COMMENT) {
5495 documentationTokens.clear(); 2448 tokens.clear();
5496 } 2449 }
5497 } else { 2450 } else {
5498 documentationTokens.clear(); 2451 tokens.clear();
5499 } 2452 }
5500 } 2453 }
5501 documentationTokens.add(commentToken); 2454 tokens.add(commentToken);
5502 } 2455 }
5503 commentToken = commentToken.next; 2456 commentToken = commentToken.next;
5504 } 2457 }
5505 if (documentationTokens.isEmpty) { 2458 return tokens.isEmpty ? null : tokens;
5506 return null;
5507 }
5508 List<CommentReference> references =
5509 _parseCommentReferences(documentationTokens);
5510 return Comment.createDocumentationCommentWithReferences(
5511 documentationTokens, references);
5512 } 2459 }
5513 2460
5514 /** 2461 /**
5515 * Parse a do statement. Return the do statement that was parsed. 2462 * Parse a do statement. Return the do statement that was parsed.
5516 * 2463 *
2464 * This method assumes that the current token matches `Keyword.DO`.
2465 *
5517 * doStatement ::= 2466 * doStatement ::=
5518 * 'do' statement 'while' '(' expression ')' ';' 2467 * 'do' statement 'while' '(' expression ')' ';'
5519 */ 2468 */
5520 Statement _parseDoStatement() { 2469 Statement parseDoStatement() {
5521 bool wasInLoop = _inLoop; 2470 bool wasInLoop = _inLoop;
5522 _inLoop = true; 2471 _inLoop = true;
5523 try { 2472 try {
5524 Token doKeyword = _expectKeyword(Keyword.DO); 2473 Token doKeyword = getAndAdvance();
5525 Statement body = parseStatement2(); 2474 Statement body = parseStatement2();
5526 Token whileKeyword = _expectKeyword(Keyword.WHILE); 2475 Token whileKeyword = _expectKeyword(Keyword.WHILE);
5527 Token leftParenthesis = _expect(TokenType.OPEN_PAREN); 2476 Token leftParenthesis = _expect(TokenType.OPEN_PAREN);
5528 Expression condition = parseExpression2(); 2477 Expression condition = parseExpression2();
5529 Token rightParenthesis = _expect(TokenType.CLOSE_PAREN); 2478 Token rightParenthesis = _expect(TokenType.CLOSE_PAREN);
5530 Token semicolon = _expect(TokenType.SEMICOLON); 2479 Token semicolon = _expect(TokenType.SEMICOLON);
5531 return new DoStatement(doKeyword, body, whileKeyword, leftParenthesis, 2480 return new DoStatement(doKeyword, body, whileKeyword, leftParenthesis,
5532 condition, rightParenthesis, semicolon); 2481 condition, rightParenthesis, semicolon);
5533 } finally { 2482 } finally {
5534 _inLoop = wasInLoop; 2483 _inLoop = wasInLoop;
5535 } 2484 }
5536 } 2485 }
5537 2486
5538 /** 2487 /**
2488 * Parse a dotted name. Return the dotted name that was parsed.
2489 *
2490 * dottedName ::=
2491 * identifier ('.' identifier)*
2492 */
2493 DottedName parseDottedName() {
2494 List<SimpleIdentifier> components = <SimpleIdentifier>[
2495 parseSimpleIdentifier()
2496 ];
2497 while (_optional(TokenType.PERIOD)) {
2498 components.add(parseSimpleIdentifier());
2499 }
2500 return new DottedName(components);
2501 }
2502
2503 /**
5539 * Parse an empty statement. Return the empty statement that was parsed. 2504 * Parse an empty statement. Return the empty statement that was parsed.
5540 * 2505 *
2506 * This method assumes that the current token matches `TokenType.SEMICOLON`.
2507 *
5541 * emptyStatement ::= 2508 * emptyStatement ::=
5542 * ';' 2509 * ';'
5543 */ 2510 */
5544 Statement _parseEmptyStatement() => new EmptyStatement(getAndAdvance()); 2511 Statement parseEmptyStatement() => new EmptyStatement(getAndAdvance());
5545
5546 EnumConstantDeclaration _parseEnumConstantDeclaration() {
5547 CommentAndMetadata commentAndMetadata = _parseCommentAndMetadata();
5548 SimpleIdentifier name;
5549 if (_matchesIdentifier()) {
5550 name = parseSimpleIdentifier();
5551 } else {
5552 name = _createSyntheticIdentifier();
5553 }
5554 if (commentAndMetadata.metadata.isNotEmpty) {
5555 _reportErrorForNode(ParserErrorCode.ANNOTATION_ON_ENUM_CONSTANT,
5556 commentAndMetadata.metadata[0]);
5557 }
5558 return new EnumConstantDeclaration(
5559 commentAndMetadata.comment, commentAndMetadata.metadata, name);
5560 }
5561 2512
5562 /** 2513 /**
5563 * Parse an enum declaration. The [commentAndMetadata] is the metadata to be 2514 * Parse an enum declaration. The [commentAndMetadata] is the metadata to be
5564 * associated with the member. Return the enum declaration that was parsed. 2515 * associated with the member. Return the enum declaration that was parsed.
5565 * 2516 *
2517 * This method assumes that the current token matches `Keyword.ENUM`.
2518 *
5566 * enumType ::= 2519 * enumType ::=
5567 * metadata 'enum' id '{' id (',' id)* (',')? '}' 2520 * metadata 'enum' id '{' id (',' id)* (',')? '}'
5568 */ 2521 */
5569 EnumDeclaration _parseEnumDeclaration(CommentAndMetadata commentAndMetadata) { 2522 EnumDeclaration parseEnumDeclaration(CommentAndMetadata commentAndMetadata) {
5570 Token keyword = _expectKeyword(Keyword.ENUM); 2523 Token keyword = getAndAdvance();
5571 SimpleIdentifier name = parseSimpleIdentifier(); 2524 SimpleIdentifier name = parseSimpleIdentifier(isDeclaration: true);
5572 Token leftBracket = null; 2525 Token leftBracket = null;
5573 List<EnumConstantDeclaration> constants = 2526 List<EnumConstantDeclaration> constants = <EnumConstantDeclaration>[];
5574 new List<EnumConstantDeclaration>();
5575 Token rightBracket = null; 2527 Token rightBracket = null;
5576 if (_matches(TokenType.OPEN_CURLY_BRACKET)) { 2528 if (_matches(TokenType.OPEN_CURLY_BRACKET)) {
5577 leftBracket = _expect(TokenType.OPEN_CURLY_BRACKET); 2529 leftBracket = getAndAdvance();
5578 if (_matchesIdentifier() || _matches(TokenType.AT)) { 2530 if (_matchesIdentifier() || _matches(TokenType.AT)) {
5579 constants.add(_parseEnumConstantDeclaration()); 2531 constants.add(_parseEnumConstantDeclaration());
5580 } else if (_matches(TokenType.COMMA) && 2532 } else if (_matches(TokenType.COMMA) &&
5581 _tokenMatchesIdentifier(_peek())) { 2533 _tokenMatchesIdentifier(_peek())) {
5582 constants.add(_parseEnumConstantDeclaration()); 2534 constants.add(_parseEnumConstantDeclaration());
5583 _reportErrorForCurrentToken(ParserErrorCode.MISSING_IDENTIFIER); 2535 _reportErrorForCurrentToken(ParserErrorCode.MISSING_IDENTIFIER);
5584 } else { 2536 } else {
5585 constants.add(_parseEnumConstantDeclaration()); 2537 constants.add(_parseEnumConstantDeclaration());
5586 _reportErrorForCurrentToken(ParserErrorCode.EMPTY_ENUM_BODY); 2538 _reportErrorForCurrentToken(ParserErrorCode.EMPTY_ENUM_BODY);
5587 } 2539 }
(...skipping 20 matching lines...) Expand all
5608 } 2560 }
5609 2561
5610 /** 2562 /**
5611 * Parse an equality expression. Return the equality expression that was 2563 * Parse an equality expression. Return the equality expression that was
5612 * parsed. 2564 * parsed.
5613 * 2565 *
5614 * equalityExpression ::= 2566 * equalityExpression ::=
5615 * relationalExpression (equalityOperator relationalExpression)? 2567 * relationalExpression (equalityOperator relationalExpression)?
5616 * | 'super' equalityOperator relationalExpression 2568 * | 'super' equalityOperator relationalExpression
5617 */ 2569 */
5618 Expression _parseEqualityExpression() { 2570 Expression parseEqualityExpression() {
5619 Expression expression; 2571 Expression expression;
5620 if (_matchesKeyword(Keyword.SUPER) && 2572 if (_currentToken.keyword == Keyword.SUPER &&
5621 _currentToken.next.type.isEqualityOperator) { 2573 _currentToken.next.type.isEqualityOperator) {
5622 expression = new SuperExpression(getAndAdvance()); 2574 expression = new SuperExpression(getAndAdvance());
5623 } else { 2575 } else {
5624 expression = _parseRelationalExpression(); 2576 expression = parseRelationalExpression();
5625 } 2577 }
5626 bool leftEqualityExpression = false; 2578 bool leftEqualityExpression = false;
5627 while (_currentToken.type.isEqualityOperator) { 2579 while (_currentToken.type.isEqualityOperator) {
5628 Token operator = getAndAdvance();
5629 if (leftEqualityExpression) { 2580 if (leftEqualityExpression) {
5630 _reportErrorForNode( 2581 _reportErrorForNode(
5631 ParserErrorCode.EQUALITY_CANNOT_BE_EQUALITY_OPERAND, expression); 2582 ParserErrorCode.EQUALITY_CANNOT_BE_EQUALITY_OPERAND, expression);
5632 } 2583 }
5633 expression = new BinaryExpression( 2584 expression = new BinaryExpression(
5634 expression, operator, _parseRelationalExpression()); 2585 expression, getAndAdvance(), parseRelationalExpression());
5635 leftEqualityExpression = true; 2586 leftEqualityExpression = true;
5636 } 2587 }
5637 return expression; 2588 return expression;
5638 } 2589 }
5639 2590
5640 /** 2591 /**
5641 * Parse an export directive. The [commentAndMetadata] is the metadata to be 2592 * Parse an export directive. The [commentAndMetadata] is the metadata to be
5642 * associated with the directive. Return the export directive that was parsed. 2593 * associated with the directive. Return the export directive that was parsed.
5643 * 2594 *
2595 * This method assumes that the current token matches `Keyword.EXPORT`.
2596 *
5644 * exportDirective ::= 2597 * exportDirective ::=
5645 * metadata 'export' stringLiteral combinator*';' 2598 * metadata 'export' stringLiteral configuration* combinator*';'
5646 */ 2599 */
5647 ExportDirective _parseExportDirective(CommentAndMetadata commentAndMetadata) { 2600 ExportDirective parseExportDirective(CommentAndMetadata commentAndMetadata) {
5648 Token exportKeyword = _expectKeyword(Keyword.EXPORT); 2601 Token exportKeyword = getAndAdvance();
5649 StringLiteral libraryUri = _parseUri(); 2602 StringLiteral libraryUri = _parseUri();
5650 List<Combinator> combinators = _parseCombinators(); 2603 List<Configuration> configurations = _parseConfigurations();
5651 Token semicolon = _expectSemicolon(); 2604 List<Combinator> combinators = parseCombinators();
2605 Token semicolon = _expect(TokenType.SEMICOLON);
5652 return new ExportDirective( 2606 return new ExportDirective(
5653 commentAndMetadata.comment, 2607 commentAndMetadata.comment,
5654 commentAndMetadata.metadata, 2608 commentAndMetadata.metadata,
5655 exportKeyword, 2609 exportKeyword,
5656 libraryUri, 2610 libraryUri,
2611 configurations,
5657 combinators, 2612 combinators,
5658 semicolon); 2613 semicolon);
5659 } 2614 }
5660 2615
5661 /** 2616 /**
2617 * Parse an expression, starting with the given [token]. Return the expression
2618 * that was parsed, or `null` if the tokens do not represent a recognizable
2619 * expression.
2620 */
2621 Expression parseExpression(Token token) {
2622 _currentToken = token;
2623 return parseExpression2();
2624 }
2625
2626 /**
2627 * Parse an expression that might contain a cascade. Return the expression
2628 * that was parsed.
2629 *
2630 * expression ::=
2631 * assignableExpression assignmentOperator expression
2632 * | conditionalExpression cascadeSection*
2633 * | throwExpression
2634 */
2635 Expression parseExpression2() {
2636 Keyword keyword = _currentToken.keyword;
2637 if (keyword == Keyword.THROW) {
2638 return parseThrowExpression();
2639 } else if (keyword == Keyword.RETHROW) {
2640 // TODO(brianwilkerson) Rethrow is a statement again.
2641 return parseRethrowExpression();
2642 }
2643 //
2644 // assignableExpression is a subset of conditionalExpression, so we can
2645 // parse a conditional expression and then determine whether it is followed
2646 // by an assignmentOperator, checking for conformance to the restricted
2647 // grammar after making that determination.
2648 //
2649 Expression expression = parseConditionalExpression();
2650 TokenType type = _currentToken.type;
2651 if (type == TokenType.PERIOD_PERIOD) {
2652 List<Expression> cascadeSections = <Expression>[];
2653 do {
2654 Expression section = parseCascadeSection();
2655 if (section != null) {
2656 cascadeSections.add(section);
2657 }
2658 } while (_currentToken.type == TokenType.PERIOD_PERIOD);
2659 return new CascadeExpression(expression, cascadeSections);
2660 } else if (type.isAssignmentOperator) {
2661 Token operator = getAndAdvance();
2662 _ensureAssignable(expression);
2663 return new AssignmentExpression(expression, operator, parseExpression2());
2664 }
2665 return expression;
2666 }
2667
2668 /**
5662 * Parse a list of expressions. Return the expression that was parsed. 2669 * Parse a list of expressions. Return the expression that was parsed.
5663 * 2670 *
5664 * expressionList ::= 2671 * expressionList ::=
5665 * expression (',' expression)* 2672 * expression (',' expression)*
5666 */ 2673 */
5667 List<Expression> _parseExpressionList() { 2674 List<Expression> parseExpressionList() {
5668 List<Expression> expressions = new List<Expression>(); 2675 List<Expression> expressions = <Expression>[parseExpression2()];
5669 expressions.add(parseExpression2());
5670 while (_optional(TokenType.COMMA)) { 2676 while (_optional(TokenType.COMMA)) {
5671 expressions.add(parseExpression2()); 2677 expressions.add(parseExpression2());
5672 } 2678 }
5673 return expressions; 2679 return expressions;
5674 } 2680 }
5675 2681
5676 /** 2682 /**
2683 * Parse an expression that does not contain any cascades. Return the
2684 * expression that was parsed.
2685 *
2686 * expressionWithoutCascade ::=
2687 * assignableExpression assignmentOperator expressionWithoutCascade
2688 * | conditionalExpression
2689 * | throwExpressionWithoutCascade
2690 */
2691 Expression parseExpressionWithoutCascade() {
2692 if (_matchesKeyword(Keyword.THROW)) {
2693 return parseThrowExpressionWithoutCascade();
2694 } else if (_matchesKeyword(Keyword.RETHROW)) {
2695 return parseRethrowExpression();
2696 }
2697 //
2698 // assignableExpression is a subset of conditionalExpression, so we can
2699 // parse a conditional expression and then determine whether it is followed
2700 // by an assignmentOperator, checking for conformance to the restricted
2701 // grammar after making that determination.
2702 //
2703 Expression expression = parseConditionalExpression();
2704 if (_currentToken.type.isAssignmentOperator) {
2705 Token operator = getAndAdvance();
2706 _ensureAssignable(expression);
2707 expression = new AssignmentExpression(
2708 expression, operator, parseExpressionWithoutCascade());
2709 }
2710 return expression;
2711 }
2712
2713 /**
2714 * Parse a class extends clause. Return the class extends clause that was
2715 * parsed.
2716 *
2717 * This method assumes that the current token matches `Keyword.EXTENDS`.
2718 *
2719 * classExtendsClause ::=
2720 * 'extends' type
2721 */
2722 ExtendsClause parseExtendsClause() {
2723 Token keyword = getAndAdvance();
2724 TypeName superclass = parseTypeName(false);
2725 _mustNotBeNullable(superclass, ParserErrorCode.NULLABLE_TYPE_IN_EXTENDS);
2726 return new ExtendsClause(keyword, superclass);
2727 }
2728
2729 /**
5677 * Parse the 'final', 'const', 'var' or type preceding a variable declaration. 2730 * Parse the 'final', 'const', 'var' or type preceding a variable declaration.
5678 * The [optional] is `true` if the keyword and type are optional. Return the 2731 * The [optional] is `true` if the keyword and type are optional. Return the
5679 * 'final', 'const', 'var' or type that was parsed. 2732 * 'final', 'const', 'var' or type that was parsed.
5680 * 2733 *
5681 * finalConstVarOrType ::= 2734 * finalConstVarOrType ::=
5682 * 'final' type? 2735 * 'final' type?
5683 * | 'const' type? 2736 * | 'const' type?
5684 * | 'var' 2737 * | 'var'
5685 * | type 2738 * | type
5686 */ 2739 */
5687 FinalConstVarOrType _parseFinalConstVarOrType(bool optional) { 2740 FinalConstVarOrType parseFinalConstVarOrType(bool optional) {
5688 Token keyword = null; 2741 Token keywordToken = null;
5689 TypeName type = null; 2742 TypeName type = null;
5690 if (_matchesKeyword(Keyword.FINAL) || _matchesKeyword(Keyword.CONST)) { 2743 Keyword keyword = _currentToken.keyword;
5691 keyword = getAndAdvance(); 2744 if (keyword == Keyword.FINAL || keyword == Keyword.CONST) {
2745 keywordToken = getAndAdvance();
5692 if (_isTypedIdentifier(_currentToken)) { 2746 if (_isTypedIdentifier(_currentToken)) {
5693 type = parseTypeName(); 2747 type = parseTypeName(false);
2748 } else {
2749 // Support `final/*=T*/ x;`
2750 type = _parseOptionalTypeNameComment();
5694 } 2751 }
5695 } else if (_matchesKeyword(Keyword.VAR)) { 2752 } else if (keyword == Keyword.VAR) {
5696 keyword = getAndAdvance(); 2753 keywordToken = getAndAdvance();
2754 // Support `var/*=T*/ x;`
2755 type = _parseOptionalTypeNameComment();
2756 if (type != null) {
2757 // Clear the keyword to prevent an error.
2758 keywordToken = null;
2759 }
2760 } else if (_isTypedIdentifier(_currentToken)) {
2761 type = parseReturnType();
2762 } else if (!optional) {
2763 _reportErrorForCurrentToken(
2764 ParserErrorCode.MISSING_CONST_FINAL_VAR_OR_TYPE);
5697 } else { 2765 } else {
5698 if (_isTypedIdentifier(_currentToken)) { 2766 // Support parameters such as `(/*=K*/ key, /*=V*/ value)`
5699 type = parseReturnType(); 2767 // This is not supported if the type is required.
5700 } else if (!optional) { 2768 type = _parseOptionalTypeNameComment();
5701 _reportErrorForCurrentToken(
5702 ParserErrorCode.MISSING_CONST_FINAL_VAR_OR_TYPE);
5703 }
5704 } 2769 }
5705 return new FinalConstVarOrType(keyword, type); 2770 return new FinalConstVarOrType(keywordToken, type);
5706 } 2771 }
5707 2772
5708 /** 2773 /**
5709 * Parse a formal parameter. At most one of `isOptional` and `isNamed` can be 2774 * Parse a formal parameter. At most one of `isOptional` and `isNamed` can be
5710 * `true`. The [kind] is the kind of parameter being expected based on the 2775 * `true`. The [kind] is the kind of parameter being expected based on the
5711 * presence or absence of group delimiters. Return the formal parameter that 2776 * presence or absence of group delimiters. Return the formal parameter that
5712 * was parsed. 2777 * was parsed.
5713 * 2778 *
5714 * defaultFormalParameter ::= 2779 * defaultFormalParameter ::=
5715 * normalFormalParameter ('=' expression)? 2780 * normalFormalParameter ('=' expression)?
5716 * 2781 *
5717 * defaultNamedParameter ::= 2782 * defaultNamedParameter ::=
5718 * normalFormalParameter (':' expression)? 2783 * normalFormalParameter (':' expression)?
5719 */ 2784 */
5720 FormalParameter _parseFormalParameter(ParameterKind kind) { 2785 FormalParameter parseFormalParameter(ParameterKind kind) {
5721 NormalFormalParameter parameter = parseNormalFormalParameter(); 2786 NormalFormalParameter parameter = parseNormalFormalParameter();
5722 if (_matches(TokenType.EQ)) { 2787 TokenType type = _currentToken.type;
5723 Token seperator = getAndAdvance(); 2788 if (type == TokenType.EQ) {
2789 Token separator = getAndAdvance();
5724 Expression defaultValue = parseExpression2(); 2790 Expression defaultValue = parseExpression2();
5725 if (kind == ParameterKind.NAMED) { 2791 if (kind == ParameterKind.NAMED) {
5726 _reportErrorForToken( 2792 _reportErrorForToken(
5727 ParserErrorCode.WRONG_SEPARATOR_FOR_NAMED_PARAMETER, seperator); 2793 ParserErrorCode.WRONG_SEPARATOR_FOR_NAMED_PARAMETER, separator);
5728 } else if (kind == ParameterKind.REQUIRED) { 2794 } else if (kind == ParameterKind.REQUIRED) {
5729 _reportErrorForNode( 2795 _reportErrorForNode(
5730 ParserErrorCode.POSITIONAL_PARAMETER_OUTSIDE_GROUP, parameter); 2796 ParserErrorCode.POSITIONAL_PARAMETER_OUTSIDE_GROUP, parameter);
5731 } 2797 }
5732 return new DefaultFormalParameter( 2798 return new DefaultFormalParameter(
5733 parameter, kind, seperator, defaultValue); 2799 parameter, kind, separator, defaultValue);
5734 } else if (_matches(TokenType.COLON)) { 2800 } else if (type == TokenType.COLON) {
5735 Token seperator = getAndAdvance(); 2801 Token separator = getAndAdvance();
5736 Expression defaultValue = parseExpression2(); 2802 Expression defaultValue = parseExpression2();
5737 if (kind == ParameterKind.POSITIONAL) { 2803 if (kind == ParameterKind.POSITIONAL) {
5738 _reportErrorForToken( 2804 _reportErrorForToken(
5739 ParserErrorCode.WRONG_SEPARATOR_FOR_POSITIONAL_PARAMETER, 2805 ParserErrorCode.WRONG_SEPARATOR_FOR_POSITIONAL_PARAMETER,
5740 seperator); 2806 separator);
5741 } else if (kind == ParameterKind.REQUIRED) { 2807 } else if (kind == ParameterKind.REQUIRED) {
5742 _reportErrorForNode( 2808 _reportErrorForNode(
5743 ParserErrorCode.NAMED_PARAMETER_OUTSIDE_GROUP, parameter); 2809 ParserErrorCode.NAMED_PARAMETER_OUTSIDE_GROUP, parameter);
5744 } 2810 }
5745 return new DefaultFormalParameter( 2811 return new DefaultFormalParameter(
5746 parameter, kind, seperator, defaultValue); 2812 parameter, kind, separator, defaultValue);
5747 } else if (kind != ParameterKind.REQUIRED) { 2813 } else if (kind != ParameterKind.REQUIRED) {
5748 return new DefaultFormalParameter(parameter, kind, null, null); 2814 return new DefaultFormalParameter(parameter, kind, null, null);
5749 } 2815 }
5750 return parameter; 2816 return parameter;
5751 } 2817 }
5752 2818
5753 /** 2819 /**
2820 * Parse a list of formal parameters. Return the formal parameters that were
2821 * parsed.
2822 *
2823 * formalParameterList ::=
2824 * '(' ')'
2825 * | '(' normalFormalParameters (',' optionalFormalParameters)? ')'
2826 * | '(' optionalFormalParameters ')'
2827 *
2828 * normalFormalParameters ::=
2829 * normalFormalParameter (',' normalFormalParameter)*
2830 *
2831 * optionalFormalParameters ::=
2832 * optionalPositionalFormalParameters
2833 * | namedFormalParameters
2834 *
2835 * optionalPositionalFormalParameters ::=
2836 * '[' defaultFormalParameter (',' defaultFormalParameter)* ']'
2837 *
2838 * namedFormalParameters ::=
2839 * '{' defaultNamedParameter (',' defaultNamedParameter)* '}'
2840 */
2841 FormalParameterList parseFormalParameterList() {
2842 if (_matches(TokenType.OPEN_PAREN)) {
2843 return _parseFormalParameterListUnchecked();
2844 }
2845 // TODO(brianwilkerson) Improve the error message.
2846 _reportErrorForCurrentToken(
2847 ParserErrorCode.EXPECTED_TOKEN, [TokenType.OPEN_PAREN.lexeme]);
2848 // Recovery: Check for an unmatched closing paren and parse parameters until
2849 // it is reached.
2850 return _parseFormalParameterListAfterParen(
2851 _createSyntheticToken(TokenType.OPEN_PAREN));
2852 }
2853
2854 /**
5754 * Parse a for statement. Return the for statement that was parsed. 2855 * Parse a for statement. Return the for statement that was parsed.
5755 * 2856 *
5756 * forStatement ::= 2857 * forStatement ::=
5757 * 'for' '(' forLoopParts ')' statement 2858 * 'for' '(' forLoopParts ')' statement
5758 * 2859 *
5759 * forLoopParts ::= 2860 * forLoopParts ::=
5760 * forInitializerStatement expression? ';' expressionList? 2861 * forInitializerStatement expression? ';' expressionList?
5761 * | declaredIdentifier 'in' expression 2862 * | declaredIdentifier 'in' expression
5762 * | identifier 'in' expression 2863 * | identifier 'in' expression
5763 * 2864 *
5764 * forInitializerStatement ::= 2865 * forInitializerStatement ::=
5765 * localVariableDeclaration ';' 2866 * localVariableDeclaration ';'
5766 * | expression? ';' 2867 * | expression? ';'
5767 */ 2868 */
5768 Statement _parseForStatement() { 2869 Statement parseForStatement() {
5769 bool wasInLoop = _inLoop; 2870 bool wasInLoop = _inLoop;
5770 _inLoop = true; 2871 _inLoop = true;
5771 try { 2872 try {
5772 Token awaitKeyword = null; 2873 Token awaitKeyword = null;
5773 if (_matchesString(_AWAIT)) { 2874 if (_matchesString(_AWAIT)) {
5774 awaitKeyword = getAndAdvance(); 2875 awaitKeyword = getAndAdvance();
5775 } 2876 }
5776 Token forKeyword = _expectKeyword(Keyword.FOR); 2877 Token forKeyword = _expectKeyword(Keyword.FOR);
5777 Token leftParenthesis = _expect(TokenType.OPEN_PAREN); 2878 Token leftParenthesis = _expect(TokenType.OPEN_PAREN);
5778 VariableDeclarationList variableList = null; 2879 VariableDeclarationList variableList = null;
5779 Expression initialization = null; 2880 Expression initialization = null;
5780 if (!_matches(TokenType.SEMICOLON)) { 2881 if (!_matches(TokenType.SEMICOLON)) {
5781 CommentAndMetadata commentAndMetadata = _parseCommentAndMetadata(); 2882 CommentAndMetadata commentAndMetadata = parseCommentAndMetadata();
5782 if (_matchesIdentifier() && 2883 if (_matchesIdentifier() &&
5783 (_tokenMatchesKeyword(_peek(), Keyword.IN) || 2884 (_tokenMatchesKeyword(_peek(), Keyword.IN) ||
5784 _tokenMatches(_peek(), TokenType.COLON))) { 2885 _tokenMatches(_peek(), TokenType.COLON))) {
5785 List<VariableDeclaration> variables = new List<VariableDeclaration>(); 2886 SimpleIdentifier variableName = _parseSimpleIdentifierUnchecked();
5786 SimpleIdentifier variableName = parseSimpleIdentifier();
5787 variables.add(new VariableDeclaration(variableName, null, null));
5788 variableList = new VariableDeclarationList(commentAndMetadata.comment, 2887 variableList = new VariableDeclarationList(commentAndMetadata.comment,
5789 commentAndMetadata.metadata, null, null, variables); 2888 commentAndMetadata.metadata, null, null, <VariableDeclaration>[
5790 } else if (_isInitializedVariableDeclaration()) { 2889 new VariableDeclaration(variableName, null, null)
2890 ]);
2891 } else if (isInitializedVariableDeclaration()) {
5791 variableList = 2892 variableList =
5792 _parseVariableDeclarationListAfterMetadata(commentAndMetadata); 2893 parseVariableDeclarationListAfterMetadata(commentAndMetadata);
5793 } else { 2894 } else {
5794 initialization = parseExpression2(); 2895 initialization = parseExpression2();
5795 } 2896 }
5796 if (_matchesKeyword(Keyword.IN) || _matches(TokenType.COLON)) { 2897 TokenType type = _currentToken.type;
5797 if (_matches(TokenType.COLON)) { 2898 if (_matchesKeyword(Keyword.IN) || type == TokenType.COLON) {
2899 if (type == TokenType.COLON) {
5798 _reportErrorForCurrentToken(ParserErrorCode.COLON_IN_PLACE_OF_IN); 2900 _reportErrorForCurrentToken(ParserErrorCode.COLON_IN_PLACE_OF_IN);
5799 } 2901 }
5800 DeclaredIdentifier loopVariable = null; 2902 DeclaredIdentifier loopVariable = null;
5801 SimpleIdentifier identifier = null; 2903 SimpleIdentifier identifier = null;
5802 if (variableList == null) { 2904 if (variableList == null) {
5803 // We found: <expression> 'in' 2905 // We found: <expression> 'in'
5804 _reportErrorForCurrentToken( 2906 _reportErrorForCurrentToken(
5805 ParserErrorCode.MISSING_VARIABLE_IN_FOR_EACH); 2907 ParserErrorCode.MISSING_VARIABLE_IN_FOR_EACH);
5806 } else { 2908 } else {
5807 NodeList<VariableDeclaration> variables = variableList.variables; 2909 NodeList<VariableDeclaration> variables = variableList.variables;
5808 if (variables.length > 1) { 2910 if (variables.length > 1) {
5809 _reportErrorForCurrentToken( 2911 _reportErrorForCurrentToken(
5810 ParserErrorCode.MULTIPLE_VARIABLES_IN_FOR_EACH, 2912 ParserErrorCode.MULTIPLE_VARIABLES_IN_FOR_EACH,
5811 [variables.length.toString()]); 2913 [variables.length.toString()]);
5812 } 2914 }
5813 VariableDeclaration variable = variables[0]; 2915 VariableDeclaration variable = variables[0];
5814 if (variable.initializer != null) { 2916 if (variable.initializer != null) {
5815 _reportErrorForCurrentToken( 2917 _reportErrorForCurrentToken(
5816 ParserErrorCode.INITIALIZED_VARIABLE_IN_FOR_EACH); 2918 ParserErrorCode.INITIALIZED_VARIABLE_IN_FOR_EACH);
5817 } 2919 }
5818 Token keyword = variableList.keyword; 2920 Token keyword = variableList.keyword;
5819 TypeName type = variableList.type; 2921 TypeName type = variableList.type;
5820 if (keyword != null || type != null) { 2922 if (keyword != null || type != null) {
5821 loopVariable = new DeclaredIdentifier(commentAndMetadata.comment, 2923 loopVariable = new DeclaredIdentifier(
5822 commentAndMetadata.metadata, keyword, type, variable.name); 2924 commentAndMetadata.comment,
2925 commentAndMetadata.metadata,
2926 keyword,
2927 type,
2928 new SimpleIdentifier(variable.name.token,
2929 isDeclaration: true));
5823 } else { 2930 } else {
5824 if (!commentAndMetadata.metadata.isEmpty) { 2931 if (commentAndMetadata.hasMetadata) {
5825 // TODO(jwren) metadata isn't allowed before the identifier in 2932 // TODO(jwren) metadata isn't allowed before the identifier in
5826 // "identifier in expression", add warning if commentAndMetadata 2933 // "identifier in expression", add warning if commentAndMetadata
5827 // has content 2934 // has content
5828 } 2935 }
5829 identifier = variable.name; 2936 identifier = variable.name;
5830 } 2937 }
5831 } 2938 }
5832 Token inKeyword = getAndAdvance(); 2939 Token inKeyword = getAndAdvance();
5833 Expression iterator = parseExpression2(); 2940 Expression iterator = parseExpression2();
5834 Token rightParenthesis = _expect(TokenType.CLOSE_PAREN); 2941 Token rightParenthesis = _expect(TokenType.CLOSE_PAREN);
(...skipping 17 matching lines...) Expand all
5852 inKeyword, 2959 inKeyword,
5853 iterator, 2960 iterator,
5854 rightParenthesis, 2961 rightParenthesis,
5855 body); 2962 body);
5856 } 2963 }
5857 } 2964 }
5858 if (awaitKeyword != null) { 2965 if (awaitKeyword != null) {
5859 _reportErrorForToken( 2966 _reportErrorForToken(
5860 ParserErrorCode.INVALID_AWAIT_IN_FOR, awaitKeyword); 2967 ParserErrorCode.INVALID_AWAIT_IN_FOR, awaitKeyword);
5861 } 2968 }
5862 Token leftSeparator = _expectSemicolon(); 2969 Token leftSeparator = _expect(TokenType.SEMICOLON);
5863 Expression condition = null; 2970 Expression condition = null;
5864 if (!_matches(TokenType.SEMICOLON)) { 2971 if (!_matches(TokenType.SEMICOLON)) {
5865 condition = parseExpression2(); 2972 condition = parseExpression2();
5866 } 2973 }
5867 Token rightSeparator = _expectSemicolon(); 2974 Token rightSeparator = _expect(TokenType.SEMICOLON);
5868 List<Expression> updaters = null; 2975 List<Expression> updaters = null;
5869 if (!_matches(TokenType.CLOSE_PAREN)) { 2976 if (!_matches(TokenType.CLOSE_PAREN)) {
5870 updaters = _parseExpressionList(); 2977 updaters = parseExpressionList();
5871 } 2978 }
5872 Token rightParenthesis = _expect(TokenType.CLOSE_PAREN); 2979 Token rightParenthesis = _expect(TokenType.CLOSE_PAREN);
5873 Statement body = parseStatement2(); 2980 Statement body = parseStatement2();
5874 return new ForStatement( 2981 return new ForStatement(
5875 forKeyword, 2982 forKeyword,
5876 leftParenthesis, 2983 leftParenthesis,
5877 variableList, 2984 variableList,
5878 initialization, 2985 initialization,
5879 leftSeparator, 2986 leftSeparator,
5880 condition, 2987 condition,
(...skipping 14 matching lines...) Expand all
5895 * not have a terminating semicolon. Return the function body that was parsed. 3002 * not have a terminating semicolon. Return the function body that was parsed.
5896 * 3003 *
5897 * functionBody ::= 3004 * functionBody ::=
5898 * '=>' expression ';' 3005 * '=>' expression ';'
5899 * | block 3006 * | block
5900 * 3007 *
5901 * functionExpressionBody ::= 3008 * functionExpressionBody ::=
5902 * '=>' expression 3009 * '=>' expression
5903 * | block 3010 * | block
5904 */ 3011 */
5905 FunctionBody _parseFunctionBody( 3012 FunctionBody parseFunctionBody(
5906 bool mayBeEmpty, ParserErrorCode emptyErrorCode, bool inExpression) { 3013 bool mayBeEmpty, ParserErrorCode emptyErrorCode, bool inExpression) {
5907 bool wasInAsync = _inAsync; 3014 bool wasInAsync = _inAsync;
5908 bool wasInGenerator = _inGenerator; 3015 bool wasInGenerator = _inGenerator;
5909 bool wasInLoop = _inLoop; 3016 bool wasInLoop = _inLoop;
5910 bool wasInSwitch = _inSwitch; 3017 bool wasInSwitch = _inSwitch;
5911 _inAsync = false; 3018 _inAsync = false;
5912 _inGenerator = false; 3019 _inGenerator = false;
5913 _inLoop = false; 3020 _inLoop = false;
5914 _inSwitch = false; 3021 _inSwitch = false;
5915 try { 3022 try {
5916 if (_matches(TokenType.SEMICOLON)) { 3023 TokenType type = _currentToken.type;
3024 if (type == TokenType.SEMICOLON) {
5917 if (!mayBeEmpty) { 3025 if (!mayBeEmpty) {
5918 _reportErrorForCurrentToken(emptyErrorCode); 3026 _reportErrorForCurrentToken(emptyErrorCode);
5919 } 3027 }
5920 return new EmptyFunctionBody(getAndAdvance()); 3028 return new EmptyFunctionBody(getAndAdvance());
5921 } else if (_matchesString(_NATIVE)) {
5922 Token nativeToken = getAndAdvance();
5923 StringLiteral stringLiteral = null;
5924 if (_matches(TokenType.STRING)) {
5925 stringLiteral = parseStringLiteral();
5926 }
5927 return new NativeFunctionBody(
5928 nativeToken, stringLiteral, _expect(TokenType.SEMICOLON));
5929 } 3029 }
5930 Token keyword = null; 3030 Token keyword = null;
5931 Token star = null; 3031 Token star = null;
5932 if (_matchesString(ASYNC)) { 3032 bool foundAsync = false;
5933 keyword = getAndAdvance(); 3033 bool foundSync = false;
5934 if (_matches(TokenType.STAR)) { 3034 if (type == TokenType.IDENTIFIER) {
5935 star = getAndAdvance(); 3035 String lexeme = _currentToken.lexeme;
5936 _inGenerator = true; 3036 if (lexeme == ASYNC) {
5937 } 3037 foundAsync = true;
5938 _inAsync = true; 3038 keyword = getAndAdvance();
5939 } else if (_matchesString(SYNC)) { 3039 if (_matches(TokenType.STAR)) {
5940 keyword = getAndAdvance(); 3040 star = getAndAdvance();
5941 if (_matches(TokenType.STAR)) { 3041 _inGenerator = true;
5942 star = getAndAdvance(); 3042 }
5943 _inGenerator = true; 3043 type = _currentToken.type;
3044 _inAsync = true;
3045 } else if (lexeme == SYNC) {
3046 foundSync = true;
3047 keyword = getAndAdvance();
3048 if (_matches(TokenType.STAR)) {
3049 star = getAndAdvance();
3050 _inGenerator = true;
3051 }
3052 type = _currentToken.type;
5944 } 3053 }
5945 } 3054 }
5946 if (_matches(TokenType.FUNCTION)) { 3055 if (type == TokenType.FUNCTION) {
5947 if (keyword != null) { 3056 if (keyword != null) {
5948 if (!_tokenMatchesString(keyword, ASYNC)) { 3057 if (!foundAsync) {
5949 _reportErrorForToken(ParserErrorCode.INVALID_SYNC, keyword); 3058 _reportErrorForToken(ParserErrorCode.INVALID_SYNC, keyword);
5950 keyword = null; 3059 keyword = null;
5951 } else if (star != null) { 3060 } else if (star != null) {
5952 _reportErrorForToken( 3061 _reportErrorForToken(
5953 ParserErrorCode.INVALID_STAR_AFTER_ASYNC, star); 3062 ParserErrorCode.INVALID_STAR_AFTER_ASYNC, star);
5954 } 3063 }
5955 } 3064 }
5956 Token functionDefinition = getAndAdvance(); 3065 Token functionDefinition = getAndAdvance();
5957 if (_matchesKeyword(Keyword.RETURN)) { 3066 if (_matchesKeyword(Keyword.RETURN)) {
5958 _reportErrorForToken(ParserErrorCode.UNEXPECTED_TOKEN, _currentToken, 3067 _reportErrorForToken(ParserErrorCode.UNEXPECTED_TOKEN, _currentToken,
5959 [_currentToken.lexeme]); 3068 [_currentToken.lexeme]);
5960 _advance(); 3069 _advance();
5961 } 3070 }
5962 Expression expression = parseExpression2(); 3071 Expression expression = parseExpression2();
5963 Token semicolon = null; 3072 Token semicolon = null;
5964 if (!inExpression) { 3073 if (!inExpression) {
5965 semicolon = _expect(TokenType.SEMICOLON); 3074 semicolon = _expect(TokenType.SEMICOLON);
5966 } 3075 }
5967 if (!_parseFunctionBodies) { 3076 if (!_parseFunctionBodies) {
5968 return new EmptyFunctionBody( 3077 return new EmptyFunctionBody(
5969 _createSyntheticToken(TokenType.SEMICOLON)); 3078 _createSyntheticToken(TokenType.SEMICOLON));
5970 } 3079 }
5971 return new ExpressionFunctionBody( 3080 return new ExpressionFunctionBody(
5972 keyword, functionDefinition, expression, semicolon); 3081 keyword, functionDefinition, expression, semicolon);
5973 } else if (_matches(TokenType.OPEN_CURLY_BRACKET)) { 3082 } else if (type == TokenType.OPEN_CURLY_BRACKET) {
5974 if (keyword != null) { 3083 if (keyword != null) {
5975 if (_tokenMatchesString(keyword, SYNC) && star == null) { 3084 if (foundSync && star == null) {
5976 _reportErrorForToken( 3085 _reportErrorForToken(
5977 ParserErrorCode.MISSING_STAR_AFTER_SYNC, keyword); 3086 ParserErrorCode.MISSING_STAR_AFTER_SYNC, keyword);
5978 } 3087 }
5979 } 3088 }
5980 if (!_parseFunctionBodies) { 3089 if (!_parseFunctionBodies) {
5981 _skipBlock(); 3090 _skipBlock();
5982 return new EmptyFunctionBody( 3091 return new EmptyFunctionBody(
5983 _createSyntheticToken(TokenType.SEMICOLON)); 3092 _createSyntheticToken(TokenType.SEMICOLON));
5984 } 3093 }
5985 return new BlockFunctionBody(keyword, star, parseBlock()); 3094 return new BlockFunctionBody(keyword, star, parseBlock());
3095 } else if (_matchesString(_NATIVE)) {
3096 Token nativeToken = getAndAdvance();
3097 StringLiteral stringLiteral = null;
3098 if (_matches(TokenType.STRING)) {
3099 stringLiteral = _parseStringLiteralUnchecked();
3100 }
3101 return new NativeFunctionBody(
3102 nativeToken, stringLiteral, _expect(TokenType.SEMICOLON));
5986 } else { 3103 } else {
5987 // Invalid function body 3104 // Invalid function body
5988 _reportErrorForCurrentToken(emptyErrorCode); 3105 _reportErrorForCurrentToken(emptyErrorCode);
5989 return new EmptyFunctionBody( 3106 return new EmptyFunctionBody(
5990 _createSyntheticToken(TokenType.SEMICOLON)); 3107 _createSyntheticToken(TokenType.SEMICOLON));
5991 } 3108 }
5992 } finally { 3109 } finally {
5993 _inAsync = wasInAsync; 3110 _inAsync = wasInAsync;
5994 _inGenerator = wasInGenerator; 3111 _inGenerator = wasInGenerator;
5995 _inLoop = wasInLoop; 3112 _inLoop = wasInLoop;
5996 _inSwitch = wasInSwitch; 3113 _inSwitch = wasInSwitch;
5997 } 3114 }
5998 } 3115 }
5999 3116
6000 /** 3117 /**
6001 * Parse a function declaration. The [commentAndMetadata] is the documentation 3118 * Parse a function declaration. The [commentAndMetadata] is the documentation
6002 * comment and metadata to be associated with the declaration. The 3119 * comment and metadata to be associated with the declaration. The
6003 * [externalKeyword] is the 'external' keyword, or `null` if the function is 3120 * [externalKeyword] is the 'external' keyword, or `null` if the function is
6004 * not external. The [returnType] is the return type, or `null` if there is no 3121 * not external. The [returnType] is the return type, or `null` if there is no
6005 * return type. The [isStatement] is `true` if the function declaration is 3122 * return type. The [isStatement] is `true` if the function declaration is
6006 * being parsed as a statement. Return the function declaration that was 3123 * being parsed as a statement. Return the function declaration that was
6007 * parsed. 3124 * parsed.
6008 * 3125 *
6009 * functionDeclaration ::= 3126 * functionDeclaration ::=
6010 * functionSignature functionBody 3127 * functionSignature functionBody
6011 * | returnType? getOrSet identifier formalParameterList functionBody 3128 * | returnType? getOrSet identifier formalParameterList functionBody
6012 */ 3129 */
6013 FunctionDeclaration _parseFunctionDeclaration( 3130 FunctionDeclaration parseFunctionDeclaration(
6014 CommentAndMetadata commentAndMetadata, 3131 CommentAndMetadata commentAndMetadata,
6015 Token externalKeyword, 3132 Token externalKeyword,
6016 TypeName returnType) { 3133 TypeName returnType) {
6017 Token keyword = null; 3134 Token keywordToken = null;
6018 bool isGetter = false; 3135 bool isGetter = false;
6019 if (_matchesKeyword(Keyword.GET) && 3136 Keyword keyword = _currentToken.keyword;
6020 !_tokenMatches(_peek(), TokenType.OPEN_PAREN)) { 3137 SimpleIdentifier name = null;
6021 keyword = getAndAdvance(); 3138 if (keyword == Keyword.GET) {
3139 keywordToken = getAndAdvance();
6022 isGetter = true; 3140 isGetter = true;
6023 } else if (_matchesKeyword(Keyword.SET) && 3141 } else if (keyword == Keyword.SET) {
6024 !_tokenMatches(_peek(), TokenType.OPEN_PAREN)) { 3142 keywordToken = getAndAdvance();
6025 keyword = getAndAdvance();
6026 } 3143 }
6027 SimpleIdentifier name = parseSimpleIdentifier(); 3144 if (keywordToken != null && _matches(TokenType.OPEN_PAREN)) {
6028 TypeParameterList typeParameters = null; 3145 name = new SimpleIdentifier(keywordToken, isDeclaration: true);
6029 if (parseGenericMethods && _matches(TokenType.LT)) { 3146 keywordToken = null;
6030 typeParameters = parseTypeParameterList(); 3147 isGetter = false;
3148 } else {
3149 name = parseSimpleIdentifier(isDeclaration: true);
6031 } 3150 }
3151 TypeParameterList typeParameters = _parseGenericMethodTypeParameters();
6032 FormalParameterList parameters = null; 3152 FormalParameterList parameters = null;
6033 if (!isGetter) { 3153 if (!isGetter) {
6034 if (_matches(TokenType.OPEN_PAREN)) { 3154 if (_matches(TokenType.OPEN_PAREN)) {
6035 parameters = parseFormalParameterList(); 3155 parameters = _parseFormalParameterListUnchecked();
6036 _validateFormalParameterList(parameters); 3156 _validateFormalParameterList(parameters);
6037 } else { 3157 } else {
6038 _reportErrorForCurrentToken( 3158 _reportErrorForCurrentToken(
6039 ParserErrorCode.MISSING_FUNCTION_PARAMETERS); 3159 ParserErrorCode.MISSING_FUNCTION_PARAMETERS);
6040 parameters = new FormalParameterList( 3160 parameters = new FormalParameterList(
6041 _createSyntheticToken(TokenType.OPEN_PAREN), 3161 _createSyntheticToken(TokenType.OPEN_PAREN),
6042 null, 3162 null,
6043 null, 3163 null,
6044 null, 3164 null,
6045 _createSyntheticToken(TokenType.CLOSE_PAREN)); 3165 _createSyntheticToken(TokenType.CLOSE_PAREN));
6046 } 3166 }
6047 } else if (_matches(TokenType.OPEN_PAREN)) { 3167 } else if (_matches(TokenType.OPEN_PAREN)) {
6048 _reportErrorForCurrentToken(ParserErrorCode.GETTER_WITH_PARAMETERS); 3168 _reportErrorForCurrentToken(ParserErrorCode.GETTER_WITH_PARAMETERS);
6049 parseFormalParameterList(); 3169 _parseFormalParameterListUnchecked();
6050 } 3170 }
6051 FunctionBody body; 3171 FunctionBody body;
6052 if (externalKeyword == null) { 3172 if (externalKeyword == null) {
6053 body = _parseFunctionBody( 3173 body = parseFunctionBody(
6054 false, ParserErrorCode.MISSING_FUNCTION_BODY, false); 3174 false, ParserErrorCode.MISSING_FUNCTION_BODY, false);
6055 } else { 3175 } else {
6056 body = new EmptyFunctionBody(_expect(TokenType.SEMICOLON)); 3176 body = new EmptyFunctionBody(_expect(TokenType.SEMICOLON));
6057 } 3177 }
6058 // if (!isStatement && matches(TokenType.SEMICOLON)) { 3178 // if (!isStatement && matches(TokenType.SEMICOLON)) {
6059 // // TODO(brianwilkerson) Improve this error message. 3179 // // TODO(brianwilkerson) Improve this error message.
6060 // reportError(ParserErrorCode.UNEXPECTED_TOKEN, currentToken.getLexeme ()); 3180 // reportError(ParserErrorCode.UNEXPECTED_TOKEN, currentToken.getLexeme ());
6061 // advance(); 3181 // advance();
6062 // } 3182 // }
6063 return new FunctionDeclaration( 3183 return new FunctionDeclaration(
6064 commentAndMetadata.comment, 3184 commentAndMetadata.comment,
6065 commentAndMetadata.metadata, 3185 commentAndMetadata.metadata,
6066 externalKeyword, 3186 externalKeyword,
6067 returnType, 3187 returnType,
6068 keyword, 3188 keywordToken,
6069 name, 3189 name,
6070 new FunctionExpression(typeParameters, parameters, body)); 3190 new FunctionExpression(typeParameters, parameters, body));
6071 } 3191 }
6072 3192
6073 /** 3193 /**
6074 * Parse a function declaration statement. Return the function declaration 3194 * Parse a function declaration statement. Return the function declaration
6075 * statement that was parsed. 3195 * statement that was parsed.
6076 * 3196 *
6077 * functionDeclarationStatement ::= 3197 * functionDeclarationStatement ::=
6078 * functionSignature functionBody 3198 * functionSignature functionBody
6079 */ 3199 */
6080 Statement _parseFunctionDeclarationStatement() { 3200 Statement parseFunctionDeclarationStatement() {
6081 Modifiers modifiers = _parseModifiers(); 3201 Modifiers modifiers = parseModifiers();
6082 _validateModifiersForFunctionDeclarationStatement(modifiers); 3202 _validateModifiersForFunctionDeclarationStatement(modifiers);
6083 return _parseFunctionDeclarationStatementAfterReturnType( 3203 return _parseFunctionDeclarationStatementAfterReturnType(
6084 _parseCommentAndMetadata(), _parseOptionalReturnType()); 3204 parseCommentAndMetadata(), _parseOptionalReturnType());
6085 } 3205 }
6086 3206
6087 /** 3207 /**
6088 * Parse a function declaration statement. The [commentAndMetadata] is the 3208 * Parse a function expression. Return the function expression that was
6089 * documentation comment and metadata to be associated with the declaration. 3209 * parsed.
6090 * The [returnType] is the return type, or `null` if there is no return type.
6091 * Return the function declaration statement that was parsed.
6092 * 3210 *
6093 * functionDeclarationStatement ::= 3211 * functionExpression ::=
6094 * functionSignature functionBody 3212 * typeParameters? formalParameterList functionExpressionBody
6095 */ 3213 */
6096 Statement _parseFunctionDeclarationStatementAfterReturnType( 3214 FunctionExpression parseFunctionExpression() {
6097 CommentAndMetadata commentAndMetadata, TypeName returnType) { 3215 TypeParameterList typeParameters = _parseGenericMethodTypeParameters();
6098 FunctionDeclaration declaration = 3216 FormalParameterList parameters = parseFormalParameterList();
6099 _parseFunctionDeclaration(commentAndMetadata, null, returnType); 3217 _validateFormalParameterList(parameters);
6100 Token propertyKeyword = declaration.propertyKeyword; 3218 FunctionBody body =
6101 if (propertyKeyword != null) { 3219 parseFunctionBody(false, ParserErrorCode.MISSING_FUNCTION_BODY, true);
6102 if ((propertyKeyword as KeywordToken).keyword == Keyword.GET) { 3220 return new FunctionExpression(typeParameters, parameters, body);
6103 _reportErrorForToken(
6104 ParserErrorCode.GETTER_IN_FUNCTION, propertyKeyword);
6105 } else {
6106 _reportErrorForToken(
6107 ParserErrorCode.SETTER_IN_FUNCTION, propertyKeyword);
6108 }
6109 }
6110 return new FunctionDeclarationStatement(declaration);
6111 } 3221 }
6112 3222
6113 /** 3223 /**
6114 * Parse a function type alias. The [commentAndMetadata] is the metadata to be
6115 * associated with the member. The [keyword] is the token representing the
6116 * 'typedef' keyword. Return the function type alias that was parsed.
6117 *
6118 * functionTypeAlias ::=
6119 * functionPrefix typeParameterList? formalParameterList ';'
6120 *
6121 * functionPrefix ::=
6122 * returnType? name
6123 */
6124 FunctionTypeAlias _parseFunctionTypeAlias(
6125 CommentAndMetadata commentAndMetadata, Token keyword) {
6126 TypeName returnType = null;
6127 if (hasReturnTypeInTypeAlias) {
6128 returnType = parseReturnType();
6129 }
6130 SimpleIdentifier name = parseSimpleIdentifier();
6131 TypeParameterList typeParameters = null;
6132 if (_matches(TokenType.LT)) {
6133 typeParameters = parseTypeParameterList();
6134 }
6135 if (_matches(TokenType.SEMICOLON) || _matches(TokenType.EOF)) {
6136 _reportErrorForCurrentToken(ParserErrorCode.MISSING_TYPEDEF_PARAMETERS);
6137 FormalParameterList parameters = new FormalParameterList(
6138 _createSyntheticToken(TokenType.OPEN_PAREN),
6139 null,
6140 null,
6141 null,
6142 _createSyntheticToken(TokenType.CLOSE_PAREN));
6143 Token semicolon = _expect(TokenType.SEMICOLON);
6144 return new FunctionTypeAlias(
6145 commentAndMetadata.comment,
6146 commentAndMetadata.metadata,
6147 keyword,
6148 returnType,
6149 name,
6150 typeParameters,
6151 parameters,
6152 semicolon);
6153 } else if (!_matches(TokenType.OPEN_PAREN)) {
6154 _reportErrorForCurrentToken(ParserErrorCode.MISSING_TYPEDEF_PARAMETERS);
6155 // TODO(brianwilkerson) Recover from this error. At the very least we
6156 // should skip to the start of the next valid compilation unit member,
6157 // allowing for the possibility of finding the typedef parameters before
6158 // that point.
6159 return new FunctionTypeAlias(
6160 commentAndMetadata.comment,
6161 commentAndMetadata.metadata,
6162 keyword,
6163 returnType,
6164 name,
6165 typeParameters,
6166 new FormalParameterList(_createSyntheticToken(TokenType.OPEN_PAREN),
6167 null, null, null, _createSyntheticToken(TokenType.CLOSE_PAREN)),
6168 _createSyntheticToken(TokenType.SEMICOLON));
6169 }
6170 FormalParameterList parameters = parseFormalParameterList();
6171 _validateFormalParameterList(parameters);
6172 Token semicolon = _expect(TokenType.SEMICOLON);
6173 return new FunctionTypeAlias(
6174 commentAndMetadata.comment,
6175 commentAndMetadata.metadata,
6176 keyword,
6177 returnType,
6178 name,
6179 typeParameters,
6180 parameters,
6181 semicolon);
6182 }
6183
6184 /**
6185 * Parse a getter. The [commentAndMetadata] is the documentation comment and 3224 * Parse a getter. The [commentAndMetadata] is the documentation comment and
6186 * metadata to be associated with the declaration. The externalKeyword] is the 3225 * metadata to be associated with the declaration. The externalKeyword] is the
6187 * 'external' token. The staticKeyword] is the static keyword, or `null` if 3226 * 'external' token. The staticKeyword] is the static keyword, or `null` if
6188 * the getter is not static. The [returnType] the return type that has already 3227 * the getter is not static. The [returnType] the return type that has already
6189 * been parsed, or `null` if there was no return type. Return the getter that 3228 * been parsed, or `null` if there was no return type. Return the getter that
6190 * was parsed. 3229 * was parsed.
6191 * 3230 *
3231 * This method assumes that the current token matches `Keyword.GET`.
3232 *
6192 * getter ::= 3233 * getter ::=
6193 * getterSignature functionBody? 3234 * getterSignature functionBody?
6194 * 3235 *
6195 * getterSignature ::= 3236 * getterSignature ::=
6196 * 'external'? 'static'? returnType? 'get' identifier 3237 * 'external'? 'static'? returnType? 'get' identifier
6197 */ 3238 */
6198 MethodDeclaration _parseGetter(CommentAndMetadata commentAndMetadata, 3239 MethodDeclaration parseGetter(CommentAndMetadata commentAndMetadata,
6199 Token externalKeyword, Token staticKeyword, TypeName returnType) { 3240 Token externalKeyword, Token staticKeyword, TypeName returnType) {
6200 Token propertyKeyword = _expectKeyword(Keyword.GET); 3241 Token propertyKeyword = getAndAdvance();
6201 SimpleIdentifier name = parseSimpleIdentifier(); 3242 SimpleIdentifier name = parseSimpleIdentifier(isDeclaration: true);
6202 if (_matches(TokenType.OPEN_PAREN) && 3243 if (_matches(TokenType.OPEN_PAREN) &&
6203 _tokenMatches(_peek(), TokenType.CLOSE_PAREN)) { 3244 _tokenMatches(_peek(), TokenType.CLOSE_PAREN)) {
6204 _reportErrorForCurrentToken(ParserErrorCode.GETTER_WITH_PARAMETERS); 3245 _reportErrorForCurrentToken(ParserErrorCode.GETTER_WITH_PARAMETERS);
6205 _advance(); 3246 _advance();
6206 _advance(); 3247 _advance();
6207 } 3248 }
6208 FunctionBody body = _parseFunctionBody( 3249 FunctionBody body = parseFunctionBody(
6209 externalKeyword != null || staticKeyword == null, 3250 externalKeyword != null || staticKeyword == null,
6210 ParserErrorCode.STATIC_GETTER_WITHOUT_BODY, 3251 ParserErrorCode.STATIC_GETTER_WITHOUT_BODY,
6211 false); 3252 false);
6212 if (externalKeyword != null && body is! EmptyFunctionBody) { 3253 if (externalKeyword != null && body is! EmptyFunctionBody) {
6213 _reportErrorForCurrentToken(ParserErrorCode.EXTERNAL_GETTER_WITH_BODY); 3254 _reportErrorForCurrentToken(ParserErrorCode.EXTERNAL_GETTER_WITH_BODY);
6214 } 3255 }
6215 return new MethodDeclaration( 3256 return new MethodDeclaration(
6216 commentAndMetadata.comment, 3257 commentAndMetadata.comment,
6217 commentAndMetadata.metadata, 3258 commentAndMetadata.metadata,
6218 externalKeyword, 3259 externalKeyword,
6219 staticKeyword, 3260 staticKeyword,
6220 returnType, 3261 returnType,
6221 propertyKeyword, 3262 propertyKeyword,
6222 null, 3263 null,
6223 name, 3264 name,
6224 null, 3265 null,
6225 null, 3266 null,
6226 body); 3267 body);
6227 } 3268 }
6228 3269
6229 /** 3270 /**
6230 * Parse a list of identifiers. Return the list of identifiers that were 3271 * Parse a list of identifiers. Return the list of identifiers that were
6231 * parsed. 3272 * parsed.
6232 * 3273 *
6233 * identifierList ::= 3274 * identifierList ::=
6234 * identifier (',' identifier)* 3275 * identifier (',' identifier)*
6235 */ 3276 */
6236 List<SimpleIdentifier> _parseIdentifierList() { 3277 List<SimpleIdentifier> parseIdentifierList() {
6237 List<SimpleIdentifier> identifiers = new List<SimpleIdentifier>(); 3278 List<SimpleIdentifier> identifiers = <SimpleIdentifier>[
6238 identifiers.add(parseSimpleIdentifier()); 3279 parseSimpleIdentifier()
6239 while (_matches(TokenType.COMMA)) { 3280 ];
6240 _advance(); 3281 while (_optional(TokenType.COMMA)) {
6241 identifiers.add(parseSimpleIdentifier()); 3282 identifiers.add(parseSimpleIdentifier());
6242 } 3283 }
6243 return identifiers; 3284 return identifiers;
6244 } 3285 }
6245 3286
6246 /** 3287 /**
3288 * Parse an if-null expression. Return the if-null expression that was
3289 * parsed.
3290 *
3291 * ifNullExpression ::= logicalOrExpression ('??' logicalOrExpression)*
3292 */
3293 Expression parseIfNullExpression() {
3294 Expression expression = parseLogicalOrExpression();
3295 while (_currentToken.type == TokenType.QUESTION_QUESTION) {
3296 expression = new BinaryExpression(
3297 expression, getAndAdvance(), parseLogicalOrExpression());
3298 }
3299 return expression;
3300 }
3301
3302 /**
6247 * Parse an if statement. Return the if statement that was parsed. 3303 * Parse an if statement. Return the if statement that was parsed.
6248 * 3304 *
3305 * This method assumes that the current token matches `Keyword.IF`.
3306 *
6249 * ifStatement ::= 3307 * ifStatement ::=
6250 * 'if' '(' expression ')' statement ('else' statement)? 3308 * 'if' '(' expression ')' statement ('else' statement)?
6251 */ 3309 */
6252 Statement _parseIfStatement() { 3310 Statement parseIfStatement() {
6253 Token ifKeyword = _expectKeyword(Keyword.IF); 3311 Token ifKeyword = getAndAdvance();
6254 Token leftParenthesis = _expect(TokenType.OPEN_PAREN); 3312 Token leftParenthesis = _expect(TokenType.OPEN_PAREN);
6255 Expression condition = parseExpression2(); 3313 Expression condition = parseExpression2();
6256 Token rightParenthesis = _expect(TokenType.CLOSE_PAREN); 3314 Token rightParenthesis = _expect(TokenType.CLOSE_PAREN);
6257 Statement thenStatement = parseStatement2(); 3315 Statement thenStatement = parseStatement2();
6258 Token elseKeyword = null; 3316 Token elseKeyword = null;
6259 Statement elseStatement = null; 3317 Statement elseStatement = null;
6260 if (_matchesKeyword(Keyword.ELSE)) { 3318 if (_matchesKeyword(Keyword.ELSE)) {
6261 elseKeyword = getAndAdvance(); 3319 elseKeyword = getAndAdvance();
6262 elseStatement = parseStatement2(); 3320 elseStatement = parseStatement2();
6263 } 3321 }
6264 return new IfStatement(ifKeyword, leftParenthesis, condition, 3322 return new IfStatement(ifKeyword, leftParenthesis, condition,
6265 rightParenthesis, thenStatement, elseKeyword, elseStatement); 3323 rightParenthesis, thenStatement, elseKeyword, elseStatement);
6266 } 3324 }
6267 3325
6268 /** 3326 /**
3327 * Parse an implements clause. Return the implements clause that was parsed.
3328 *
3329 * This method assumes that the current token matches `Keyword.IMPLEMENTS`.
3330 *
3331 * implementsClause ::=
3332 * 'implements' type (',' type)*
3333 */
3334 ImplementsClause parseImplementsClause() {
3335 Token keyword = getAndAdvance();
3336 List<TypeName> interfaces = <TypeName>[];
3337 do {
3338 TypeName typeName = parseTypeName(false);
3339 _mustNotBeNullable(typeName, ParserErrorCode.NULLABLE_TYPE_IN_IMPLEMENTS);
3340 interfaces.add(typeName);
3341 } while (_optional(TokenType.COMMA));
3342 return new ImplementsClause(keyword, interfaces);
3343 }
3344
3345 /**
6269 * Parse an import directive. The [commentAndMetadata] is the metadata to be 3346 * Parse an import directive. The [commentAndMetadata] is the metadata to be
6270 * associated with the directive. Return the import directive that was parsed. 3347 * associated with the directive. Return the import directive that was parsed.
6271 * 3348 *
3349 * This method assumes that the current token matches `Keyword.IMPORT`.
3350 *
6272 * importDirective ::= 3351 * importDirective ::=
6273 * metadata 'import' stringLiteral (deferred)? ('as' identifier)? comb inator*';' 3352 * metadata 'import' stringLiteral configuration* (deferred)? ('as' id entifier)? combinator*';'
6274 */ 3353 */
6275 ImportDirective _parseImportDirective(CommentAndMetadata commentAndMetadata) { 3354 ImportDirective parseImportDirective(CommentAndMetadata commentAndMetadata) {
6276 Token importKeyword = _expectKeyword(Keyword.IMPORT); 3355 Token importKeyword = getAndAdvance();
6277 StringLiteral libraryUri = _parseUri(); 3356 StringLiteral libraryUri = _parseUri();
3357 List<Configuration> configurations = _parseConfigurations();
6278 Token deferredToken = null; 3358 Token deferredToken = null;
6279 Token asToken = null; 3359 Token asToken = null;
6280 SimpleIdentifier prefix = null; 3360 SimpleIdentifier prefix = null;
6281 if (_matchesKeyword(Keyword.DEFERRED)) { 3361 if (_matchesKeyword(Keyword.DEFERRED)) {
6282 deferredToken = getAndAdvance(); 3362 deferredToken = getAndAdvance();
6283 } 3363 }
6284 if (_matchesKeyword(Keyword.AS)) { 3364 if (_matchesKeyword(Keyword.AS)) {
6285 asToken = getAndAdvance(); 3365 asToken = getAndAdvance();
6286 prefix = parseSimpleIdentifier(); 3366 prefix = parseSimpleIdentifier(isDeclaration: true);
6287 } else if (deferredToken != null) { 3367 } else if (deferredToken != null) {
6288 _reportErrorForCurrentToken( 3368 _reportErrorForCurrentToken(
6289 ParserErrorCode.MISSING_PREFIX_IN_DEFERRED_IMPORT); 3369 ParserErrorCode.MISSING_PREFIX_IN_DEFERRED_IMPORT);
6290 } else if (!_matches(TokenType.SEMICOLON) && 3370 } else if (!_matches(TokenType.SEMICOLON) &&
6291 !_matchesString(_SHOW) && 3371 !_matchesString(_SHOW) &&
6292 !_matchesString(_HIDE)) { 3372 !_matchesString(_HIDE)) {
6293 Token nextToken = _peek(); 3373 Token nextToken = _peek();
6294 if (_tokenMatchesKeyword(nextToken, Keyword.AS) || 3374 if (_tokenMatchesKeyword(nextToken, Keyword.AS) ||
6295 _tokenMatchesString(nextToken, _SHOW) || 3375 _tokenMatchesString(nextToken, _SHOW) ||
6296 _tokenMatchesString(nextToken, _HIDE)) { 3376 _tokenMatchesString(nextToken, _HIDE)) {
6297 _reportErrorForCurrentToken( 3377 _reportErrorForCurrentToken(
6298 ParserErrorCode.UNEXPECTED_TOKEN, [_currentToken]); 3378 ParserErrorCode.UNEXPECTED_TOKEN, [_currentToken]);
6299 _advance(); 3379 _advance();
6300 if (_matchesKeyword(Keyword.AS)) { 3380 if (_matchesKeyword(Keyword.AS)) {
6301 asToken = getAndAdvance(); 3381 asToken = getAndAdvance();
6302 prefix = parseSimpleIdentifier(); 3382 prefix = parseSimpleIdentifier(isDeclaration: true);
6303 } 3383 }
6304 } 3384 }
6305 } 3385 }
6306 List<Combinator> combinators = _parseCombinators(); 3386 List<Combinator> combinators = parseCombinators();
6307 Token semicolon = _expectSemicolon(); 3387 Token semicolon = _expect(TokenType.SEMICOLON);
6308 return new ImportDirective( 3388 return new ImportDirective(
6309 commentAndMetadata.comment, 3389 commentAndMetadata.comment,
6310 commentAndMetadata.metadata, 3390 commentAndMetadata.metadata,
6311 importKeyword, 3391 importKeyword,
6312 libraryUri, 3392 libraryUri,
3393 configurations,
6313 deferredToken, 3394 deferredToken,
6314 asToken, 3395 asToken,
6315 prefix, 3396 prefix,
6316 combinators, 3397 combinators,
6317 semicolon); 3398 semicolon);
6318 } 3399 }
6319 3400
6320 /** 3401 /**
6321 * Parse a list of initialized identifiers. The [commentAndMetadata] is the 3402 * Parse a list of initialized identifiers. The [commentAndMetadata] is the
6322 * documentation comment and metadata to be associated with the declaration. 3403 * documentation comment and metadata to be associated with the declaration.
6323 * The [staticKeyword] is the static keyword, or `null` if the getter is not 3404 * The [staticKeyword] is the static keyword, or `null` if the getter is not
6324 * static. The [keyword] is the token representing the 'final', 'const' or 3405 * static. The [keyword] is the token representing the 'final', 'const' or
6325 * 'var' keyword, or `null` if there is no keyword. The [type] is the type 3406 * 'var' keyword, or `null` if there is no keyword. The [type] is the type
6326 * that has already been parsed, or `null` if 'var' was provided. Return the 3407 * that has already been parsed, or `null` if 'var' was provided. Return the
6327 * getter that was parsed. 3408 * getter that was parsed.
6328 * 3409 *
6329 * ?? ::= 3410 * ?? ::=
6330 * 'static'? ('var' | type) initializedIdentifierList ';' 3411 * 'static'? ('var' | type) initializedIdentifierList ';'
6331 * | 'final' type? initializedIdentifierList ';' 3412 * | 'final' type? initializedIdentifierList ';'
6332 * 3413 *
6333 * initializedIdentifierList ::= 3414 * initializedIdentifierList ::=
6334 * initializedIdentifier (',' initializedIdentifier)* 3415 * initializedIdentifier (',' initializedIdentifier)*
6335 * 3416 *
6336 * initializedIdentifier ::= 3417 * initializedIdentifier ::=
6337 * identifier ('=' expression)? 3418 * identifier ('=' expression)?
6338 */ 3419 */
6339 FieldDeclaration _parseInitializedIdentifierList( 3420 FieldDeclaration parseInitializedIdentifierList(
6340 CommentAndMetadata commentAndMetadata, 3421 CommentAndMetadata commentAndMetadata,
6341 Token staticKeyword, 3422 Token staticKeyword,
6342 Token keyword, 3423 Token keyword,
6343 TypeName type) { 3424 TypeName type) {
6344 VariableDeclarationList fieldList = 3425 VariableDeclarationList fieldList =
6345 _parseVariableDeclarationListAfterType(null, keyword, type); 3426 parseVariableDeclarationListAfterType(null, keyword, type);
6346 return new FieldDeclaration( 3427 return new FieldDeclaration(
6347 commentAndMetadata.comment, 3428 commentAndMetadata.comment,
6348 commentAndMetadata.metadata, 3429 commentAndMetadata.metadata,
6349 staticKeyword, 3430 staticKeyword,
6350 fieldList, 3431 fieldList,
6351 _expect(TokenType.SEMICOLON)); 3432 _expect(TokenType.SEMICOLON));
6352 } 3433 }
6353 3434
6354 /** 3435 /**
6355 * Parse an instance creation expression. The [keyword] is the 'new' or 3436 * Parse an instance creation expression. The [keyword] is the 'new' or
6356 * 'const' keyword that introduces the expression. Return the instance 3437 * 'const' keyword that introduces the expression. Return the instance
6357 * creation expression that was parsed. 3438 * creation expression that was parsed.
6358 * 3439 *
6359 * instanceCreationExpression ::= 3440 * instanceCreationExpression ::=
6360 * ('new' | 'const') type ('.' identifier)? argumentList 3441 * ('new' | 'const') type ('.' identifier)? argumentList
6361 */ 3442 */
6362 InstanceCreationExpression _parseInstanceCreationExpression(Token keyword) { 3443 InstanceCreationExpression parseInstanceCreationExpression(Token keyword) {
6363 ConstructorName constructorName = parseConstructorName(); 3444 ConstructorName constructorName = parseConstructorName();
6364 ArgumentList argumentList = parseArgumentList(); 3445 ArgumentList argumentList = _parseArgumentListChecked();
6365 return new InstanceCreationExpression( 3446 return new InstanceCreationExpression(
6366 keyword, constructorName, argumentList); 3447 keyword, constructorName, argumentList);
6367 } 3448 }
6368 3449
6369 /** 3450 /**
3451 * Parse a label. Return the label that was parsed.
3452 *
3453 * This method assumes that the current token matches an identifier and that
3454 * the following token matches `TokenType.COLON`.
3455 *
3456 * label ::=
3457 * identifier ':'
3458 */
3459 Label parseLabel({bool isDeclaration: false}) {
3460 SimpleIdentifier label =
3461 _parseSimpleIdentifierUnchecked(isDeclaration: isDeclaration);
3462 Token colon = getAndAdvance();
3463 return new Label(label, colon);
3464 }
3465
3466 /**
6370 * Parse a library directive. The [commentAndMetadata] is the metadata to be 3467 * Parse a library directive. The [commentAndMetadata] is the metadata to be
6371 * associated with the directive. Return the library directive that was 3468 * associated with the directive. Return the library directive that was
6372 * parsed. 3469 * parsed.
6373 * 3470 *
3471 * This method assumes that the current token matches `Keyword.LIBRARY`.
3472 *
6374 * libraryDirective ::= 3473 * libraryDirective ::=
6375 * metadata 'library' identifier ';' 3474 * metadata 'library' identifier ';'
6376 */ 3475 */
6377 LibraryDirective _parseLibraryDirective( 3476 LibraryDirective parseLibraryDirective(
6378 CommentAndMetadata commentAndMetadata) { 3477 CommentAndMetadata commentAndMetadata) {
6379 Token keyword = _expectKeyword(Keyword.LIBRARY); 3478 Token keyword = getAndAdvance();
6380 LibraryIdentifier libraryName = _parseLibraryName( 3479 LibraryIdentifier libraryName = _parseLibraryName(
6381 ParserErrorCode.MISSING_NAME_IN_LIBRARY_DIRECTIVE, keyword); 3480 ParserErrorCode.MISSING_NAME_IN_LIBRARY_DIRECTIVE, keyword);
6382 Token semicolon = _expect(TokenType.SEMICOLON); 3481 Token semicolon = _expect(TokenType.SEMICOLON);
6383 return new LibraryDirective(commentAndMetadata.comment, 3482 return new LibraryDirective(commentAndMetadata.comment,
6384 commentAndMetadata.metadata, keyword, libraryName, semicolon); 3483 commentAndMetadata.metadata, keyword, libraryName, semicolon);
6385 } 3484 }
6386 3485
6387 /** 3486 /**
6388 * Parse a library name. The [missingNameError] is the error code to be used 3487 * Parse a library identifier. Return the library identifier that was parsed.
6389 * if the library name is missing. The [missingNameToken] is the token
6390 * associated with the error produced if the library name is missing. Return
6391 * the library name that was parsed.
6392 * 3488 *
6393 * libraryName ::= 3489 * libraryIdentifier ::=
6394 * libraryIdentifier 3490 * identifier ('.' identifier)*
6395 */ 3491 */
6396 LibraryIdentifier _parseLibraryName( 3492 LibraryIdentifier parseLibraryIdentifier() {
6397 ParserErrorCode missingNameError, Token missingNameToken) { 3493 List<SimpleIdentifier> components = <SimpleIdentifier>[];
6398 if (_matchesIdentifier()) { 3494 components.add(parseSimpleIdentifier());
6399 return parseLibraryIdentifier(); 3495 while (_optional(TokenType.PERIOD)) {
6400 } else if (_matches(TokenType.STRING)) { 3496 components.add(parseSimpleIdentifier());
6401 // TODO(brianwilkerson) Recovery: This should be extended to handle
6402 // arbitrary tokens until we can find a token that can start a compilation
6403 // unit member.
6404 StringLiteral string = parseStringLiteral();
6405 _reportErrorForNode(ParserErrorCode.NON_IDENTIFIER_LIBRARY_NAME, string);
6406 } else {
6407 _reportErrorForToken(missingNameError, missingNameToken);
6408 } 3497 }
6409 List<SimpleIdentifier> components = new List<SimpleIdentifier>();
6410 components.add(_createSyntheticIdentifier());
6411 return new LibraryIdentifier(components); 3498 return new LibraryIdentifier(components);
6412 } 3499 }
6413 3500
6414 /** 3501 /**
6415 * Parse a list literal. The [modifier] is the 'const' modifier appearing 3502 * Parse a list literal. The [modifier] is the 'const' modifier appearing
6416 * before the literal, or `null` if there is no modifier. The [typeArguments] 3503 * before the literal, or `null` if there is no modifier. The [typeArguments]
6417 * is the type arguments appearing before the literal, or `null` if there are 3504 * is the type arguments appearing before the literal, or `null` if there are
6418 * no type arguments. Return the list literal that was parsed. 3505 * no type arguments. Return the list literal that was parsed.
6419 * 3506 *
3507 * This method assumes that the current token matches either
3508 * `TokenType.OPEN_SQUARE_BRACKET` or `TokenType.INDEX`.
3509 *
6420 * listLiteral ::= 3510 * listLiteral ::=
6421 * 'const'? typeArguments? '[' (expressionList ','?)? ']' 3511 * 'const'? typeArguments? '[' (expressionList ','?)? ']'
6422 */ 3512 */
6423 ListLiteral _parseListLiteral( 3513 ListLiteral parseListLiteral(Token modifier, TypeArgumentList typeArguments) {
6424 Token modifier, TypeArgumentList typeArguments) {
6425 // may be empty list literal
6426 if (_matches(TokenType.INDEX)) { 3514 if (_matches(TokenType.INDEX)) {
3515 // Split the token into two separate tokens.
6427 BeginToken leftBracket = _createToken( 3516 BeginToken leftBracket = _createToken(
6428 _currentToken, TokenType.OPEN_SQUARE_BRACKET, 3517 _currentToken, TokenType.OPEN_SQUARE_BRACKET,
6429 isBegin: true); 3518 isBegin: true);
6430 Token rightBracket = 3519 Token rightBracket =
6431 new Token(TokenType.CLOSE_SQUARE_BRACKET, _currentToken.offset + 1); 3520 new Token(TokenType.CLOSE_SQUARE_BRACKET, _currentToken.offset + 1);
6432 leftBracket.endToken = rightBracket; 3521 leftBracket.endToken = rightBracket;
6433 rightBracket.setNext(_currentToken.next); 3522 rightBracket.setNext(_currentToken.next);
6434 leftBracket.setNext(rightBracket); 3523 leftBracket.setNext(rightBracket);
6435 _currentToken.previous.setNext(leftBracket); 3524 _currentToken.previous.setNext(leftBracket);
6436 _currentToken = _currentToken.next; 3525 _currentToken = _currentToken.next;
6437 return new ListLiteral( 3526 return new ListLiteral(
6438 modifier, typeArguments, leftBracket, null, rightBracket); 3527 modifier, typeArguments, leftBracket, null, rightBracket);
6439 } 3528 }
6440 // open 3529 Token leftBracket = getAndAdvance();
6441 Token leftBracket = _expect(TokenType.OPEN_SQUARE_BRACKET);
6442 if (_matches(TokenType.CLOSE_SQUARE_BRACKET)) { 3530 if (_matches(TokenType.CLOSE_SQUARE_BRACKET)) {
6443 return new ListLiteral( 3531 return new ListLiteral(
6444 modifier, typeArguments, leftBracket, null, getAndAdvance()); 3532 modifier, typeArguments, leftBracket, null, getAndAdvance());
6445 } 3533 }
6446 bool wasInInitializer = _inInitializer; 3534 bool wasInInitializer = _inInitializer;
6447 _inInitializer = false; 3535 _inInitializer = false;
6448 try { 3536 try {
6449 List<Expression> elements = new List<Expression>(); 3537 List<Expression> elements = <Expression>[parseExpression2()];
6450 elements.add(parseExpression2());
6451 while (_optional(TokenType.COMMA)) { 3538 while (_optional(TokenType.COMMA)) {
6452 if (_matches(TokenType.CLOSE_SQUARE_BRACKET)) { 3539 if (_matches(TokenType.CLOSE_SQUARE_BRACKET)) {
6453 return new ListLiteral( 3540 return new ListLiteral(
6454 modifier, typeArguments, leftBracket, elements, getAndAdvance()); 3541 modifier, typeArguments, leftBracket, elements, getAndAdvance());
6455 } 3542 }
6456 elements.add(parseExpression2()); 3543 elements.add(parseExpression2());
6457 } 3544 }
6458 Token rightBracket = _expect(TokenType.CLOSE_SQUARE_BRACKET); 3545 Token rightBracket = _expect(TokenType.CLOSE_SQUARE_BRACKET);
6459 return new ListLiteral( 3546 return new ListLiteral(
6460 modifier, typeArguments, leftBracket, elements, rightBracket); 3547 modifier, typeArguments, leftBracket, elements, rightBracket);
6461 } finally { 3548 } finally {
6462 _inInitializer = wasInInitializer; 3549 _inInitializer = wasInInitializer;
6463 } 3550 }
6464 } 3551 }
6465 3552
6466 /** 3553 /**
6467 * Parse a list or map literal. The [modifier] is the 'const' modifier 3554 * Parse a list or map literal. The [modifier] is the 'const' modifier
6468 * appearing before the literal, or `null` if there is no modifier. Return the 3555 * appearing before the literal, or `null` if there is no modifier. Return the
6469 * list or map literal that was parsed. 3556 * list or map literal that was parsed.
6470 * 3557 *
6471 * listOrMapLiteral ::= 3558 * listOrMapLiteral ::=
6472 * listLiteral 3559 * listLiteral
6473 * | mapLiteral 3560 * | mapLiteral
6474 */ 3561 */
6475 TypedLiteral _parseListOrMapLiteral(Token modifier) { 3562 TypedLiteral parseListOrMapLiteral(Token modifier) {
6476 TypeArgumentList typeArguments = null; 3563 TypeArgumentList typeArguments = _parseOptionalTypeArguments();
6477 if (_matches(TokenType.LT)) {
6478 typeArguments = parseTypeArgumentList();
6479 }
6480 if (_matches(TokenType.OPEN_CURLY_BRACKET)) { 3564 if (_matches(TokenType.OPEN_CURLY_BRACKET)) {
6481 return _parseMapLiteral(modifier, typeArguments); 3565 return parseMapLiteral(modifier, typeArguments);
6482 } else if (_matches(TokenType.OPEN_SQUARE_BRACKET) || 3566 } else if (_matches(TokenType.OPEN_SQUARE_BRACKET) ||
6483 _matches(TokenType.INDEX)) { 3567 _matches(TokenType.INDEX)) {
6484 return _parseListLiteral(modifier, typeArguments); 3568 return parseListLiteral(modifier, typeArguments);
6485 } 3569 }
6486 _reportErrorForCurrentToken(ParserErrorCode.EXPECTED_LIST_OR_MAP_LITERAL); 3570 _reportErrorForCurrentToken(ParserErrorCode.EXPECTED_LIST_OR_MAP_LITERAL);
6487 return new ListLiteral( 3571 return new ListLiteral(
6488 modifier, 3572 modifier,
6489 typeArguments, 3573 typeArguments,
6490 _createSyntheticToken(TokenType.OPEN_SQUARE_BRACKET), 3574 _createSyntheticToken(TokenType.OPEN_SQUARE_BRACKET),
6491 null, 3575 null,
6492 _createSyntheticToken(TokenType.CLOSE_SQUARE_BRACKET)); 3576 _createSyntheticToken(TokenType.CLOSE_SQUARE_BRACKET));
6493 } 3577 }
6494 3578
6495 /** 3579 /**
6496 * Parse a logical and expression. Return the logical and expression that was 3580 * Parse a logical and expression. Return the logical and expression that was
6497 * parsed. 3581 * parsed.
6498 * 3582 *
6499 * logicalAndExpression ::= 3583 * logicalAndExpression ::=
6500 * equalityExpression ('&&' equalityExpression)* 3584 * equalityExpression ('&&' equalityExpression)*
6501 */ 3585 */
6502 Expression _parseLogicalAndExpression() { 3586 Expression parseLogicalAndExpression() {
6503 Expression expression = _parseEqualityExpression(); 3587 Expression expression = parseEqualityExpression();
6504 while (_matches(TokenType.AMPERSAND_AMPERSAND)) { 3588 while (_currentToken.type == TokenType.AMPERSAND_AMPERSAND) {
6505 Token operator = getAndAdvance();
6506 expression = new BinaryExpression( 3589 expression = new BinaryExpression(
6507 expression, operator, _parseEqualityExpression()); 3590 expression, getAndAdvance(), parseEqualityExpression());
6508 } 3591 }
6509 return expression; 3592 return expression;
6510 } 3593 }
3594
3595 /**
3596 * Parse a logical or expression. Return the logical or expression that was
3597 * parsed.
3598 *
3599 * logicalOrExpression ::=
3600 * logicalAndExpression ('||' logicalAndExpression)*
3601 */
3602 Expression parseLogicalOrExpression() {
3603 Expression expression = parseLogicalAndExpression();
3604 while (_currentToken.type == TokenType.BAR_BAR) {
3605 expression = new BinaryExpression(
3606 expression, getAndAdvance(), parseLogicalAndExpression());
3607 }
3608 return expression;
3609 }
6511 3610
6512 /** 3611 /**
6513 * Parse a map literal. The [modifier] is the 'const' modifier appearing 3612 * Parse a map literal. The [modifier] is the 'const' modifier appearing
6514 * before the literal, or `null` if there is no modifier. The [typeArguments] 3613 * before the literal, or `null` if there is no modifier. The [typeArguments]
6515 * is the type arguments that were declared, or `null` if there are no type 3614 * is the type arguments that were declared, or `null` if there are no type
6516 * arguments. Return the map literal that was parsed. 3615 * arguments. Return the map literal that was parsed.
6517 * 3616 *
3617 * This method assumes that the current token matches
3618 * `TokenType.OPEN_CURLY_BRACKET`.
3619 *
6518 * mapLiteral ::= 3620 * mapLiteral ::=
6519 * 'const'? typeArguments? '{' (mapLiteralEntry (',' mapLiteralEntry)* ','?)? '}' 3621 * 'const'? typeArguments? '{' (mapLiteralEntry (',' mapLiteralEntry)* ','?)? '}'
6520 */ 3622 */
6521 MapLiteral _parseMapLiteral(Token modifier, TypeArgumentList typeArguments) { 3623 MapLiteral parseMapLiteral(Token modifier, TypeArgumentList typeArguments) {
6522 Token leftBracket = _expect(TokenType.OPEN_CURLY_BRACKET); 3624 Token leftBracket = getAndAdvance();
6523 List<MapLiteralEntry> entries = new List<MapLiteralEntry>();
6524 if (_matches(TokenType.CLOSE_CURLY_BRACKET)) { 3625 if (_matches(TokenType.CLOSE_CURLY_BRACKET)) {
6525 return new MapLiteral( 3626 return new MapLiteral(
6526 modifier, typeArguments, leftBracket, entries, getAndAdvance()); 3627 modifier, typeArguments, leftBracket, null, getAndAdvance());
6527 } 3628 }
6528 bool wasInInitializer = _inInitializer; 3629 bool wasInInitializer = _inInitializer;
6529 _inInitializer = false; 3630 _inInitializer = false;
6530 try { 3631 try {
6531 entries.add(parseMapLiteralEntry()); 3632 List<MapLiteralEntry> entries = <MapLiteralEntry>[parseMapLiteralEntry()];
6532 while (_optional(TokenType.COMMA)) { 3633 while (_optional(TokenType.COMMA)) {
6533 if (_matches(TokenType.CLOSE_CURLY_BRACKET)) { 3634 if (_matches(TokenType.CLOSE_CURLY_BRACKET)) {
6534 return new MapLiteral( 3635 return new MapLiteral(
6535 modifier, typeArguments, leftBracket, entries, getAndAdvance()); 3636 modifier, typeArguments, leftBracket, entries, getAndAdvance());
6536 } 3637 }
6537 entries.add(parseMapLiteralEntry()); 3638 entries.add(parseMapLiteralEntry());
6538 } 3639 }
6539 Token rightBracket = _expect(TokenType.CLOSE_CURLY_BRACKET); 3640 Token rightBracket = _expect(TokenType.CLOSE_CURLY_BRACKET);
6540 return new MapLiteral( 3641 return new MapLiteral(
6541 modifier, typeArguments, leftBracket, entries, rightBracket); 3642 modifier, typeArguments, leftBracket, entries, rightBracket);
6542 } finally { 3643 } finally {
6543 _inInitializer = wasInInitializer; 3644 _inInitializer = wasInInitializer;
6544 } 3645 }
6545 } 3646 }
6546 3647
6547 /** 3648 /**
6548 * Parse a method declaration. The [commentAndMetadata] is the documentation 3649 * Parse a map literal entry. Return the map literal entry that was parsed.
6549 * comment and metadata to be associated with the declaration. The
6550 * [externalKeyword] is the 'external' token. The [staticKeyword] is the
6551 * static keyword, or `null` if the getter is not static. The [returnType] is
6552 * the return type of the method. The [name] is the name of the method. The
6553 * [parameters] is the parameters to the method. Return the method declaration
6554 * that was parsed.
6555 * 3650 *
6556 * functionDeclaration ::= 3651 * mapLiteralEntry ::=
6557 * ('external' 'static'?)? functionSignature functionBody 3652 * expression ':' expression
6558 * | 'external'? functionSignature ';'
6559 */ 3653 */
6560 MethodDeclaration _parseMethodDeclarationAfterParameters( 3654 MapLiteralEntry parseMapLiteralEntry() {
6561 CommentAndMetadata commentAndMetadata, 3655 Expression key = parseExpression2();
6562 Token externalKeyword, 3656 Token separator = _expect(TokenType.COLON);
6563 Token staticKeyword, 3657 Expression value = parseExpression2();
6564 TypeName returnType, 3658 return new MapLiteralEntry(key, separator, value);
6565 SimpleIdentifier name,
6566 TypeParameterList typeParameters,
6567 FormalParameterList parameters) {
6568 FunctionBody body = _parseFunctionBody(
6569 externalKeyword != null || staticKeyword == null,
6570 ParserErrorCode.MISSING_FUNCTION_BODY,
6571 false);
6572 if (externalKeyword != null) {
6573 if (body is! EmptyFunctionBody) {
6574 _reportErrorForNode(ParserErrorCode.EXTERNAL_METHOD_WITH_BODY, body);
6575 }
6576 } else if (staticKeyword != null) {
6577 if (body is EmptyFunctionBody && _parseFunctionBodies) {
6578 _reportErrorForNode(ParserErrorCode.ABSTRACT_STATIC_METHOD, body);
6579 }
6580 }
6581 return new MethodDeclaration(
6582 commentAndMetadata.comment,
6583 commentAndMetadata.metadata,
6584 externalKeyword,
6585 staticKeyword,
6586 returnType,
6587 null,
6588 null,
6589 name,
6590 typeParameters,
6591 parameters,
6592 body);
6593 } 3659 }
6594 3660
6595 /** 3661 /**
6596 * Parse a method declaration. The [commentAndMetadata] is the documentation
6597 * comment and metadata to be associated with the declaration. The
6598 * [externalKeyword] is the 'external' token. The [staticKeyword] is the
6599 * static keyword, or `null` if the getter is not static. The [returnType] is
6600 * the return type of the method. Return the method declaration that was
6601 * parsed.
6602 *
6603 * functionDeclaration ::=
6604 * 'external'? 'static'? functionSignature functionBody
6605 * | 'external'? functionSignature ';'
6606 */
6607 MethodDeclaration _parseMethodDeclarationAfterReturnType(
6608 CommentAndMetadata commentAndMetadata,
6609 Token externalKeyword,
6610 Token staticKeyword,
6611 TypeName returnType) {
6612 SimpleIdentifier methodName = parseSimpleIdentifier();
6613 TypeParameterList typeParameters = null;
6614 if (parseGenericMethods && _matches(TokenType.LT)) {
6615 typeParameters = parseTypeParameterList();
6616 }
6617 FormalParameterList parameters;
6618 if (!_matches(TokenType.OPEN_PAREN) &&
6619 (_matches(TokenType.OPEN_CURLY_BRACKET) ||
6620 _matches(TokenType.FUNCTION))) {
6621 _reportErrorForToken(
6622 ParserErrorCode.MISSING_METHOD_PARAMETERS, _currentToken.previous);
6623 parameters = new FormalParameterList(
6624 _createSyntheticToken(TokenType.OPEN_PAREN),
6625 null,
6626 null,
6627 null,
6628 _createSyntheticToken(TokenType.CLOSE_PAREN));
6629 } else {
6630 parameters = parseFormalParameterList();
6631 }
6632 _validateFormalParameterList(parameters);
6633 return _parseMethodDeclarationAfterParameters(
6634 commentAndMetadata,
6635 externalKeyword,
6636 staticKeyword,
6637 returnType,
6638 methodName,
6639 typeParameters,
6640 parameters);
6641 }
6642
6643 /**
6644 * Parse the modifiers preceding a declaration. This method allows the 3662 * Parse the modifiers preceding a declaration. This method allows the
6645 * modifiers to appear in any order but does generate errors for duplicated 3663 * modifiers to appear in any order but does generate errors for duplicated
6646 * modifiers. Checks for other problems, such as having the modifiers appear 3664 * modifiers. Checks for other problems, such as having the modifiers appear
6647 * in the wrong order or specifying both 'const' and 'final', are reported in 3665 * in the wrong order or specifying both 'const' and 'final', are reported in
6648 * one of the methods whose name is prefixed with `validateModifiersFor`. 3666 * one of the methods whose name is prefixed with `validateModifiersFor`.
6649 * Return the modifiers that were parsed. 3667 * Return the modifiers that were parsed.
6650 * 3668 *
6651 * modifiers ::= 3669 * modifiers ::=
6652 * ('abstract' | 'const' | 'external' | 'factory' | 'final' | 'static' | 'var')* 3670 * ('abstract' | 'const' | 'external' | 'factory' | 'final' | 'static' | 'var')*
6653 */ 3671 */
6654 Modifiers _parseModifiers() { 3672 Modifiers parseModifiers() {
6655 Modifiers modifiers = new Modifiers(); 3673 Modifiers modifiers = new Modifiers();
6656 bool progress = true; 3674 bool progress = true;
6657 while (progress) { 3675 while (progress) {
6658 if (_tokenMatches(_peek(), TokenType.PERIOD) || 3676 TokenType nextType = _peek().type;
6659 _tokenMatches(_peek(), TokenType.LT) || 3677 if (nextType == TokenType.PERIOD ||
6660 _tokenMatches(_peek(), TokenType.OPEN_PAREN)) { 3678 nextType == TokenType.LT ||
3679 nextType == TokenType.OPEN_PAREN) {
6661 return modifiers; 3680 return modifiers;
6662 } 3681 }
6663 if (_matchesKeyword(Keyword.ABSTRACT)) { 3682 Keyword keyword = _currentToken.keyword;
3683 if (keyword == Keyword.ABSTRACT) {
6664 if (modifiers.abstractKeyword != null) { 3684 if (modifiers.abstractKeyword != null) {
6665 _reportErrorForCurrentToken( 3685 _reportErrorForCurrentToken(
6666 ParserErrorCode.DUPLICATED_MODIFIER, [_currentToken.lexeme]); 3686 ParserErrorCode.DUPLICATED_MODIFIER, [_currentToken.lexeme]);
6667 _advance(); 3687 _advance();
6668 } else { 3688 } else {
6669 modifiers.abstractKeyword = getAndAdvance(); 3689 modifiers.abstractKeyword = getAndAdvance();
6670 } 3690 }
6671 } else if (_matchesKeyword(Keyword.CONST)) { 3691 } else if (keyword == Keyword.CONST) {
6672 if (modifiers.constKeyword != null) { 3692 if (modifiers.constKeyword != null) {
6673 _reportErrorForCurrentToken( 3693 _reportErrorForCurrentToken(
6674 ParserErrorCode.DUPLICATED_MODIFIER, [_currentToken.lexeme]); 3694 ParserErrorCode.DUPLICATED_MODIFIER, [_currentToken.lexeme]);
6675 _advance(); 3695 _advance();
6676 } else { 3696 } else {
6677 modifiers.constKeyword = getAndAdvance(); 3697 modifiers.constKeyword = getAndAdvance();
6678 } 3698 }
6679 } else if (_matchesKeyword(Keyword.EXTERNAL) && 3699 } else if (keyword == Keyword.EXTERNAL) {
6680 !_tokenMatches(_peek(), TokenType.PERIOD) &&
6681 !_tokenMatches(_peek(), TokenType.LT)) {
6682 if (modifiers.externalKeyword != null) { 3700 if (modifiers.externalKeyword != null) {
6683 _reportErrorForCurrentToken( 3701 _reportErrorForCurrentToken(
6684 ParserErrorCode.DUPLICATED_MODIFIER, [_currentToken.lexeme]); 3702 ParserErrorCode.DUPLICATED_MODIFIER, [_currentToken.lexeme]);
6685 _advance(); 3703 _advance();
6686 } else { 3704 } else {
6687 modifiers.externalKeyword = getAndAdvance(); 3705 modifiers.externalKeyword = getAndAdvance();
6688 } 3706 }
6689 } else if (_matchesKeyword(Keyword.FACTORY) && 3707 } else if (keyword == Keyword.FACTORY) {
6690 !_tokenMatches(_peek(), TokenType.PERIOD) &&
6691 !_tokenMatches(_peek(), TokenType.LT)) {
6692 if (modifiers.factoryKeyword != null) { 3708 if (modifiers.factoryKeyword != null) {
6693 _reportErrorForCurrentToken( 3709 _reportErrorForCurrentToken(
6694 ParserErrorCode.DUPLICATED_MODIFIER, [_currentToken.lexeme]); 3710 ParserErrorCode.DUPLICATED_MODIFIER, [_currentToken.lexeme]);
6695 _advance(); 3711 _advance();
6696 } else { 3712 } else {
6697 modifiers.factoryKeyword = getAndAdvance(); 3713 modifiers.factoryKeyword = getAndAdvance();
6698 } 3714 }
6699 } else if (_matchesKeyword(Keyword.FINAL)) { 3715 } else if (keyword == Keyword.FINAL) {
6700 if (modifiers.finalKeyword != null) { 3716 if (modifiers.finalKeyword != null) {
6701 _reportErrorForCurrentToken( 3717 _reportErrorForCurrentToken(
6702 ParserErrorCode.DUPLICATED_MODIFIER, [_currentToken.lexeme]); 3718 ParserErrorCode.DUPLICATED_MODIFIER, [_currentToken.lexeme]);
6703 _advance(); 3719 _advance();
6704 } else { 3720 } else {
6705 modifiers.finalKeyword = getAndAdvance(); 3721 modifiers.finalKeyword = getAndAdvance();
6706 } 3722 }
6707 } else if (_matchesKeyword(Keyword.STATIC) && 3723 } else if (keyword == Keyword.STATIC) {
6708 !_tokenMatches(_peek(), TokenType.PERIOD) &&
6709 !_tokenMatches(_peek(), TokenType.LT)) {
6710 if (modifiers.staticKeyword != null) { 3724 if (modifiers.staticKeyword != null) {
6711 _reportErrorForCurrentToken( 3725 _reportErrorForCurrentToken(
6712 ParserErrorCode.DUPLICATED_MODIFIER, [_currentToken.lexeme]); 3726 ParserErrorCode.DUPLICATED_MODIFIER, [_currentToken.lexeme]);
6713 _advance(); 3727 _advance();
6714 } else { 3728 } else {
6715 modifiers.staticKeyword = getAndAdvance(); 3729 modifiers.staticKeyword = getAndAdvance();
6716 } 3730 }
6717 } else if (_matchesKeyword(Keyword.VAR)) { 3731 } else if (keyword == Keyword.VAR) {
6718 if (modifiers.varKeyword != null) { 3732 if (modifiers.varKeyword != null) {
6719 _reportErrorForCurrentToken( 3733 _reportErrorForCurrentToken(
6720 ParserErrorCode.DUPLICATED_MODIFIER, [_currentToken.lexeme]); 3734 ParserErrorCode.DUPLICATED_MODIFIER, [_currentToken.lexeme]);
6721 _advance(); 3735 _advance();
6722 } else { 3736 } else {
6723 modifiers.varKeyword = getAndAdvance(); 3737 modifiers.varKeyword = getAndAdvance();
6724 } 3738 }
6725 } else { 3739 } else {
6726 progress = false; 3740 progress = false;
6727 } 3741 }
6728 } 3742 }
6729 return modifiers; 3743 return modifiers;
6730 } 3744 }
6731 3745
6732 /** 3746 /**
6733 * Parse a multiplicative expression. Return the multiplicative expression 3747 * Parse a multiplicative expression. Return the multiplicative expression
6734 * that was parsed. 3748 * that was parsed.
6735 * 3749 *
6736 * multiplicativeExpression ::= 3750 * multiplicativeExpression ::=
6737 * unaryExpression (multiplicativeOperator unaryExpression)* 3751 * unaryExpression (multiplicativeOperator unaryExpression)*
6738 * | 'super' (multiplicativeOperator unaryExpression)+ 3752 * | 'super' (multiplicativeOperator unaryExpression)+
6739 */ 3753 */
6740 Expression _parseMultiplicativeExpression() { 3754 Expression parseMultiplicativeExpression() {
6741 Expression expression; 3755 Expression expression;
6742 if (_matchesKeyword(Keyword.SUPER) && 3756 if (_currentToken.keyword == Keyword.SUPER &&
6743 _currentToken.next.type.isMultiplicativeOperator) { 3757 _currentToken.next.type.isMultiplicativeOperator) {
6744 expression = new SuperExpression(getAndAdvance()); 3758 expression = new SuperExpression(getAndAdvance());
6745 } else { 3759 } else {
6746 expression = _parseUnaryExpression(); 3760 expression = parseUnaryExpression();
6747 } 3761 }
6748 while (_currentToken.type.isMultiplicativeOperator) { 3762 while (_currentToken.type.isMultiplicativeOperator) {
6749 Token operator = getAndAdvance(); 3763 expression = new BinaryExpression(
6750 expression = 3764 expression, getAndAdvance(), parseUnaryExpression());
6751 new BinaryExpression(expression, operator, _parseUnaryExpression());
6752 } 3765 }
6753 return expression; 3766 return expression;
6754 } 3767 }
6755 3768
6756 /** 3769 /**
6757 * Parse a class native clause. Return the native clause that was parsed. 3770 * Parse a new expression. Return the new expression that was parsed.
6758 * 3771 *
6759 * classNativeClause ::= 3772 * This method assumes that the current token matches `Keyword.NEW`.
6760 * 'native' name
6761 */
6762 NativeClause _parseNativeClause() {
6763 Token keyword = getAndAdvance();
6764 StringLiteral name = parseStringLiteral();
6765 return new NativeClause(keyword, name);
6766 }
6767
6768 /**
6769 * Parse a new expression. Return the new expression that was parsed.
6770 * 3773 *
6771 * newExpression ::= 3774 * newExpression ::=
6772 * instanceCreationExpression 3775 * instanceCreationExpression
6773 */ 3776 */
6774 InstanceCreationExpression _parseNewExpression() => 3777 InstanceCreationExpression parseNewExpression() =>
6775 _parseInstanceCreationExpression(_expectKeyword(Keyword.NEW)); 3778 parseInstanceCreationExpression(getAndAdvance());
6776 3779
6777 /** 3780 /**
6778 * Parse a non-labeled statement. Return the non-labeled statement that was 3781 * Parse a non-labeled statement. Return the non-labeled statement that was
6779 * parsed. 3782 * parsed.
6780 * 3783 *
6781 * nonLabeledStatement ::= 3784 * nonLabeledStatement ::=
6782 * block 3785 * block
6783 * | assertStatement 3786 * | assertStatement
6784 * | breakStatement 3787 * | breakStatement
6785 * | continueStatement 3788 * | continueStatement
6786 * | doStatement 3789 * | doStatement
6787 * | forStatement 3790 * | forStatement
6788 * | ifStatement 3791 * | ifStatement
6789 * | returnStatement 3792 * | returnStatement
6790 * | switchStatement 3793 * | switchStatement
6791 * | tryStatement 3794 * | tryStatement
6792 * | whileStatement 3795 * | whileStatement
6793 * | variableDeclarationList ';' 3796 * | variableDeclarationList ';'
6794 * | expressionStatement 3797 * | expressionStatement
6795 * | functionSignature functionBody 3798 * | functionSignature functionBody
6796 */ 3799 */
6797 Statement _parseNonLabeledStatement() { 3800 Statement parseNonLabeledStatement() {
6798 // TODO(brianwilkerson) Pass the comment and metadata on where appropriate. 3801 // TODO(brianwilkerson) Pass the comment and metadata on where appropriate.
6799 CommentAndMetadata commentAndMetadata = _parseCommentAndMetadata(); 3802 CommentAndMetadata commentAndMetadata = parseCommentAndMetadata();
6800 if (_matches(TokenType.OPEN_CURLY_BRACKET)) { 3803 TokenType type = _currentToken.type;
3804 if (type == TokenType.OPEN_CURLY_BRACKET) {
6801 if (_tokenMatches(_peek(), TokenType.STRING)) { 3805 if (_tokenMatches(_peek(), TokenType.STRING)) {
6802 Token afterString = _skipStringLiteral(_currentToken.next); 3806 Token afterString = skipStringLiteral(_currentToken.next);
6803 if (afterString != null && afterString.type == TokenType.COLON) { 3807 if (afterString != null && afterString.type == TokenType.COLON) {
6804 return new ExpressionStatement( 3808 return new ExpressionStatement(
6805 parseExpression2(), _expect(TokenType.SEMICOLON)); 3809 parseExpression2(), _expect(TokenType.SEMICOLON));
6806 } 3810 }
6807 } 3811 }
6808 return parseBlock(); 3812 return parseBlock();
6809 } else if (_matches(TokenType.KEYWORD) && 3813 } else if (type == TokenType.KEYWORD &&
6810 !(_currentToken as KeywordToken).keyword.isPseudoKeyword) { 3814 !_currentToken.keyword.isPseudoKeyword) {
6811 Keyword keyword = (_currentToken as KeywordToken).keyword; 3815 Keyword keyword = _currentToken.keyword;
6812 // TODO(jwren) compute some metrics to figure out a better order for this 3816 // TODO(jwren) compute some metrics to figure out a better order for this
6813 // if-then sequence to optimize performance 3817 // if-then sequence to optimize performance
6814 if (keyword == Keyword.ASSERT) { 3818 if (keyword == Keyword.ASSERT) {
6815 return _parseAssertStatement(); 3819 return parseAssertStatement();
6816 } else if (keyword == Keyword.BREAK) { 3820 } else if (keyword == Keyword.BREAK) {
6817 return _parseBreakStatement(); 3821 return parseBreakStatement();
6818 } else if (keyword == Keyword.CONTINUE) { 3822 } else if (keyword == Keyword.CONTINUE) {
6819 return _parseContinueStatement(); 3823 return parseContinueStatement();
6820 } else if (keyword == Keyword.DO) { 3824 } else if (keyword == Keyword.DO) {
6821 return _parseDoStatement(); 3825 return parseDoStatement();
6822 } else if (keyword == Keyword.FOR) { 3826 } else if (keyword == Keyword.FOR) {
6823 return _parseForStatement(); 3827 return parseForStatement();
6824 } else if (keyword == Keyword.IF) { 3828 } else if (keyword == Keyword.IF) {
6825 return _parseIfStatement(); 3829 return parseIfStatement();
6826 } else if (keyword == Keyword.RETHROW) { 3830 } else if (keyword == Keyword.RETHROW) {
6827 return new ExpressionStatement( 3831 return new ExpressionStatement(
6828 _parseRethrowExpression(), _expect(TokenType.SEMICOLON)); 3832 parseRethrowExpression(), _expect(TokenType.SEMICOLON));
6829 } else if (keyword == Keyword.RETURN) { 3833 } else if (keyword == Keyword.RETURN) {
6830 return _parseReturnStatement(); 3834 return parseReturnStatement();
6831 } else if (keyword == Keyword.SWITCH) { 3835 } else if (keyword == Keyword.SWITCH) {
6832 return _parseSwitchStatement(); 3836 return parseSwitchStatement();
6833 } else if (keyword == Keyword.THROW) { 3837 } else if (keyword == Keyword.THROW) {
6834 return new ExpressionStatement( 3838 return new ExpressionStatement(
6835 _parseThrowExpression(), _expect(TokenType.SEMICOLON)); 3839 parseThrowExpression(), _expect(TokenType.SEMICOLON));
6836 } else if (keyword == Keyword.TRY) { 3840 } else if (keyword == Keyword.TRY) {
6837 return _parseTryStatement(); 3841 return parseTryStatement();
6838 } else if (keyword == Keyword.WHILE) { 3842 } else if (keyword == Keyword.WHILE) {
6839 return _parseWhileStatement(); 3843 return parseWhileStatement();
6840 } else if (keyword == Keyword.VAR || keyword == Keyword.FINAL) { 3844 } else if (keyword == Keyword.VAR || keyword == Keyword.FINAL) {
6841 return _parseVariableDeclarationStatementAfterMetadata( 3845 return parseVariableDeclarationStatementAfterMetadata(
6842 commentAndMetadata); 3846 commentAndMetadata);
6843 } else if (keyword == Keyword.VOID) { 3847 } else if (keyword == Keyword.VOID) {
6844 TypeName returnType = parseReturnType(); 3848 TypeName returnType =
3849 new TypeName(new SimpleIdentifier(getAndAdvance()), null);
3850 Token next = _currentToken.next;
6845 if (_matchesIdentifier() && 3851 if (_matchesIdentifier() &&
6846 _peek().matchesAny([ 3852 next.matchesAny(const <TokenType>[
6847 TokenType.OPEN_PAREN, 3853 TokenType.OPEN_PAREN,
6848 TokenType.OPEN_CURLY_BRACKET, 3854 TokenType.OPEN_CURLY_BRACKET,
6849 TokenType.FUNCTION 3855 TokenType.FUNCTION,
3856 TokenType.LT
6850 ])) { 3857 ])) {
6851 return _parseFunctionDeclarationStatementAfterReturnType( 3858 return _parseFunctionDeclarationStatementAfterReturnType(
6852 commentAndMetadata, returnType); 3859 commentAndMetadata, returnType);
6853 } else { 3860 } else {
6854 // 3861 //
6855 // We have found an error of some kind. Try to recover. 3862 // We have found an error of some kind. Try to recover.
6856 // 3863 //
6857 if (_matchesIdentifier()) { 3864 if (_matchesIdentifier()) {
6858 if (_peek().matchesAny( 3865 if (next.matchesAny(const <TokenType>[
6859 [TokenType.EQ, TokenType.COMMA, TokenType.SEMICOLON])) { 3866 TokenType.EQ,
3867 TokenType.COMMA,
3868 TokenType.SEMICOLON
3869 ])) {
6860 // 3870 //
6861 // We appear to have a variable declaration with a type of "void". 3871 // We appear to have a variable declaration with a type of "void".
6862 // 3872 //
6863 _reportErrorForNode(ParserErrorCode.VOID_VARIABLE, returnType); 3873 _reportErrorForNode(ParserErrorCode.VOID_VARIABLE, returnType);
6864 return _parseVariableDeclarationStatementAfterMetadata( 3874 return parseVariableDeclarationStatementAfterMetadata(
6865 commentAndMetadata); 3875 commentAndMetadata);
6866 } 3876 }
6867 } else if (_matches(TokenType.CLOSE_CURLY_BRACKET)) { 3877 } else if (_matches(TokenType.CLOSE_CURLY_BRACKET)) {
6868 // 3878 //
6869 // We appear to have found an incomplete statement at the end of a 3879 // We appear to have found an incomplete statement at the end of a
6870 // block. Parse it as a variable declaration. 3880 // block. Parse it as a variable declaration.
6871 // 3881 //
6872 return _parseVariableDeclarationStatementAfterType( 3882 return _parseVariableDeclarationStatementAfterType(
6873 commentAndMetadata, null, returnType); 3883 commentAndMetadata, null, returnType);
6874 } 3884 }
6875 _reportErrorForCurrentToken(ParserErrorCode.MISSING_STATEMENT); 3885 _reportErrorForCurrentToken(ParserErrorCode.MISSING_STATEMENT);
6876 // TODO(brianwilkerson) Recover from this error. 3886 // TODO(brianwilkerson) Recover from this error.
6877 return new EmptyStatement(_createSyntheticToken(TokenType.SEMICOLON)); 3887 return new EmptyStatement(_createSyntheticToken(TokenType.SEMICOLON));
6878 } 3888 }
6879 } else if (keyword == Keyword.CONST) { 3889 } else if (keyword == Keyword.CONST) {
6880 if (_peek().matchesAny([ 3890 Token next = _currentToken.next;
3891 if (next.matchesAny(const <TokenType>[
6881 TokenType.LT, 3892 TokenType.LT,
6882 TokenType.OPEN_CURLY_BRACKET, 3893 TokenType.OPEN_CURLY_BRACKET,
6883 TokenType.OPEN_SQUARE_BRACKET, 3894 TokenType.OPEN_SQUARE_BRACKET,
6884 TokenType.INDEX 3895 TokenType.INDEX
6885 ])) { 3896 ])) {
6886 return new ExpressionStatement( 3897 return new ExpressionStatement(
6887 parseExpression2(), _expect(TokenType.SEMICOLON)); 3898 parseExpression2(), _expect(TokenType.SEMICOLON));
6888 } else if (_tokenMatches(_peek(), TokenType.IDENTIFIER)) { 3899 } else if (_tokenMatches(next, TokenType.IDENTIFIER)) {
6889 Token afterType = _skipTypeName(_peek()); 3900 Token afterType = skipTypeName(next);
6890 if (afterType != null) { 3901 if (afterType != null) {
6891 if (_tokenMatches(afterType, TokenType.OPEN_PAREN) || 3902 if (_tokenMatches(afterType, TokenType.OPEN_PAREN) ||
6892 (_tokenMatches(afterType, TokenType.PERIOD) && 3903 (_tokenMatches(afterType, TokenType.PERIOD) &&
6893 _tokenMatches(afterType.next, TokenType.IDENTIFIER) && 3904 _tokenMatches(afterType.next, TokenType.IDENTIFIER) &&
6894 _tokenMatches(afterType.next.next, TokenType.OPEN_PAREN))) { 3905 _tokenMatches(afterType.next.next, TokenType.OPEN_PAREN))) {
6895 return new ExpressionStatement( 3906 return new ExpressionStatement(
6896 parseExpression2(), _expect(TokenType.SEMICOLON)); 3907 parseExpression2(), _expect(TokenType.SEMICOLON));
6897 } 3908 }
6898 } 3909 }
6899 } 3910 }
6900 return _parseVariableDeclarationStatementAfterMetadata( 3911 return parseVariableDeclarationStatementAfterMetadata(
6901 commentAndMetadata); 3912 commentAndMetadata);
6902 } else if (keyword == Keyword.NEW || 3913 } else if (keyword == Keyword.NEW ||
6903 keyword == Keyword.TRUE || 3914 keyword == Keyword.TRUE ||
6904 keyword == Keyword.FALSE || 3915 keyword == Keyword.FALSE ||
6905 keyword == Keyword.NULL || 3916 keyword == Keyword.NULL ||
6906 keyword == Keyword.SUPER || 3917 keyword == Keyword.SUPER ||
6907 keyword == Keyword.THIS) { 3918 keyword == Keyword.THIS) {
6908 return new ExpressionStatement( 3919 return new ExpressionStatement(
6909 parseExpression2(), _expect(TokenType.SEMICOLON)); 3920 parseExpression2(), _expect(TokenType.SEMICOLON));
6910 } else { 3921 } else {
6911 // 3922 //
6912 // We have found an error of some kind. Try to recover. 3923 // We have found an error of some kind. Try to recover.
6913 // 3924 //
6914 _reportErrorForCurrentToken(ParserErrorCode.MISSING_STATEMENT); 3925 _reportErrorForCurrentToken(ParserErrorCode.MISSING_STATEMENT);
6915 return new EmptyStatement(_createSyntheticToken(TokenType.SEMICOLON)); 3926 return new EmptyStatement(_createSyntheticToken(TokenType.SEMICOLON));
6916 } 3927 }
6917 } else if (_inGenerator && _matchesString(_YIELD)) { 3928 } else if (_inGenerator && _matchesString(_YIELD)) {
6918 return _parseYieldStatement(); 3929 return parseYieldStatement();
6919 } else if (_inAsync && _matchesString(_AWAIT)) { 3930 } else if (_inAsync && _matchesString(_AWAIT)) {
6920 if (_tokenMatchesKeyword(_peek(), Keyword.FOR)) { 3931 if (_tokenMatchesKeyword(_peek(), Keyword.FOR)) {
6921 return _parseForStatement(); 3932 return parseForStatement();
6922 } 3933 }
6923 return new ExpressionStatement( 3934 return new ExpressionStatement(
6924 parseExpression2(), _expect(TokenType.SEMICOLON)); 3935 parseExpression2(), _expect(TokenType.SEMICOLON));
6925 } else if (_matchesString(_AWAIT) && 3936 } else if (_matchesString(_AWAIT) &&
6926 _tokenMatchesKeyword(_peek(), Keyword.FOR)) { 3937 _tokenMatchesKeyword(_peek(), Keyword.FOR)) {
6927 Token awaitToken = _currentToken; 3938 Token awaitToken = _currentToken;
6928 Statement statement = _parseForStatement(); 3939 Statement statement = parseForStatement();
6929 if (statement is! ForStatement) { 3940 if (statement is! ForStatement) {
6930 _reportErrorForToken( 3941 _reportErrorForToken(
6931 CompileTimeErrorCode.ASYNC_FOR_IN_WRONG_CONTEXT, awaitToken); 3942 CompileTimeErrorCode.ASYNC_FOR_IN_WRONG_CONTEXT, awaitToken);
6932 } 3943 }
6933 return statement; 3944 return statement;
6934 } else if (_matches(TokenType.SEMICOLON)) { 3945 } else if (type == TokenType.SEMICOLON) {
6935 return _parseEmptyStatement(); 3946 return parseEmptyStatement();
6936 } else if (_isInitializedVariableDeclaration()) { 3947 } else if (isInitializedVariableDeclaration()) {
6937 return _parseVariableDeclarationStatementAfterMetadata( 3948 return parseVariableDeclarationStatementAfterMetadata(commentAndMetadata);
6938 commentAndMetadata); 3949 } else if (isFunctionDeclaration()) {
6939 } else if (_isFunctionDeclaration()) { 3950 return parseFunctionDeclarationStatement();
6940 return _parseFunctionDeclarationStatement(); 3951 } else if (type == TokenType.CLOSE_CURLY_BRACKET) {
6941 } else if (_matches(TokenType.CLOSE_CURLY_BRACKET)) {
6942 _reportErrorForCurrentToken(ParserErrorCode.MISSING_STATEMENT); 3952 _reportErrorForCurrentToken(ParserErrorCode.MISSING_STATEMENT);
6943 return new EmptyStatement(_createSyntheticToken(TokenType.SEMICOLON)); 3953 return new EmptyStatement(_createSyntheticToken(TokenType.SEMICOLON));
6944 } else { 3954 } else {
6945 return new ExpressionStatement(parseExpression2(), _expectSemicolon()); 3955 return new ExpressionStatement(
3956 parseExpression2(), _expect(TokenType.SEMICOLON));
6946 } 3957 }
6947 } 3958 }
6948 3959
6949 /** 3960 /**
3961 * Parse a normal formal parameter. Return the normal formal parameter that
3962 * was parsed.
3963 *
3964 * normalFormalParameter ::=
3965 * functionSignature
3966 * | fieldFormalParameter
3967 * | simpleFormalParameter
3968 *
3969 * functionSignature:
3970 * metadata returnType? identifier typeParameters? formalParameterList
3971 *
3972 * fieldFormalParameter ::=
3973 * metadata finalConstVarOrType? 'this' '.' identifier
3974 *
3975 * simpleFormalParameter ::=
3976 * declaredIdentifier
3977 * | metadata identifier
3978 */
3979 NormalFormalParameter parseNormalFormalParameter() {
3980 CommentAndMetadata commentAndMetadata = parseCommentAndMetadata();
3981 FinalConstVarOrType holder = parseFinalConstVarOrType(true);
3982 Token thisKeyword = null;
3983 Token period = null;
3984 if (_matchesKeyword(Keyword.THIS)) {
3985 thisKeyword = getAndAdvance();
3986 period = _expect(TokenType.PERIOD);
3987 }
3988 SimpleIdentifier identifier = parseSimpleIdentifier();
3989 TypeParameterList typeParameters = _parseGenericMethodTypeParameters();
3990 if (_matches(TokenType.OPEN_PAREN)) {
3991 FormalParameterList parameters = _parseFormalParameterListUnchecked();
3992 if (thisKeyword == null) {
3993 if (holder.keyword != null) {
3994 _reportErrorForToken(
3995 ParserErrorCode.FUNCTION_TYPED_PARAMETER_VAR, holder.keyword);
3996 }
3997 Token question = null;
3998 if (enableNnbd && _matches(TokenType.QUESTION)) {
3999 question = getAndAdvance();
4000 }
4001 return new FunctionTypedFormalParameter(
4002 commentAndMetadata.comment,
4003 commentAndMetadata.metadata,
4004 holder.type,
4005 new SimpleIdentifier(identifier.token, isDeclaration: true),
4006 typeParameters,
4007 parameters,
4008 question: question);
4009 } else {
4010 return new FieldFormalParameter(
4011 commentAndMetadata.comment,
4012 commentAndMetadata.metadata,
4013 holder.keyword,
4014 holder.type,
4015 thisKeyword,
4016 period,
4017 identifier,
4018 typeParameters,
4019 parameters);
4020 }
4021 } else if (typeParameters != null) {
4022 // TODO(brianwilkerson) Report an error. It looks like a function-typed
4023 // parameter with no parameter list.
4024 //_reportErrorForToken(ParserErrorCode.MISSING_PARAMETERS, typeParameters. endToken);
4025 }
4026 TypeName type = holder.type;
4027 if (type != null) {
4028 if (_tokenMatchesKeyword(type.name.beginToken, Keyword.VOID)) {
4029 _reportErrorForToken(
4030 ParserErrorCode.VOID_PARAMETER, type.name.beginToken);
4031 } else if (holder.keyword != null &&
4032 _tokenMatchesKeyword(holder.keyword, Keyword.VAR)) {
4033 _reportErrorForToken(ParserErrorCode.VAR_AND_TYPE, holder.keyword);
4034 }
4035 }
4036 if (thisKeyword != null) {
4037 // TODO(brianwilkerson) If there are type parameters but no parameters,
4038 // should we create a synthetic empty parameter list here so we can
4039 // capture the type parameters?
4040 return new FieldFormalParameter(
4041 commentAndMetadata.comment,
4042 commentAndMetadata.metadata,
4043 holder.keyword,
4044 holder.type,
4045 thisKeyword,
4046 period,
4047 identifier,
4048 null,
4049 null);
4050 }
4051 return new SimpleFormalParameter(
4052 commentAndMetadata.comment,
4053 commentAndMetadata.metadata,
4054 holder.keyword,
4055 holder.type,
4056 new SimpleIdentifier(identifier.token, isDeclaration: true));
4057 }
4058
4059 /**
6950 * Parse an operator declaration. The [commentAndMetadata] is the 4060 * Parse an operator declaration. The [commentAndMetadata] is the
6951 * documentation comment and metadata to be associated with the declaration. 4061 * documentation comment and metadata to be associated with the declaration.
6952 * The [externalKeyword] is the 'external' token. The [returnType] is the 4062 * The [externalKeyword] is the 'external' token. The [returnType] is the
6953 * return type that has already been parsed, or `null` if there was no return 4063 * return type that has already been parsed, or `null` if there was no return
6954 * type. Return the operator declaration that was parsed. 4064 * type. Return the operator declaration that was parsed.
6955 * 4065 *
6956 * operatorDeclaration ::= 4066 * operatorDeclaration ::=
6957 * operatorSignature (';' | functionBody) 4067 * operatorSignature (';' | functionBody)
6958 * 4068 *
6959 * operatorSignature ::= 4069 * operatorSignature ::=
6960 * 'external'? returnType? 'operator' operator formalParameterList 4070 * 'external'? returnType? 'operator' operator formalParameterList
6961 */ 4071 */
6962 MethodDeclaration _parseOperator(CommentAndMetadata commentAndMetadata, 4072 MethodDeclaration parseOperator(CommentAndMetadata commentAndMetadata,
6963 Token externalKeyword, TypeName returnType) { 4073 Token externalKeyword, TypeName returnType) {
6964 Token operatorKeyword; 4074 Token operatorKeyword;
6965 if (_matchesKeyword(Keyword.OPERATOR)) { 4075 if (_matchesKeyword(Keyword.OPERATOR)) {
6966 operatorKeyword = getAndAdvance(); 4076 operatorKeyword = getAndAdvance();
6967 } else { 4077 } else {
6968 _reportErrorForToken( 4078 _reportErrorForToken(
6969 ParserErrorCode.MISSING_KEYWORD_OPERATOR, _currentToken); 4079 ParserErrorCode.MISSING_KEYWORD_OPERATOR, _currentToken);
6970 operatorKeyword = _createSyntheticKeyword(Keyword.OPERATOR); 4080 operatorKeyword = _createSyntheticKeyword(Keyword.OPERATOR);
6971 } 4081 }
6972 if (!_currentToken.isUserDefinableOperator) { 4082 return _parseOperatorAfterKeyword(
6973 _reportErrorForCurrentToken( 4083 commentAndMetadata, externalKeyword, returnType, operatorKeyword);
6974 ParserErrorCode.NON_USER_DEFINABLE_OPERATOR, [_currentToken.lexeme]);
6975 }
6976 SimpleIdentifier name = new SimpleIdentifier(getAndAdvance());
6977 if (_matches(TokenType.EQ)) {
6978 Token previous = _currentToken.previous;
6979 if ((_tokenMatches(previous, TokenType.EQ_EQ) ||
6980 _tokenMatches(previous, TokenType.BANG_EQ)) &&
6981 _currentToken.offset == previous.offset + 2) {
6982 _reportErrorForCurrentToken(ParserErrorCode.INVALID_OPERATOR,
6983 ["${previous.lexeme}${_currentToken.lexeme}"]);
6984 _advance();
6985 }
6986 }
6987 FormalParameterList parameters = parseFormalParameterList();
6988 _validateFormalParameterList(parameters);
6989 FunctionBody body =
6990 _parseFunctionBody(true, ParserErrorCode.MISSING_FUNCTION_BODY, false);
6991 if (externalKeyword != null && body is! EmptyFunctionBody) {
6992 _reportErrorForCurrentToken(ParserErrorCode.EXTERNAL_OPERATOR_WITH_BODY);
6993 }
6994 return new MethodDeclaration(
6995 commentAndMetadata.comment,
6996 commentAndMetadata.metadata,
6997 externalKeyword,
6998 null,
6999 returnType,
7000 null,
7001 operatorKeyword,
7002 name,
7003 null,
7004 parameters,
7005 body);
7006 } 4084 }
7007 4085
7008 /** 4086 /**
7009 * Parse a return type if one is given, otherwise return `null` without
7010 * advancing. Return the return type that was parsed.
7011 */
7012 TypeName _parseOptionalReturnType() {
7013 if (_matchesKeyword(Keyword.VOID)) {
7014 return parseReturnType();
7015 } else if (_matchesIdentifier() &&
7016 !_matchesKeyword(Keyword.GET) &&
7017 !_matchesKeyword(Keyword.SET) &&
7018 !_matchesKeyword(Keyword.OPERATOR) &&
7019 (_tokenMatchesIdentifier(_peek()) ||
7020 _tokenMatches(_peek(), TokenType.LT))) {
7021 return parseReturnType();
7022 } else if (_matchesIdentifier() &&
7023 _tokenMatches(_peek(), TokenType.PERIOD) &&
7024 _tokenMatchesIdentifier(_peekAt(2)) &&
7025 (_tokenMatchesIdentifier(_peekAt(3)) ||
7026 _tokenMatches(_peekAt(3), TokenType.LT))) {
7027 return parseReturnType();
7028 }
7029 return null;
7030 }
7031
7032 /**
7033 * Parse a part or part-of directive. The [commentAndMetadata] is the metadata 4087 * Parse a part or part-of directive. The [commentAndMetadata] is the metadata
7034 * to be associated with the directive. Return the part or part-of directive 4088 * to be associated with the directive. Return the part or part-of directive
7035 * that was parsed. 4089 * that was parsed.
7036 * 4090 *
4091 * This method assumes that the current token matches `Keyword.PART`.
4092 *
7037 * partDirective ::= 4093 * partDirective ::=
7038 * metadata 'part' stringLiteral ';' 4094 * metadata 'part' stringLiteral ';'
7039 * 4095 *
7040 * partOfDirective ::= 4096 * partOfDirective ::=
7041 * metadata 'part' 'of' identifier ';' 4097 * metadata 'part' 'of' identifier ';'
7042 */ 4098 */
7043 Directive _parsePartDirective(CommentAndMetadata commentAndMetadata) { 4099 Directive parsePartOrPartOfDirective(CommentAndMetadata commentAndMetadata) {
7044 Token partKeyword = _expectKeyword(Keyword.PART); 4100 if (_tokenMatchesString(_peek(), _OF)) {
7045 if (_matchesString(_OF)) { 4101 return _parsePartOfDirective(commentAndMetadata);
7046 Token ofKeyword = getAndAdvance();
7047 LibraryIdentifier libraryName = _parseLibraryName(
7048 ParserErrorCode.MISSING_NAME_IN_PART_OF_DIRECTIVE, ofKeyword);
7049 Token semicolon = _expect(TokenType.SEMICOLON);
7050 return new PartOfDirective(
7051 commentAndMetadata.comment,
7052 commentAndMetadata.metadata,
7053 partKeyword,
7054 ofKeyword,
7055 libraryName,
7056 semicolon);
7057 } 4102 }
7058 StringLiteral partUri = _parseUri(); 4103 return _parsePartDirective(commentAndMetadata);
7059 Token semicolon = _expect(TokenType.SEMICOLON);
7060 return new PartDirective(commentAndMetadata.comment,
7061 commentAndMetadata.metadata, partKeyword, partUri, semicolon);
7062 } 4104 }
7063 4105
7064 /** 4106 /**
7065 * Parse a postfix expression. Return the postfix expression that was parsed. 4107 * Parse a postfix expression. Return the postfix expression that was parsed.
7066 * 4108 *
7067 * postfixExpression ::= 4109 * postfixExpression ::=
7068 * assignableExpression postfixOperator 4110 * assignableExpression postfixOperator
7069 * | primary selector* 4111 * | primary selector*
7070 * 4112 *
7071 * selector ::= 4113 * selector ::=
7072 * assignableSelector 4114 * assignableSelector
7073 * | argumentList 4115 * | argumentList
7074 */ 4116 */
7075 Expression _parsePostfixExpression() { 4117 Expression parsePostfixExpression() {
7076 Expression operand = _parseAssignableExpression(true); 4118 Expression operand = parseAssignableExpression(true);
7077 if (_matches(TokenType.OPEN_SQUARE_BRACKET) || 4119 TokenType type = _currentToken.type;
7078 _matches(TokenType.PERIOD) || 4120 if (type == TokenType.OPEN_SQUARE_BRACKET ||
7079 _matches(TokenType.QUESTION_PERIOD) || 4121 type == TokenType.PERIOD ||
7080 _matches(TokenType.OPEN_PAREN) || 4122 type == TokenType.QUESTION_PERIOD ||
7081 (parseGenericMethods && _matches(TokenType.LT))) { 4123 type == TokenType.OPEN_PAREN ||
4124 (parseGenericMethods && type == TokenType.LT)) {
7082 do { 4125 do {
7083 if (_isLikelyParameterList()) { 4126 if (_isLikelyArgumentList()) {
7084 TypeArgumentList typeArguments = null; 4127 TypeArgumentList typeArguments = _parseOptionalTypeArguments();
7085 if (_matches(TokenType.LT)) {
7086 typeArguments = parseTypeArgumentList();
7087 }
7088 ArgumentList argumentList = parseArgumentList(); 4128 ArgumentList argumentList = parseArgumentList();
7089 if (operand is PropertyAccess) { 4129 Expression currentOperand = operand;
7090 PropertyAccess access = operand as PropertyAccess; 4130 if (currentOperand is PropertyAccess) {
7091 operand = new MethodInvocation(access.target, access.operator, 4131 operand = new MethodInvocation(
7092 access.propertyName, typeArguments, argumentList); 4132 currentOperand.target,
4133 currentOperand.operator,
4134 currentOperand.propertyName,
4135 typeArguments,
4136 argumentList);
7093 } else { 4137 } else {
7094 operand = new FunctionExpressionInvocation( 4138 operand = new FunctionExpressionInvocation(
7095 operand, typeArguments, argumentList); 4139 operand, typeArguments, argumentList);
7096 } 4140 }
7097 } else { 4141 } else {
7098 operand = _parseAssignableSelector(operand, true); 4142 operand = parseAssignableSelector(operand, true);
7099 } 4143 }
7100 } while (_matches(TokenType.OPEN_SQUARE_BRACKET) || 4144 type = _currentToken.type;
7101 _matches(TokenType.PERIOD) || 4145 } while (type == TokenType.OPEN_SQUARE_BRACKET ||
7102 _matches(TokenType.QUESTION_PERIOD) || 4146 type == TokenType.PERIOD ||
7103 _matches(TokenType.OPEN_PAREN)); 4147 type == TokenType.QUESTION_PERIOD ||
4148 type == TokenType.OPEN_PAREN);
7104 return operand; 4149 return operand;
7105 } 4150 }
7106 if (!_currentToken.type.isIncrementOperator) { 4151 if (!_currentToken.type.isIncrementOperator) {
7107 return operand; 4152 return operand;
7108 } 4153 }
7109 _ensureAssignable(operand); 4154 _ensureAssignable(operand);
7110 Token operator = getAndAdvance(); 4155 Token operator = getAndAdvance();
7111 return new PostfixExpression(operand, operator); 4156 return new PostfixExpression(operand, operator);
7112 } 4157 }
7113 4158
7114 /** 4159 /**
4160 * Parse a prefixed identifier. Return the prefixed identifier that was
4161 * parsed.
4162 *
4163 * prefixedIdentifier ::=
4164 * identifier ('.' identifier)?
4165 */
4166 Identifier parsePrefixedIdentifier() {
4167 return _parsePrefixedIdentifierAfterIdentifier(parseSimpleIdentifier());
4168 }
4169
4170 /**
7115 * Parse a primary expression. Return the primary expression that was parsed. 4171 * Parse a primary expression. Return the primary expression that was parsed.
7116 * 4172 *
7117 * primary ::= 4173 * primary ::=
7118 * thisExpression 4174 * thisExpression
7119 * | 'super' unconditionalAssignableSelector 4175 * | 'super' unconditionalAssignableSelector
7120 * | functionExpression 4176 * | functionExpression
7121 * | literal 4177 * | literal
7122 * | identifier 4178 * | identifier
7123 * | newExpression 4179 * | newExpression
7124 * | constObjectExpression 4180 * | constObjectExpression
7125 * | '(' expression ')' 4181 * | '(' expression ')'
7126 * | argumentDefinitionTest 4182 * | argumentDefinitionTest
7127 * 4183 *
7128 * literal ::= 4184 * literal ::=
7129 * nullLiteral 4185 * nullLiteral
7130 * | booleanLiteral 4186 * | booleanLiteral
7131 * | numericLiteral 4187 * | numericLiteral
7132 * | stringLiteral 4188 * | stringLiteral
7133 * | symbolLiteral 4189 * | symbolLiteral
7134 * | mapLiteral 4190 * | mapLiteral
7135 * | listLiteral 4191 * | listLiteral
7136 */ 4192 */
7137 Expression _parsePrimaryExpression() { 4193 Expression parsePrimaryExpression() {
7138 if (_matchesKeyword(Keyword.THIS)) { 4194 if (_matchesIdentifier()) {
4195 // TODO(brianwilkerson) The code below was an attempt to recover from an
4196 // error case, but it needs to be applied as a recovery only after we
4197 // know that parsing it as an identifier doesn't work. Leaving the code as
4198 // a reminder of how to recover.
4199 // if (isFunctionExpression(_peek())) {
4200 // //
4201 // // Function expressions were allowed to have names at one point, but t his is now illegal.
4202 // //
4203 // reportError(ParserErrorCode.NAMED_FUNCTION_EXPRESSION, getAndAdvance() );
4204 // return parseFunctionExpression();
4205 // }
4206 return _parsePrefixedIdentifierUnchecked();
4207 }
4208 TokenType type = _currentToken.type;
4209 if (type == TokenType.STRING) {
4210 return parseStringLiteral();
4211 } else if (type == TokenType.INT) {
4212 Token token = getAndAdvance();
4213 int value = null;
4214 try {
4215 value = int.parse(token.lexeme);
4216 } on FormatException {
4217 // The invalid format should have been reported by the scanner.
4218 }
4219 return new IntegerLiteral(token, value);
4220 }
4221 Keyword keyword = _currentToken.keyword;
4222 if (keyword == Keyword.NULL) {
4223 return new NullLiteral(getAndAdvance());
4224 } else if (keyword == Keyword.NEW) {
4225 return parseNewExpression();
4226 } else if (keyword == Keyword.THIS) {
7139 return new ThisExpression(getAndAdvance()); 4227 return new ThisExpression(getAndAdvance());
7140 } else if (_matchesKeyword(Keyword.SUPER)) { 4228 } else if (keyword == Keyword.SUPER) {
7141 // TODO(paulberry): verify with Gilad that "super" must be followed by 4229 // TODO(paulberry): verify with Gilad that "super" must be followed by
7142 // unconditionalAssignableSelector in this case. 4230 // unconditionalAssignableSelector in this case.
7143 return _parseAssignableSelector( 4231 return parseAssignableSelector(
7144 new SuperExpression(getAndAdvance()), false, 4232 new SuperExpression(getAndAdvance()), false,
7145 allowConditional: false); 4233 allowConditional: false);
7146 } else if (_matchesKeyword(Keyword.NULL)) { 4234 } else if (keyword == Keyword.FALSE) {
7147 return new NullLiteral(getAndAdvance());
7148 } else if (_matchesKeyword(Keyword.FALSE)) {
7149 return new BooleanLiteral(getAndAdvance(), false); 4235 return new BooleanLiteral(getAndAdvance(), false);
7150 } else if (_matchesKeyword(Keyword.TRUE)) { 4236 } else if (keyword == Keyword.TRUE) {
7151 return new BooleanLiteral(getAndAdvance(), true); 4237 return new BooleanLiteral(getAndAdvance(), true);
7152 } else if (_matches(TokenType.DOUBLE)) { 4238 }
4239 if (type == TokenType.DOUBLE) {
7153 Token token = getAndAdvance(); 4240 Token token = getAndAdvance();
7154 double value = 0.0; 4241 double value = 0.0;
7155 try { 4242 try {
7156 value = double.parse(token.lexeme); 4243 value = double.parse(token.lexeme);
7157 } on FormatException { 4244 } on FormatException {
7158 // The invalid format should have been reported by the scanner. 4245 // The invalid format should have been reported by the scanner.
7159 } 4246 }
7160 return new DoubleLiteral(token, value); 4247 return new DoubleLiteral(token, value);
7161 } else if (_matches(TokenType.HEXADECIMAL)) { 4248 } else if (type == TokenType.HEXADECIMAL) {
7162 Token token = getAndAdvance(); 4249 Token token = getAndAdvance();
7163 int value = null; 4250 int value = null;
7164 try { 4251 try {
7165 value = int.parse(token.lexeme.substring(2), radix: 16); 4252 value = int.parse(token.lexeme.substring(2), radix: 16);
7166 } on FormatException { 4253 } on FormatException {
7167 // The invalid format should have been reported by the scanner. 4254 // The invalid format should have been reported by the scanner.
7168 } 4255 }
7169 return new IntegerLiteral(token, value); 4256 return new IntegerLiteral(token, value);
7170 } else if (_matches(TokenType.INT)) { 4257 } else if (keyword == Keyword.CONST) {
7171 Token token = getAndAdvance(); 4258 return parseConstExpression();
7172 int value = null; 4259 } else if (type == TokenType.OPEN_PAREN) {
7173 try { 4260 if (isFunctionExpression(_currentToken)) {
7174 value = int.parse(token.lexeme);
7175 } on FormatException {
7176 // The invalid format should have been reported by the scanner.
7177 }
7178 return new IntegerLiteral(token, value);
7179 } else if (_matches(TokenType.STRING)) {
7180 return parseStringLiteral();
7181 } else if (_matches(TokenType.OPEN_CURLY_BRACKET)) {
7182 return _parseMapLiteral(null, null);
7183 } else if (_matches(TokenType.OPEN_SQUARE_BRACKET) ||
7184 _matches(TokenType.INDEX)) {
7185 return _parseListLiteral(null, null);
7186 } else if (_matchesIdentifier()) {
7187 // TODO(brianwilkerson) The code below was an attempt to recover from an
7188 // error case, but it needs to be applied as a recovery only after we
7189 // know that parsing it as an identifier doesn't work. Leaving the code as
7190 // a reminder of how to recover.
7191 // if (isFunctionExpression(peek())) {
7192 // //
7193 // // Function expressions were allowed to have names at one point, but this is now illegal.
7194 // //
7195 // reportError(ParserErrorCode.NAMED_FUNCTION_EXPRESSION, getAndAdv ance());
7196 // return parseFunctionExpression();
7197 // }
7198 return parsePrefixedIdentifier();
7199 } else if (_matchesKeyword(Keyword.NEW)) {
7200 return _parseNewExpression();
7201 } else if (_matchesKeyword(Keyword.CONST)) {
7202 return _parseConstExpression();
7203 } else if (_matches(TokenType.OPEN_PAREN)) {
7204 if (_isFunctionExpression(_currentToken)) {
7205 return parseFunctionExpression(); 4261 return parseFunctionExpression();
7206 } 4262 }
7207 Token leftParenthesis = getAndAdvance(); 4263 Token leftParenthesis = getAndAdvance();
7208 bool wasInInitializer = _inInitializer; 4264 bool wasInInitializer = _inInitializer;
7209 _inInitializer = false; 4265 _inInitializer = false;
7210 try { 4266 try {
7211 Expression expression = parseExpression2(); 4267 Expression expression = parseExpression2();
7212 Token rightParenthesis = _expect(TokenType.CLOSE_PAREN); 4268 Token rightParenthesis = _expect(TokenType.CLOSE_PAREN);
7213 return new ParenthesizedExpression( 4269 return new ParenthesizedExpression(
7214 leftParenthesis, expression, rightParenthesis); 4270 leftParenthesis, expression, rightParenthesis);
7215 } finally { 4271 } finally {
7216 _inInitializer = wasInInitializer; 4272 _inInitializer = wasInInitializer;
7217 } 4273 }
7218 } else if (_matches(TokenType.LT)) { 4274 } else if (type == TokenType.LT || _injectGenericCommentTypeList()) {
7219 return _parseListOrMapLiteral(null); 4275 return parseListOrMapLiteral(null);
7220 } else if (_matches(TokenType.QUESTION) && 4276 } else if (type == TokenType.OPEN_CURLY_BRACKET) {
4277 return parseMapLiteral(null, null);
4278 } else if (type == TokenType.OPEN_SQUARE_BRACKET ||
4279 type == TokenType.INDEX) {
4280 return parseListLiteral(null, null);
4281 } else if (type == TokenType.QUESTION &&
7221 _tokenMatches(_peek(), TokenType.IDENTIFIER)) { 4282 _tokenMatches(_peek(), TokenType.IDENTIFIER)) {
7222 _reportErrorForCurrentToken( 4283 _reportErrorForCurrentToken(
7223 ParserErrorCode.UNEXPECTED_TOKEN, [_currentToken.lexeme]); 4284 ParserErrorCode.UNEXPECTED_TOKEN, [_currentToken.lexeme]);
7224 _advance(); 4285 _advance();
7225 return _parsePrimaryExpression(); 4286 return parsePrimaryExpression();
7226 } else if (_matchesKeyword(Keyword.VOID)) { 4287 } else if (keyword == Keyword.VOID) {
7227 // 4288 //
7228 // Recover from having a return type of "void" where a return type is not 4289 // Recover from having a return type of "void" where a return type is not
7229 // expected. 4290 // expected.
7230 // 4291 //
7231 // TODO(brianwilkerson) Improve this error message. 4292 // TODO(brianwilkerson) Improve this error message.
7232 _reportErrorForCurrentToken( 4293 _reportErrorForCurrentToken(
7233 ParserErrorCode.UNEXPECTED_TOKEN, [_currentToken.lexeme]); 4294 ParserErrorCode.UNEXPECTED_TOKEN, [_currentToken.lexeme]);
7234 _advance(); 4295 _advance();
7235 return _parsePrimaryExpression(); 4296 return parsePrimaryExpression();
7236 } else if (_matches(TokenType.HASH)) { 4297 } else if (type == TokenType.HASH) {
7237 return _parseSymbolLiteral(); 4298 return parseSymbolLiteral();
7238 } else { 4299 } else {
7239 _reportErrorForCurrentToken(ParserErrorCode.MISSING_IDENTIFIER); 4300 _reportErrorForCurrentToken(ParserErrorCode.MISSING_IDENTIFIER);
7240 return _createSyntheticIdentifier(); 4301 return createSyntheticIdentifier();
7241 } 4302 }
7242 } 4303 }
7243 4304
7244 /** 4305 /**
7245 * Parse a redirecting constructor invocation. Return the redirecting 4306 * Parse a redirecting constructor invocation. The flag [hasPeriod] should be
4307 * `true` if the `this` is followed by a period. Return the redirecting
7246 * constructor invocation that was parsed. 4308 * constructor invocation that was parsed.
7247 * 4309 *
4310 * This method assumes that the current token matches `Keyword.THIS`.
4311 *
7248 * redirectingConstructorInvocation ::= 4312 * redirectingConstructorInvocation ::=
7249 * 'this' ('.' identifier)? arguments 4313 * 'this' ('.' identifier)? arguments
7250 */ 4314 */
7251 RedirectingConstructorInvocation _parseRedirectingConstructorInvocation() { 4315 RedirectingConstructorInvocation parseRedirectingConstructorInvocation(
7252 Token keyword = _expectKeyword(Keyword.THIS); 4316 bool hasPeriod) {
4317 Token keyword = getAndAdvance();
7253 Token period = null; 4318 Token period = null;
7254 SimpleIdentifier constructorName = null; 4319 SimpleIdentifier constructorName = null;
7255 if (_matches(TokenType.PERIOD)) { 4320 if (hasPeriod) {
7256 period = getAndAdvance(); 4321 period = getAndAdvance();
7257 constructorName = parseSimpleIdentifier(); 4322 if (_matchesIdentifier()) {
4323 constructorName = _parseSimpleIdentifierUnchecked(isDeclaration: false);
4324 } else {
4325 _reportErrorForCurrentToken(ParserErrorCode.MISSING_IDENTIFIER);
4326 constructorName = createSyntheticIdentifier(isDeclaration: false);
4327 _advance();
4328 }
7258 } 4329 }
7259 ArgumentList argumentList = parseArgumentList(); 4330 ArgumentList argumentList = _parseArgumentListChecked();
7260 return new RedirectingConstructorInvocation( 4331 return new RedirectingConstructorInvocation(
7261 keyword, period, constructorName, argumentList); 4332 keyword, period, constructorName, argumentList);
7262 } 4333 }
7263 4334
7264 /** 4335 /**
7265 * Parse a relational expression. Return the relational expression that was 4336 * Parse a relational expression. Return the relational expression that was
7266 * parsed. 4337 * parsed.
7267 * 4338 *
7268 * relationalExpression ::= 4339 * relationalExpression ::=
7269 * bitwiseOrExpression ('is' '!'? type | 'as' type | relationalOperato r bitwiseOrExpression)? 4340 * bitwiseOrExpression ('is' '!'? type | 'as' type | relationalOperato r bitwiseOrExpression)?
7270 * | 'super' relationalOperator bitwiseOrExpression 4341 * | 'super' relationalOperator bitwiseOrExpression
7271 */ 4342 */
7272 Expression _parseRelationalExpression() { 4343 Expression parseRelationalExpression() {
7273 if (_matchesKeyword(Keyword.SUPER) && 4344 if (_currentToken.keyword == Keyword.SUPER &&
7274 _currentToken.next.type.isRelationalOperator) { 4345 _currentToken.next.type.isRelationalOperator) {
7275 Expression expression = new SuperExpression(getAndAdvance()); 4346 Expression expression = new SuperExpression(getAndAdvance());
7276 Token operator = getAndAdvance(); 4347 Token operator = getAndAdvance();
7277 expression = new BinaryExpression( 4348 return new BinaryExpression(
7278 expression, operator, parseBitwiseOrExpression()); 4349 expression, operator, parseBitwiseOrExpression());
7279 return expression;
7280 } 4350 }
7281 Expression expression = parseBitwiseOrExpression(); 4351 Expression expression = parseBitwiseOrExpression();
7282 if (_matchesKeyword(Keyword.AS)) { 4352 Keyword keyword = _currentToken.keyword;
4353 if (keyword == Keyword.AS) {
7283 Token asOperator = getAndAdvance(); 4354 Token asOperator = getAndAdvance();
7284 expression = new AsExpression(expression, asOperator, parseTypeName()); 4355 return new AsExpression(expression, asOperator, parseTypeName(true));
7285 } else if (_matchesKeyword(Keyword.IS)) { 4356 } else if (keyword == Keyword.IS) {
7286 Token isOperator = getAndAdvance(); 4357 Token isOperator = getAndAdvance();
7287 Token notOperator = null; 4358 Token notOperator = null;
7288 if (_matches(TokenType.BANG)) { 4359 if (_matches(TokenType.BANG)) {
7289 notOperator = getAndAdvance(); 4360 notOperator = getAndAdvance();
7290 } 4361 }
7291 expression = new IsExpression( 4362 return new IsExpression(
7292 expression, isOperator, notOperator, parseTypeName()); 4363 expression, isOperator, notOperator, parseTypeName(true));
7293 } else if (_currentToken.type.isRelationalOperator) { 4364 } else if (_currentToken.type.isRelationalOperator) {
7294 Token operator = getAndAdvance(); 4365 Token operator = getAndAdvance();
7295 expression = new BinaryExpression( 4366 return new BinaryExpression(
7296 expression, operator, parseBitwiseOrExpression()); 4367 expression, operator, parseBitwiseOrExpression());
7297 } 4368 }
7298 return expression; 4369 return expression;
7299 } 4370 }
7300 4371
7301 /** 4372 /**
7302 * Parse a rethrow expression. Return the rethrow expression that was parsed. 4373 * Parse a rethrow expression. Return the rethrow expression that was parsed.
7303 * 4374 *
4375 * This method assumes that the current token matches `Keyword.RETHROW`.
4376 *
7304 * rethrowExpression ::= 4377 * rethrowExpression ::=
7305 * 'rethrow' 4378 * 'rethrow'
7306 */ 4379 */
7307 Expression _parseRethrowExpression() => 4380 Expression parseRethrowExpression() => new RethrowExpression(getAndAdvance());
7308 new RethrowExpression(_expectKeyword(Keyword.RETHROW));
7309 4381
7310 /** 4382 /**
7311 * Parse a return statement. Return the return statement that was parsed. 4383 * Parse a return statement. Return the return statement that was parsed.
7312 * 4384 *
4385 * This method assumes that the current token matches `Keyword.RETURN`.
4386 *
7313 * returnStatement ::= 4387 * returnStatement ::=
7314 * 'return' expression? ';' 4388 * 'return' expression? ';'
7315 */ 4389 */
7316 Statement _parseReturnStatement() { 4390 Statement parseReturnStatement() {
7317 Token returnKeyword = _expectKeyword(Keyword.RETURN); 4391 Token returnKeyword = getAndAdvance();
7318 if (_matches(TokenType.SEMICOLON)) { 4392 if (_matches(TokenType.SEMICOLON)) {
7319 return new ReturnStatement(returnKeyword, null, getAndAdvance()); 4393 return new ReturnStatement(returnKeyword, null, getAndAdvance());
7320 } 4394 }
7321 Expression expression = parseExpression2(); 4395 Expression expression = parseExpression2();
7322 Token semicolon = _expect(TokenType.SEMICOLON); 4396 Token semicolon = _expect(TokenType.SEMICOLON);
7323 return new ReturnStatement(returnKeyword, expression, semicolon); 4397 return new ReturnStatement(returnKeyword, expression, semicolon);
7324 } 4398 }
7325 4399
7326 /** 4400 /**
4401 * Parse a return type. Return the return type that was parsed.
4402 *
4403 * returnType ::=
4404 * 'void'
4405 * | type
4406 */
4407 TypeName parseReturnType() {
4408 if (_currentToken.keyword == Keyword.VOID) {
4409 return new TypeName(new SimpleIdentifier(getAndAdvance()), null);
4410 } else {
4411 return parseTypeName(false);
4412 }
4413 }
4414
4415 /**
7327 * Parse a setter. The [commentAndMetadata] is the documentation comment and 4416 * Parse a setter. The [commentAndMetadata] is the documentation comment and
7328 * metadata to be associated with the declaration. The [externalKeyword] is 4417 * metadata to be associated with the declaration. The [externalKeyword] is
7329 * the 'external' token. The [staticKeyword] is the static keyword, or `null` 4418 * the 'external' token. The [staticKeyword] is the static keyword, or `null`
7330 * if the setter is not static. The [returnType] is the return type that has 4419 * if the setter is not static. The [returnType] is the return type that has
7331 * already been parsed, or `null` if there was no return type. Return the 4420 * already been parsed, or `null` if there was no return type. Return the
7332 * setter that was parsed. 4421 * setter that was parsed.
7333 * 4422 *
4423 * This method assumes that the current token matches `Keyword.SET`.
4424 *
7334 * setter ::= 4425 * setter ::=
7335 * setterSignature functionBody? 4426 * setterSignature functionBody?
7336 * 4427 *
7337 * setterSignature ::= 4428 * setterSignature ::=
7338 * 'external'? 'static'? returnType? 'set' identifier formalParameterL ist 4429 * 'external'? 'static'? returnType? 'set' identifier formalParameterL ist
7339 */ 4430 */
7340 MethodDeclaration _parseSetter(CommentAndMetadata commentAndMetadata, 4431 MethodDeclaration parseSetter(CommentAndMetadata commentAndMetadata,
7341 Token externalKeyword, Token staticKeyword, TypeName returnType) { 4432 Token externalKeyword, Token staticKeyword, TypeName returnType) {
7342 Token propertyKeyword = _expectKeyword(Keyword.SET); 4433 Token propertyKeyword = getAndAdvance();
7343 SimpleIdentifier name = parseSimpleIdentifier(); 4434 SimpleIdentifier name = parseSimpleIdentifier(isDeclaration: true);
7344 FormalParameterList parameters = parseFormalParameterList(); 4435 FormalParameterList parameters = parseFormalParameterList();
7345 _validateFormalParameterList(parameters); 4436 _validateFormalParameterList(parameters);
7346 FunctionBody body = _parseFunctionBody( 4437 FunctionBody body = parseFunctionBody(
7347 externalKeyword != null || staticKeyword == null, 4438 externalKeyword != null || staticKeyword == null,
7348 ParserErrorCode.STATIC_SETTER_WITHOUT_BODY, 4439 ParserErrorCode.STATIC_SETTER_WITHOUT_BODY,
7349 false); 4440 false);
7350 if (externalKeyword != null && body is! EmptyFunctionBody) { 4441 if (externalKeyword != null && body is! EmptyFunctionBody) {
7351 _reportErrorForCurrentToken(ParserErrorCode.EXTERNAL_SETTER_WITH_BODY); 4442 _reportErrorForCurrentToken(ParserErrorCode.EXTERNAL_SETTER_WITH_BODY);
7352 } 4443 }
7353 return new MethodDeclaration( 4444 return new MethodDeclaration(
7354 commentAndMetadata.comment, 4445 commentAndMetadata.comment,
7355 commentAndMetadata.metadata, 4446 commentAndMetadata.metadata,
7356 externalKeyword, 4447 externalKeyword,
7357 staticKeyword, 4448 staticKeyword,
7358 returnType, 4449 returnType,
7359 propertyKeyword, 4450 propertyKeyword,
7360 null, 4451 null,
7361 name, 4452 name,
7362 null, 4453 null,
7363 parameters, 4454 parameters,
7364 body); 4455 body);
7365 } 4456 }
7366 4457
7367 /** 4458 /**
7368 * Parse a shift expression. Return the shift expression that was parsed. 4459 * Parse a shift expression. Return the shift expression that was parsed.
7369 * 4460 *
7370 * shiftExpression ::= 4461 * shiftExpression ::=
7371 * additiveExpression (shiftOperator additiveExpression)* 4462 * additiveExpression (shiftOperator additiveExpression)*
7372 * | 'super' (shiftOperator additiveExpression)+ 4463 * | 'super' (shiftOperator additiveExpression)+
7373 */ 4464 */
7374 Expression _parseShiftExpression() { 4465 Expression parseShiftExpression() {
7375 Expression expression; 4466 Expression expression;
7376 if (_matchesKeyword(Keyword.SUPER) && 4467 if (_currentToken.keyword == Keyword.SUPER &&
7377 _currentToken.next.type.isShiftOperator) { 4468 _currentToken.next.type.isShiftOperator) {
7378 expression = new SuperExpression(getAndAdvance()); 4469 expression = new SuperExpression(getAndAdvance());
7379 } else { 4470 } else {
7380 expression = _parseAdditiveExpression(); 4471 expression = parseAdditiveExpression();
7381 } 4472 }
7382 while (_currentToken.type.isShiftOperator) { 4473 while (_currentToken.type.isShiftOperator) {
7383 Token operator = getAndAdvance();
7384 expression = new BinaryExpression( 4474 expression = new BinaryExpression(
7385 expression, operator, _parseAdditiveExpression()); 4475 expression, getAndAdvance(), parseAdditiveExpression());
7386 } 4476 }
7387 return expression; 4477 return expression;
7388 } 4478 }
7389 4479
7390 /** 4480 /**
7391 * Parse a list of statements within a switch statement. Return the statements 4481 * Parse a simple identifier. Return the simple identifier that was parsed.
7392 * that were parsed.
7393 * 4482 *
7394 * statements ::= 4483 * identifier ::=
7395 * statement* 4484 * IDENTIFIER
7396 */ 4485 */
7397 List<Statement> _parseStatementList() { 4486 SimpleIdentifier parseSimpleIdentifier({bool isDeclaration: false}) {
7398 List<Statement> statements = new List<Statement>(); 4487 if (_matchesIdentifier()) {
7399 Token statementStart = _currentToken; 4488 return _parseSimpleIdentifierUnchecked(isDeclaration: isDeclaration);
7400 while (!_matches(TokenType.EOF) &&
7401 !_matches(TokenType.CLOSE_CURLY_BRACKET) &&
7402 !_isSwitchMember()) {
7403 statements.add(parseStatement2());
7404 if (identical(_currentToken, statementStart)) {
7405 _reportErrorForToken(ParserErrorCode.UNEXPECTED_TOKEN, _currentToken,
7406 [_currentToken.lexeme]);
7407 _advance();
7408 }
7409 statementStart = _currentToken;
7410 } 4489 }
7411 return statements; 4490 _reportErrorForCurrentToken(ParserErrorCode.MISSING_IDENTIFIER);
4491 return createSyntheticIdentifier(isDeclaration: isDeclaration);
7412 } 4492 }
7413 4493
7414 /** 4494 /**
7415 * Parse a string literal that contains interpolations. Return the string 4495 * Parse a statement, starting with the given [token]. Return the statement
7416 * literal that was parsed. 4496 * that was parsed, or `null` if the tokens do not represent a recognizable
4497 * statement.
7417 */ 4498 */
7418 StringInterpolation _parseStringInterpolation(Token string) { 4499 Statement parseStatement(Token token) {
7419 List<InterpolationElement> elements = new List<InterpolationElement>(); 4500 _currentToken = token;
7420 bool hasMore = _matches(TokenType.STRING_INTERPOLATION_EXPRESSION) || 4501 return parseStatement2();
7421 _matches(TokenType.STRING_INTERPOLATION_IDENTIFIER); 4502 }
7422 elements.add(new InterpolationString( 4503
7423 string, _computeStringValue(string.lexeme, true, !hasMore))); 4504 /**
7424 while (hasMore) { 4505 * Parse a statement. Return the statement that was parsed.
7425 if (_matches(TokenType.STRING_INTERPOLATION_EXPRESSION)) { 4506 *
7426 Token openToken = getAndAdvance(); 4507 * statement ::=
7427 bool wasInInitializer = _inInitializer; 4508 * label* nonLabeledStatement
7428 _inInitializer = false; 4509 */
7429 try { 4510 Statement parseStatement2() {
7430 Expression expression = parseExpression2(); 4511 List<Label> labels = null;
7431 Token rightBracket = _expect(TokenType.CLOSE_CURLY_BRACKET); 4512 while (_matchesIdentifier() && _currentToken.next.type == TokenType.COLON) {
7432 elements.add( 4513 Label label = parseLabel(isDeclaration: true);
7433 new InterpolationExpression(openToken, expression, rightBracket)); 4514 if (labels == null) {
7434 } finally { 4515 labels = <Label>[label];
7435 _inInitializer = wasInInitializer;
7436 }
7437 } else { 4516 } else {
7438 Token openToken = getAndAdvance(); 4517 labels.add(label);
7439 Expression expression = null;
7440 if (_matchesKeyword(Keyword.THIS)) {
7441 expression = new ThisExpression(getAndAdvance());
7442 } else {
7443 expression = parseSimpleIdentifier();
7444 }
7445 elements.add(new InterpolationExpression(openToken, expression, null));
7446 }
7447 if (_matches(TokenType.STRING)) {
7448 string = getAndAdvance();
7449 hasMore = _matches(TokenType.STRING_INTERPOLATION_EXPRESSION) ||
7450 _matches(TokenType.STRING_INTERPOLATION_IDENTIFIER);
7451 elements.add(new InterpolationString(
7452 string, _computeStringValue(string.lexeme, false, !hasMore)));
7453 } else {
7454 hasMore = false;
7455 } 4518 }
7456 } 4519 }
7457 return new StringInterpolation(elements); 4520 Statement statement = parseNonLabeledStatement();
4521 if (labels == null) {
4522 return statement;
4523 }
4524 return new LabeledStatement(labels, statement);
4525 }
4526
4527 /**
4528 * Parse a sequence of statements, starting with the given [token]. Return the
4529 * statements that were parsed, or `null` if the tokens do not represent a
4530 * recognizable sequence of statements.
4531 */
4532 List<Statement> parseStatements(Token token) {
4533 _currentToken = token;
4534 return _parseStatementList();
4535 }
4536
4537 /**
4538 * Parse a string literal. Return the string literal that was parsed.
4539 *
4540 * stringLiteral ::=
4541 * MULTI_LINE_STRING+
4542 * | SINGLE_LINE_STRING+
4543 */
4544 StringLiteral parseStringLiteral() {
4545 if (_matches(TokenType.STRING)) {
4546 return _parseStringLiteralUnchecked();
4547 }
4548 _reportErrorForCurrentToken(ParserErrorCode.EXPECTED_STRING_LITERAL);
4549 return createSyntheticStringLiteral();
7458 } 4550 }
7459 4551
7460 /** 4552 /**
7461 * Parse a super constructor invocation. Return the super constructor 4553 * Parse a super constructor invocation. Return the super constructor
7462 * invocation that was parsed. 4554 * invocation that was parsed.
7463 * 4555 *
4556 * This method assumes that the current token matches [Keyword.SUPER].
4557 *
7464 * superConstructorInvocation ::= 4558 * superConstructorInvocation ::=
7465 * 'super' ('.' identifier)? arguments 4559 * 'super' ('.' identifier)? arguments
7466 */ 4560 */
7467 SuperConstructorInvocation _parseSuperConstructorInvocation() { 4561 SuperConstructorInvocation parseSuperConstructorInvocation() {
7468 Token keyword = _expectKeyword(Keyword.SUPER); 4562 Token keyword = getAndAdvance();
7469 Token period = null; 4563 Token period = null;
7470 SimpleIdentifier constructorName = null; 4564 SimpleIdentifier constructorName = null;
7471 if (_matches(TokenType.PERIOD)) { 4565 if (_matches(TokenType.PERIOD)) {
7472 period = getAndAdvance(); 4566 period = getAndAdvance();
7473 constructorName = parseSimpleIdentifier(); 4567 constructorName = parseSimpleIdentifier();
7474 } 4568 }
7475 ArgumentList argumentList = parseArgumentList(); 4569 ArgumentList argumentList = _parseArgumentListChecked();
7476 return new SuperConstructorInvocation( 4570 return new SuperConstructorInvocation(
7477 keyword, period, constructorName, argumentList); 4571 keyword, period, constructorName, argumentList);
7478 } 4572 }
7479 4573
7480 /** 4574 /**
7481 * Parse a switch statement. Return the switch statement that was parsed. 4575 * Parse a switch statement. Return the switch statement that was parsed.
7482 * 4576 *
7483 * switchStatement ::= 4577 * switchStatement ::=
7484 * 'switch' '(' expression ')' '{' switchCase* defaultCase? '}' 4578 * 'switch' '(' expression ')' '{' switchCase* defaultCase? '}'
7485 * 4579 *
7486 * switchCase ::= 4580 * switchCase ::=
7487 * label* ('case' expression ':') statements 4581 * label* ('case' expression ':') statements
7488 * 4582 *
7489 * defaultCase ::= 4583 * defaultCase ::=
7490 * label* 'default' ':' statements 4584 * label* 'default' ':' statements
7491 */ 4585 */
7492 SwitchStatement _parseSwitchStatement() { 4586 SwitchStatement parseSwitchStatement() {
7493 bool wasInSwitch = _inSwitch; 4587 bool wasInSwitch = _inSwitch;
7494 _inSwitch = true; 4588 _inSwitch = true;
7495 try { 4589 try {
7496 HashSet<String> definedLabels = new HashSet<String>(); 4590 HashSet<String> definedLabels = new HashSet<String>();
7497 Token keyword = _expectKeyword(Keyword.SWITCH); 4591 Token keyword = _expectKeyword(Keyword.SWITCH);
7498 Token leftParenthesis = _expect(TokenType.OPEN_PAREN); 4592 Token leftParenthesis = _expect(TokenType.OPEN_PAREN);
7499 Expression expression = parseExpression2(); 4593 Expression expression = parseExpression2();
7500 Token rightParenthesis = _expect(TokenType.CLOSE_PAREN); 4594 Token rightParenthesis = _expect(TokenType.CLOSE_PAREN);
7501 Token leftBracket = _expect(TokenType.OPEN_CURLY_BRACKET); 4595 Token leftBracket = _expect(TokenType.OPEN_CURLY_BRACKET);
7502 Token defaultKeyword = null; 4596 Token defaultKeyword = null;
7503 List<SwitchMember> members = new List<SwitchMember>(); 4597 List<SwitchMember> members = <SwitchMember>[];
7504 while (!_matches(TokenType.EOF) && 4598 TokenType type = _currentToken.type;
7505 !_matches(TokenType.CLOSE_CURLY_BRACKET)) { 4599 while (type != TokenType.EOF && type != TokenType.CLOSE_CURLY_BRACKET) {
7506 List<Label> labels = new List<Label>(); 4600 List<Label> labels = <Label>[];
7507 while ( 4601 while (
7508 _matchesIdentifier() && _tokenMatches(_peek(), TokenType.COLON)) { 4602 _matchesIdentifier() && _tokenMatches(_peek(), TokenType.COLON)) {
7509 SimpleIdentifier identifier = parseSimpleIdentifier(); 4603 SimpleIdentifier identifier =
4604 _parseSimpleIdentifierUnchecked(isDeclaration: true);
7510 String label = identifier.token.lexeme; 4605 String label = identifier.token.lexeme;
7511 if (definedLabels.contains(label)) { 4606 if (definedLabels.contains(label)) {
7512 _reportErrorForToken( 4607 _reportErrorForToken(
7513 ParserErrorCode.DUPLICATE_LABEL_IN_SWITCH_STATEMENT, 4608 ParserErrorCode.DUPLICATE_LABEL_IN_SWITCH_STATEMENT,
7514 identifier.token, 4609 identifier.token,
7515 [label]); 4610 [label]);
7516 } else { 4611 } else {
7517 definedLabels.add(label); 4612 definedLabels.add(label);
7518 } 4613 }
7519 Token colon = _expect(TokenType.COLON); 4614 Token colon = getAndAdvance();
7520 labels.add(new Label(identifier, colon)); 4615 labels.add(new Label(identifier, colon));
7521 } 4616 }
7522 if (_matchesKeyword(Keyword.CASE)) { 4617 Keyword keyword = _currentToken.keyword;
4618 if (keyword == Keyword.CASE) {
7523 Token caseKeyword = getAndAdvance(); 4619 Token caseKeyword = getAndAdvance();
7524 Expression caseExpression = parseExpression2(); 4620 Expression caseExpression = parseExpression2();
7525 Token colon = _expect(TokenType.COLON); 4621 Token colon = _expect(TokenType.COLON);
7526 members.add(new SwitchCase(labels, caseKeyword, caseExpression, colon, 4622 members.add(new SwitchCase(labels, caseKeyword, caseExpression, colon,
7527 _parseStatementList())); 4623 _parseStatementList()));
7528 if (defaultKeyword != null) { 4624 if (defaultKeyword != null) {
7529 _reportErrorForToken( 4625 _reportErrorForToken(
7530 ParserErrorCode.SWITCH_HAS_CASE_AFTER_DEFAULT_CASE, 4626 ParserErrorCode.SWITCH_HAS_CASE_AFTER_DEFAULT_CASE,
7531 caseKeyword); 4627 caseKeyword);
7532 } 4628 }
7533 } else if (_matchesKeyword(Keyword.DEFAULT)) { 4629 } else if (keyword == Keyword.DEFAULT) {
7534 if (defaultKeyword != null) { 4630 if (defaultKeyword != null) {
7535 _reportErrorForToken( 4631 _reportErrorForToken(
7536 ParserErrorCode.SWITCH_HAS_MULTIPLE_DEFAULT_CASES, _peek()); 4632 ParserErrorCode.SWITCH_HAS_MULTIPLE_DEFAULT_CASES, _peek());
7537 } 4633 }
7538 defaultKeyword = getAndAdvance(); 4634 defaultKeyword = getAndAdvance();
7539 Token colon = _expect(TokenType.COLON); 4635 Token colon = _expect(TokenType.COLON);
7540 members.add(new SwitchDefault( 4636 members.add(new SwitchDefault(
7541 labels, defaultKeyword, colon, _parseStatementList())); 4637 labels, defaultKeyword, colon, _parseStatementList()));
7542 } else { 4638 } else {
7543 // We need to advance, otherwise we could end up in an infinite loop, 4639 // We need to advance, otherwise we could end up in an infinite loop,
7544 // but this could be a lot smarter about recovering from the error. 4640 // but this could be a lot smarter about recovering from the error.
7545 _reportErrorForCurrentToken(ParserErrorCode.EXPECTED_CASE_OR_DEFAULT); 4641 _reportErrorForCurrentToken(ParserErrorCode.EXPECTED_CASE_OR_DEFAULT);
7546 while (!_matches(TokenType.EOF) && 4642 bool atEndOrNextMember() {
7547 !_matches(TokenType.CLOSE_CURLY_BRACKET) && 4643 TokenType type = _currentToken.type;
7548 !_matchesKeyword(Keyword.CASE) && 4644 if (type == TokenType.EOF ||
7549 !_matchesKeyword(Keyword.DEFAULT)) { 4645 type == TokenType.CLOSE_CURLY_BRACKET) {
4646 return true;
4647 }
4648 Keyword keyword = _currentToken.keyword;
4649 return keyword == Keyword.CASE || keyword == Keyword.DEFAULT;
4650 }
4651
4652 while (!atEndOrNextMember()) {
7550 _advance(); 4653 _advance();
7551 } 4654 }
7552 } 4655 }
4656 type = _currentToken.type;
7553 } 4657 }
7554 Token rightBracket = _expect(TokenType.CLOSE_CURLY_BRACKET); 4658 Token rightBracket = _expect(TokenType.CLOSE_CURLY_BRACKET);
7555 return new SwitchStatement(keyword, leftParenthesis, expression, 4659 return new SwitchStatement(keyword, leftParenthesis, expression,
7556 rightParenthesis, leftBracket, members, rightBracket); 4660 rightParenthesis, leftBracket, members, rightBracket);
7557 } finally { 4661 } finally {
7558 _inSwitch = wasInSwitch; 4662 _inSwitch = wasInSwitch;
7559 } 4663 }
7560 } 4664 }
7561 4665
7562 /** 4666 /**
7563 * Parse a symbol literal. Return the symbol literal that was parsed. 4667 * Parse a symbol literal. Return the symbol literal that was parsed.
7564 * 4668 *
4669 * This method assumes that the current token matches [TokenType.HASH].
4670 *
7565 * symbolLiteral ::= 4671 * symbolLiteral ::=
7566 * '#' identifier ('.' identifier)* 4672 * '#' identifier ('.' identifier)*
7567 */ 4673 */
7568 SymbolLiteral _parseSymbolLiteral() { 4674 SymbolLiteral parseSymbolLiteral() {
7569 Token poundSign = getAndAdvance(); 4675 Token poundSign = getAndAdvance();
7570 List<Token> components = new List<Token>(); 4676 List<Token> components = <Token>[];
7571 if (_matchesIdentifier()) { 4677 if (_matchesIdentifier()) {
7572 components.add(getAndAdvance()); 4678 components.add(getAndAdvance());
7573 while (_matches(TokenType.PERIOD)) { 4679 while (_optional(TokenType.PERIOD)) {
7574 _advance();
7575 if (_matchesIdentifier()) { 4680 if (_matchesIdentifier()) {
7576 components.add(getAndAdvance()); 4681 components.add(getAndAdvance());
7577 } else { 4682 } else {
7578 _reportErrorForCurrentToken(ParserErrorCode.MISSING_IDENTIFIER); 4683 _reportErrorForCurrentToken(ParserErrorCode.MISSING_IDENTIFIER);
7579 components.add(_createSyntheticToken(TokenType.IDENTIFIER)); 4684 components.add(_createSyntheticToken(TokenType.IDENTIFIER));
7580 break; 4685 break;
7581 } 4686 }
7582 } 4687 }
7583 } else if (_currentToken.isOperator) { 4688 } else if (_currentToken.isOperator) {
7584 components.add(getAndAdvance()); 4689 components.add(getAndAdvance());
7585 } else if (_tokenMatchesKeyword(_currentToken, Keyword.VOID)) { 4690 } else if (_matchesKeyword(Keyword.VOID)) {
7586 components.add(getAndAdvance()); 4691 components.add(getAndAdvance());
7587 } else { 4692 } else {
7588 _reportErrorForCurrentToken(ParserErrorCode.MISSING_IDENTIFIER); 4693 _reportErrorForCurrentToken(ParserErrorCode.MISSING_IDENTIFIER);
7589 components.add(_createSyntheticToken(TokenType.IDENTIFIER)); 4694 components.add(_createSyntheticToken(TokenType.IDENTIFIER));
7590 } 4695 }
7591 return new SymbolLiteral(poundSign, components); 4696 return new SymbolLiteral(poundSign, components);
7592 } 4697 }
7593 4698
7594 /** 4699 /**
7595 * Parse a throw expression. Return the throw expression that was parsed. 4700 * Parse a throw expression. Return the throw expression that was parsed.
7596 * 4701 *
4702 * This method assumes that the current token matches [Keyword.THROW].
4703 *
7597 * throwExpression ::= 4704 * throwExpression ::=
7598 * 'throw' expression 4705 * 'throw' expression
7599 */ 4706 */
7600 Expression _parseThrowExpression() { 4707 Expression parseThrowExpression() {
7601 Token keyword = _expectKeyword(Keyword.THROW); 4708 Token keyword = getAndAdvance();
7602 if (_matches(TokenType.SEMICOLON) || _matches(TokenType.CLOSE_PAREN)) { 4709 TokenType type = _currentToken.type;
4710 if (type == TokenType.SEMICOLON || type == TokenType.CLOSE_PAREN) {
7603 _reportErrorForToken( 4711 _reportErrorForToken(
7604 ParserErrorCode.MISSING_EXPRESSION_IN_THROW, _currentToken); 4712 ParserErrorCode.MISSING_EXPRESSION_IN_THROW, _currentToken);
7605 return new ThrowExpression(keyword, _createSyntheticIdentifier()); 4713 return new ThrowExpression(keyword, createSyntheticIdentifier());
7606 } 4714 }
7607 Expression expression = parseExpression2(); 4715 Expression expression = parseExpression2();
7608 return new ThrowExpression(keyword, expression); 4716 return new ThrowExpression(keyword, expression);
7609 } 4717 }
7610 4718
7611 /** 4719 /**
7612 * Parse a throw expression. Return the throw expression that was parsed. 4720 * Parse a throw expression. Return the throw expression that was parsed.
7613 * 4721 *
4722 * This method assumes that the current token matches [Keyword.THROW].
4723 *
7614 * throwExpressionWithoutCascade ::= 4724 * throwExpressionWithoutCascade ::=
7615 * 'throw' expressionWithoutCascade 4725 * 'throw' expressionWithoutCascade
7616 */ 4726 */
7617 Expression _parseThrowExpressionWithoutCascade() { 4727 Expression parseThrowExpressionWithoutCascade() {
7618 Token keyword = _expectKeyword(Keyword.THROW); 4728 Token keyword = getAndAdvance();
7619 if (_matches(TokenType.SEMICOLON) || _matches(TokenType.CLOSE_PAREN)) { 4729 TokenType type = _currentToken.type;
4730 if (type == TokenType.SEMICOLON || type == TokenType.CLOSE_PAREN) {
7620 _reportErrorForToken( 4731 _reportErrorForToken(
7621 ParserErrorCode.MISSING_EXPRESSION_IN_THROW, _currentToken); 4732 ParserErrorCode.MISSING_EXPRESSION_IN_THROW, _currentToken);
7622 return new ThrowExpression(keyword, _createSyntheticIdentifier()); 4733 return new ThrowExpression(keyword, createSyntheticIdentifier());
7623 } 4734 }
7624 Expression expression = parseExpressionWithoutCascade(); 4735 Expression expression = parseExpressionWithoutCascade();
7625 return new ThrowExpression(keyword, expression); 4736 return new ThrowExpression(keyword, expression);
7626 } 4737 }
7627 4738
7628 /** 4739 /**
7629 * Parse a try statement. Return the try statement that was parsed. 4740 * Parse a try statement. Return the try statement that was parsed.
7630 * 4741 *
4742 * This method assumes that the current token matches [Keyword.TRY].
4743 *
7631 * tryStatement ::= 4744 * tryStatement ::=
7632 * 'try' block (onPart+ finallyPart? | finallyPart) 4745 * 'try' block (onPart+ finallyPart? | finallyPart)
7633 * 4746 *
7634 * onPart ::= 4747 * onPart ::=
7635 * catchPart block 4748 * catchPart block
7636 * | 'on' type catchPart? block 4749 * | 'on' type catchPart? block
7637 * 4750 *
7638 * catchPart ::= 4751 * catchPart ::=
7639 * 'catch' '(' identifier (',' identifier)? ')' 4752 * 'catch' '(' identifier (',' identifier)? ')'
7640 * 4753 *
7641 * finallyPart ::= 4754 * finallyPart ::=
7642 * 'finally' block 4755 * 'finally' block
7643 */ 4756 */
7644 Statement _parseTryStatement() { 4757 Statement parseTryStatement() {
7645 Token tryKeyword = _expectKeyword(Keyword.TRY); 4758 Token tryKeyword = getAndAdvance();
7646 Block body = parseBlock(); 4759 Block body = _parseBlockChecked();
7647 List<CatchClause> catchClauses = new List<CatchClause>(); 4760 List<CatchClause> catchClauses = <CatchClause>[];
7648 Block finallyClause = null; 4761 Block finallyClause = null;
7649 while (_matchesString(_ON) || _matchesKeyword(Keyword.CATCH)) { 4762 while (_matchesString(_ON) || _matchesKeyword(Keyword.CATCH)) {
7650 Token onKeyword = null; 4763 Token onKeyword = null;
7651 TypeName exceptionType = null; 4764 TypeName exceptionType = null;
7652 if (_matchesString(_ON)) { 4765 if (_matchesString(_ON)) {
7653 onKeyword = getAndAdvance(); 4766 onKeyword = getAndAdvance();
7654 exceptionType = parseTypeName(); 4767 exceptionType = parseTypeName(false);
7655 } 4768 }
7656 Token catchKeyword = null; 4769 Token catchKeyword = null;
7657 Token leftParenthesis = null; 4770 Token leftParenthesis = null;
7658 SimpleIdentifier exceptionParameter = null; 4771 SimpleIdentifier exceptionParameter = null;
7659 Token comma = null; 4772 Token comma = null;
7660 SimpleIdentifier stackTraceParameter = null; 4773 SimpleIdentifier stackTraceParameter = null;
7661 Token rightParenthesis = null; 4774 Token rightParenthesis = null;
7662 if (_matchesKeyword(Keyword.CATCH)) { 4775 if (_matchesKeyword(Keyword.CATCH)) {
7663 catchKeyword = getAndAdvance(); 4776 catchKeyword = getAndAdvance();
7664 leftParenthesis = _expect(TokenType.OPEN_PAREN); 4777 leftParenthesis = _expect(TokenType.OPEN_PAREN);
7665 exceptionParameter = parseSimpleIdentifier(); 4778 exceptionParameter = parseSimpleIdentifier(isDeclaration: true);
7666 if (_matches(TokenType.COMMA)) { 4779 if (_matches(TokenType.COMMA)) {
7667 comma = getAndAdvance(); 4780 comma = getAndAdvance();
7668 stackTraceParameter = parseSimpleIdentifier(); 4781 stackTraceParameter = parseSimpleIdentifier(isDeclaration: true);
7669 } 4782 }
7670 rightParenthesis = _expect(TokenType.CLOSE_PAREN); 4783 rightParenthesis = _expect(TokenType.CLOSE_PAREN);
7671 } 4784 }
7672 Block catchBody = parseBlock(); 4785 Block catchBody = _parseBlockChecked();
7673 catchClauses.add(new CatchClause( 4786 catchClauses.add(new CatchClause(
7674 onKeyword, 4787 onKeyword,
7675 exceptionType, 4788 exceptionType,
7676 catchKeyword, 4789 catchKeyword,
7677 leftParenthesis, 4790 leftParenthesis,
7678 exceptionParameter, 4791 exceptionParameter,
7679 comma, 4792 comma,
7680 stackTraceParameter, 4793 stackTraceParameter,
7681 rightParenthesis, 4794 rightParenthesis,
7682 catchBody)); 4795 catchBody));
7683 } 4796 }
7684 Token finallyKeyword = null; 4797 Token finallyKeyword = null;
7685 if (_matchesKeyword(Keyword.FINALLY)) { 4798 if (_matchesKeyword(Keyword.FINALLY)) {
7686 finallyKeyword = getAndAdvance(); 4799 finallyKeyword = getAndAdvance();
7687 finallyClause = parseBlock(); 4800 finallyClause = _parseBlockChecked();
7688 } else { 4801 } else if (catchClauses.isEmpty) {
7689 if (catchClauses.isEmpty) { 4802 _reportErrorForCurrentToken(ParserErrorCode.MISSING_CATCH_OR_FINALLY);
7690 _reportErrorForCurrentToken(ParserErrorCode.MISSING_CATCH_OR_FINALLY);
7691 }
7692 } 4803 }
7693 return new TryStatement( 4804 return new TryStatement(
7694 tryKeyword, body, catchClauses, finallyKeyword, finallyClause); 4805 tryKeyword, body, catchClauses, finallyKeyword, finallyClause);
7695 } 4806 }
7696 4807
7697 /** 4808 /**
7698 * Parse a type alias. The [commentAndMetadata] is the metadata to be 4809 * Parse a type alias. The [commentAndMetadata] is the metadata to be
7699 * associated with the member. Return the type alias that was parsed. 4810 * associated with the member. Return the type alias that was parsed.
7700 * 4811 *
4812 * This method assumes that the current token matches [Keyword.TYPEDEF].
4813 *
7701 * typeAlias ::= 4814 * typeAlias ::=
7702 * 'typedef' typeAliasBody 4815 * 'typedef' typeAliasBody
7703 * 4816 *
7704 * typeAliasBody ::= 4817 * typeAliasBody ::=
7705 * classTypeAlias 4818 * classTypeAlias
7706 * | functionTypeAlias 4819 * | functionTypeAlias
7707 * 4820 *
7708 * classTypeAlias ::= 4821 * classTypeAlias ::=
7709 * identifier typeParameters? '=' 'abstract'? mixinApplication 4822 * identifier typeParameters? '=' 'abstract'? mixinApplication
7710 * 4823 *
7711 * mixinApplication ::= 4824 * mixinApplication ::=
7712 * qualified withClause implementsClause? ';' 4825 * qualified withClause implementsClause? ';'
7713 * 4826 *
7714 * functionTypeAlias ::= 4827 * functionTypeAlias ::=
7715 * functionPrefix typeParameterList? formalParameterList ';' 4828 * functionPrefix typeParameterList? formalParameterList ';'
7716 * 4829 *
7717 * functionPrefix ::= 4830 * functionPrefix ::=
7718 * returnType? name 4831 * returnType? name
7719 */ 4832 */
7720 TypeAlias _parseTypeAlias(CommentAndMetadata commentAndMetadata) { 4833 TypeAlias parseTypeAlias(CommentAndMetadata commentAndMetadata) {
7721 Token keyword = _expectKeyword(Keyword.TYPEDEF); 4834 Token keyword = getAndAdvance();
7722 if (_matchesIdentifier()) { 4835 if (_matchesIdentifier()) {
7723 Token next = _peek(); 4836 Token next = _peek();
7724 if (_tokenMatches(next, TokenType.LT)) { 4837 if (_tokenMatches(next, TokenType.LT)) {
7725 next = _skipTypeParameterList(next); 4838 next = _skipTypeParameterList(next);
7726 if (next != null && _tokenMatches(next, TokenType.EQ)) { 4839 if (next != null && _tokenMatches(next, TokenType.EQ)) {
7727 TypeAlias typeAlias = 4840 TypeAlias typeAlias =
7728 _parseClassTypeAlias(commentAndMetadata, null, keyword); 4841 parseClassTypeAlias(commentAndMetadata, null, keyword);
7729 _reportErrorForToken( 4842 _reportErrorForToken(
7730 ParserErrorCode.DEPRECATED_CLASS_TYPE_ALIAS, keyword); 4843 ParserErrorCode.DEPRECATED_CLASS_TYPE_ALIAS, keyword);
7731 return typeAlias; 4844 return typeAlias;
7732 } 4845 }
7733 } else if (_tokenMatches(next, TokenType.EQ)) { 4846 } else if (_tokenMatches(next, TokenType.EQ)) {
7734 TypeAlias typeAlias = 4847 TypeAlias typeAlias =
7735 _parseClassTypeAlias(commentAndMetadata, null, keyword); 4848 parseClassTypeAlias(commentAndMetadata, null, keyword);
7736 _reportErrorForToken( 4849 _reportErrorForToken(
7737 ParserErrorCode.DEPRECATED_CLASS_TYPE_ALIAS, keyword); 4850 ParserErrorCode.DEPRECATED_CLASS_TYPE_ALIAS, keyword);
7738 return typeAlias; 4851 return typeAlias;
7739 } 4852 }
7740 } 4853 }
7741 return _parseFunctionTypeAlias(commentAndMetadata, keyword); 4854 return _parseFunctionTypeAlias(commentAndMetadata, keyword);
7742 } 4855 }
7743 4856
7744 /** 4857 /**
4858 * Parse a list of type arguments. Return the type argument list that was
4859 * parsed.
4860 *
4861 * This method assumes that the current token matches `TokenType.LT`.
4862 *
4863 * typeArguments ::=
4864 * '<' typeList '>'
4865 *
4866 * typeList ::=
4867 * type (',' type)*
4868 */
4869 TypeArgumentList parseTypeArgumentList() {
4870 Token leftBracket = getAndAdvance();
4871 List<TypeName> arguments = <TypeName>[parseTypeName(false)];
4872 while (_optional(TokenType.COMMA)) {
4873 arguments.add(parseTypeName(false));
4874 }
4875 Token rightBracket = _expectGt();
4876 return new TypeArgumentList(leftBracket, arguments, rightBracket);
4877 }
4878
4879 /**
4880 * Parse a type name. Return the type name that was parsed.
4881 *
4882 * type ::=
4883 * qualified typeArguments?
4884 */
4885 TypeName parseTypeName(bool inExpression) {
4886 TypeName realType = _parseTypeName(inExpression);
4887 // If this is followed by a generic method type comment, allow the comment
4888 // type to replace the real type name.
4889 // TODO(jmesserly): this feels like a big hammer. Can we restrict it to
4890 // only work inside generic methods?
4891 TypeName typeFromComment = _parseOptionalTypeNameComment();
4892 return typeFromComment ?? realType;
4893 }
4894
4895 /**
4896 * Parse a type parameter. Return the type parameter that was parsed.
4897 *
4898 * typeParameter ::=
4899 * metadata name ('extends' bound)?
4900 */
4901 TypeParameter parseTypeParameter() {
4902 CommentAndMetadata commentAndMetadata = parseCommentAndMetadata();
4903 SimpleIdentifier name = parseSimpleIdentifier(isDeclaration: true);
4904 if (_matches(TokenType.QUESTION)) {
4905 _reportErrorForCurrentToken(ParserErrorCode.NULLABLE_TYPE_PARAMETER);
4906 _advance();
4907 }
4908 if (_matchesKeyword(Keyword.EXTENDS)) {
4909 Token keyword = getAndAdvance();
4910 TypeName bound = parseTypeName(false);
4911 return new TypeParameter(commentAndMetadata.comment,
4912 commentAndMetadata.metadata, name, keyword, bound);
4913 }
4914 return new TypeParameter(commentAndMetadata.comment,
4915 commentAndMetadata.metadata, name, null, null);
4916 }
4917
4918 /**
4919 * Parse a list of type parameters. Return the list of type parameters that
4920 * were parsed.
4921 *
4922 * This method assumes that the current token matches `TokenType.LT`.
4923 *
4924 * typeParameterList ::=
4925 * '<' typeParameter (',' typeParameter)* '>'
4926 */
4927 TypeParameterList parseTypeParameterList() {
4928 Token leftBracket = getAndAdvance();
4929 List<TypeParameter> typeParameters = <TypeParameter>[parseTypeParameter()];
4930 while (_optional(TokenType.COMMA)) {
4931 typeParameters.add(parseTypeParameter());
4932 }
4933 Token rightBracket = _expectGt();
4934 return new TypeParameterList(leftBracket, typeParameters, rightBracket);
4935 }
4936
4937 /**
7745 * Parse a unary expression. Return the unary expression that was parsed. 4938 * Parse a unary expression. Return the unary expression that was parsed.
7746 * 4939 *
7747 * unaryExpression ::= 4940 * unaryExpression ::=
7748 * prefixOperator unaryExpression 4941 * prefixOperator unaryExpression
7749 * | awaitExpression 4942 * | awaitExpression
7750 * | postfixExpression 4943 * | postfixExpression
7751 * | unaryOperator 'super' 4944 * | unaryOperator 'super'
7752 * | '-' 'super' 4945 * | '-' 'super'
7753 * | incrementOperator assignableExpression 4946 * | incrementOperator assignableExpression
7754 */ 4947 */
7755 Expression _parseUnaryExpression() { 4948 Expression parseUnaryExpression() {
7756 if (_matches(TokenType.MINUS) || 4949 TokenType type = _currentToken.type;
7757 _matches(TokenType.BANG) || 4950 if (type == TokenType.MINUS ||
7758 _matches(TokenType.TILDE)) { 4951 type == TokenType.BANG ||
4952 type == TokenType.TILDE) {
7759 Token operator = getAndAdvance(); 4953 Token operator = getAndAdvance();
7760 if (_matchesKeyword(Keyword.SUPER)) { 4954 if (_matchesKeyword(Keyword.SUPER)) {
7761 if (_tokenMatches(_peek(), TokenType.OPEN_SQUARE_BRACKET) || 4955 TokenType nextType = _peek().type;
7762 _tokenMatches(_peek(), TokenType.PERIOD)) { 4956 if (nextType == TokenType.OPEN_SQUARE_BRACKET ||
4957 nextType == TokenType.PERIOD) {
7763 // "prefixOperator unaryExpression" 4958 // "prefixOperator unaryExpression"
7764 // --> "prefixOperator postfixExpression" 4959 // --> "prefixOperator postfixExpression"
7765 // --> "prefixOperator primary selector*" 4960 // --> "prefixOperator primary selector*"
7766 // --> "prefixOperator 'super' assignableSelector selector*" 4961 // --> "prefixOperator 'super' assignableSelector selector*"
7767 return new PrefixExpression(operator, _parseUnaryExpression()); 4962 return new PrefixExpression(operator, parseUnaryExpression());
7768 } 4963 }
7769 return new PrefixExpression( 4964 return new PrefixExpression(
7770 operator, new SuperExpression(getAndAdvance())); 4965 operator, new SuperExpression(getAndAdvance()));
7771 } 4966 }
7772 return new PrefixExpression(operator, _parseUnaryExpression()); 4967 return new PrefixExpression(operator, parseUnaryExpression());
7773 } else if (_currentToken.type.isIncrementOperator) { 4968 } else if (_currentToken.type.isIncrementOperator) {
7774 Token operator = getAndAdvance(); 4969 Token operator = getAndAdvance();
7775 if (_matchesKeyword(Keyword.SUPER)) { 4970 if (_matchesKeyword(Keyword.SUPER)) {
7776 if (_tokenMatches(_peek(), TokenType.OPEN_SQUARE_BRACKET) || 4971 TokenType nextType = _peek().type;
7777 _tokenMatches(_peek(), TokenType.PERIOD)) { 4972 if (nextType == TokenType.OPEN_SQUARE_BRACKET ||
4973 nextType == TokenType.PERIOD) {
7778 // --> "prefixOperator 'super' assignableSelector selector*" 4974 // --> "prefixOperator 'super' assignableSelector selector*"
7779 return new PrefixExpression(operator, _parseUnaryExpression()); 4975 return new PrefixExpression(operator, parseUnaryExpression());
7780 } 4976 }
7781 // 4977 //
7782 // Even though it is not valid to use an incrementing operator 4978 // Even though it is not valid to use an incrementing operator
7783 // ('++' or '--') before 'super', we can (and therefore must) interpret 4979 // ('++' or '--') before 'super', we can (and therefore must) interpret
7784 // "--super" as semantically equivalent to "-(-super)". Unfortunately, 4980 // "--super" as semantically equivalent to "-(-super)". Unfortunately,
7785 // we cannot do the same for "++super" because "+super" is also not 4981 // we cannot do the same for "++super" because "+super" is also not
7786 // valid. 4982 // valid.
7787 // 4983 //
7788 if (operator.type == TokenType.MINUS_MINUS) { 4984 if (type == TokenType.MINUS_MINUS) {
7789 Token firstOperator = _createToken(operator, TokenType.MINUS); 4985 Token firstOperator = _createToken(operator, TokenType.MINUS);
7790 Token secondOperator = 4986 Token secondOperator =
7791 new Token(TokenType.MINUS, operator.offset + 1); 4987 new Token(TokenType.MINUS, operator.offset + 1);
7792 secondOperator.setNext(_currentToken); 4988 secondOperator.setNext(_currentToken);
7793 firstOperator.setNext(secondOperator); 4989 firstOperator.setNext(secondOperator);
7794 operator.previous.setNext(firstOperator); 4990 operator.previous.setNext(firstOperator);
7795 return new PrefixExpression( 4991 return new PrefixExpression(
7796 firstOperator, 4992 firstOperator,
7797 new PrefixExpression( 4993 new PrefixExpression(
7798 secondOperator, new SuperExpression(getAndAdvance()))); 4994 secondOperator, new SuperExpression(getAndAdvance())));
7799 } else {
7800 // Invalid operator before 'super'
7801 _reportErrorForCurrentToken(
7802 ParserErrorCode.INVALID_OPERATOR_FOR_SUPER, [operator.lexeme]);
7803 return new PrefixExpression(
7804 operator, new SuperExpression(getAndAdvance()));
7805 } 4995 }
4996 // Invalid operator before 'super'
4997 _reportErrorForCurrentToken(
4998 ParserErrorCode.INVALID_OPERATOR_FOR_SUPER, [operator.lexeme]);
4999 return new PrefixExpression(
5000 operator, new SuperExpression(getAndAdvance()));
7806 } 5001 }
7807 return new PrefixExpression(operator, _parseAssignableExpression(false)); 5002 return new PrefixExpression(
7808 } else if (_matches(TokenType.PLUS)) { 5003 operator, _parseAssignableExpressionNotStartingWithSuper(false));
5004 } else if (type == TokenType.PLUS) {
7809 _reportErrorForCurrentToken(ParserErrorCode.MISSING_IDENTIFIER); 5005 _reportErrorForCurrentToken(ParserErrorCode.MISSING_IDENTIFIER);
7810 return _createSyntheticIdentifier(); 5006 return createSyntheticIdentifier();
7811 } else if (_inAsync && _matchesString(_AWAIT)) { 5007 } else if (_inAsync && _matchesString(_AWAIT)) {
7812 return _parseAwaitExpression(); 5008 return parseAwaitExpression();
7813 } 5009 }
7814 return _parsePostfixExpression(); 5010 return parsePostfixExpression();
7815 } 5011 }
7816 5012
7817 /** 5013 /**
7818 * Parse a string literal representing a URI. Return the string literal that
7819 * was parsed.
7820 */
7821 StringLiteral _parseUri() {
7822 bool iskeywordAfterUri(Token token) => token.lexeme == Keyword.AS.syntax ||
7823 token.lexeme == _HIDE ||
7824 token.lexeme == _SHOW;
7825 if (!_matches(TokenType.STRING) &&
7826 !_matches(TokenType.SEMICOLON) &&
7827 !iskeywordAfterUri(_currentToken)) {
7828 // Attempt to recover in the case where the URI was not enclosed in
7829 // quotes.
7830 Token token = _currentToken;
7831 while ((_tokenMatchesIdentifier(token) && !iskeywordAfterUri(token)) ||
7832 _tokenMatches(token, TokenType.COLON) ||
7833 _tokenMatches(token, TokenType.SLASH) ||
7834 _tokenMatches(token, TokenType.PERIOD) ||
7835 _tokenMatches(token, TokenType.PERIOD_PERIOD) ||
7836 _tokenMatches(token, TokenType.PERIOD_PERIOD_PERIOD) ||
7837 _tokenMatches(token, TokenType.INT) ||
7838 _tokenMatches(token, TokenType.DOUBLE)) {
7839 token = token.next;
7840 }
7841 if (_tokenMatches(token, TokenType.SEMICOLON) ||
7842 iskeywordAfterUri(token)) {
7843 Token endToken = token.previous;
7844 token = _currentToken;
7845 int endOffset = token.end;
7846 StringBuffer buffer = new StringBuffer();
7847 buffer.write(token.lexeme);
7848 while (token != endToken) {
7849 token = token.next;
7850 if (token.offset != endOffset || token.precedingComments != null) {
7851 return parseStringLiteral();
7852 }
7853 buffer.write(token.lexeme);
7854 endOffset = token.end;
7855 }
7856 String value = buffer.toString();
7857 Token newToken =
7858 new StringToken(TokenType.STRING, "'$value'", _currentToken.offset);
7859 _reportErrorForToken(
7860 ParserErrorCode.NON_STRING_LITERAL_AS_URI, newToken);
7861 _currentToken = endToken.next;
7862 return new SimpleStringLiteral(newToken, value);
7863 }
7864 }
7865 return parseStringLiteral();
7866 }
7867
7868 /**
7869 * Parse a variable declaration. Return the variable declaration that was 5014 * Parse a variable declaration. Return the variable declaration that was
7870 * parsed. 5015 * parsed.
7871 * 5016 *
7872 * variableDeclaration ::= 5017 * variableDeclaration ::=
7873 * identifier ('=' expression)? 5018 * identifier ('=' expression)?
7874 */ 5019 */
7875 VariableDeclaration _parseVariableDeclaration() { 5020 VariableDeclaration parseVariableDeclaration() {
7876 // TODO(paulberry): prior to the fix for bug 23204, we permitted 5021 // TODO(paulberry): prior to the fix for bug 23204, we permitted
7877 // annotations before variable declarations (e.g. "String @deprecated s;"). 5022 // annotations before variable declarations (e.g. "String @deprecated s;").
7878 // Although such constructions are prohibited by the spec, we may want to 5023 // Although such constructions are prohibited by the spec, we may want to
7879 // consider handling them anyway to allow for better parser recovery in the 5024 // consider handling them anyway to allow for better parser recovery in the
7880 // event that the user erroneously tries to use them. However, as a 5025 // event that the user erroneously tries to use them. However, as a
7881 // counterargument, this would likely degrade parser recovery in the event 5026 // counterargument, this would likely degrade parser recovery in the event
7882 // of a construct like "class C { int @deprecated foo() {} }" (i.e. the 5027 // of a construct like "class C { int @deprecated foo() {} }" (i.e. the
7883 // user is in the middle of inserting "int bar;" prior to 5028 // user is in the middle of inserting "int bar;" prior to
7884 // "@deprecated foo() {}"). 5029 // "@deprecated foo() {}").
7885 SimpleIdentifier name = parseSimpleIdentifier(); 5030 SimpleIdentifier name = parseSimpleIdentifier(isDeclaration: true);
7886 Token equals = null; 5031 Token equals = null;
7887 Expression initializer = null; 5032 Expression initializer = null;
7888 if (_matches(TokenType.EQ)) { 5033 if (_matches(TokenType.EQ)) {
7889 equals = getAndAdvance(); 5034 equals = getAndAdvance();
7890 initializer = parseExpression2(); 5035 initializer = parseExpression2();
7891 } 5036 }
7892 return new VariableDeclaration(name, equals, initializer); 5037 return new VariableDeclaration(name, equals, initializer);
7893 } 5038 }
7894 5039
7895 /** 5040 /**
7896 * Parse a variable declaration list. The [commentAndMetadata] is the metadata 5041 * Parse a variable declaration list. The [commentAndMetadata] is the metadata
7897 * to be associated with the variable declaration list. Return the variable 5042 * to be associated with the variable declaration list. Return the variable
7898 * declaration list that was parsed. 5043 * declaration list that was parsed.
7899 * 5044 *
7900 * variableDeclarationList ::= 5045 * variableDeclarationList ::=
7901 * finalConstVarOrType variableDeclaration (',' variableDeclaration)* 5046 * finalConstVarOrType variableDeclaration (',' variableDeclaration)*
7902 */ 5047 */
7903 VariableDeclarationList _parseVariableDeclarationListAfterMetadata( 5048 VariableDeclarationList parseVariableDeclarationListAfterMetadata(
7904 CommentAndMetadata commentAndMetadata) { 5049 CommentAndMetadata commentAndMetadata) {
7905 FinalConstVarOrType holder = _parseFinalConstVarOrType(false); 5050 FinalConstVarOrType holder = parseFinalConstVarOrType(false);
7906 return _parseVariableDeclarationListAfterType( 5051 return parseVariableDeclarationListAfterType(
7907 commentAndMetadata, holder.keyword, holder.type); 5052 commentAndMetadata, holder.keyword, holder.type);
7908 } 5053 }
7909 5054
7910 /** 5055 /**
7911 * Parse a variable declaration list. The [commentAndMetadata] is the metadata 5056 * Parse a variable declaration list. The [commentAndMetadata] is the metadata
7912 * to be associated with the variable declaration list, or `null` if there is 5057 * to be associated with the variable declaration list, or `null` if there is
7913 * no attempt at parsing the comment and metadata. The [keyword] is the token 5058 * no attempt at parsing the comment and metadata. The [keyword] is the token
7914 * representing the 'final', 'const' or 'var' keyword, or `null` if there is 5059 * representing the 'final', 'const' or 'var' keyword, or `null` if there is
7915 * no keyword. The [type] is the type of the variables in the list. Return the 5060 * no keyword. The [type] is the type of the variables in the list. Return the
7916 * variable declaration list that was parsed. 5061 * variable declaration list that was parsed.
7917 * 5062 *
7918 * variableDeclarationList ::= 5063 * variableDeclarationList ::=
7919 * finalConstVarOrType variableDeclaration (',' variableDeclaration)* 5064 * finalConstVarOrType variableDeclaration (',' variableDeclaration)*
7920 */ 5065 */
7921 VariableDeclarationList _parseVariableDeclarationListAfterType( 5066 VariableDeclarationList parseVariableDeclarationListAfterType(
7922 CommentAndMetadata commentAndMetadata, Token keyword, TypeName type) { 5067 CommentAndMetadata commentAndMetadata, Token keyword, TypeName type) {
7923 if (type != null && 5068 if (type != null &&
7924 keyword != null && 5069 keyword != null &&
7925 _tokenMatchesKeyword(keyword, Keyword.VAR)) { 5070 _tokenMatchesKeyword(keyword, Keyword.VAR)) {
7926 _reportErrorForToken(ParserErrorCode.VAR_AND_TYPE, keyword); 5071 _reportErrorForToken(ParserErrorCode.VAR_AND_TYPE, keyword);
7927 } 5072 }
7928 List<VariableDeclaration> variables = new List<VariableDeclaration>(); 5073 List<VariableDeclaration> variables = <VariableDeclaration>[
7929 variables.add(_parseVariableDeclaration()); 5074 parseVariableDeclaration()
7930 while (_matches(TokenType.COMMA)) { 5075 ];
7931 _advance(); 5076 while (_optional(TokenType.COMMA)) {
7932 variables.add(_parseVariableDeclaration()); 5077 variables.add(parseVariableDeclaration());
7933 } 5078 }
7934 return new VariableDeclarationList( 5079 return new VariableDeclarationList(commentAndMetadata?.comment,
7935 commentAndMetadata != null ? commentAndMetadata.comment : null, 5080 commentAndMetadata?.metadata, keyword, type, variables);
7936 commentAndMetadata != null ? commentAndMetadata.metadata : null,
7937 keyword,
7938 type,
7939 variables);
7940 } 5081 }
7941 5082
7942 /** 5083 /**
7943 * Parse a variable declaration statement. The [commentAndMetadata] is the 5084 * Parse a variable declaration statement. The [commentAndMetadata] is the
7944 * metadata to be associated with the variable declaration statement, or 5085 * metadata to be associated with the variable declaration statement, or
7945 * `null` if there is no attempt at parsing the comment and metadata. Return 5086 * `null` if there is no attempt at parsing the comment and metadata. Return
7946 * the variable declaration statement that was parsed. 5087 * the variable declaration statement that was parsed.
7947 * 5088 *
7948 * variableDeclarationStatement ::= 5089 * variableDeclarationStatement ::=
7949 * variableDeclarationList ';' 5090 * variableDeclarationList ';'
7950 */ 5091 */
7951 VariableDeclarationStatement _parseVariableDeclarationStatementAfterMetadata( 5092 VariableDeclarationStatement parseVariableDeclarationStatementAfterMetadata(
7952 CommentAndMetadata commentAndMetadata) { 5093 CommentAndMetadata commentAndMetadata) {
7953 // Token startToken = currentToken; 5094 // Token startToken = currentToken;
7954 VariableDeclarationList variableList = 5095 VariableDeclarationList variableList =
7955 _parseVariableDeclarationListAfterMetadata(commentAndMetadata); 5096 parseVariableDeclarationListAfterMetadata(commentAndMetadata);
7956 // if (!matches(TokenType.SEMICOLON)) { 5097 // if (!matches(TokenType.SEMICOLON)) {
7957 // if (matches(startToken, Keyword.VAR) && isTypedIdentifier(startToken .getNext())) { 5098 // if (matches(startToken, Keyword.VAR) && isTypedIdentifier(startToken .getNext())) {
7958 // // TODO(brianwilkerson) This appears to be of the form "var type v ariable". We should do 5099 // // TODO(brianwilkerson) This appears to be of the form "var type v ariable". We should do
7959 // // a better job of recovering in this case. 5100 // // a better job of recovering in this case.
7960 // } 5101 // }
7961 // } 5102 // }
7962 Token semicolon = _expect(TokenType.SEMICOLON); 5103 Token semicolon = _expect(TokenType.SEMICOLON);
7963 return new VariableDeclarationStatement(variableList, semicolon); 5104 return new VariableDeclarationStatement(variableList, semicolon);
7964 } 5105 }
7965 5106
7966 /** 5107 /**
7967 * Parse a variable declaration statement. The [commentAndMetadata] is the
7968 * metadata to be associated with the variable declaration statement, or
7969 * `null` if there is no attempt at parsing the comment and metadata. The
7970 * [keyword] is the token representing the 'final', 'const' or 'var' keyword,
7971 * or `null` if there is no keyword. The [type] is the type of the variables
7972 * in the list. Return the variable declaration statement that was parsed.
7973 *
7974 * variableDeclarationStatement ::=
7975 * variableDeclarationList ';'
7976 */
7977 VariableDeclarationStatement _parseVariableDeclarationStatementAfterType(
7978 CommentAndMetadata commentAndMetadata, Token keyword, TypeName type) {
7979 VariableDeclarationList variableList =
7980 _parseVariableDeclarationListAfterType(
7981 commentAndMetadata, keyword, type);
7982 Token semicolon = _expect(TokenType.SEMICOLON);
7983 return new VariableDeclarationStatement(variableList, semicolon);
7984 }
7985
7986 /**
7987 * Parse a while statement. Return the while statement that was parsed. 5108 * Parse a while statement. Return the while statement that was parsed.
7988 * 5109 *
5110 * This method assumes that the current token matches [Keyword.WHILE].
5111 *
7989 * whileStatement ::= 5112 * whileStatement ::=
7990 * 'while' '(' expression ')' statement 5113 * 'while' '(' expression ')' statement
7991 */ 5114 */
7992 Statement _parseWhileStatement() { 5115 Statement parseWhileStatement() {
7993 bool wasInLoop = _inLoop; 5116 bool wasInLoop = _inLoop;
7994 _inLoop = true; 5117 _inLoop = true;
7995 try { 5118 try {
7996 Token keyword = _expectKeyword(Keyword.WHILE); 5119 Token keyword = getAndAdvance();
7997 Token leftParenthesis = _expect(TokenType.OPEN_PAREN); 5120 Token leftParenthesis = _expect(TokenType.OPEN_PAREN);
7998 Expression condition = parseExpression2(); 5121 Expression condition = parseExpression2();
7999 Token rightParenthesis = _expect(TokenType.CLOSE_PAREN); 5122 Token rightParenthesis = _expect(TokenType.CLOSE_PAREN);
8000 Statement body = parseStatement2(); 5123 Statement body = parseStatement2();
8001 return new WhileStatement( 5124 return new WhileStatement(
8002 keyword, leftParenthesis, condition, rightParenthesis, body); 5125 keyword, leftParenthesis, condition, rightParenthesis, body);
8003 } finally { 5126 } finally {
8004 _inLoop = wasInLoop; 5127 _inLoop = wasInLoop;
8005 } 5128 }
8006 } 5129 }
8007 5130
8008 /** 5131 /**
5132 * Parse a with clause. Return the with clause that was parsed.
5133 *
5134 * This method assumes that the current token matches `Keyword.WITH`.
5135 *
5136 * withClause ::=
5137 * 'with' typeName (',' typeName)*
5138 */
5139 WithClause parseWithClause() {
5140 Token withKeyword = getAndAdvance();
5141 List<TypeName> types = <TypeName>[];
5142 do {
5143 TypeName typeName = parseTypeName(false);
5144 _mustNotBeNullable(typeName, ParserErrorCode.NULLABLE_TYPE_IN_WITH);
5145 types.add(typeName);
5146 } while (_optional(TokenType.COMMA));
5147 return new WithClause(withKeyword, types);
5148 }
5149
5150 /**
8009 * Parse a yield statement. Return the yield statement that was parsed. 5151 * Parse a yield statement. Return the yield statement that was parsed.
8010 * 5152 *
5153 * This method assumes that the current token matches [Keyword.YIELD].
5154 *
8011 * yieldStatement ::= 5155 * yieldStatement ::=
8012 * 'yield' '*'? expression ';' 5156 * 'yield' '*'? expression ';'
8013 */ 5157 */
8014 YieldStatement _parseYieldStatement() { 5158 YieldStatement parseYieldStatement() {
8015 Token yieldToken = getAndAdvance(); 5159 Token yieldToken = getAndAdvance();
8016 Token star = null; 5160 Token star = null;
8017 if (_matches(TokenType.STAR)) { 5161 if (_matches(TokenType.STAR)) {
8018 star = getAndAdvance(); 5162 star = getAndAdvance();
8019 } 5163 }
8020 Expression expression = parseExpression2(); 5164 Expression expression = parseExpression2();
8021 Token semicolon = _expect(TokenType.SEMICOLON); 5165 Token semicolon = _expect(TokenType.SEMICOLON);
8022 return new YieldStatement(yieldToken, star, expression, semicolon); 5166 return new YieldStatement(yieldToken, star, expression, semicolon);
8023 } 5167 }
8024 5168
8025 /** 5169 /**
5170 * Parse a prefixed identifier, starting at the [startToken], without actually
5171 * creating a prefixed identifier or changing the current token. Return the
5172 * token following the prefixed identifier that was parsed, or `null` if the
5173 * given token is not the first token in a valid prefixed identifier.
5174 *
5175 * This method must be kept in sync with [parsePrefixedIdentifier].
5176 *
5177 * prefixedIdentifier ::=
5178 * identifier ('.' identifier)?
5179 */
5180 Token skipPrefixedIdentifier(Token startToken) {
5181 Token token = skipSimpleIdentifier(startToken);
5182 if (token == null) {
5183 return null;
5184 } else if (!_tokenMatches(token, TokenType.PERIOD)) {
5185 return token;
5186 }
5187 token = token.next;
5188 Token nextToken = skipSimpleIdentifier(token);
5189 if (nextToken != null) {
5190 return nextToken;
5191 } else if (_tokenMatches(token, TokenType.CLOSE_PAREN) ||
5192 _tokenMatches(token, TokenType.COMMA)) {
5193 // If the `id.` is followed by something that cannot produce a valid
5194 // structure then assume this is a prefixed identifier but missing the
5195 // trailing identifier
5196 return token;
5197 }
5198 return null;
5199 }
5200
5201 /**
5202 * Parse a return type, starting at the [startToken], without actually
5203 * creating a return type or changing the current token. Return the token
5204 * following the return type that was parsed, or `null` if the given token is
5205 * not the first token in a valid return type.
5206 *
5207 * This method must be kept in sync with [parseReturnType].
5208 *
5209 * returnType ::=
5210 * 'void'
5211 * | type
5212 */
5213 Token skipReturnType(Token startToken) {
5214 if (_tokenMatchesKeyword(startToken, Keyword.VOID)) {
5215 return startToken.next;
5216 } else {
5217 return skipTypeName(startToken);
5218 }
5219 }
5220
5221 /**
5222 * Parse a simple identifier, starting at the [startToken], without actually
5223 * creating a simple identifier or changing the current token. Return the
5224 * token following the simple identifier that was parsed, or `null` if the
5225 * given token is not the first token in a valid simple identifier.
5226 *
5227 * This method must be kept in sync with [parseSimpleIdentifier].
5228 *
5229 * identifier ::=
5230 * IDENTIFIER
5231 */
5232 Token skipSimpleIdentifier(Token startToken) {
5233 if (_tokenMatches(startToken, TokenType.IDENTIFIER) ||
5234 _tokenMatchesPseudoKeyword(startToken)) {
5235 return startToken.next;
5236 }
5237 return null;
5238 }
5239
5240 /**
5241 * Parse a string literal, starting at the [startToken], without actually
5242 * creating a string literal or changing the current token. Return the token
5243 * following the string literal that was parsed, or `null` if the given token
5244 * is not the first token in a valid string literal.
5245 *
5246 * This method must be kept in sync with [parseStringLiteral].
5247 *
5248 * stringLiteral ::=
5249 * MULTI_LINE_STRING+
5250 * | SINGLE_LINE_STRING+
5251 */
5252 Token skipStringLiteral(Token startToken) {
5253 Token token = startToken;
5254 while (token != null && _tokenMatches(token, TokenType.STRING)) {
5255 token = token.next;
5256 TokenType type = token.type;
5257 if (type == TokenType.STRING_INTERPOLATION_EXPRESSION ||
5258 type == TokenType.STRING_INTERPOLATION_IDENTIFIER) {
5259 token = _skipStringInterpolation(token);
5260 }
5261 }
5262 if (identical(token, startToken)) {
5263 return null;
5264 }
5265 return token;
5266 }
5267
5268 /**
5269 * Parse a list of type arguments, starting at the [startToken], without
5270 * actually creating a type argument list or changing the current token.
5271 * Return the token following the type argument list that was parsed, or
5272 * `null` if the given token is not the first token in a valid type argument
5273 * list.
5274 *
5275 * This method must be kept in sync with [parseTypeArgumentList].
5276 *
5277 * typeArguments ::=
5278 * '<' typeList '>'
5279 *
5280 * typeList ::=
5281 * type (',' type)*
5282 */
5283 Token skipTypeArgumentList(Token startToken) {
5284 Token token = startToken;
5285 if (!_tokenMatches(token, TokenType.LT) &&
5286 !_injectGenericCommentTypeList()) {
5287 return null;
5288 }
5289 token = skipTypeName(token.next);
5290 if (token == null) {
5291 // If the start token '<' is followed by '>'
5292 // then assume this should be type argument list but is missing a type
5293 token = startToken.next;
5294 if (_tokenMatches(token, TokenType.GT)) {
5295 return token.next;
5296 }
5297 return null;
5298 }
5299 while (_tokenMatches(token, TokenType.COMMA)) {
5300 token = skipTypeName(token.next);
5301 if (token == null) {
5302 return null;
5303 }
5304 }
5305 if (token.type == TokenType.GT) {
5306 return token.next;
5307 } else if (token.type == TokenType.GT_GT) {
5308 Token second = new Token(TokenType.GT, token.offset + 1);
5309 second.setNextWithoutSettingPrevious(token.next);
5310 return second;
5311 }
5312 return null;
5313 }
5314
5315 /**
5316 * Parse a type name, starting at the [startToken], without actually creating
5317 * a type name or changing the current token. Return the token following the
5318 * type name that was parsed, or `null` if the given token is not the first
5319 * token in a valid type name.
5320 *
5321 * This method must be kept in sync with [parseTypeName].
5322 *
5323 * type ::=
5324 * qualified typeArguments?
5325 */
5326 Token skipTypeName(Token startToken) {
5327 Token token = skipPrefixedIdentifier(startToken);
5328 if (token == null) {
5329 return null;
5330 }
5331 if (_tokenMatches(token, TokenType.LT)) {
5332 token = skipTypeArgumentList(token);
5333 }
5334 return token;
5335 }
5336
5337 /**
5338 * Advance to the next token in the token stream.
5339 */
5340 void _advance() {
5341 _currentToken = _currentToken.next;
5342 }
5343
5344 /**
5345 * Append the character equivalent of the given [codePoint] to the given
5346 * [builder]. Use the [startIndex] and [endIndex] to report an error, and
5347 * don't append anything to the builder, if the code point is invalid. The
5348 * [escapeSequence] is the escape sequence that was parsed to produce the
5349 * code point (used for error reporting).
5350 */
5351 void _appendCodePoint(StringBuffer buffer, String source, int codePoint,
5352 int startIndex, int endIndex) {
5353 if (codePoint < 0 || codePoint > Character.MAX_CODE_POINT) {
5354 String escapeSequence = source.substring(startIndex, endIndex + 1);
5355 _reportErrorForCurrentToken(
5356 ParserErrorCode.INVALID_CODE_POINT, [escapeSequence]);
5357 return;
5358 }
5359 if (codePoint < Character.MAX_VALUE) {
5360 buffer.writeCharCode(codePoint);
5361 } else {
5362 buffer.write(Character.toChars(codePoint));
5363 }
5364 }
5365
5366 /**
5367 * Clone all token starting from the given [token] up to the end of the token
5368 * stream, and return the first token in the new token stream.
5369 */
5370 Token _cloneTokens(Token token) {
5371 if (token == null) {
5372 return null;
5373 }
5374 token = token is CommentToken ? token.parent : token;
5375 Token head = new Token(TokenType.EOF, -1);
5376 head.setNext(head);
5377 Token current = head;
5378 while (token.type != TokenType.EOF) {
5379 Token clone = token.copy();
5380 current.setNext(clone);
5381 current = clone;
5382 token = token.next;
5383 }
5384 Token tail = new Token(TokenType.EOF, 0);
5385 tail.setNext(tail);
5386 current.setNext(tail);
5387 return head.next;
5388 }
5389
5390 /**
5391 * Convert the given [method] declaration into the nearest valid top-level
5392 * function declaration (that is, the function declaration that most closely
5393 * captures the components of the given method declaration).
5394 */
5395 FunctionDeclaration _convertToFunctionDeclaration(MethodDeclaration method) =>
5396 new FunctionDeclaration(
5397 method.documentationComment,
5398 method.metadata,
5399 method.externalKeyword,
5400 method.returnType,
5401 method.propertyKeyword,
5402 method.name,
5403 new FunctionExpression(
5404 method.typeParameters, method.parameters, method.body));
5405
5406 /**
5407 * Return `true` if the current token could be the start of a compilation unit
5408 * member. This method is used for recovery purposes to decide when to stop
5409 * skipping tokens after finding an error while parsing a compilation unit
5410 * member.
5411 */
5412 bool _couldBeStartOfCompilationUnitMember() {
5413 Keyword keyword = _currentToken.keyword;
5414 Token next = _currentToken.next;
5415 TokenType nextType = next.type;
5416 if ((keyword == Keyword.IMPORT ||
5417 keyword == Keyword.EXPORT ||
5418 keyword == Keyword.LIBRARY ||
5419 keyword == Keyword.PART) &&
5420 nextType != TokenType.PERIOD &&
5421 nextType != TokenType.LT) {
5422 // This looks like the start of a directive
5423 return true;
5424 } else if (keyword == Keyword.CLASS) {
5425 // This looks like the start of a class definition
5426 return true;
5427 } else if (keyword == Keyword.TYPEDEF &&
5428 nextType != TokenType.PERIOD &&
5429 nextType != TokenType.LT) {
5430 // This looks like the start of a typedef
5431 return true;
5432 } else if (keyword == Keyword.VOID ||
5433 ((keyword == Keyword.GET || keyword == Keyword.SET) &&
5434 _tokenMatchesIdentifier(next)) ||
5435 (keyword == Keyword.OPERATOR && _isOperator(next))) {
5436 // This looks like the start of a function
5437 return true;
5438 } else if (_matchesIdentifier()) {
5439 if (nextType == TokenType.OPEN_PAREN) {
5440 // This looks like the start of a function
5441 return true;
5442 }
5443 Token token = skipReturnType(_currentToken);
5444 if (token == null) {
5445 return false;
5446 }
5447 // TODO(brianwilkerson) This looks wrong; should we be checking 'token'?
5448 if (keyword == Keyword.GET ||
5449 keyword == Keyword.SET ||
5450 (keyword == Keyword.OPERATOR && _isOperator(next)) ||
5451 _matchesIdentifier()) {
5452 return true;
5453 }
5454 }
5455 return false;
5456 }
5457
5458 /**
5459 * Return a synthetic token representing the given [keyword].
5460 */
5461 Token _createSyntheticKeyword(Keyword keyword) => _injectToken(
5462 new Parser_SyntheticKeywordToken(keyword, _currentToken.offset));
5463
5464 /**
5465 * Return a synthetic token with the given [type].
5466 */
5467 Token _createSyntheticToken(TokenType type) =>
5468 _injectToken(new StringToken(type, "", _currentToken.offset));
5469
5470 /**
5471 * Create and return a new token with the given [type]. The token will replace
5472 * the first portion of the given [token], so it will have the same offset and
5473 * will have any comments that might have preceeded the token.
5474 */
5475 Token _createToken(Token token, TokenType type, {bool isBegin: false}) {
5476 CommentToken comments = token.precedingComments;
5477 if (comments == null) {
5478 if (isBegin) {
5479 return new BeginToken(type, token.offset);
5480 }
5481 return new Token(type, token.offset);
5482 } else if (isBegin) {
5483 return new BeginTokenWithComment(type, token.offset, comments);
5484 }
5485 return new TokenWithComment(type, token.offset, comments);
5486 }
5487
5488 /**
5489 * Check that the given [expression] is assignable and report an error if it
5490 * isn't.
5491 *
5492 * assignableExpression ::=
5493 * primary (arguments* assignableSelector)+
5494 * | 'super' unconditionalAssignableSelector
5495 * | identifier
5496 *
5497 * unconditionalAssignableSelector ::=
5498 * '[' expression ']'
5499 * | '.' identifier
5500 *
5501 * assignableSelector ::=
5502 * unconditionalAssignableSelector
5503 * | '?.' identifier
5504 */
5505 void _ensureAssignable(Expression expression) {
5506 if (expression != null && !expression.isAssignable) {
5507 _reportErrorForCurrentToken(
5508 ParserErrorCode.ILLEGAL_ASSIGNMENT_TO_NON_ASSIGNABLE);
5509 }
5510 }
5511
5512 /**
5513 * If the current token has the expected type, return it after advancing to
5514 * the next token. Otherwise report an error and return the current token
5515 * without advancing.
5516 *
5517 * Note that the method [_expectGt] should be used if the argument to this
5518 * method would be [TokenType.GT].
5519 *
5520 * The [type] is the type of token that is expected.
5521 */
5522 Token _expect(TokenType type) {
5523 if (_matches(type)) {
5524 return getAndAdvance();
5525 }
5526 // Remove uses of this method in favor of matches?
5527 // Pass in the error code to use to report the error?
5528 if (type == TokenType.SEMICOLON) {
5529 if (_tokenMatches(_currentToken.next, TokenType.SEMICOLON)) {
5530 _reportErrorForCurrentToken(
5531 ParserErrorCode.UNEXPECTED_TOKEN, [_currentToken.lexeme]);
5532 _advance();
5533 return getAndAdvance();
5534 }
5535 _reportErrorForToken(ParserErrorCode.EXPECTED_TOKEN,
5536 _currentToken.previous, [type.lexeme]);
5537 return _createSyntheticToken(TokenType.SEMICOLON);
5538 }
5539 _reportErrorForCurrentToken(ParserErrorCode.EXPECTED_TOKEN, [type.lexeme]);
5540 return _createSyntheticToken(type);
5541 }
5542
5543 /**
5544 * If the current token has the type [TokenType.GT], return it after advancing
5545 * to the next token. Otherwise report an error and create a synthetic token.
5546 */
5547 Token _expectGt() {
5548 if (_matchesGt()) {
5549 return getAndAdvance();
5550 }
5551 _reportErrorForCurrentToken(
5552 ParserErrorCode.EXPECTED_TOKEN, [TokenType.GT.lexeme]);
5553 return _createSyntheticToken(TokenType.GT);
5554 }
5555
5556 /**
5557 * If the current token is a keyword matching the given [keyword], return it
5558 * after advancing to the next token. Otherwise report an error and return the
5559 * current token without advancing.
5560 */
5561 Token _expectKeyword(Keyword keyword) {
5562 if (_matchesKeyword(keyword)) {
5563 return getAndAdvance();
5564 }
5565 // Remove uses of this method in favor of matches?
5566 // Pass in the error code to use to report the error?
5567 _reportErrorForCurrentToken(
5568 ParserErrorCode.EXPECTED_TOKEN, [keyword.syntax]);
5569 return _currentToken;
5570 }
5571
5572 /**
5573 * Search the given list of [ranges] for a range that contains the given
5574 * [index]. Return the range that was found, or `null` if none of the ranges
5575 * contain the index.
5576 */
5577 List<int> _findRange(List<List<int>> ranges, int index) {
5578 int rangeCount = ranges.length;
5579 for (int i = 0; i < rangeCount; i++) {
5580 List<int> range = ranges[i];
5581 if (range[0] <= index && index <= range[1]) {
5582 return range;
5583 } else if (index < range[0]) {
5584 return null;
5585 }
5586 }
5587 return null;
5588 }
5589
5590 /**
5591 * Return a list of the ranges of characters in the given [comment] that
5592 * should be treated as code blocks.
5593 */
5594 List<List<int>> _getCodeBlockRanges(String comment) {
5595 List<List<int>> ranges = <List<int>>[];
5596 int length = comment.length;
5597 if (length < 3) {
5598 return ranges;
5599 }
5600 int index = 0;
5601 int firstChar = comment.codeUnitAt(0);
5602 if (firstChar == 0x2F) {
5603 int secondChar = comment.codeUnitAt(1);
5604 int thirdChar = comment.codeUnitAt(2);
5605 if ((secondChar == 0x2A && thirdChar == 0x2A) ||
5606 (secondChar == 0x2F && thirdChar == 0x2F)) {
5607 index = 3;
5608 }
5609 }
5610 if (StringUtilities.startsWith4(comment, index, 0x20, 0x20, 0x20, 0x20)) {
5611 int end = index + 4;
5612 while (end < length &&
5613 comment.codeUnitAt(end) != 0xD &&
5614 comment.codeUnitAt(end) != 0xA) {
5615 end = end + 1;
5616 }
5617 ranges.add(<int>[index, end]);
5618 index = end;
5619 }
5620 while (index < length) {
5621 int currentChar = comment.codeUnitAt(index);
5622 if (currentChar == 0xD || currentChar == 0xA) {
5623 index = index + 1;
5624 while (index < length &&
5625 Character.isWhitespace(comment.codeUnitAt(index))) {
5626 index = index + 1;
5627 }
5628 if (StringUtilities.startsWith6(
5629 comment, index, 0x2A, 0x20, 0x20, 0x20, 0x20, 0x20)) {
5630 int end = index + 6;
5631 while (end < length &&
5632 comment.codeUnitAt(end) != 0xD &&
5633 comment.codeUnitAt(end) != 0xA) {
5634 end = end + 1;
5635 }
5636 ranges.add(<int>[index, end]);
5637 index = end;
5638 }
5639 } else if (index + 1 < length &&
5640 currentChar == 0x5B &&
5641 comment.codeUnitAt(index + 1) == 0x3A) {
5642 int end = StringUtilities.indexOf2(comment, index + 2, 0x3A, 0x5D);
5643 if (end < 0) {
5644 end = length;
5645 }
5646 ranges.add(<int>[index, end]);
5647 index = end + 1;
5648 } else {
5649 index = index + 1;
5650 }
5651 }
5652 return ranges;
5653 }
5654
5655 /**
5656 * Return the end token associated with the given [beginToken], or `null` if
5657 * either the given token is not a begin token or it does not have an end
5658 * token associated with it.
5659 */
5660 Token _getEndToken(Token beginToken) {
5661 if (beginToken is BeginToken) {
5662 return beginToken.endToken;
5663 }
5664 return null;
5665 }
5666
5667 bool _injectGenericComment(TokenType type, int prefixLen) {
5668 if (parseGenericMethodComments) {
5669 CommentToken t = _currentToken.precedingComments;
5670 for (; t != null; t = t.next) {
5671 if (t.type == type) {
5672 String comment = t.lexeme.substring(prefixLen, t.lexeme.length - 2);
5673 Token list = _scanGenericMethodComment(comment, t.offset + prefixLen);
5674 if (list != null) {
5675 // Remove the token from the comment stream.
5676 t.remove();
5677 // Insert the tokens into the stream.
5678 _injectTokenList(list);
5679 return true;
5680 }
5681 }
5682 }
5683 }
5684 return false;
5685 }
5686
5687 /**
5688 * Matches a generic comment type substitution and injects it into the token
5689 * stream. Returns true if a match was injected, otherwise false.
5690 *
5691 * These comments are of the form `/*=T*/`, in other words, a [TypeName]
5692 * inside a slash-star comment, preceded by equals sign.
5693 */
5694 bool _injectGenericCommentTypeAssign() {
5695 return _injectGenericComment(TokenType.GENERIC_METHOD_TYPE_ASSIGN, 3);
5696 }
5697
5698 /**
5699 * Matches a generic comment type parameters and injects them into the token
5700 * stream. Returns true if a match was injected, otherwise false.
5701 *
5702 * These comments are of the form `/*<K, V>*/`, in other words, a
5703 * [TypeParameterList] or [TypeArgumentList] inside a slash-star comment.
5704 */
5705 bool _injectGenericCommentTypeList() {
5706 return _injectGenericComment(TokenType.GENERIC_METHOD_TYPE_LIST, 2);
5707 }
5708
5709 /**
5710 * Inject the given [token] into the token stream immediately before the
5711 * current token.
5712 */
5713 Token _injectToken(Token token) {
5714 Token previous = _currentToken.previous;
5715 token.setNext(_currentToken);
5716 previous.setNext(token);
5717 return token;
5718 }
5719
5720 void _injectTokenList(Token firstToken) {
5721 // Scanner creates a cyclic EOF token.
5722 Token lastToken = firstToken;
5723 while (lastToken.next.type != TokenType.EOF) {
5724 lastToken = lastToken.next;
5725 }
5726 // Inject these new tokens into the stream.
5727 Token previous = _currentToken.previous;
5728 lastToken.setNext(_currentToken);
5729 previous.setNext(firstToken);
5730 _currentToken = firstToken;
5731 }
5732
5733 /**
5734 * Return `true` if the current token could be the question mark in a
5735 * condition expression. The current token is assumed to be a question mark.
5736 */
5737 bool _isConditionalOperator() {
5738 void parseOperation(Parser parser) {
5739 parser.parseExpressionWithoutCascade();
5740 }
5741
5742 Token token = _skip(_currentToken.next, parseOperation);
5743 if (token == null || !_tokenMatches(token, TokenType.COLON)) {
5744 return false;
5745 }
5746 token = _skip(token.next, parseOperation);
5747 return token != null;
5748 }
5749
5750 /**
5751 * Return `true` if the given [character] is a valid hexadecimal digit.
5752 */
5753 bool _isHexDigit(int character) =>
5754 (0x30 <= character && character <= 0x39) ||
5755 (0x41 <= character && character <= 0x46) ||
5756 (0x61 <= character && character <= 0x66);
5757
5758 bool _isLikelyArgumentList() {
5759 // Try to reduce the amount of lookahead required here before enabling
5760 // generic methods.
5761 if (_matches(TokenType.OPEN_PAREN)) {
5762 return true;
5763 }
5764 if (!parseGenericMethods) {
5765 return false;
5766 }
5767 Token token = skipTypeArgumentList(_currentToken);
5768 return token != null && _tokenMatches(token, TokenType.OPEN_PAREN);
5769 }
5770
5771 /**
5772 * Given that we have just found bracketed text within the given [comment],
5773 * look to see whether that text is (a) followed by a parenthesized link
5774 * address, (b) followed by a colon, or (c) followed by optional whitespace
5775 * and another square bracket. The [rightIndex] is the index of the right
5776 * bracket. Return `true` if the bracketed text is followed by a link address.
5777 *
5778 * This method uses the syntax described by the
5779 * <a href="http://daringfireball.net/projects/markdown/syntax">markdown</a>
5780 * project.
5781 */
5782 bool _isLinkText(String comment, int rightIndex) {
5783 int length = comment.length;
5784 int index = rightIndex + 1;
5785 if (index >= length) {
5786 return false;
5787 }
5788 int nextChar = comment.codeUnitAt(index);
5789 if (nextChar == 0x28 || nextChar == 0x3A) {
5790 return true;
5791 }
5792 while (Character.isWhitespace(nextChar)) {
5793 index = index + 1;
5794 if (index >= length) {
5795 return false;
5796 }
5797 nextChar = comment.codeUnitAt(index);
5798 }
5799 return nextChar == 0x5B;
5800 }
5801
5802 /**
5803 * Return `true` if the given [startToken] appears to be the beginning of an
5804 * operator declaration.
5805 */
5806 bool _isOperator(Token startToken) {
5807 // Accept any operator here, even if it is not user definable.
5808 if (!startToken.isOperator) {
5809 return false;
5810 }
5811 // Token "=" means that it is actually a field initializer.
5812 if (startToken.type == TokenType.EQ) {
5813 return false;
5814 }
5815 // Consume all operator tokens.
5816 Token token = startToken.next;
5817 while (token.isOperator) {
5818 token = token.next;
5819 }
5820 // Formal parameter list is expect now.
5821 return _tokenMatches(token, TokenType.OPEN_PAREN);
5822 }
5823
5824 bool _isPeekGenericTypeParametersAndOpenParen() {
5825 if (!parseGenericMethods) {
5826 return false;
5827 }
5828 Token token = _skipTypeParameterList(_peek());
5829 return token != null && _tokenMatches(token, TokenType.OPEN_PAREN);
5830 }
5831
5832 /**
5833 * Return `true` if the [startToken] appears to be the first token of a type
5834 * name that is followed by a variable or field formal parameter.
5835 */
5836 bool _isTypedIdentifier(Token startToken) {
5837 Token token = skipReturnType(startToken);
5838 if (token == null) {
5839 return false;
5840 } else if (_tokenMatchesIdentifier(token)) {
5841 return true;
5842 } else if (_tokenMatchesKeyword(token, Keyword.THIS) &&
5843 _tokenMatches(token.next, TokenType.PERIOD) &&
5844 _tokenMatchesIdentifier(token.next.next)) {
5845 return true;
5846 } else if (_tokenMatchesKeyword(startToken, Keyword.VOID)) {
5847 // The keyword 'void' isn't a valid identifier, so it should be assumed to
5848 // be a type name.
5849 return true;
5850 } else if (startToken.next != token &&
5851 !_tokenMatches(token, TokenType.OPEN_PAREN)) {
5852 // The type is more than a simple identifier, so it should be assumed to
5853 // be a type name.
5854 return true;
5855 }
5856 return false;
5857 }
5858
5859 /**
5860 * Increments the error reporting lock level. If level is more than `0`, then
5861 * [reportError] wont report any error.
5862 */
5863 void _lockErrorListener() {
5864 _errorListenerLock++;
5865 }
5866
5867 /**
5868 * Return `true` if the current token has the given [type]. Note that the
5869 * method [_matchesGt] should be used if the argument to this method would be
5870 * [TokenType.GT].
5871 */
5872 bool _matches(TokenType type) => _currentToken.type == type;
5873
5874 /**
5875 * Return `true` if the current token has a type of [TokenType.GT]. Note that
5876 * this method, unlike other variants, will modify the token stream if
5877 * possible to match desired type. In particular, if the next token is either
5878 * a '>>' or '>>>', the token stream will be re-written and `true` will be
5879 * returned.
5880 */
5881 bool _matchesGt() {
5882 TokenType currentType = _currentToken.type;
5883 if (currentType == TokenType.GT) {
5884 return true;
5885 } else if (currentType == TokenType.GT_GT) {
5886 Token first = _createToken(_currentToken, TokenType.GT);
5887 Token second = new Token(TokenType.GT, _currentToken.offset + 1);
5888 second.setNext(_currentToken.next);
5889 first.setNext(second);
5890 _currentToken.previous.setNext(first);
5891 _currentToken = first;
5892 return true;
5893 } else if (currentType == TokenType.GT_EQ) {
5894 Token first = _createToken(_currentToken, TokenType.GT);
5895 Token second = new Token(TokenType.EQ, _currentToken.offset + 1);
5896 second.setNext(_currentToken.next);
5897 first.setNext(second);
5898 _currentToken.previous.setNext(first);
5899 _currentToken = first;
5900 return true;
5901 } else if (currentType == TokenType.GT_GT_EQ) {
5902 int offset = _currentToken.offset;
5903 Token first = _createToken(_currentToken, TokenType.GT);
5904 Token second = new Token(TokenType.GT, offset + 1);
5905 Token third = new Token(TokenType.EQ, offset + 2);
5906 third.setNext(_currentToken.next);
5907 second.setNext(third);
5908 first.setNext(second);
5909 _currentToken.previous.setNext(first);
5910 _currentToken = first;
5911 return true;
5912 }
5913 return false;
5914 }
5915
5916 /**
5917 * Return `true` if the current token is a valid identifier. Valid identifiers
5918 * include built-in identifiers (pseudo-keywords).
5919 */
5920 bool _matchesIdentifier() => _tokenMatchesIdentifier(_currentToken);
5921
5922 /**
5923 * Return `true` if the current token matches the given [keyword].
5924 */
5925 bool _matchesKeyword(Keyword keyword) =>
5926 _tokenMatchesKeyword(_currentToken, keyword);
5927
5928 /**
5929 * Return `true` if the current token matches the given [identifier].
5930 */
5931 bool _matchesString(String identifier) =>
5932 _currentToken.type == TokenType.IDENTIFIER &&
5933 _currentToken.lexeme == identifier;
5934
5935 /**
5936 * Report an error with the given [errorCode] if the given [typeName] has been
5937 * marked as nullable.
5938 */
5939 void _mustNotBeNullable(TypeName typeName, ParserErrorCode errorCode) {
5940 if (typeName.question != null) {
5941 _reportErrorForToken(errorCode, typeName.question);
5942 }
5943 }
5944
5945 /**
5946 * If the current token has the given [type], then advance to the next token
5947 * and return `true`. Otherwise, return `false` without advancing. This method
5948 * should not be invoked with an argument value of [TokenType.GT].
5949 */
5950 bool _optional(TokenType type) {
5951 if (_currentToken.type == type) {
5952 _advance();
5953 return true;
5954 }
5955 return false;
5956 }
5957
5958 /**
5959 * Parse an argument list when we need to check for an open paren and recover
5960 * when there isn't one. Return the argument list that was parsed.
5961 */
5962 ArgumentList _parseArgumentListChecked() {
5963 if (_matches(TokenType.OPEN_PAREN)) {
5964 return parseArgumentList();
5965 }
5966 _reportErrorForCurrentToken(
5967 ParserErrorCode.EXPECTED_TOKEN, [TokenType.OPEN_PAREN.lexeme]);
5968 // Recovery: Look to see whether there is a close paren that isn't matched
5969 // to an open paren and if so parse the list of arguments as normal.
5970 return new ArgumentList(_createSyntheticToken(TokenType.OPEN_PAREN), null,
5971 _createSyntheticToken(TokenType.CLOSE_PAREN));
5972 }
5973
5974 /**
5975 * Parse an assert within a constructor's initializer list. Return the assert.
5976 *
5977 * This method assumes that the current token matches `Keyword.ASSERT`.
5978 *
5979 * assertInitializer ::=
5980 * 'assert' '(' expression [',' expression] ')'
5981 */
5982 void _parseAssertInitializer() {
5983 // TODO(brianwilkerson) Capture the syntax in the AST using a new class,
5984 // such as AssertInitializer
5985 Token keyword = getAndAdvance();
5986 Token leftParen = _expect(TokenType.OPEN_PAREN);
5987 Expression expression = parseExpression2();
5988 Token comma;
5989 Expression message;
5990 if (_matches(TokenType.COMMA)) {
5991 comma = getAndAdvance();
5992 message = parseExpression2();
5993 }
5994 Token rightParen = _expect(TokenType.CLOSE_PAREN);
5995 // return new AssertInitializer(
5996 // keyword, leftParen, expression, comma, message, rightParen);
5997 }
5998
5999 /**
6000 * Parse an assignable expression given that the current token is not 'super'.
6001 * The [primaryAllowed] is `true` if the expression is allowed to be a primary
6002 * without any assignable selector. Return the assignable expression that was
6003 * parsed.
6004 */
6005 Expression _parseAssignableExpressionNotStartingWithSuper(
6006 bool primaryAllowed) {
6007 //
6008 // A primary expression can start with an identifier. We resolve the
6009 // ambiguity by determining whether the primary consists of anything other
6010 // than an identifier and/or is followed by an assignableSelector.
6011 //
6012 Expression expression = parsePrimaryExpression();
6013 bool isOptional = primaryAllowed || expression is SimpleIdentifier;
6014 while (true) {
6015 while (_isLikelyArgumentList()) {
6016 TypeArgumentList typeArguments = _parseOptionalTypeArguments();
6017 ArgumentList argumentList = parseArgumentList();
6018 Expression currentExpression = expression;
6019 if (currentExpression is SimpleIdentifier) {
6020 expression = new MethodInvocation(
6021 null, null, currentExpression, typeArguments, argumentList);
6022 } else if (currentExpression is PrefixedIdentifier) {
6023 expression = new MethodInvocation(
6024 currentExpression.prefix,
6025 currentExpression.period,
6026 currentExpression.identifier,
6027 typeArguments,
6028 argumentList);
6029 } else if (currentExpression is PropertyAccess) {
6030 expression = new MethodInvocation(
6031 currentExpression.target,
6032 currentExpression.operator,
6033 currentExpression.propertyName,
6034 typeArguments,
6035 argumentList);
6036 } else {
6037 expression = new FunctionExpressionInvocation(
6038 expression, typeArguments, argumentList);
6039 }
6040 if (!primaryAllowed) {
6041 isOptional = false;
6042 }
6043 }
6044 Expression selectorExpression = parseAssignableSelector(
6045 expression, isOptional || (expression is PrefixedIdentifier));
6046 if (identical(selectorExpression, expression)) {
6047 if (!isOptional && (expression is PrefixedIdentifier)) {
6048 PrefixedIdentifier identifier = expression as PrefixedIdentifier;
6049 expression = new PropertyAccess(
6050 identifier.prefix, identifier.period, identifier.identifier);
6051 }
6052 return expression;
6053 }
6054 expression = selectorExpression;
6055 isOptional = true;
6056 }
6057 }
6058
6059 /**
6060 * Parse a block when we need to check for an open curly brace and recover
6061 * when there isn't one. Return the block that was parsed.
6062 *
6063 * block ::=
6064 * '{' statements '}'
6065 */
6066 Block _parseBlockChecked() {
6067 if (_matches(TokenType.OPEN_CURLY_BRACKET)) {
6068 return parseBlock();
6069 }
6070 // TODO(brianwilkerson) Improve the error message.
6071 _reportErrorForCurrentToken(
6072 ParserErrorCode.EXPECTED_TOKEN, [TokenType.OPEN_CURLY_BRACKET.lexeme]);
6073 // Recovery: Check for an unmatched closing curly bracket and parse
6074 // statements until it is reached.
6075 return new Block(_createSyntheticToken(TokenType.OPEN_CURLY_BRACKET), null,
6076 _createSyntheticToken(TokenType.CLOSE_CURLY_BRACKET));
6077 }
6078
6079 /**
6080 * Parse a list of class members. The [className] is the name of the class
6081 * whose members are being parsed. The [closingBracket] is the closing bracket
6082 * for the class, or `null` if the closing bracket is missing. Return the list
6083 * of class members that were parsed.
6084 *
6085 * classMembers ::=
6086 * (metadata memberDefinition)*
6087 */
6088 List<ClassMember> _parseClassMembers(String className, Token closingBracket) {
6089 List<ClassMember> members = <ClassMember>[];
6090 Token memberStart = _currentToken;
6091 TokenType type = _currentToken.type;
6092 Keyword keyword = _currentToken.keyword;
6093 while (type != TokenType.EOF &&
6094 type != TokenType.CLOSE_CURLY_BRACKET &&
6095 (closingBracket != null ||
6096 (keyword != Keyword.CLASS && keyword != Keyword.TYPEDEF))) {
6097 if (type == TokenType.SEMICOLON) {
6098 _reportErrorForToken(ParserErrorCode.UNEXPECTED_TOKEN, _currentToken,
6099 [_currentToken.lexeme]);
6100 _advance();
6101 } else {
6102 ClassMember member = parseClassMember(className);
6103 if (member != null) {
6104 members.add(member);
6105 }
6106 }
6107 if (identical(_currentToken, memberStart)) {
6108 _reportErrorForToken(ParserErrorCode.UNEXPECTED_TOKEN, _currentToken,
6109 [_currentToken.lexeme]);
6110 _advance();
6111 }
6112 memberStart = _currentToken;
6113 type = _currentToken.type;
6114 keyword = _currentToken.keyword;
6115 }
6116 return members;
6117 }
6118
6119 /**
6120 * Parse a class type alias. The [commentAndMetadata] is the metadata to be
6121 * associated with the member. The [abstractKeyword] is the token representing
6122 * the 'abstract' keyword. The [classKeyword] is the token representing the
6123 * 'class' keyword. The [className] is the name of the alias, and the
6124 * [typeParameters] are the type parameters following the name. Return the
6125 * class type alias that was parsed.
6126 *
6127 * classTypeAlias ::=
6128 * identifier typeParameters? '=' 'abstract'? mixinApplication
6129 *
6130 * mixinApplication ::=
6131 * type withClause implementsClause? ';'
6132 */
6133 ClassTypeAlias _parseClassTypeAliasAfterName(
6134 CommentAndMetadata commentAndMetadata,
6135 Token abstractKeyword,
6136 Token classKeyword,
6137 SimpleIdentifier className,
6138 TypeParameterList typeParameters) {
6139 Token equals = _expect(TokenType.EQ);
6140 TypeName superclass = parseTypeName(false);
6141 WithClause withClause = null;
6142 if (_matchesKeyword(Keyword.WITH)) {
6143 withClause = parseWithClause();
6144 } else {
6145 _reportErrorForCurrentToken(
6146 ParserErrorCode.EXPECTED_TOKEN, [Keyword.WITH.syntax]);
6147 }
6148 ImplementsClause implementsClause = null;
6149 if (_matchesKeyword(Keyword.IMPLEMENTS)) {
6150 implementsClause = parseImplementsClause();
6151 }
6152 Token semicolon;
6153 if (_matches(TokenType.SEMICOLON)) {
6154 semicolon = getAndAdvance();
6155 } else {
6156 if (_matches(TokenType.OPEN_CURLY_BRACKET)) {
6157 _reportErrorForCurrentToken(
6158 ParserErrorCode.EXPECTED_TOKEN, [TokenType.SEMICOLON.lexeme]);
6159 Token leftBracket = getAndAdvance();
6160 _parseClassMembers(className.name, _getEndToken(leftBracket));
6161 _expect(TokenType.CLOSE_CURLY_BRACKET);
6162 } else {
6163 _reportErrorForToken(ParserErrorCode.EXPECTED_TOKEN,
6164 _currentToken.previous, [TokenType.SEMICOLON.lexeme]);
6165 }
6166 semicolon = _createSyntheticToken(TokenType.SEMICOLON);
6167 }
6168 return new ClassTypeAlias(
6169 commentAndMetadata.comment,
6170 commentAndMetadata.metadata,
6171 classKeyword,
6172 className,
6173 typeParameters,
6174 equals,
6175 abstractKeyword,
6176 superclass,
6177 withClause,
6178 implementsClause,
6179 semicolon);
6180 }
6181
6182 /**
6183 * Parse a list of configurations. Return the configurations that were parsed,
6184 * or `null` if there are no configurations.
6185 */
6186 List<Configuration> _parseConfigurations() {
6187 List<Configuration> configurations = null;
6188 while (_matchesKeyword(Keyword.IF)) {
6189 configurations ??= <Configuration>[];
6190 configurations.add(parseConfiguration());
6191 }
6192 return configurations;
6193 }
6194
6195 ConstructorDeclaration _parseConstructor(
6196 CommentAndMetadata commentAndMetadata,
6197 Token externalKeyword,
6198 Token constKeyword,
6199 Token factoryKeyword,
6200 SimpleIdentifier returnType,
6201 Token period,
6202 SimpleIdentifier name,
6203 FormalParameterList parameters) {
6204 bool bodyAllowed = externalKeyword == null;
6205 Token separator = null;
6206 List<ConstructorInitializer> initializers = null;
6207 if (_matches(TokenType.COLON)) {
6208 separator = getAndAdvance();
6209 initializers = <ConstructorInitializer>[];
6210 do {
6211 Keyword keyword = _currentToken.keyword;
6212 if (keyword == Keyword.THIS) {
6213 TokenType nextType = _peek().type;
6214 if (nextType == TokenType.OPEN_PAREN) {
6215 bodyAllowed = false;
6216 initializers.add(parseRedirectingConstructorInvocation(false));
6217 } else if (nextType == TokenType.PERIOD &&
6218 _tokenMatches(_peekAt(3), TokenType.OPEN_PAREN)) {
6219 bodyAllowed = false;
6220 initializers.add(parseRedirectingConstructorInvocation(true));
6221 } else {
6222 initializers.add(parseConstructorFieldInitializer(true));
6223 }
6224 } else if (keyword == Keyword.SUPER) {
6225 initializers.add(parseSuperConstructorInvocation());
6226 } else if (_matches(TokenType.OPEN_CURLY_BRACKET) ||
6227 _matches(TokenType.FUNCTION)) {
6228 _reportErrorForCurrentToken(ParserErrorCode.MISSING_INITIALIZER);
6229 } else if (_enableAssertInitializer &&
6230 _matchesKeyword(Keyword.ASSERT)) {
6231 _parseAssertInitializer();
6232 } else {
6233 initializers.add(parseConstructorFieldInitializer(false));
6234 }
6235 } while (_optional(TokenType.COMMA));
6236 if (factoryKeyword != null) {
6237 _reportErrorForToken(
6238 ParserErrorCode.FACTORY_WITH_INITIALIZERS, factoryKeyword);
6239 }
6240 }
6241 ConstructorName redirectedConstructor = null;
6242 FunctionBody body;
6243 if (_matches(TokenType.EQ)) {
6244 separator = getAndAdvance();
6245 redirectedConstructor = parseConstructorName();
6246 body = new EmptyFunctionBody(_expect(TokenType.SEMICOLON));
6247 if (factoryKeyword == null) {
6248 _reportErrorForNode(
6249 ParserErrorCode.REDIRECTION_IN_NON_FACTORY_CONSTRUCTOR,
6250 redirectedConstructor);
6251 }
6252 } else {
6253 body =
6254 parseFunctionBody(true, ParserErrorCode.MISSING_FUNCTION_BODY, false);
6255 if (constKeyword != null &&
6256 factoryKeyword != null &&
6257 externalKeyword == null) {
6258 _reportErrorForToken(ParserErrorCode.CONST_FACTORY, factoryKeyword);
6259 } else if (body is EmptyFunctionBody) {
6260 if (factoryKeyword != null &&
6261 externalKeyword == null &&
6262 _parseFunctionBodies) {
6263 _reportErrorForToken(
6264 ParserErrorCode.FACTORY_WITHOUT_BODY, factoryKeyword);
6265 }
6266 } else {
6267 if (constKeyword != null) {
6268 _reportErrorForNode(
6269 ParserErrorCode.CONST_CONSTRUCTOR_WITH_BODY, body);
6270 } else if (externalKeyword != null) {
6271 _reportErrorForNode(
6272 ParserErrorCode.EXTERNAL_CONSTRUCTOR_WITH_BODY, body);
6273 } else if (!bodyAllowed) {
6274 _reportErrorForNode(
6275 ParserErrorCode.REDIRECTING_CONSTRUCTOR_WITH_BODY, body);
6276 }
6277 }
6278 }
6279 return new ConstructorDeclaration(
6280 commentAndMetadata.comment,
6281 commentAndMetadata.metadata,
6282 externalKeyword,
6283 constKeyword,
6284 factoryKeyword,
6285 returnType,
6286 period,
6287 name,
6288 parameters,
6289 separator,
6290 initializers,
6291 redirectedConstructor,
6292 body);
6293 }
6294
6295 /**
6296 * Parse an enum constant declaration. Return the enum constant declaration
6297 * that was parsed.
6298 *
6299 * Specified:
6300 *
6301 * enumConstant ::=
6302 * id
6303 *
6304 * Actual:
6305 *
6306 * enumConstant ::=
6307 * metadata id
6308 */
6309 EnumConstantDeclaration _parseEnumConstantDeclaration() {
6310 CommentAndMetadata commentAndMetadata = parseCommentAndMetadata();
6311 SimpleIdentifier name;
6312 if (_matchesIdentifier()) {
6313 name = _parseSimpleIdentifierUnchecked(isDeclaration: true);
6314 } else {
6315 name = createSyntheticIdentifier();
6316 }
6317 if (commentAndMetadata.hasMetadata) {
6318 _reportErrorForNode(ParserErrorCode.ANNOTATION_ON_ENUM_CONSTANT,
6319 commentAndMetadata.metadata[0]);
6320 }
6321 return new EnumConstantDeclaration(
6322 commentAndMetadata.comment, commentAndMetadata.metadata, name);
6323 }
6324
6325 /**
6326 * Parse a list of formal parameters given that the list starts with the given
6327 * [leftParenthesis]. Return the formal parameters that were parsed.
6328 */
6329 FormalParameterList _parseFormalParameterListAfterParen(
6330 Token leftParenthesis) {
6331 if (_matches(TokenType.CLOSE_PAREN)) {
6332 return new FormalParameterList(
6333 leftParenthesis, null, null, null, getAndAdvance());
6334 }
6335 //
6336 // Even though it is invalid to have default parameters outside of brackets,
6337 // required parameters inside of brackets, or multiple groups of default and
6338 // named parameters, we allow all of these cases so that we can recover
6339 // better.
6340 //
6341 List<FormalParameter> parameters = <FormalParameter>[];
6342 Token leftSquareBracket = null;
6343 Token rightSquareBracket = null;
6344 Token leftCurlyBracket = null;
6345 Token rightCurlyBracket = null;
6346 ParameterKind kind = ParameterKind.REQUIRED;
6347 bool firstParameter = true;
6348 bool reportedMultiplePositionalGroups = false;
6349 bool reportedMultipleNamedGroups = false;
6350 bool reportedMixedGroups = false;
6351 bool wasOptionalParameter = false;
6352 Token initialToken = null;
6353 do {
6354 if (firstParameter) {
6355 firstParameter = false;
6356 } else if (!_optional(TokenType.COMMA)) {
6357 // TODO(brianwilkerson) The token is wrong, we need to recover from this
6358 // case.
6359 if (_getEndToken(leftParenthesis) != null) {
6360 _reportErrorForCurrentToken(
6361 ParserErrorCode.EXPECTED_TOKEN, [TokenType.COMMA.lexeme]);
6362 } else {
6363 _reportErrorForToken(ParserErrorCode.MISSING_CLOSING_PARENTHESIS,
6364 _currentToken.previous);
6365 break;
6366 }
6367 }
6368 initialToken = _currentToken;
6369 //
6370 // Handle the beginning of parameter groups.
6371 //
6372 TokenType type = _currentToken.type;
6373 if (type == TokenType.OPEN_SQUARE_BRACKET) {
6374 wasOptionalParameter = true;
6375 if (leftSquareBracket != null && !reportedMultiplePositionalGroups) {
6376 _reportErrorForCurrentToken(
6377 ParserErrorCode.MULTIPLE_POSITIONAL_PARAMETER_GROUPS);
6378 reportedMultiplePositionalGroups = true;
6379 }
6380 if (leftCurlyBracket != null && !reportedMixedGroups) {
6381 _reportErrorForCurrentToken(ParserErrorCode.MIXED_PARAMETER_GROUPS);
6382 reportedMixedGroups = true;
6383 }
6384 leftSquareBracket = getAndAdvance();
6385 kind = ParameterKind.POSITIONAL;
6386 } else if (type == TokenType.OPEN_CURLY_BRACKET) {
6387 wasOptionalParameter = true;
6388 if (leftCurlyBracket != null && !reportedMultipleNamedGroups) {
6389 _reportErrorForCurrentToken(
6390 ParserErrorCode.MULTIPLE_NAMED_PARAMETER_GROUPS);
6391 reportedMultipleNamedGroups = true;
6392 }
6393 if (leftSquareBracket != null && !reportedMixedGroups) {
6394 _reportErrorForCurrentToken(ParserErrorCode.MIXED_PARAMETER_GROUPS);
6395 reportedMixedGroups = true;
6396 }
6397 leftCurlyBracket = getAndAdvance();
6398 kind = ParameterKind.NAMED;
6399 }
6400 //
6401 // Parse and record the parameter.
6402 //
6403 FormalParameter parameter = parseFormalParameter(kind);
6404 parameters.add(parameter);
6405 if (kind == ParameterKind.REQUIRED && wasOptionalParameter) {
6406 _reportErrorForNode(
6407 ParserErrorCode.NORMAL_BEFORE_OPTIONAL_PARAMETERS, parameter);
6408 }
6409 //
6410 // Handle the end of parameter groups.
6411 //
6412 // TODO(brianwilkerson) Improve the detection and reporting of missing and
6413 // mismatched delimiters.
6414 type = _currentToken.type;
6415
6416 // Advance past trailing commas as appropriate.
6417 if (type == TokenType.COMMA) {
6418 // Only parse commas trailing normal (non-positional/named) params.
6419 if (rightSquareBracket == null && rightCurlyBracket == null) {
6420 Token next = _peek();
6421 if (next.type == TokenType.CLOSE_PAREN ||
6422 next.type == TokenType.CLOSE_CURLY_BRACKET ||
6423 next.type == TokenType.CLOSE_SQUARE_BRACKET) {
6424 _advance();
6425 type = _currentToken.type;
6426 }
6427 }
6428 }
6429
6430 if (type == TokenType.CLOSE_SQUARE_BRACKET) {
6431 rightSquareBracket = getAndAdvance();
6432 if (leftSquareBracket == null) {
6433 if (leftCurlyBracket != null) {
6434 _reportErrorForCurrentToken(
6435 ParserErrorCode.WRONG_TERMINATOR_FOR_PARAMETER_GROUP, ["}"]);
6436 rightCurlyBracket = rightSquareBracket;
6437 rightSquareBracket = null;
6438 } else {
6439 _reportErrorForCurrentToken(
6440 ParserErrorCode.UNEXPECTED_TERMINATOR_FOR_PARAMETER_GROUP,
6441 ["["]);
6442 }
6443 }
6444 kind = ParameterKind.REQUIRED;
6445 } else if (type == TokenType.CLOSE_CURLY_BRACKET) {
6446 rightCurlyBracket = getAndAdvance();
6447 if (leftCurlyBracket == null) {
6448 if (leftSquareBracket != null) {
6449 _reportErrorForCurrentToken(
6450 ParserErrorCode.WRONG_TERMINATOR_FOR_PARAMETER_GROUP, ["]"]);
6451 rightSquareBracket = rightCurlyBracket;
6452 rightCurlyBracket = null;
6453 } else {
6454 _reportErrorForCurrentToken(
6455 ParserErrorCode.UNEXPECTED_TERMINATOR_FOR_PARAMETER_GROUP,
6456 ["{"]);
6457 }
6458 }
6459 kind = ParameterKind.REQUIRED;
6460 }
6461 } while (!_matches(TokenType.CLOSE_PAREN) &&
6462 !identical(initialToken, _currentToken));
6463 Token rightParenthesis = _expect(TokenType.CLOSE_PAREN);
6464 //
6465 // Check that the groups were closed correctly.
6466 //
6467 if (leftSquareBracket != null && rightSquareBracket == null) {
6468 _reportErrorForCurrentToken(
6469 ParserErrorCode.MISSING_TERMINATOR_FOR_PARAMETER_GROUP, ["]"]);
6470 }
6471 if (leftCurlyBracket != null && rightCurlyBracket == null) {
6472 _reportErrorForCurrentToken(
6473 ParserErrorCode.MISSING_TERMINATOR_FOR_PARAMETER_GROUP, ["}"]);
6474 }
6475 //
6476 // Build the parameter list.
6477 //
6478 leftSquareBracket ??= leftCurlyBracket;
6479 rightSquareBracket ??= rightCurlyBracket;
6480 return new FormalParameterList(leftParenthesis, parameters,
6481 leftSquareBracket, rightSquareBracket, rightParenthesis);
6482 }
6483
6484 /**
6485 * Parse a list of formal parameters. Return the formal parameters that were
6486 * parsed.
6487 *
6488 * This method assumes that the current token matches `TokenType.OPEN_PAREN`.
6489 */
6490 FormalParameterList _parseFormalParameterListUnchecked() {
6491 return _parseFormalParameterListAfterParen(getAndAdvance());
6492 }
6493
6494 /**
6495 * Parse a function declaration statement. The [commentAndMetadata] is the
6496 * documentation comment and metadata to be associated with the declaration.
6497 * The [returnType] is the return type, or `null` if there is no return type.
6498 * Return the function declaration statement that was parsed.
6499 *
6500 * functionDeclarationStatement ::=
6501 * functionSignature functionBody
6502 */
6503 Statement _parseFunctionDeclarationStatementAfterReturnType(
6504 CommentAndMetadata commentAndMetadata, TypeName returnType) {
6505 FunctionDeclaration declaration =
6506 parseFunctionDeclaration(commentAndMetadata, null, returnType);
6507 Token propertyKeyword = declaration.propertyKeyword;
6508 if (propertyKeyword != null) {
6509 if (propertyKeyword.keyword == Keyword.GET) {
6510 _reportErrorForToken(
6511 ParserErrorCode.GETTER_IN_FUNCTION, propertyKeyword);
6512 } else {
6513 _reportErrorForToken(
6514 ParserErrorCode.SETTER_IN_FUNCTION, propertyKeyword);
6515 }
6516 }
6517 return new FunctionDeclarationStatement(declaration);
6518 }
6519
6520 /**
6521 * Parse a function type alias. The [commentAndMetadata] is the metadata to be
6522 * associated with the member. The [keyword] is the token representing the
6523 * 'typedef' keyword. Return the function type alias that was parsed.
6524 *
6525 * functionTypeAlias ::=
6526 * functionPrefix typeParameterList? formalParameterList ';'
6527 *
6528 * functionPrefix ::=
6529 * returnType? name
6530 */
6531 FunctionTypeAlias _parseFunctionTypeAlias(
6532 CommentAndMetadata commentAndMetadata, Token keyword) {
6533 TypeName returnType = null;
6534 if (hasReturnTypeInTypeAlias) {
6535 returnType = parseReturnType();
6536 }
6537 SimpleIdentifier name = parseSimpleIdentifier(isDeclaration: true);
6538 TypeParameterList typeParameters = null;
6539 if (_matches(TokenType.LT)) {
6540 typeParameters = parseTypeParameterList();
6541 }
6542 TokenType type = _currentToken.type;
6543 if (type == TokenType.SEMICOLON || type == TokenType.EOF) {
6544 _reportErrorForCurrentToken(ParserErrorCode.MISSING_TYPEDEF_PARAMETERS);
6545 FormalParameterList parameters = new FormalParameterList(
6546 _createSyntheticToken(TokenType.OPEN_PAREN),
6547 null,
6548 null,
6549 null,
6550 _createSyntheticToken(TokenType.CLOSE_PAREN));
6551 Token semicolon = _expect(TokenType.SEMICOLON);
6552 return new FunctionTypeAlias(
6553 commentAndMetadata.comment,
6554 commentAndMetadata.metadata,
6555 keyword,
6556 returnType,
6557 name,
6558 typeParameters,
6559 parameters,
6560 semicolon);
6561 } else if (type == TokenType.OPEN_PAREN) {
6562 FormalParameterList parameters = _parseFormalParameterListUnchecked();
6563 _validateFormalParameterList(parameters);
6564 Token semicolon = _expect(TokenType.SEMICOLON);
6565 return new FunctionTypeAlias(
6566 commentAndMetadata.comment,
6567 commentAndMetadata.metadata,
6568 keyword,
6569 returnType,
6570 name,
6571 typeParameters,
6572 parameters,
6573 semicolon);
6574 } else {
6575 _reportErrorForCurrentToken(ParserErrorCode.MISSING_TYPEDEF_PARAMETERS);
6576 // Recovery: At the very least we should skip to the start of the next
6577 // valid compilation unit member, allowing for the possibility of finding
6578 // the typedef parameters before that point.
6579 return new FunctionTypeAlias(
6580 commentAndMetadata.comment,
6581 commentAndMetadata.metadata,
6582 keyword,
6583 returnType,
6584 name,
6585 typeParameters,
6586 new FormalParameterList(_createSyntheticToken(TokenType.OPEN_PAREN),
6587 null, null, null, _createSyntheticToken(TokenType.CLOSE_PAREN)),
6588 _createSyntheticToken(TokenType.SEMICOLON));
6589 }
6590 }
6591
6592 /**
6593 * Parses generic type parameters from a comment.
6594 *
6595 * Normally this is handled by [_parseGenericMethodTypeParameters], but if the
6596 * code already handles the normal generic type parameters, the comment
6597 * matcher can be called directly. For example, we may have already tried
6598 * matching `<` (less than sign) in a method declaration, and be currently
6599 * on the `(` (open paren) because we didn't find it. In that case, this
6600 * function will parse the preceding comment such as `/*<T, R>*/`.
6601 */
6602 TypeParameterList _parseGenericCommentTypeParameters() {
6603 if (_injectGenericCommentTypeList()) {
6604 return parseTypeParameterList();
6605 }
6606 return null;
6607 }
6608
6609 /**
6610 * Parse the generic method or function's type parameters.
6611 *
6612 * For backwards compatibility this can optionally use comments.
6613 * See [parseGenericMethodComments].
6614 */
6615 TypeParameterList _parseGenericMethodTypeParameters() {
6616 if (parseGenericMethods && _matches(TokenType.LT) ||
6617 _injectGenericCommentTypeList()) {
6618 return parseTypeParameterList();
6619 }
6620 return null;
6621 }
6622
6623 /**
6624 * Parse a library name. The [missingNameError] is the error code to be used
6625 * if the library name is missing. The [missingNameToken] is the token
6626 * associated with the error produced if the library name is missing. Return
6627 * the library name that was parsed.
6628 *
6629 * libraryName ::=
6630 * libraryIdentifier
6631 */
6632 LibraryIdentifier _parseLibraryName(
6633 ParserErrorCode missingNameError, Token missingNameToken) {
6634 if (_matchesIdentifier()) {
6635 return parseLibraryIdentifier();
6636 } else if (_matches(TokenType.STRING)) {
6637 // Recovery: This should be extended to handle arbitrary tokens until we
6638 // can find a token that can start a compilation unit member.
6639 StringLiteral string = parseStringLiteral();
6640 _reportErrorForNode(ParserErrorCode.NON_IDENTIFIER_LIBRARY_NAME, string);
6641 } else {
6642 _reportErrorForToken(missingNameError, missingNameToken);
6643 }
6644 return new LibraryIdentifier(
6645 <SimpleIdentifier>[createSyntheticIdentifier()]);
6646 }
6647
6648 /**
6649 * Parse a method declaration. The [commentAndMetadata] is the documentation
6650 * comment and metadata to be associated with the declaration. The
6651 * [externalKeyword] is the 'external' token. The [staticKeyword] is the
6652 * static keyword, or `null` if the getter is not static. The [returnType] is
6653 * the return type of the method. The [name] is the name of the method. The
6654 * [parameters] is the parameters to the method. Return the method declaration
6655 * that was parsed.
6656 *
6657 * functionDeclaration ::=
6658 * ('external' 'static'?)? functionSignature functionBody
6659 * | 'external'? functionSignature ';'
6660 */
6661 MethodDeclaration _parseMethodDeclarationAfterParameters(
6662 CommentAndMetadata commentAndMetadata,
6663 Token externalKeyword,
6664 Token staticKeyword,
6665 TypeName returnType,
6666 SimpleIdentifier name,
6667 TypeParameterList typeParameters,
6668 FormalParameterList parameters) {
6669 FunctionBody body = parseFunctionBody(
6670 externalKeyword != null || staticKeyword == null,
6671 ParserErrorCode.MISSING_FUNCTION_BODY,
6672 false);
6673 if (externalKeyword != null) {
6674 if (body is! EmptyFunctionBody) {
6675 _reportErrorForNode(ParserErrorCode.EXTERNAL_METHOD_WITH_BODY, body);
6676 }
6677 } else if (staticKeyword != null) {
6678 if (body is EmptyFunctionBody && _parseFunctionBodies) {
6679 _reportErrorForNode(ParserErrorCode.ABSTRACT_STATIC_METHOD, body);
6680 }
6681 }
6682 return new MethodDeclaration(
6683 commentAndMetadata.comment,
6684 commentAndMetadata.metadata,
6685 externalKeyword,
6686 staticKeyword,
6687 returnType,
6688 null,
6689 null,
6690 name,
6691 typeParameters,
6692 parameters,
6693 body);
6694 }
6695
6696 /**
6697 * Parse a method declaration. The [commentAndMetadata] is the documentation
6698 * comment and metadata to be associated with the declaration. The
6699 * [externalKeyword] is the 'external' token. The [staticKeyword] is the
6700 * static keyword, or `null` if the getter is not static. The [returnType] is
6701 * the return type of the method. Return the method declaration that was
6702 * parsed.
6703 *
6704 * functionDeclaration ::=
6705 * 'external'? 'static'? functionSignature functionBody
6706 * | 'external'? functionSignature ';'
6707 */
6708 MethodDeclaration _parseMethodDeclarationAfterReturnType(
6709 CommentAndMetadata commentAndMetadata,
6710 Token externalKeyword,
6711 Token staticKeyword,
6712 TypeName returnType) {
6713 SimpleIdentifier methodName = parseSimpleIdentifier(isDeclaration: true);
6714 TypeParameterList typeParameters = _parseGenericMethodTypeParameters();
6715 FormalParameterList parameters;
6716 TokenType type = _currentToken.type;
6717 // TODO(brianwilkerson) Figure out why we care what the current token is if
6718 // it isn't a paren.
6719 if (type != TokenType.OPEN_PAREN &&
6720 (type == TokenType.OPEN_CURLY_BRACKET || type == TokenType.FUNCTION)) {
6721 _reportErrorForToken(
6722 ParserErrorCode.MISSING_METHOD_PARAMETERS, _currentToken.previous);
6723 parameters = new FormalParameterList(
6724 _createSyntheticToken(TokenType.OPEN_PAREN),
6725 null,
6726 null,
6727 null,
6728 _createSyntheticToken(TokenType.CLOSE_PAREN));
6729 } else {
6730 parameters = parseFormalParameterList();
6731 }
6732 _validateFormalParameterList(parameters);
6733 return _parseMethodDeclarationAfterParameters(
6734 commentAndMetadata,
6735 externalKeyword,
6736 staticKeyword,
6737 returnType,
6738 methodName,
6739 typeParameters,
6740 parameters);
6741 }
6742
6743 /**
6744 * Parse a class native clause. Return the native clause that was parsed.
6745 *
6746 * This method assumes that the current token matches `_NATIVE`.
6747 *
6748 * classNativeClause ::=
6749 * 'native' name
6750 */
6751 NativeClause _parseNativeClause() {
6752 Token keyword = getAndAdvance();
6753 StringLiteral name = parseStringLiteral();
6754 return new NativeClause(keyword, name);
6755 }
6756
6757 /**
6758 * Parse an operator declaration starting after the 'operator' keyword. The
6759 * [commentAndMetadata] is the documentation comment and metadata to be
6760 * associated with the declaration. The [externalKeyword] is the 'external'
6761 * token. The [returnType] is the return type that has already been parsed, or
6762 * `null` if there was no return type. The [operatorKeyword] is the 'operator'
6763 * keyword. Return the operator declaration that was parsed.
6764 *
6765 * operatorDeclaration ::=
6766 * operatorSignature (';' | functionBody)
6767 *
6768 * operatorSignature ::=
6769 * 'external'? returnType? 'operator' operator formalParameterList
6770 */
6771 MethodDeclaration _parseOperatorAfterKeyword(
6772 CommentAndMetadata commentAndMetadata,
6773 Token externalKeyword,
6774 TypeName returnType,
6775 Token operatorKeyword) {
6776 if (!_currentToken.isUserDefinableOperator) {
6777 _reportErrorForCurrentToken(
6778 ParserErrorCode.NON_USER_DEFINABLE_OPERATOR, [_currentToken.lexeme]);
6779 }
6780 SimpleIdentifier name =
6781 new SimpleIdentifier(getAndAdvance(), isDeclaration: true);
6782 if (_matches(TokenType.EQ)) {
6783 Token previous = _currentToken.previous;
6784 if ((_tokenMatches(previous, TokenType.EQ_EQ) ||
6785 _tokenMatches(previous, TokenType.BANG_EQ)) &&
6786 _currentToken.offset == previous.offset + 2) {
6787 _reportErrorForCurrentToken(ParserErrorCode.INVALID_OPERATOR,
6788 ["${previous.lexeme}${_currentToken.lexeme}"]);
6789 _advance();
6790 }
6791 }
6792 FormalParameterList parameters = parseFormalParameterList();
6793 _validateFormalParameterList(parameters);
6794 FunctionBody body =
6795 parseFunctionBody(true, ParserErrorCode.MISSING_FUNCTION_BODY, false);
6796 if (externalKeyword != null && body is! EmptyFunctionBody) {
6797 _reportErrorForCurrentToken(ParserErrorCode.EXTERNAL_OPERATOR_WITH_BODY);
6798 }
6799 return new MethodDeclaration(
6800 commentAndMetadata.comment,
6801 commentAndMetadata.metadata,
6802 externalKeyword,
6803 null,
6804 returnType,
6805 null,
6806 operatorKeyword,
6807 name,
6808 null,
6809 parameters,
6810 body);
6811 }
6812
6813 /**
6814 * Parse a return type if one is given, otherwise return `null` without
6815 * advancing. Return the return type that was parsed.
6816 */
6817 TypeName _parseOptionalReturnType() {
6818 TypeName typeComment = _parseOptionalTypeNameComment();
6819 if (typeComment != null) {
6820 return typeComment;
6821 }
6822 Keyword keyword = _currentToken.keyword;
6823 if (keyword == Keyword.VOID) {
6824 return new TypeName(new SimpleIdentifier(getAndAdvance()), null);
6825 } else if (_matchesIdentifier()) {
6826 Token next = _peek();
6827 if (keyword != Keyword.GET &&
6828 keyword != Keyword.SET &&
6829 keyword != Keyword.OPERATOR &&
6830 (_tokenMatchesIdentifier(next) ||
6831 _tokenMatches(next, TokenType.LT))) {
6832 return parseReturnType();
6833 }
6834 Token next2 = next.next;
6835 Token next3 = next2.next;
6836 if (_tokenMatches(next, TokenType.PERIOD) &&
6837 _tokenMatchesIdentifier(next2) &&
6838 (_tokenMatchesIdentifier(next3) ||
6839 _tokenMatches(next3, TokenType.LT))) {
6840 return parseReturnType();
6841 }
6842 }
6843 return null;
6844 }
6845
6846 /**
6847 * Parse a [TypeArgumentList] if present, otherwise return null.
6848 * This also supports the comment form, if enabled: `/*<T>*/`
6849 */
6850 TypeArgumentList _parseOptionalTypeArguments() {
6851 if (_matches(TokenType.LT) || _injectGenericCommentTypeList()) {
6852 return parseTypeArgumentList();
6853 }
6854 return null;
6855 }
6856
6857 TypeName _parseOptionalTypeNameComment() {
6858 if (_injectGenericCommentTypeAssign()) {
6859 return _parseTypeName(false);
6860 }
6861 return null;
6862 }
6863
6864 /**
6865 * Parse a part directive. The [commentAndMetadata] is the metadata to be
6866 * associated with the directive. Return the part or part-of directive that
6867 * was parsed.
6868 *
6869 * This method assumes that the current token matches `Keyword.PART`.
6870 *
6871 * partDirective ::=
6872 * metadata 'part' stringLiteral ';'
6873 */
6874 Directive _parsePartDirective(CommentAndMetadata commentAndMetadata) {
6875 Token partKeyword = getAndAdvance();
6876 StringLiteral partUri = _parseUri();
6877 Token semicolon = _expect(TokenType.SEMICOLON);
6878 return new PartDirective(commentAndMetadata.comment,
6879 commentAndMetadata.metadata, partKeyword, partUri, semicolon);
6880 }
6881
6882 /**
6883 * Parse a part-of directive. The [commentAndMetadata] is the metadata to be
6884 * associated with the directive. Return the part or part-of directive that
6885 * was parsed.
6886 *
6887 * This method assumes that the current token matches [Keyword.PART] and that
6888 * the following token matches the identifier 'of'.
6889 *
6890 * partOfDirective ::=
6891 * metadata 'part' 'of' identifier ';'
6892 */
6893 Directive _parsePartOfDirective(CommentAndMetadata commentAndMetadata) {
6894 Token partKeyword = getAndAdvance();
6895 Token ofKeyword = getAndAdvance();
6896 LibraryIdentifier libraryName = _parseLibraryName(
6897 ParserErrorCode.MISSING_NAME_IN_PART_OF_DIRECTIVE, ofKeyword);
6898 Token semicolon = _expect(TokenType.SEMICOLON);
6899 return new PartOfDirective(
6900 commentAndMetadata.comment,
6901 commentAndMetadata.metadata,
6902 partKeyword,
6903 ofKeyword,
6904 libraryName,
6905 semicolon);
6906 }
6907
6908 /**
6909 * Parse a prefixed identifier given that the given [qualifier] was already
6910 * parsed. Return the prefixed identifier that was parsed.
6911 *
6912 * prefixedIdentifier ::=
6913 * identifier ('.' identifier)?
6914 */
6915 Identifier _parsePrefixedIdentifierAfterIdentifier(
6916 SimpleIdentifier qualifier) {
6917 if (!_matches(TokenType.PERIOD) || _injectGenericCommentTypeList()) {
6918 return qualifier;
6919 }
6920 Token period = getAndAdvance();
6921 SimpleIdentifier qualified = parseSimpleIdentifier();
6922 return new PrefixedIdentifier(qualifier, period, qualified);
6923 }
6924
6925 /**
6926 * Parse a prefixed identifier. Return the prefixed identifier that was
6927 * parsed.
6928 *
6929 * This method assumes that the current token matches an identifier.
6930 *
6931 * prefixedIdentifier ::=
6932 * identifier ('.' identifier)?
6933 */
6934 Identifier _parsePrefixedIdentifierUnchecked() {
6935 return _parsePrefixedIdentifierAfterIdentifier(
6936 _parseSimpleIdentifierUnchecked());
6937 }
6938
6939 /**
6940 * Parse a simple identifier. Return the simple identifier that was parsed.
6941 *
6942 * This method assumes that the current token matches an identifier.
6943 *
6944 * identifier ::=
6945 * IDENTIFIER
6946 */
6947 SimpleIdentifier _parseSimpleIdentifierUnchecked(
6948 {bool isDeclaration: false}) {
6949 String lexeme = _currentToken.lexeme;
6950 if ((_inAsync || _inGenerator) &&
6951 (lexeme == ASYNC || lexeme == _AWAIT || lexeme == _YIELD)) {
6952 _reportErrorForCurrentToken(
6953 ParserErrorCode.ASYNC_KEYWORD_USED_AS_IDENTIFIER);
6954 }
6955 return new SimpleIdentifier(getAndAdvance(), isDeclaration: isDeclaration);
6956 }
6957
6958 /**
6959 * Parse a list of statements within a switch statement. Return the statements
6960 * that were parsed.
6961 *
6962 * statements ::=
6963 * statement*
6964 */
6965 List<Statement> _parseStatementList() {
6966 List<Statement> statements = <Statement>[];
6967 Token statementStart = _currentToken;
6968 TokenType type = _currentToken.type;
6969 while (type != TokenType.EOF &&
6970 type != TokenType.CLOSE_CURLY_BRACKET &&
6971 !isSwitchMember()) {
6972 statements.add(parseStatement2());
6973 if (identical(_currentToken, statementStart)) {
6974 _reportErrorForToken(ParserErrorCode.UNEXPECTED_TOKEN, _currentToken,
6975 [_currentToken.lexeme]);
6976 _advance();
6977 }
6978 statementStart = _currentToken;
6979 type = _currentToken.type;
6980 }
6981 return statements;
6982 }
6983
6984 /**
6985 * Parse a string literal that contains interpolations. Return the string
6986 * literal that was parsed.
6987 *
6988 * This method assumes that the current token matches either
6989 * [TokenType.STRING_INTERPOLATION_EXPRESSION] or
6990 * [TokenType.STRING_INTERPOLATION_IDENTIFIER].
6991 */
6992 StringInterpolation _parseStringInterpolation(Token string) {
6993 List<InterpolationElement> elements = <InterpolationElement>[
6994 new InterpolationString(
6995 string, computeStringValue(string.lexeme, true, false))
6996 ];
6997 bool hasMore = true;
6998 bool isExpression = _matches(TokenType.STRING_INTERPOLATION_EXPRESSION);
6999 while (hasMore) {
7000 if (isExpression) {
7001 Token openToken = getAndAdvance();
7002 bool wasInInitializer = _inInitializer;
7003 _inInitializer = false;
7004 try {
7005 Expression expression = parseExpression2();
7006 Token rightBracket = _expect(TokenType.CLOSE_CURLY_BRACKET);
7007 elements.add(
7008 new InterpolationExpression(openToken, expression, rightBracket));
7009 } finally {
7010 _inInitializer = wasInInitializer;
7011 }
7012 } else {
7013 Token openToken = getAndAdvance();
7014 Expression expression = null;
7015 if (_matchesKeyword(Keyword.THIS)) {
7016 expression = new ThisExpression(getAndAdvance());
7017 } else {
7018 expression = parseSimpleIdentifier();
7019 }
7020 elements.add(new InterpolationExpression(openToken, expression, null));
7021 }
7022 if (_matches(TokenType.STRING)) {
7023 string = getAndAdvance();
7024 isExpression = _matches(TokenType.STRING_INTERPOLATION_EXPRESSION);
7025 hasMore =
7026 isExpression || _matches(TokenType.STRING_INTERPOLATION_IDENTIFIER);
7027 elements.add(new InterpolationString(
7028 string, computeStringValue(string.lexeme, false, !hasMore)));
7029 } else {
7030 hasMore = false;
7031 }
7032 }
7033 return new StringInterpolation(elements);
7034 }
7035
7036 /**
7037 * Parse a string literal. Return the string literal that was parsed.
7038 *
7039 * This method assumes that the current token matches `TokenType.STRING`.
7040 *
7041 * stringLiteral ::=
7042 * MULTI_LINE_STRING+
7043 * | SINGLE_LINE_STRING+
7044 */
7045 StringLiteral _parseStringLiteralUnchecked() {
7046 List<StringLiteral> strings = <StringLiteral>[];
7047 do {
7048 Token string = getAndAdvance();
7049 if (_matches(TokenType.STRING_INTERPOLATION_EXPRESSION) ||
7050 _matches(TokenType.STRING_INTERPOLATION_IDENTIFIER)) {
7051 strings.add(_parseStringInterpolation(string));
7052 } else {
7053 strings.add(new SimpleStringLiteral(
7054 string, computeStringValue(string.lexeme, true, true)));
7055 }
7056 } while (_matches(TokenType.STRING));
7057 return strings.length == 1 ? strings[0] : new AdjacentStrings(strings);
7058 }
7059
7060 TypeName _parseTypeName(bool inExpression) {
7061 Identifier typeName;
7062 if (_matchesIdentifier()) {
7063 typeName = _parsePrefixedIdentifierUnchecked();
7064 } else if (_matchesKeyword(Keyword.VAR)) {
7065 _reportErrorForCurrentToken(ParserErrorCode.VAR_AS_TYPE_NAME);
7066 typeName = new SimpleIdentifier(getAndAdvance());
7067 } else {
7068 typeName = createSyntheticIdentifier();
7069 _reportErrorForCurrentToken(ParserErrorCode.EXPECTED_TYPE_NAME);
7070 }
7071 TypeArgumentList typeArguments = _parseOptionalTypeArguments();
7072 Token question = null;
7073 if (enableNnbd && _matches(TokenType.QUESTION)) {
7074 if (!inExpression || !_isConditionalOperator()) {
7075 question = getAndAdvance();
7076 }
7077 }
7078 return new TypeName(typeName, typeArguments, question: question);
7079 }
7080
7081 /**
7082 * Parse a type name. Return the type name that was parsed.
7083 *
7084 * This method assumes that the current token is an identifier.
7085 *
7086 * type ::=
7087 * qualified typeArguments?
7088 */
7089 TypeName _parseTypeNameAfterIdentifier() {
7090 Identifier typeName = _parsePrefixedIdentifierUnchecked();
7091 TypeArgumentList typeArguments = _parseOptionalTypeArguments();
7092 // If this is followed by a generic method type comment, allow the comment
7093 // type to replace the real type name.
7094 // TODO(jmesserly): this feels like a big hammer. Can we restrict it to
7095 // only work inside generic methods?
7096 TypeName typeFromComment = _parseOptionalTypeNameComment();
7097 return typeFromComment ?? new TypeName(typeName, typeArguments);
7098 }
7099
7100 /**
7101 * Parse a string literal representing a URI. Return the string literal that
7102 * was parsed.
7103 */
7104 StringLiteral _parseUri() {
7105 // TODO(brianwilkerson) Should this function also return true for valid
7106 // top-level keywords?
7107 bool isKeywordAfterUri(Token token) =>
7108 token.lexeme == Keyword.AS.syntax ||
7109 token.lexeme == _HIDE ||
7110 token.lexeme == _SHOW;
7111 TokenType type = _currentToken.type;
7112 if (type != TokenType.STRING &&
7113 type != TokenType.SEMICOLON &&
7114 !isKeywordAfterUri(_currentToken)) {
7115 // Attempt to recover in the case where the URI was not enclosed in
7116 // quotes.
7117 Token token = _currentToken;
7118 bool isValidInUri(Token token) {
7119 TokenType type = token.type;
7120 return type == TokenType.COLON ||
7121 type == TokenType.SLASH ||
7122 type == TokenType.PERIOD ||
7123 type == TokenType.PERIOD_PERIOD ||
7124 type == TokenType.PERIOD_PERIOD_PERIOD ||
7125 type == TokenType.INT ||
7126 type == TokenType.DOUBLE;
7127 }
7128
7129 while ((_tokenMatchesIdentifier(token) && !isKeywordAfterUri(token)) ||
7130 isValidInUri(token)) {
7131 token = token.next;
7132 }
7133 if (_tokenMatches(token, TokenType.SEMICOLON) ||
7134 isKeywordAfterUri(token)) {
7135 Token endToken = token.previous;
7136 token = _currentToken;
7137 int endOffset = token.end;
7138 StringBuffer buffer = new StringBuffer();
7139 buffer.write(token.lexeme);
7140 while (token != endToken) {
7141 token = token.next;
7142 if (token.offset != endOffset || token.precedingComments != null) {
7143 return parseStringLiteral();
7144 }
7145 buffer.write(token.lexeme);
7146 endOffset = token.end;
7147 }
7148 String value = buffer.toString();
7149 Token newToken =
7150 new StringToken(TokenType.STRING, "'$value'", _currentToken.offset);
7151 _reportErrorForToken(
7152 ParserErrorCode.NON_STRING_LITERAL_AS_URI, newToken);
7153 _currentToken = endToken.next;
7154 return new SimpleStringLiteral(newToken, value);
7155 }
7156 }
7157 return parseStringLiteral();
7158 }
7159
7160 /**
7161 * Parse a variable declaration statement. The [commentAndMetadata] is the
7162 * metadata to be associated with the variable declaration statement, or
7163 * `null` if there is no attempt at parsing the comment and metadata. The
7164 * [keyword] is the token representing the 'final', 'const' or 'var' keyword,
7165 * or `null` if there is no keyword. The [type] is the type of the variables
7166 * in the list. Return the variable declaration statement that was parsed.
7167 *
7168 * variableDeclarationStatement ::=
7169 * variableDeclarationList ';'
7170 */
7171 VariableDeclarationStatement _parseVariableDeclarationStatementAfterType(
7172 CommentAndMetadata commentAndMetadata, Token keyword, TypeName type) {
7173 VariableDeclarationList variableList =
7174 parseVariableDeclarationListAfterType(
7175 commentAndMetadata, keyword, type);
7176 Token semicolon = _expect(TokenType.SEMICOLON);
7177 return new VariableDeclarationStatement(variableList, semicolon);
7178 }
7179
7180 /**
8026 * Return the token that is immediately after the current token. This is 7181 * Return the token that is immediately after the current token. This is
8027 * equivalent to [_peekAt](1). 7182 * equivalent to [_peekAt](1).
8028 */ 7183 */
8029 Token _peek() => _currentToken.next; 7184 Token _peek() => _currentToken.next;
8030 7185
8031 /** 7186 /**
8032 * Return the token that is the given [distance] after the current token, 7187 * Return the token that is the given [distance] after the current token,
8033 * where the distance is the number of tokens to look ahead. A distance of `0` 7188 * where the distance is the number of tokens to look ahead. A distance of `0`
8034 * is the current token, `1` is the next token, etc. 7189 * is the current token, `1` is the next token, etc.
8035 */ 7190 */
8036 Token _peekAt(int distance) { 7191 Token _peekAt(int distance) {
8037 Token token = _currentToken; 7192 Token token = _currentToken;
8038 for (int i = 0; i < distance; i++) { 7193 for (int i = 0; i < distance; i++) {
8039 token = token.next; 7194 token = token.next;
8040 } 7195 }
8041 return token; 7196 return token;
8042 } 7197 }
8043 7198
7199 String _removeGitHubInlineCode(String comment) {
7200 int index = 0;
7201 while (true) {
7202 int beginIndex = comment.indexOf('`', index);
7203 if (beginIndex == -1) {
7204 break;
7205 }
7206 int endIndex = comment.indexOf('`', beginIndex + 1);
7207 if (endIndex == -1) {
7208 break;
7209 }
7210 comment = comment.substring(0, beginIndex + 1) +
7211 ' ' * (endIndex - beginIndex - 1) +
7212 comment.substring(endIndex);
7213 index = endIndex + 1;
7214 }
7215 return comment;
7216 }
7217
8044 /** 7218 /**
8045 * Report the given [error]. 7219 * Report the given [error].
8046 */ 7220 */
8047 void _reportError(AnalysisError error) { 7221 void _reportError(AnalysisError error) {
8048 if (_errorListenerLock != 0) { 7222 if (_errorListenerLock != 0) {
8049 return; 7223 return;
8050 } 7224 }
8051 _errorListener.onError(error); 7225 _errorListener.onError(error);
8052 } 7226 }
8053 7227
(...skipping 23 matching lines...) Expand all
8077 void _reportErrorForToken(ErrorCode errorCode, Token token, 7251 void _reportErrorForToken(ErrorCode errorCode, Token token,
8078 [List<Object> arguments]) { 7252 [List<Object> arguments]) {
8079 if (token.type == TokenType.EOF) { 7253 if (token.type == TokenType.EOF) {
8080 token = token.previous; 7254 token = token.previous;
8081 } 7255 }
8082 _reportError(new AnalysisError(_source, token.offset, 7256 _reportError(new AnalysisError(_source, token.offset,
8083 math.max(token.length, 1), errorCode, arguments)); 7257 math.max(token.length, 1), errorCode, arguments));
8084 } 7258 }
8085 7259
8086 /** 7260 /**
7261 * Scans the generic method comment, and returns the tokens, otherwise
7262 * returns null.
7263 */
7264 Token _scanGenericMethodComment(String code, int offset) {
7265 BooleanErrorListener listener = new BooleanErrorListener();
7266 Scanner scanner =
7267 new Scanner(null, new SubSequenceReader(code, offset), listener);
7268 scanner.setSourceStart(1, 1);
7269 Token firstToken = scanner.tokenize();
7270 if (listener.errorReported) {
7271 return null;
7272 }
7273 return firstToken;
7274 }
7275
7276 /**
7277 * Execute the given [parseOperation] in a temporary parser whose current
7278 * token has been set to the given [startToken]. If the parse does not
7279 * generate any errors or exceptions, then return the token following the
7280 * matching portion of the token stream. Otherwise, return `null`.
7281 *
7282 * Note: This is an extremely inefficient way of testing whether the tokens in
7283 * the token stream match a given production. It should not be used for
7284 * production code.
7285 */
7286 Token _skip(Token startToken, parseOperation(Parser parser)) {
7287 BooleanErrorListener listener = new BooleanErrorListener();
7288 Parser parser = new Parser(_source, listener);
7289 parser._currentToken = _cloneTokens(startToken);
7290 parser._enableAssertInitializer = _enableAssertInitializer;
7291 parser._enableNnbd = _enableNnbd;
7292 parser._inAsync = _inAsync;
7293 parser._inGenerator = _inGenerator;
7294 parser._inInitializer = _inInitializer;
7295 parser._inLoop = _inLoop;
7296 parser._inSwitch = _inSwitch;
7297 parser._parseFunctionBodies = _parseFunctionBodies;
7298 try {
7299 parseOperation(parser);
7300 } catch (exception) {
7301 return null;
7302 }
7303 if (listener.errorReported) {
7304 return null;
7305 }
7306 return parser._currentToken;
7307 }
7308
7309 /**
8087 * Skips a block with all containing blocks. 7310 * Skips a block with all containing blocks.
8088 */ 7311 */
8089 void _skipBlock() { 7312 void _skipBlock() {
8090 Token endToken = (_currentToken as BeginToken).endToken; 7313 Token endToken = (_currentToken as BeginToken).endToken;
8091 if (endToken == null) { 7314 if (endToken == null) {
8092 endToken = _currentToken.next; 7315 endToken = _currentToken.next;
8093 while (!identical(endToken, _currentToken)) { 7316 while (!identical(endToken, _currentToken)) {
8094 _currentToken = endToken; 7317 _currentToken = endToken;
8095 endToken = _currentToken.next; 7318 endToken = _currentToken.next;
8096 } 7319 }
(...skipping 12 matching lines...) Expand all
8109 * [startToken] is the token at which parsing is to begin. Return the token 7332 * [startToken] is the token at which parsing is to begin. Return the token
8110 * following the type that was parsed. 7333 * following the type that was parsed.
8111 * 7334 *
8112 * finalConstVarOrType ::= 7335 * finalConstVarOrType ::=
8113 * | 'final' type? 7336 * | 'final' type?
8114 * | 'const' type? 7337 * | 'const' type?
8115 * | 'var' 7338 * | 'var'
8116 * | type 7339 * | type
8117 */ 7340 */
8118 Token _skipFinalConstVarOrType(Token startToken) { 7341 Token _skipFinalConstVarOrType(Token startToken) {
8119 if (_tokenMatchesKeyword(startToken, Keyword.FINAL) || 7342 Keyword keyword = startToken.keyword;
8120 _tokenMatchesKeyword(startToken, Keyword.CONST)) { 7343 if (keyword == Keyword.FINAL || keyword == Keyword.CONST) {
8121 Token next = startToken.next; 7344 Token next = startToken.next;
8122 if (_tokenMatchesIdentifier(next)) { 7345 if (_tokenMatchesIdentifier(next)) {
8123 Token next2 = next.next; 7346 Token next2 = next.next;
8124 // "Type parameter" or "Type<" or "prefix.Type" 7347 // "Type parameter" or "Type<" or "prefix.Type"
8125 if (_tokenMatchesIdentifier(next2) || 7348 if (_tokenMatchesIdentifier(next2) ||
8126 _tokenMatches(next2, TokenType.LT) || 7349 _tokenMatches(next2, TokenType.LT) ||
8127 _tokenMatches(next2, TokenType.PERIOD)) { 7350 _tokenMatches(next2, TokenType.PERIOD)) {
8128 return _skipTypeName(next); 7351 return skipTypeName(next);
8129 } 7352 }
8130 // "parameter" 7353 // "parameter"
8131 return next; 7354 return next;
8132 } 7355 }
8133 } else if (_tokenMatchesKeyword(startToken, Keyword.VAR)) { 7356 } else if (keyword == Keyword.VAR) {
8134 return startToken.next; 7357 return startToken.next;
8135 } else if (_tokenMatchesIdentifier(startToken)) { 7358 } else if (_tokenMatchesIdentifier(startToken)) {
8136 Token next = startToken.next; 7359 Token next = startToken.next;
8137 if (_tokenMatchesIdentifier(next) || 7360 if (_tokenMatchesIdentifier(next) ||
8138 _tokenMatches(next, TokenType.LT) || 7361 _tokenMatches(next, TokenType.LT) ||
8139 _tokenMatchesKeyword(next, Keyword.THIS) || 7362 _tokenMatchesKeyword(next, Keyword.THIS) ||
8140 (_tokenMatches(next, TokenType.PERIOD) && 7363 (_tokenMatches(next, TokenType.PERIOD) &&
8141 _tokenMatchesIdentifier(next.next) && 7364 _tokenMatchesIdentifier(next.next) &&
8142 (_tokenMatchesIdentifier(next.next.next) || 7365 (_tokenMatchesIdentifier(next.next.next) ||
8143 _tokenMatches(next.next.next, TokenType.LT) || 7366 _tokenMatches(next.next.next, TokenType.LT) ||
8144 _tokenMatchesKeyword(next.next.next, Keyword.THIS)))) { 7367 _tokenMatchesKeyword(next.next.next, Keyword.THIS)))) {
8145 return _skipReturnType(startToken); 7368 return skipReturnType(startToken);
8146 } 7369 }
8147 } 7370 }
8148 return null; 7371 return null;
8149 } 7372 }
8150 7373
8151 /** 7374 /**
8152 * Parse a list of formal parameters, starting at the [startToken], without 7375 * Parse a list of formal parameters, starting at the [startToken], without
8153 * actually creating a formal parameter list or changing the current token. 7376 * actually creating a formal parameter list or changing the current token.
8154 * Return the token following the formal parameter list that was parsed, or 7377 * Return the token following the formal parameter list that was parsed, or
8155 * `null` if the given token is not the first token in a valid list of formal 7378 * `null` if the given token is not the first token in a valid list of formal
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
8187 return null; 7410 return null;
8188 } 7411 }
8189 Token next = startToken.next; 7412 Token next = startToken.next;
8190 if (_tokenMatches(next, TokenType.CLOSE_PAREN)) { 7413 if (_tokenMatches(next, TokenType.CLOSE_PAREN)) {
8191 return next.next; 7414 return next.next;
8192 } 7415 }
8193 // 7416 //
8194 // Look to see whether the token after the open parenthesis is something 7417 // Look to see whether the token after the open parenthesis is something
8195 // that should only occur at the beginning of a parameter list. 7418 // that should only occur at the beginning of a parameter list.
8196 // 7419 //
8197 if (next.matchesAny([ 7420 if (next.matchesAny(const <TokenType>[
8198 TokenType.AT, 7421 TokenType.AT,
8199 TokenType.OPEN_SQUARE_BRACKET, 7422 TokenType.OPEN_SQUARE_BRACKET,
8200 TokenType.OPEN_CURLY_BRACKET 7423 TokenType.OPEN_CURLY_BRACKET
8201 ]) || 7424 ]) ||
8202 _tokenMatchesKeyword(next, Keyword.VOID) || 7425 _tokenMatchesKeyword(next, Keyword.VOID) ||
8203 (_tokenMatchesIdentifier(next) && 7426 (_tokenMatchesIdentifier(next) &&
8204 (next.next.matchesAny([TokenType.COMMA, TokenType.CLOSE_PAREN])))) { 7427 (next.next.matchesAny(
7428 const <TokenType>[TokenType.COMMA, TokenType.CLOSE_PAREN])))) {
8205 return _skipPastMatchingToken(startToken); 7429 return _skipPastMatchingToken(startToken);
8206 } 7430 }
8207 // 7431 //
8208 // Look to see whether the first parameter is a function typed parameter 7432 // Look to see whether the first parameter is a function typed parameter
8209 // without a return type. 7433 // without a return type.
8210 // 7434 //
8211 if (_tokenMatchesIdentifier(next) && 7435 if (_tokenMatchesIdentifier(next) &&
8212 _tokenMatches(next.next, TokenType.OPEN_PAREN)) { 7436 _tokenMatches(next.next, TokenType.OPEN_PAREN)) {
8213 Token afterParameters = _skipFormalParameterList(next.next); 7437 Token afterParameters = _skipFormalParameterList(next.next);
8214 if (afterParameters != null && 7438 if (afterParameters != null &&
8215 (afterParameters 7439 afterParameters.matchesAny(
8216 .matchesAny([TokenType.COMMA, TokenType.CLOSE_PAREN]))) { 7440 const <TokenType>[TokenType.COMMA, TokenType.CLOSE_PAREN])) {
8217 return _skipPastMatchingToken(startToken); 7441 return _skipPastMatchingToken(startToken);
8218 } 7442 }
8219 } 7443 }
8220 // 7444 //
8221 // Look to see whether the first parameter has a type or is a function typed 7445 // Look to see whether the first parameter has a type or is a function typed
8222 // parameter with a return type. 7446 // parameter with a return type.
8223 // 7447 //
8224 Token afterType = _skipFinalConstVarOrType(next); 7448 Token afterType = _skipFinalConstVarOrType(next);
8225 if (afterType == null) { 7449 if (afterType == null) {
8226 return null; 7450 return null;
8227 } 7451 }
8228 if (_skipSimpleIdentifier(afterType) == null) { 7452 if (skipSimpleIdentifier(afterType) == null) {
8229 return null; 7453 return null;
8230 } 7454 }
8231 return _skipPastMatchingToken(startToken); 7455 return _skipPastMatchingToken(startToken);
8232 } 7456 }
8233 7457
8234 /** 7458 /**
8235 * If the [startToken] is a begin token with an associated end token, then 7459 * If the [startToken] is a begin token with an associated end token, then
8236 * return the token following the end token. Otherwise, return `null`. 7460 * return the token following the end token. Otherwise, return `null`.
8237 */ 7461 */
8238 Token _skipPastMatchingToken(Token startToken) { 7462 Token _skipPastMatchingToken(Token startToken) {
8239 if (startToken is! BeginToken) { 7463 if (startToken is! BeginToken) {
8240 return null; 7464 return null;
8241 } 7465 }
8242 Token closeParen = (startToken as BeginToken).endToken; 7466 Token closeParen = (startToken as BeginToken).endToken;
8243 if (closeParen == null) { 7467 if (closeParen == null) {
8244 return null; 7468 return null;
8245 } 7469 }
8246 return closeParen.next; 7470 return closeParen.next;
8247 } 7471 }
8248 7472
8249 /** 7473 /**
8250 * Parse a prefixed identifier, starting at the [startToken], without actually
8251 * creating a prefixed identifier or changing the current token. Return the
8252 * token following the prefixed identifier that was parsed, or `null` if the
8253 * given token is not the first token in a valid prefixed identifier.
8254 *
8255 * This method must be kept in sync with [parsePrefixedIdentifier].
8256 *
8257 * prefixedIdentifier ::=
8258 * identifier ('.' identifier)?
8259 */
8260 Token _skipPrefixedIdentifier(Token startToken) {
8261 Token token = _skipSimpleIdentifier(startToken);
8262 if (token == null) {
8263 return null;
8264 } else if (!_tokenMatches(token, TokenType.PERIOD)) {
8265 return token;
8266 }
8267 token = token.next;
8268 Token nextToken = _skipSimpleIdentifier(token);
8269 if (nextToken != null) {
8270 return nextToken;
8271 } else if (_tokenMatches(token, TokenType.CLOSE_PAREN) ||
8272 _tokenMatches(token, TokenType.COMMA)) {
8273 // If the `id.` is followed by something that cannot produce a valid
8274 // structure then assume this is a prefixed identifier but missing the
8275 // trailing identifier
8276 return token;
8277 }
8278 return null;
8279 }
8280
8281 /**
8282 * Parse a return type, starting at the [startToken], without actually
8283 * creating a return type or changing the current token. Return the token
8284 * following the return type that was parsed, or `null` if the given token is
8285 * not the first token in a valid return type.
8286 *
8287 * This method must be kept in sync with [parseReturnType].
8288 *
8289 * returnType ::=
8290 * 'void'
8291 * | type
8292 */
8293 Token _skipReturnType(Token startToken) {
8294 if (_tokenMatchesKeyword(startToken, Keyword.VOID)) {
8295 return startToken.next;
8296 } else {
8297 return _skipTypeName(startToken);
8298 }
8299 }
8300
8301 /**
8302 * Parse a simple identifier, starting at the [startToken], without actually
8303 * creating a simple identifier or changing the current token. Return the
8304 * token following the simple identifier that was parsed, or `null` if the
8305 * given token is not the first token in a valid simple identifier.
8306 *
8307 * This method must be kept in sync with [parseSimpleIdentifier].
8308 *
8309 * identifier ::=
8310 * IDENTIFIER
8311 */
8312 Token _skipSimpleIdentifier(Token startToken) {
8313 if (_tokenMatches(startToken, TokenType.IDENTIFIER) ||
8314 _tokenMatchesPseudoKeyword(startToken)) {
8315 return startToken.next;
8316 }
8317 return null;
8318 }
8319
8320 /**
8321 * Parse a string literal that contains interpolations, starting at the 7474 * Parse a string literal that contains interpolations, starting at the
8322 * [startToken], without actually creating a string literal or changing the 7475 * [startToken], without actually creating a string literal or changing the
8323 * current token. Return the token following the string literal that was 7476 * current token. Return the token following the string literal that was
8324 * parsed, or `null` if the given token is not the first token in a valid 7477 * parsed, or `null` if the given token is not the first token in a valid
8325 * string literal. 7478 * string literal.
8326 * 7479 *
8327 * This method must be kept in sync with [parseStringInterpolation]. 7480 * This method must be kept in sync with [parseStringInterpolation].
8328 */ 7481 */
8329 Token _skipStringInterpolation(Token startToken) { 7482 Token _skipStringInterpolation(Token startToken) {
8330 Token token = startToken; 7483 Token token = startToken;
8331 TokenType type = token.type; 7484 TokenType type = token.type;
8332 while (type == TokenType.STRING_INTERPOLATION_EXPRESSION || 7485 while (type == TokenType.STRING_INTERPOLATION_EXPRESSION ||
8333 type == TokenType.STRING_INTERPOLATION_IDENTIFIER) { 7486 type == TokenType.STRING_INTERPOLATION_IDENTIFIER) {
8334 if (type == TokenType.STRING_INTERPOLATION_EXPRESSION) { 7487 if (type == TokenType.STRING_INTERPOLATION_EXPRESSION) {
8335 token = token.next; 7488 token = token.next;
8336 type = token.type; 7489 type = token.type;
8337 // 7490 //
8338 // Rather than verify that the following tokens represent a valid 7491 // Rather than verify that the following tokens represent a valid
8339 // expression, we simply skip tokens until we reach the end of the 7492 // expression, we simply skip tokens until we reach the end of the
8340 // interpolation, being careful to handle nested string literals. 7493 // interpolation, being careful to handle nested string literals.
8341 // 7494 //
8342 int bracketNestingLevel = 1; 7495 int bracketNestingLevel = 1;
8343 while (bracketNestingLevel > 0) { 7496 while (bracketNestingLevel > 0) {
8344 if (type == TokenType.EOF) { 7497 if (type == TokenType.EOF) {
8345 return null; 7498 return null;
8346 } else if (type == TokenType.OPEN_CURLY_BRACKET) { 7499 } else if (type == TokenType.OPEN_CURLY_BRACKET) {
8347 bracketNestingLevel++; 7500 bracketNestingLevel++;
7501 token = token.next;
8348 } else if (type == TokenType.CLOSE_CURLY_BRACKET) { 7502 } else if (type == TokenType.CLOSE_CURLY_BRACKET) {
8349 bracketNestingLevel--; 7503 bracketNestingLevel--;
7504 token = token.next;
8350 } else if (type == TokenType.STRING) { 7505 } else if (type == TokenType.STRING) {
8351 token = _skipStringLiteral(token); 7506 token = skipStringLiteral(token);
8352 if (token == null) { 7507 if (token == null) {
8353 return null; 7508 return null;
8354 } 7509 }
8355 } else { 7510 } else {
8356 token = token.next; 7511 token = token.next;
8357 } 7512 }
8358 type = token.type; 7513 type = token.type;
8359 } 7514 }
8360 token = token.next; 7515 token = token.next;
8361 type = token.type; 7516 type = token.type;
8362 } else { 7517 } else {
8363 token = token.next; 7518 token = token.next;
8364 if (token.type != TokenType.IDENTIFIER) { 7519 if (token.type != TokenType.IDENTIFIER) {
8365 return null; 7520 return null;
8366 } 7521 }
8367 token = token.next; 7522 token = token.next;
8368 } 7523 }
8369 type = token.type; 7524 type = token.type;
8370 if (type == TokenType.STRING) { 7525 if (type == TokenType.STRING) {
8371 token = token.next; 7526 token = token.next;
8372 type = token.type; 7527 type = token.type;
8373 } 7528 }
8374 } 7529 }
8375 return token; 7530 return token;
8376 } 7531 }
8377 7532
8378 /** 7533 /**
8379 * Parse a string literal, starting at the [startToken], without actually
8380 * creating a string literal or changing the current token. Return the token
8381 * following the string literal that was parsed, or `null` if the given token
8382 * is not the first token in a valid string literal.
8383 *
8384 * This method must be kept in sync with [parseStringLiteral].
8385 *
8386 * stringLiteral ::=
8387 * MULTI_LINE_STRING+
8388 * | SINGLE_LINE_STRING+
8389 */
8390 Token _skipStringLiteral(Token startToken) {
8391 Token token = startToken;
8392 while (token != null && _tokenMatches(token, TokenType.STRING)) {
8393 token = token.next;
8394 TokenType type = token.type;
8395 if (type == TokenType.STRING_INTERPOLATION_EXPRESSION ||
8396 type == TokenType.STRING_INTERPOLATION_IDENTIFIER) {
8397 token = _skipStringInterpolation(token);
8398 }
8399 }
8400 if (identical(token, startToken)) {
8401 return null;
8402 }
8403 return token;
8404 }
8405
8406 /**
8407 * Parse a list of type arguments, starting at the [startToken], without
8408 * actually creating a type argument list or changing the current token.
8409 * Return the token following the type argument list that was parsed, or
8410 * `null` if the given token is not the first token in a valid type argument
8411 * list.
8412 *
8413 * This method must be kept in sync with [parseTypeArgumentList].
8414 *
8415 * typeArguments ::=
8416 * '<' typeList '>'
8417 *
8418 * typeList ::=
8419 * type (',' type)*
8420 */
8421 Token _skipTypeArgumentList(Token startToken) {
8422 Token token = startToken;
8423 if (!_tokenMatches(token, TokenType.LT)) {
8424 return null;
8425 }
8426 token = _skipTypeName(token.next);
8427 if (token == null) {
8428 // If the start token '<' is followed by '>'
8429 // then assume this should be type argument list but is missing a type
8430 token = startToken.next;
8431 if (_tokenMatches(token, TokenType.GT)) {
8432 return token.next;
8433 }
8434 return null;
8435 }
8436 while (_tokenMatches(token, TokenType.COMMA)) {
8437 token = _skipTypeName(token.next);
8438 if (token == null) {
8439 return null;
8440 }
8441 }
8442 if (token.type == TokenType.GT) {
8443 return token.next;
8444 } else if (token.type == TokenType.GT_GT) {
8445 Token second = new Token(TokenType.GT, token.offset + 1);
8446 second.setNextWithoutSettingPrevious(token.next);
8447 return second;
8448 }
8449 return null;
8450 }
8451
8452 /**
8453 * Parse a type name, starting at the [startToken], without actually creating
8454 * a type name or changing the current token. Return the token following the
8455 * type name that was parsed, or `null` if the given token is not the first
8456 * token in a valid type name.
8457 *
8458 * This method must be kept in sync with [parseTypeName].
8459 *
8460 * type ::=
8461 * qualified typeArguments?
8462 */
8463 Token _skipTypeName(Token startToken) {
8464 Token token = _skipPrefixedIdentifier(startToken);
8465 if (token == null) {
8466 return null;
8467 }
8468 if (_tokenMatches(token, TokenType.LT)) {
8469 token = _skipTypeArgumentList(token);
8470 }
8471 return token;
8472 }
8473
8474 /**
8475 * Parse a list of type parameters, starting at the [startToken], without 7534 * Parse a list of type parameters, starting at the [startToken], without
8476 * actually creating a type parameter list or changing the current token. 7535 * actually creating a type parameter list or changing the current token.
8477 * Return the token following the type parameter list that was parsed, or 7536 * Return the token following the type parameter list that was parsed, or
8478 * `null` if the given token is not the first token in a valid type parameter 7537 * `null` if the given token is not the first token in a valid type parameter
8479 * list. 7538 * list.
8480 * 7539 *
8481 * This method must be kept in sync with [parseTypeParameterList]. 7540 * This method must be kept in sync with [parseTypeParameterList].
8482 * 7541 *
8483 * typeParameterList ::= 7542 * typeParameterList ::=
8484 * '<' typeParameter (',' typeParameter)* '>' 7543 * '<' typeParameter (',' typeParameter)* '>'
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
8528 * Return `true` if the given [token] has the given [type]. 7587 * Return `true` if the given [token] has the given [type].
8529 */ 7588 */
8530 bool _tokenMatches(Token token, TokenType type) => token.type == type; 7589 bool _tokenMatches(Token token, TokenType type) => token.type == type;
8531 7590
8532 /** 7591 /**
8533 * Return `true` if the given [token] is a valid identifier. Valid identifiers 7592 * Return `true` if the given [token] is a valid identifier. Valid identifiers
8534 * include built-in identifiers (pseudo-keywords). 7593 * include built-in identifiers (pseudo-keywords).
8535 */ 7594 */
8536 bool _tokenMatchesIdentifier(Token token) => 7595 bool _tokenMatchesIdentifier(Token token) =>
8537 _tokenMatches(token, TokenType.IDENTIFIER) || 7596 _tokenMatches(token, TokenType.IDENTIFIER) ||
8538 _tokenMatchesPseudoKeyword(token); 7597 _tokenMatchesPseudoKeyword(token);
8539 7598
8540 /** 7599 /**
8541 * Return `true` if the given [token] matches the given [keyword]. 7600 * Return `true` if the given [token] matches the given [keyword].
8542 */ 7601 */
8543 bool _tokenMatchesKeyword(Token token, Keyword keyword) => 7602 bool _tokenMatchesKeyword(Token token, Keyword keyword) =>
8544 token.type == TokenType.KEYWORD && 7603 token.keyword == keyword;
8545 (token as KeywordToken).keyword == keyword;
8546 7604
8547 /** 7605 /**
8548 * Return `true` if the given [token] matches a pseudo keyword. 7606 * Return `true` if the given [token] matches a pseudo keyword.
8549 */ 7607 */
8550 bool _tokenMatchesPseudoKeyword(Token token) => 7608 bool _tokenMatchesPseudoKeyword(Token token) =>
8551 _tokenMatches(token, TokenType.KEYWORD) && 7609 token.keyword?.isPseudoKeyword ?? false;
8552 (token as KeywordToken).keyword.isPseudoKeyword;
8553 7610
8554 /** 7611 /**
8555 * Return `true` if the given [token] matches the given [identifier]. 7612 * Return `true` if the given [token] matches the given [identifier].
8556 */ 7613 */
8557 bool _tokenMatchesString(Token token, String identifier) => 7614 bool _tokenMatchesString(Token token, String identifier) =>
8558 token.type == TokenType.IDENTIFIER && token.lexeme == identifier; 7615 token.type == TokenType.IDENTIFIER && token.lexeme == identifier;
8559 7616
8560 /** 7617 /**
8561 * Translate the characters at the given [index] in the given [lexeme], 7618 * Translate the characters at the given [index] in the given [lexeme],
8562 * appending the translated character to the given [buffer]. The index is 7619 * appending the translated character to the given [buffer]. The index is
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after
8654 // Illegal escape sequence: incomplete escape 7711 // Illegal escape sequence: incomplete escape
8655 _reportErrorForCurrentToken(ParserErrorCode.INVALID_UNICODE_ESCAPE); 7712 _reportErrorForCurrentToken(ParserErrorCode.INVALID_UNICODE_ESCAPE);
8656 return length; 7713 return length;
8657 } 7714 }
8658 currentChar = lexeme.codeUnitAt(currentIndex); 7715 currentChar = lexeme.codeUnitAt(currentIndex);
8659 } 7716 }
8660 if (digitCount < 1 || digitCount > 6) { 7717 if (digitCount < 1 || digitCount > 6) {
8661 // Illegal escape sequence: not enough or too many hex digits 7718 // Illegal escape sequence: not enough or too many hex digits
8662 _reportErrorForCurrentToken(ParserErrorCode.INVALID_UNICODE_ESCAPE); 7719 _reportErrorForCurrentToken(ParserErrorCode.INVALID_UNICODE_ESCAPE);
8663 } 7720 }
8664 _appendScalarValue(buffer, lexeme.substring(index, currentIndex + 1), 7721 _appendCodePoint(buffer, lexeme, value, index, currentIndex);
8665 value, index, currentIndex);
8666 return currentIndex + 1; 7722 return currentIndex + 1;
8667 } else { 7723 } else {
8668 if (currentIndex + 3 >= length) { 7724 if (currentIndex + 3 >= length) {
8669 // Illegal escape sequence: not enough hex digits 7725 // Illegal escape sequence: not enough hex digits
8670 _reportErrorForCurrentToken(ParserErrorCode.INVALID_UNICODE_ESCAPE); 7726 _reportErrorForCurrentToken(ParserErrorCode.INVALID_UNICODE_ESCAPE);
8671 return length; 7727 return length;
8672 } 7728 }
8673 int firstDigit = currentChar; 7729 int firstDigit = currentChar;
8674 int secondDigit = lexeme.codeUnitAt(currentIndex + 1); 7730 int secondDigit = lexeme.codeUnitAt(currentIndex + 1);
8675 int thirdDigit = lexeme.codeUnitAt(currentIndex + 2); 7731 int thirdDigit = lexeme.codeUnitAt(currentIndex + 2);
8676 int fourthDigit = lexeme.codeUnitAt(currentIndex + 3); 7732 int fourthDigit = lexeme.codeUnitAt(currentIndex + 3);
8677 if (!_isHexDigit(firstDigit) || 7733 if (!_isHexDigit(firstDigit) ||
8678 !_isHexDigit(secondDigit) || 7734 !_isHexDigit(secondDigit) ||
8679 !_isHexDigit(thirdDigit) || 7735 !_isHexDigit(thirdDigit) ||
8680 !_isHexDigit(fourthDigit)) { 7736 !_isHexDigit(fourthDigit)) {
8681 // Illegal escape sequence: invalid hex digits 7737 // Illegal escape sequence: invalid hex digits
8682 _reportErrorForCurrentToken(ParserErrorCode.INVALID_UNICODE_ESCAPE); 7738 _reportErrorForCurrentToken(ParserErrorCode.INVALID_UNICODE_ESCAPE);
8683 } else { 7739 } else {
8684 _appendScalarValue( 7740 _appendCodePoint(
8685 buffer, 7741 buffer,
8686 lexeme.substring(index, currentIndex + 1), 7742 lexeme,
8687 (((((Character.digit(firstDigit, 16) << 4) + 7743 (((((Character.digit(firstDigit, 16) << 4) +
8688 Character.digit(secondDigit, 16)) << 7744 Character.digit(secondDigit, 16)) <<
8689 4) + 7745 4) +
8690 Character.digit(thirdDigit, 16)) << 7746 Character.digit(thirdDigit, 16)) <<
8691 4) + 7747 4) +
8692 Character.digit(fourthDigit, 16), 7748 Character.digit(fourthDigit, 16),
8693 index, 7749 index,
8694 currentIndex + 3); 7750 currentIndex + 3);
8695 } 7751 }
8696 return currentIndex + 4; 7752 return currentIndex + 4;
8697 } 7753 }
8698 } else { 7754 } else {
8699 buffer.writeCharCode(currentChar); 7755 buffer.writeCharCode(currentChar);
8700 } 7756 }
8701 return currentIndex + 1; 7757 return currentIndex + 1;
8702 } 7758 }
8703 7759
8704 /** 7760 /**
8705 * Decrements the error reporting lock level. If level is more than `0`, then 7761 * Decrements the error reporting lock level. If level is more than `0`, then
8706 * [reportError] wont report any error. 7762 * [reportError] wont report any error.
8707 */ 7763 */
8708 void _unlockErrorListener() { 7764 void _unlockErrorListener() {
8709 if (_errorListenerLock == 0) { 7765 if (_errorListenerLock == 0) {
8710 throw new IllegalStateException( 7766 throw new StateError("Attempt to unlock not locked error listener.");
8711 "Attempt to unlock not locked error listener.");
8712 } 7767 }
8713 _errorListenerLock--; 7768 _errorListenerLock--;
8714 } 7769 }
8715 7770
8716 /** 7771 /**
8717 * Validate that the given [parameterList] does not contain any field 7772 * Validate that the given [parameterList] does not contain any field
8718 * initializers. 7773 * initializers.
8719 */ 7774 */
8720 void _validateFormalParameterList(FormalParameterList parameterList) { 7775 void _validateFormalParameterList(FormalParameterList parameterList) {
8721 for (FormalParameter parameter in parameterList.parameters) { 7776 for (FormalParameter parameter in parameterList.parameters) {
(...skipping 322 matching lines...) Expand 10 before | Expand all | Expand 10 after
9044 */ 8099 */
9045 Parser_SyntheticKeywordToken(Keyword keyword, int offset) 8100 Parser_SyntheticKeywordToken(Keyword keyword, int offset)
9046 : super(keyword, offset); 8101 : super(keyword, offset);
9047 8102
9048 @override 8103 @override
9049 int get length => 0; 8104 int get length => 0;
9050 8105
9051 @override 8106 @override
9052 Token copy() => new Parser_SyntheticKeywordToken(keyword, offset); 8107 Token copy() => new Parser_SyntheticKeywordToken(keyword, offset);
9053 } 8108 }
9054
9055 /**
9056 * The error codes used for errors detected by the parser. The convention for
9057 * this class is for the name of the error code to indicate the problem that
9058 * caused the error to be generated and for the error message to explain what
9059 * is wrong and, when appropriate, how the problem can be corrected.
9060 */
9061 class ParserErrorCode extends ErrorCode {
9062 static const ParserErrorCode ABSTRACT_CLASS_MEMBER = const ParserErrorCode(
9063 'ABSTRACT_CLASS_MEMBER',
9064 "Members of classes cannot be declared to be 'abstract'");
9065
9066 static const ParserErrorCode ABSTRACT_ENUM = const ParserErrorCode(
9067 'ABSTRACT_ENUM', "Enums cannot be declared to be 'abstract'");
9068
9069 static const ParserErrorCode ABSTRACT_STATIC_METHOD = const ParserErrorCode(
9070 'ABSTRACT_STATIC_METHOD',
9071 "Static methods cannot be declared to be 'abstract'");
9072
9073 static const ParserErrorCode ABSTRACT_TOP_LEVEL_FUNCTION =
9074 const ParserErrorCode('ABSTRACT_TOP_LEVEL_FUNCTION',
9075 "Top-level functions cannot be declared to be 'abstract'");
9076
9077 static const ParserErrorCode ABSTRACT_TOP_LEVEL_VARIABLE =
9078 const ParserErrorCode('ABSTRACT_TOP_LEVEL_VARIABLE',
9079 "Top-level variables cannot be declared to be 'abstract'");
9080
9081 static const ParserErrorCode ABSTRACT_TYPEDEF = const ParserErrorCode(
9082 'ABSTRACT_TYPEDEF', "Type aliases cannot be declared to be 'abstract'");
9083
9084 static const ParserErrorCode ANNOTATION_ON_ENUM_CONSTANT =
9085 const ParserErrorCode('ANNOTATION_ON_ENUM_CONSTANT',
9086 "Enum constants cannot have annotations");
9087
9088 static const ParserErrorCode ASSERT_DOES_NOT_TAKE_ASSIGNMENT =
9089 const ParserErrorCode('ASSERT_DOES_NOT_TAKE_ASSIGNMENT',
9090 "Assert cannot be called on an assignment");
9091
9092 static const ParserErrorCode ASSERT_DOES_NOT_TAKE_CASCADE =
9093 const ParserErrorCode(
9094 'ASSERT_DOES_NOT_TAKE_CASCADE', "Assert cannot be called on cascade");
9095
9096 static const ParserErrorCode ASSERT_DOES_NOT_TAKE_THROW =
9097 const ParserErrorCode(
9098 'ASSERT_DOES_NOT_TAKE_THROW', "Assert cannot be called on throws");
9099
9100 static const ParserErrorCode ASSERT_DOES_NOT_TAKE_RETHROW =
9101 const ParserErrorCode('ASSERT_DOES_NOT_TAKE_RETHROW',
9102 "Assert cannot be called on rethrows");
9103
9104 /**
9105 * 16.32 Identifier Reference: It is a compile-time error if any of the
9106 * identifiers async, await, or yield is used as an identifier in a function
9107 * body marked with either async, async*, or sync*.
9108 */
9109 static const ParserErrorCode ASYNC_KEYWORD_USED_AS_IDENTIFIER =
9110 const ParserErrorCode('ASYNC_KEYWORD_USED_AS_IDENTIFIER',
9111 "The keywords 'async', 'await', and 'yield' may not be used as identif iers in an asynchronous or generator function.");
9112
9113 static const ParserErrorCode BREAK_OUTSIDE_OF_LOOP = const ParserErrorCode(
9114 'BREAK_OUTSIDE_OF_LOOP',
9115 "A break statement cannot be used outside of a loop or switch statement");
9116
9117 static const ParserErrorCode CLASS_IN_CLASS = const ParserErrorCode(
9118 'CLASS_IN_CLASS', "Classes cannot be declared inside other classes");
9119
9120 static const ParserErrorCode COLON_IN_PLACE_OF_IN = const ParserErrorCode(
9121 'COLON_IN_PLACE_OF_IN', "For-in loops use 'in' rather than a colon");
9122
9123 static const ParserErrorCode CONST_AND_FINAL = const ParserErrorCode(
9124 'CONST_AND_FINAL',
9125 "Members cannot be declared to be both 'const' and 'final'");
9126
9127 static const ParserErrorCode CONST_AND_VAR = const ParserErrorCode(
9128 'CONST_AND_VAR',
9129 "Members cannot be declared to be both 'const' and 'var'");
9130
9131 static const ParserErrorCode CONST_CLASS = const ParserErrorCode(
9132 'CONST_CLASS', "Classes cannot be declared to be 'const'");
9133
9134 static const ParserErrorCode CONST_CONSTRUCTOR_WITH_BODY =
9135 const ParserErrorCode('CONST_CONSTRUCTOR_WITH_BODY',
9136 "'const' constructors cannot have a body");
9137
9138 static const ParserErrorCode CONST_ENUM = const ParserErrorCode(
9139 'CONST_ENUM', "Enums cannot be declared to be 'const'");
9140
9141 static const ParserErrorCode CONST_FACTORY = const ParserErrorCode(
9142 'CONST_FACTORY',
9143 "Only redirecting factory constructors can be declared to be 'const'");
9144
9145 static const ParserErrorCode CONST_METHOD = const ParserErrorCode(
9146 'CONST_METHOD',
9147 "Getters, setters and methods cannot be declared to be 'const'");
9148
9149 static const ParserErrorCode CONST_TYPEDEF = const ParserErrorCode(
9150 'CONST_TYPEDEF', "Type aliases cannot be declared to be 'const'");
9151
9152 static const ParserErrorCode CONSTRUCTOR_WITH_RETURN_TYPE =
9153 const ParserErrorCode('CONSTRUCTOR_WITH_RETURN_TYPE',
9154 "Constructors cannot have a return type");
9155
9156 static const ParserErrorCode CONTINUE_OUTSIDE_OF_LOOP = const ParserErrorCode(
9157 'CONTINUE_OUTSIDE_OF_LOOP',
9158 "A continue statement cannot be used outside of a loop or switch statement ");
9159
9160 static const ParserErrorCode CONTINUE_WITHOUT_LABEL_IN_CASE =
9161 const ParserErrorCode('CONTINUE_WITHOUT_LABEL_IN_CASE',
9162 "A continue statement in a switch statement must have a label as a tar get");
9163
9164 static const ParserErrorCode DEPRECATED_CLASS_TYPE_ALIAS =
9165 const ParserErrorCode('DEPRECATED_CLASS_TYPE_ALIAS',
9166 "The 'typedef' mixin application was replaced with 'class'");
9167
9168 static const ParserErrorCode DIRECTIVE_AFTER_DECLARATION =
9169 const ParserErrorCode('DIRECTIVE_AFTER_DECLARATION',
9170 "Directives must appear before any declarations");
9171
9172 static const ParserErrorCode DUPLICATE_LABEL_IN_SWITCH_STATEMENT =
9173 const ParserErrorCode('DUPLICATE_LABEL_IN_SWITCH_STATEMENT',
9174 "The label {0} was already used in this switch statement");
9175
9176 static const ParserErrorCode DUPLICATED_MODIFIER = const ParserErrorCode(
9177 'DUPLICATED_MODIFIER', "The modifier '{0}' was already specified.");
9178
9179 static const ParserErrorCode EMPTY_ENUM_BODY = const ParserErrorCode(
9180 'EMPTY_ENUM_BODY', "An enum must declare at least one constant name");
9181
9182 static const ParserErrorCode ENUM_IN_CLASS = const ParserErrorCode(
9183 'ENUM_IN_CLASS', "Enums cannot be declared inside classes");
9184
9185 static const ParserErrorCode EQUALITY_CANNOT_BE_EQUALITY_OPERAND =
9186 const ParserErrorCode('EQUALITY_CANNOT_BE_EQUALITY_OPERAND',
9187 "Equality expression cannot be operand of another equality expression. ");
9188
9189 static const ParserErrorCode EXPECTED_CASE_OR_DEFAULT = const ParserErrorCode(
9190 'EXPECTED_CASE_OR_DEFAULT', "Expected 'case' or 'default'");
9191
9192 static const ParserErrorCode EXPECTED_CLASS_MEMBER =
9193 const ParserErrorCode('EXPECTED_CLASS_MEMBER', "Expected a class member");
9194
9195 static const ParserErrorCode EXPECTED_EXECUTABLE = const ParserErrorCode(
9196 'EXPECTED_EXECUTABLE',
9197 "Expected a method, getter, setter or operator declaration");
9198
9199 static const ParserErrorCode EXPECTED_LIST_OR_MAP_LITERAL =
9200 const ParserErrorCode(
9201 'EXPECTED_LIST_OR_MAP_LITERAL', "Expected a list or map literal");
9202
9203 static const ParserErrorCode EXPECTED_STRING_LITERAL = const ParserErrorCode(
9204 'EXPECTED_STRING_LITERAL', "Expected a string literal");
9205
9206 static const ParserErrorCode EXPECTED_TOKEN =
9207 const ParserErrorCode('EXPECTED_TOKEN', "Expected to find '{0}'");
9208
9209 static const ParserErrorCode EXPECTED_TYPE_NAME =
9210 const ParserErrorCode('EXPECTED_TYPE_NAME', "Expected a type name");
9211
9212 static const ParserErrorCode EXPORT_DIRECTIVE_AFTER_PART_DIRECTIVE =
9213 const ParserErrorCode('EXPORT_DIRECTIVE_AFTER_PART_DIRECTIVE',
9214 "Export directives must preceed part directives");
9215
9216 static const ParserErrorCode EXTERNAL_AFTER_CONST = const ParserErrorCode(
9217 'EXTERNAL_AFTER_CONST',
9218 "The modifier 'external' should be before the modifier 'const'");
9219
9220 static const ParserErrorCode EXTERNAL_AFTER_FACTORY = const ParserErrorCode(
9221 'EXTERNAL_AFTER_FACTORY',
9222 "The modifier 'external' should be before the modifier 'factory'");
9223
9224 static const ParserErrorCode EXTERNAL_AFTER_STATIC = const ParserErrorCode(
9225 'EXTERNAL_AFTER_STATIC',
9226 "The modifier 'external' should be before the modifier 'static'");
9227
9228 static const ParserErrorCode EXTERNAL_CLASS = const ParserErrorCode(
9229 'EXTERNAL_CLASS', "Classes cannot be declared to be 'external'");
9230
9231 static const ParserErrorCode EXTERNAL_CONSTRUCTOR_WITH_BODY =
9232 const ParserErrorCode('EXTERNAL_CONSTRUCTOR_WITH_BODY',
9233 "External constructors cannot have a body");
9234
9235 static const ParserErrorCode EXTERNAL_ENUM = const ParserErrorCode(
9236 'EXTERNAL_ENUM', "Enums cannot be declared to be 'external'");
9237
9238 static const ParserErrorCode EXTERNAL_FIELD = const ParserErrorCode(
9239 'EXTERNAL_FIELD', "Fields cannot be declared to be 'external'");
9240
9241 static const ParserErrorCode EXTERNAL_GETTER_WITH_BODY =
9242 const ParserErrorCode(
9243 'EXTERNAL_GETTER_WITH_BODY', "External getters cannot have a body");
9244
9245 static const ParserErrorCode EXTERNAL_METHOD_WITH_BODY =
9246 const ParserErrorCode(
9247 'EXTERNAL_METHOD_WITH_BODY', "External methods cannot have a body");
9248
9249 static const ParserErrorCode EXTERNAL_OPERATOR_WITH_BODY =
9250 const ParserErrorCode('EXTERNAL_OPERATOR_WITH_BODY',
9251 "External operators cannot have a body");
9252
9253 static const ParserErrorCode EXTERNAL_SETTER_WITH_BODY =
9254 const ParserErrorCode(
9255 'EXTERNAL_SETTER_WITH_BODY', "External setters cannot have a body");
9256
9257 static const ParserErrorCode EXTERNAL_TYPEDEF = const ParserErrorCode(
9258 'EXTERNAL_TYPEDEF', "Type aliases cannot be declared to be 'external'");
9259
9260 static const ParserErrorCode FACTORY_TOP_LEVEL_DECLARATION =
9261 const ParserErrorCode('FACTORY_TOP_LEVEL_DECLARATION',
9262 "Top-level declarations cannot be declared to be 'factory'");
9263
9264 static const ParserErrorCode FACTORY_WITH_INITIALIZERS =
9265 const ParserErrorCode(
9266 'FACTORY_WITH_INITIALIZERS',
9267 "A 'factory' constructor cannot have initializers",
9268 "Either remove the 'factory' keyword to make this a generative "
9269 "constructor or remove the initializers.");
9270
9271 static const ParserErrorCode FACTORY_WITHOUT_BODY = const ParserErrorCode(
9272 'FACTORY_WITHOUT_BODY',
9273 "A non-redirecting 'factory' constructor must have a body");
9274
9275 static const ParserErrorCode FIELD_INITIALIZER_OUTSIDE_CONSTRUCTOR =
9276 const ParserErrorCode('FIELD_INITIALIZER_OUTSIDE_CONSTRUCTOR',
9277 "Field initializers can only be used in a constructor");
9278
9279 static const ParserErrorCode FINAL_AND_VAR = const ParserErrorCode(
9280 'FINAL_AND_VAR',
9281 "Members cannot be declared to be both 'final' and 'var'");
9282
9283 static const ParserErrorCode FINAL_CLASS = const ParserErrorCode(
9284 'FINAL_CLASS', "Classes cannot be declared to be 'final'");
9285
9286 static const ParserErrorCode FINAL_CONSTRUCTOR = const ParserErrorCode(
9287 'FINAL_CONSTRUCTOR', "A constructor cannot be declared to be 'final'");
9288
9289 static const ParserErrorCode FINAL_ENUM = const ParserErrorCode(
9290 'FINAL_ENUM', "Enums cannot be declared to be 'final'");
9291
9292 static const ParserErrorCode FINAL_METHOD = const ParserErrorCode(
9293 'FINAL_METHOD',
9294 "Getters, setters and methods cannot be declared to be 'final'");
9295
9296 static const ParserErrorCode FINAL_TYPEDEF = const ParserErrorCode(
9297 'FINAL_TYPEDEF', "Type aliases cannot be declared to be 'final'");
9298
9299 static const ParserErrorCode FUNCTION_TYPED_PARAMETER_VAR = const ParserErrorC ode(
9300 'FUNCTION_TYPED_PARAMETER_VAR',
9301 "Function typed parameters cannot specify 'const', 'final' or 'var' instea d of return type");
9302
9303 static const ParserErrorCode GETTER_IN_FUNCTION = const ParserErrorCode(
9304 'GETTER_IN_FUNCTION',
9305 "Getters cannot be defined within methods or functions");
9306
9307 static const ParserErrorCode GETTER_WITH_PARAMETERS = const ParserErrorCode(
9308 'GETTER_WITH_PARAMETERS',
9309 "Getter should be declared without a parameter list");
9310
9311 static const ParserErrorCode ILLEGAL_ASSIGNMENT_TO_NON_ASSIGNABLE =
9312 const ParserErrorCode('ILLEGAL_ASSIGNMENT_TO_NON_ASSIGNABLE',
9313 "Illegal assignment to non-assignable expression");
9314
9315 static const ParserErrorCode IMPLEMENTS_BEFORE_EXTENDS =
9316 const ParserErrorCode('IMPLEMENTS_BEFORE_EXTENDS',
9317 "The extends clause must be before the implements clause");
9318
9319 static const ParserErrorCode IMPLEMENTS_BEFORE_WITH = const ParserErrorCode(
9320 'IMPLEMENTS_BEFORE_WITH',
9321 "The with clause must be before the implements clause");
9322
9323 static const ParserErrorCode IMPORT_DIRECTIVE_AFTER_PART_DIRECTIVE =
9324 const ParserErrorCode('IMPORT_DIRECTIVE_AFTER_PART_DIRECTIVE',
9325 "Import directives must preceed part directives");
9326
9327 static const ParserErrorCode INITIALIZED_VARIABLE_IN_FOR_EACH =
9328 const ParserErrorCode('INITIALIZED_VARIABLE_IN_FOR_EACH',
9329 "The loop variable in a for-each loop cannot be initialized");
9330
9331 static const ParserErrorCode INVALID_AWAIT_IN_FOR = const ParserErrorCode(
9332 'INVALID_AWAIT_IN_FOR',
9333 "The modifier 'await' is not allowed for a normal 'for' statement",
9334 "Remove the keyword or use a for-each statement.");
9335
9336 static const ParserErrorCode INVALID_CODE_POINT = const ParserErrorCode(
9337 'INVALID_CODE_POINT',
9338 "The escape sequence '{0}' is not a valid code point");
9339
9340 static const ParserErrorCode INVALID_COMMENT_REFERENCE = const ParserErrorCode (
9341 'INVALID_COMMENT_REFERENCE',
9342 "Comment references should contain a possibly prefixed identifier and can start with 'new', but should not contain anything else");
9343
9344 static const ParserErrorCode INVALID_HEX_ESCAPE = const ParserErrorCode(
9345 'INVALID_HEX_ESCAPE',
9346 "An escape sequence starting with '\\x' must be followed by 2 hexidecimal digits");
9347
9348 static const ParserErrorCode INVALID_OPERATOR = const ParserErrorCode(
9349 'INVALID_OPERATOR', "The string '{0}' is not a valid operator");
9350
9351 static const ParserErrorCode INVALID_OPERATOR_FOR_SUPER =
9352 const ParserErrorCode('INVALID_OPERATOR_FOR_SUPER',
9353 "The operator '{0}' cannot be used with 'super'");
9354
9355 static const ParserErrorCode INVALID_STAR_AFTER_ASYNC = const ParserErrorCode(
9356 'INVALID_STAR_AFTER_ASYNC',
9357 "The modifier 'async*' is not allowed for an expression function body",
9358 "Convert the body to a block.");
9359
9360 static const ParserErrorCode INVALID_SYNC = const ParserErrorCode(
9361 'INVALID_SYNC',
9362 "The modifier 'sync' is not allowed for an exrpression function body",
9363 "Convert the body to a block.");
9364
9365 static const ParserErrorCode INVALID_UNICODE_ESCAPE = const ParserErrorCode(
9366 'INVALID_UNICODE_ESCAPE',
9367 "An escape sequence starting with '\\u' must be followed by 4 hexidecimal digits or from 1 to 6 digits between '{' and '}'");
9368
9369 static const ParserErrorCode LIBRARY_DIRECTIVE_NOT_FIRST =
9370 const ParserErrorCode('LIBRARY_DIRECTIVE_NOT_FIRST',
9371 "The library directive must appear before all other directives");
9372
9373 static const ParserErrorCode LOCAL_FUNCTION_DECLARATION_MODIFIER =
9374 const ParserErrorCode('LOCAL_FUNCTION_DECLARATION_MODIFIER',
9375 "Local function declarations cannot specify any modifier");
9376
9377 static const ParserErrorCode MISSING_ASSIGNABLE_SELECTOR =
9378 const ParserErrorCode('MISSING_ASSIGNABLE_SELECTOR',
9379 "Missing selector such as \".<identifier>\" or \"[0]\"");
9380
9381 static const ParserErrorCode MISSING_ASSIGNMENT_IN_INITIALIZER =
9382 const ParserErrorCode('MISSING_ASSIGNMENT_IN_INITIALIZER',
9383 "Expected an assignment after the field name");
9384
9385 static const ParserErrorCode MISSING_CATCH_OR_FINALLY = const ParserErrorCode(
9386 'MISSING_CATCH_OR_FINALLY',
9387 "A try statement must have either a catch or finally clause");
9388
9389 static const ParserErrorCode MISSING_CLASS_BODY = const ParserErrorCode(
9390 'MISSING_CLASS_BODY',
9391 "A class definition must have a body, even if it is empty");
9392
9393 static const ParserErrorCode MISSING_CLOSING_PARENTHESIS =
9394 const ParserErrorCode(
9395 'MISSING_CLOSING_PARENTHESIS', "The closing parenthesis is missing");
9396
9397 static const ParserErrorCode MISSING_CONST_FINAL_VAR_OR_TYPE =
9398 const ParserErrorCode('MISSING_CONST_FINAL_VAR_OR_TYPE',
9399 "Variables must be declared using the keywords 'const', 'final', 'var' or a type name");
9400
9401 static const ParserErrorCode MISSING_ENUM_BODY = const ParserErrorCode(
9402 'MISSING_ENUM_BODY',
9403 "An enum definition must have a body with at least one constant name");
9404
9405 static const ParserErrorCode MISSING_EXPRESSION_IN_INITIALIZER =
9406 const ParserErrorCode('MISSING_EXPRESSION_IN_INITIALIZER',
9407 "Expected an expression after the assignment operator");
9408
9409 static const ParserErrorCode MISSING_EXPRESSION_IN_THROW =
9410 const ParserErrorCode('MISSING_EXPRESSION_IN_THROW',
9411 "Throw expressions must compute the object to be thrown");
9412
9413 static const ParserErrorCode MISSING_FUNCTION_BODY = const ParserErrorCode(
9414 'MISSING_FUNCTION_BODY', "A function body must be provided");
9415
9416 static const ParserErrorCode MISSING_FUNCTION_PARAMETERS =
9417 const ParserErrorCode('MISSING_FUNCTION_PARAMETERS',
9418 "Functions must have an explicit list of parameters");
9419
9420 static const ParserErrorCode MISSING_METHOD_PARAMETERS =
9421 const ParserErrorCode('MISSING_METHOD_PARAMETERS',
9422 "Methods must have an explicit list of parameters");
9423
9424 static const ParserErrorCode MISSING_GET = const ParserErrorCode(
9425 'MISSING_GET',
9426 "Getters must have the keyword 'get' before the getter name");
9427
9428 static const ParserErrorCode MISSING_IDENTIFIER =
9429 const ParserErrorCode('MISSING_IDENTIFIER', "Expected an identifier");
9430
9431 static const ParserErrorCode MISSING_INITIALIZER =
9432 const ParserErrorCode('MISSING_INITIALIZER', "Expected an initializer");
9433
9434 static const ParserErrorCode MISSING_KEYWORD_OPERATOR = const ParserErrorCode(
9435 'MISSING_KEYWORD_OPERATOR',
9436 "Operator declarations must be preceeded by the keyword 'operator'");
9437
9438 static const ParserErrorCode MISSING_NAME_IN_LIBRARY_DIRECTIVE =
9439 const ParserErrorCode('MISSING_NAME_IN_LIBRARY_DIRECTIVE',
9440 "Library directives must include a library name");
9441
9442 static const ParserErrorCode MISSING_NAME_IN_PART_OF_DIRECTIVE =
9443 const ParserErrorCode('MISSING_NAME_IN_PART_OF_DIRECTIVE',
9444 "Library directives must include a library name");
9445
9446 static const ParserErrorCode MISSING_PREFIX_IN_DEFERRED_IMPORT =
9447 const ParserErrorCode('MISSING_PREFIX_IN_DEFERRED_IMPORT',
9448 "Deferred imports must have a prefix");
9449
9450 static const ParserErrorCode MISSING_STAR_AFTER_SYNC = const ParserErrorCode(
9451 'MISSING_STAR_AFTER_SYNC',
9452 "The modifier 'sync' must be followed by a star ('*')",
9453 "Remove the modifier or add a star.");
9454
9455 static const ParserErrorCode MISSING_STATEMENT =
9456 const ParserErrorCode('MISSING_STATEMENT', "Expected a statement");
9457
9458 static const ParserErrorCode MISSING_TERMINATOR_FOR_PARAMETER_GROUP =
9459 const ParserErrorCode('MISSING_TERMINATOR_FOR_PARAMETER_GROUP',
9460 "There is no '{0}' to close the parameter group");
9461
9462 static const ParserErrorCode MISSING_TYPEDEF_PARAMETERS =
9463 const ParserErrorCode('MISSING_TYPEDEF_PARAMETERS',
9464 "Type aliases for functions must have an explicit list of parameters") ;
9465
9466 static const ParserErrorCode MISSING_VARIABLE_IN_FOR_EACH = const ParserErrorC ode(
9467 'MISSING_VARIABLE_IN_FOR_EACH',
9468 "A loop variable must be declared in a for-each loop before the 'in', but none were found");
9469
9470 static const ParserErrorCode MIXED_PARAMETER_GROUPS = const ParserErrorCode(
9471 'MIXED_PARAMETER_GROUPS',
9472 "Cannot have both positional and named parameters in a single parameter li st");
9473
9474 static const ParserErrorCode MULTIPLE_EXTENDS_CLAUSES = const ParserErrorCode(
9475 'MULTIPLE_EXTENDS_CLAUSES',
9476 "Each class definition can have at most one extends clause");
9477
9478 static const ParserErrorCode MULTIPLE_IMPLEMENTS_CLAUSES =
9479 const ParserErrorCode('MULTIPLE_IMPLEMENTS_CLAUSES',
9480 "Each class definition can have at most one implements clause");
9481
9482 static const ParserErrorCode MULTIPLE_LIBRARY_DIRECTIVES =
9483 const ParserErrorCode('MULTIPLE_LIBRARY_DIRECTIVES',
9484 "Only one library directive may be declared in a file");
9485
9486 static const ParserErrorCode MULTIPLE_NAMED_PARAMETER_GROUPS =
9487 const ParserErrorCode('MULTIPLE_NAMED_PARAMETER_GROUPS',
9488 "Cannot have multiple groups of named parameters in a single parameter list");
9489
9490 static const ParserErrorCode MULTIPLE_PART_OF_DIRECTIVES =
9491 const ParserErrorCode('MULTIPLE_PART_OF_DIRECTIVES',
9492 "Only one part-of directive may be declared in a file");
9493
9494 static const ParserErrorCode MULTIPLE_POSITIONAL_PARAMETER_GROUPS =
9495 const ParserErrorCode('MULTIPLE_POSITIONAL_PARAMETER_GROUPS',
9496 "Cannot have multiple groups of positional parameters in a single para meter list");
9497
9498 static const ParserErrorCode MULTIPLE_VARIABLES_IN_FOR_EACH =
9499 const ParserErrorCode('MULTIPLE_VARIABLES_IN_FOR_EACH',
9500 "A single loop variable must be declared in a for-each loop before the 'in', but {0} were found");
9501
9502 static const ParserErrorCode MULTIPLE_WITH_CLAUSES = const ParserErrorCode(
9503 'MULTIPLE_WITH_CLAUSES',
9504 "Each class definition can have at most one with clause");
9505
9506 static const ParserErrorCode NAMED_FUNCTION_EXPRESSION =
9507 const ParserErrorCode(
9508 'NAMED_FUNCTION_EXPRESSION', "Function expressions cannot be named");
9509
9510 static const ParserErrorCode NAMED_PARAMETER_OUTSIDE_GROUP =
9511 const ParserErrorCode('NAMED_PARAMETER_OUTSIDE_GROUP',
9512 "Named parameters must be enclosed in curly braces ('{' and '}')");
9513
9514 static const ParserErrorCode NATIVE_CLAUSE_IN_NON_SDK_CODE =
9515 const ParserErrorCode('NATIVE_CLAUSE_IN_NON_SDK_CODE',
9516 "Native clause can only be used in the SDK and code that is loaded thr ough native extensions");
9517
9518 static const ParserErrorCode NATIVE_FUNCTION_BODY_IN_NON_SDK_CODE =
9519 const ParserErrorCode('NATIVE_FUNCTION_BODY_IN_NON_SDK_CODE',
9520 "Native functions can only be declared in the SDK and code that is loa ded through native extensions");
9521
9522 static const ParserErrorCode NON_CONSTRUCTOR_FACTORY = const ParserErrorCode(
9523 'NON_CONSTRUCTOR_FACTORY',
9524 "Only constructors can be declared to be a 'factory'");
9525
9526 static const ParserErrorCode NON_IDENTIFIER_LIBRARY_NAME =
9527 const ParserErrorCode('NON_IDENTIFIER_LIBRARY_NAME',
9528 "The name of a library must be an identifier");
9529
9530 static const ParserErrorCode NON_PART_OF_DIRECTIVE_IN_PART =
9531 const ParserErrorCode('NON_PART_OF_DIRECTIVE_IN_PART',
9532 "The part-of directive must be the only directive in a part");
9533
9534 static const ParserErrorCode NON_STRING_LITERAL_AS_URI =
9535 const ParserErrorCode(
9536 'NON_STRING_LITERAL_AS_URI',
9537 "The URI must be a string literal",
9538 "Enclose the URI in either single or double quotes.");
9539
9540 static const ParserErrorCode NON_USER_DEFINABLE_OPERATOR =
9541 const ParserErrorCode('NON_USER_DEFINABLE_OPERATOR',
9542 "The operator '{0}' is not user definable");
9543
9544 static const ParserErrorCode NORMAL_BEFORE_OPTIONAL_PARAMETERS =
9545 const ParserErrorCode('NORMAL_BEFORE_OPTIONAL_PARAMETERS',
9546 "Normal parameters must occur before optional parameters");
9547
9548 static const ParserErrorCode POSITIONAL_AFTER_NAMED_ARGUMENT =
9549 const ParserErrorCode('POSITIONAL_AFTER_NAMED_ARGUMENT',
9550 "Positional arguments must occur before named arguments");
9551
9552 static const ParserErrorCode POSITIONAL_PARAMETER_OUTSIDE_GROUP =
9553 const ParserErrorCode('POSITIONAL_PARAMETER_OUTSIDE_GROUP',
9554 "Positional parameters must be enclosed in square brackets ('[' and '] ')");
9555
9556 static const ParserErrorCode REDIRECTION_IN_NON_FACTORY_CONSTRUCTOR =
9557 const ParserErrorCode('REDIRECTION_IN_NON_FACTORY_CONSTRUCTOR',
9558 "Only factory constructor can specify '=' redirection.");
9559
9560 static const ParserErrorCode SETTER_IN_FUNCTION = const ParserErrorCode(
9561 'SETTER_IN_FUNCTION',
9562 "Setters cannot be defined within methods or functions");
9563
9564 static const ParserErrorCode STATIC_AFTER_CONST = const ParserErrorCode(
9565 'STATIC_AFTER_CONST',
9566 "The modifier 'static' should be before the modifier 'const'");
9567
9568 static const ParserErrorCode STATIC_AFTER_FINAL = const ParserErrorCode(
9569 'STATIC_AFTER_FINAL',
9570 "The modifier 'static' should be before the modifier 'final'");
9571
9572 static const ParserErrorCode STATIC_AFTER_VAR = const ParserErrorCode(
9573 'STATIC_AFTER_VAR',
9574 "The modifier 'static' should be before the modifier 'var'");
9575
9576 static const ParserErrorCode STATIC_CONSTRUCTOR = const ParserErrorCode(
9577 'STATIC_CONSTRUCTOR', "Constructors cannot be static");
9578
9579 static const ParserErrorCode STATIC_GETTER_WITHOUT_BODY =
9580 const ParserErrorCode(
9581 'STATIC_GETTER_WITHOUT_BODY', "A 'static' getter must have a body");
9582
9583 static const ParserErrorCode STATIC_OPERATOR =
9584 const ParserErrorCode('STATIC_OPERATOR', "Operators cannot be static");
9585
9586 static const ParserErrorCode STATIC_SETTER_WITHOUT_BODY =
9587 const ParserErrorCode(
9588 'STATIC_SETTER_WITHOUT_BODY', "A 'static' setter must have a body");
9589
9590 static const ParserErrorCode STATIC_TOP_LEVEL_DECLARATION =
9591 const ParserErrorCode('STATIC_TOP_LEVEL_DECLARATION',
9592 "Top-level declarations cannot be declared to be 'static'");
9593
9594 static const ParserErrorCode SWITCH_HAS_CASE_AFTER_DEFAULT_CASE =
9595 const ParserErrorCode('SWITCH_HAS_CASE_AFTER_DEFAULT_CASE',
9596 "The 'default' case should be the last case in a switch statement");
9597
9598 static const ParserErrorCode SWITCH_HAS_MULTIPLE_DEFAULT_CASES =
9599 const ParserErrorCode('SWITCH_HAS_MULTIPLE_DEFAULT_CASES',
9600 "The 'default' case can only be declared once");
9601
9602 static const ParserErrorCode TOP_LEVEL_OPERATOR = const ParserErrorCode(
9603 'TOP_LEVEL_OPERATOR', "Operators must be declared within a class");
9604
9605 static const ParserErrorCode TYPEDEF_IN_CLASS = const ParserErrorCode(
9606 'TYPEDEF_IN_CLASS',
9607 "Function type aliases cannot be declared inside classes");
9608
9609 static const ParserErrorCode UNEXPECTED_TERMINATOR_FOR_PARAMETER_GROUP =
9610 const ParserErrorCode('UNEXPECTED_TERMINATOR_FOR_PARAMETER_GROUP',
9611 "There is no '{0}' to open a parameter group");
9612
9613 static const ParserErrorCode UNEXPECTED_TOKEN =
9614 const ParserErrorCode('UNEXPECTED_TOKEN', "Unexpected token '{0}'");
9615
9616 static const ParserErrorCode WITH_BEFORE_EXTENDS = const ParserErrorCode(
9617 'WITH_BEFORE_EXTENDS',
9618 "The extends clause must be before the with clause");
9619
9620 static const ParserErrorCode WITH_WITHOUT_EXTENDS = const ParserErrorCode(
9621 'WITH_WITHOUT_EXTENDS',
9622 "The with clause cannot be used without an extends clause");
9623
9624 static const ParserErrorCode WRONG_SEPARATOR_FOR_NAMED_PARAMETER =
9625 const ParserErrorCode('WRONG_SEPARATOR_FOR_NAMED_PARAMETER',
9626 "The default value of a named parameter should be preceeded by ':'");
9627
9628 static const ParserErrorCode WRONG_SEPARATOR_FOR_POSITIONAL_PARAMETER =
9629 const ParserErrorCode('WRONG_SEPARATOR_FOR_POSITIONAL_PARAMETER',
9630 "The default value of a positional parameter should be preceeded by '= '");
9631
9632 static const ParserErrorCode WRONG_TERMINATOR_FOR_PARAMETER_GROUP =
9633 const ParserErrorCode('WRONG_TERMINATOR_FOR_PARAMETER_GROUP',
9634 "Expected '{0}' to close parameter group");
9635
9636 static const ParserErrorCode VAR_AND_TYPE = const ParserErrorCode(
9637 'VAR_AND_TYPE',
9638 "Variables cannot be declared using both 'var' and a type name; remove the 'var'");
9639
9640 static const ParserErrorCode VAR_AS_TYPE_NAME = const ParserErrorCode(
9641 'VAR_AS_TYPE_NAME', "The keyword 'var' cannot be used as a type name");
9642
9643 static const ParserErrorCode VAR_CLASS = const ParserErrorCode(
9644 'VAR_CLASS', "Classes cannot be declared to be 'var'");
9645
9646 static const ParserErrorCode VAR_ENUM =
9647 const ParserErrorCode('VAR_ENUM', "Enums cannot be declared to be 'var'");
9648
9649 static const ParserErrorCode VAR_RETURN_TYPE = const ParserErrorCode(
9650 'VAR_RETURN_TYPE', "The return type cannot be 'var'");
9651
9652 static const ParserErrorCode VAR_TYPEDEF = const ParserErrorCode(
9653 'VAR_TYPEDEF', "Type aliases cannot be declared to be 'var'");
9654
9655 static const ParserErrorCode VOID_PARAMETER = const ParserErrorCode(
9656 'VOID_PARAMETER', "Parameters cannot have a type of 'void'");
9657
9658 static const ParserErrorCode VOID_VARIABLE = const ParserErrorCode(
9659 'VOID_VARIABLE', "Variables cannot have a type of 'void'");
9660
9661 /**
9662 * Initialize a newly created error code to have the given [name]. The message
9663 * associated with the error will be created from the given [message]
9664 * template. The correction associated with the error will be created from the
9665 * given [correction] template.
9666 */
9667 const ParserErrorCode(String name, String message, [String correction])
9668 : super(name, message, correction);
9669
9670 @override
9671 ErrorSeverity get errorSeverity => ErrorSeverity.ERROR;
9672
9673 @override
9674 ErrorType get type => ErrorType.SYNTACTIC_ERROR;
9675 }
9676
9677 /**
9678 * An object that copies resolution information from one AST structure to
9679 * another as long as the structures of the corresponding children of a pair of
9680 * nodes are the same.
9681 */
9682 class ResolutionCopier implements AstVisitor<bool> {
9683 /**
9684 * The AST node with which the node being visited is to be compared. This is
9685 * only valid at the beginning of each visit method (until [isEqualNodes] is
9686 * invoked).
9687 */
9688 AstNode _toNode;
9689
9690 @override
9691 bool visitAdjacentStrings(AdjacentStrings node) {
9692 AdjacentStrings toNode = this._toNode as AdjacentStrings;
9693 return _isEqualNodeLists(node.strings, toNode.strings);
9694 }
9695
9696 @override
9697 bool visitAnnotation(Annotation node) {
9698 Annotation toNode = this._toNode as Annotation;
9699 if (_and(
9700 _isEqualTokens(node.atSign, toNode.atSign),
9701 _isEqualNodes(node.name, toNode.name),
9702 _isEqualTokens(node.period, toNode.period),
9703 _isEqualNodes(node.constructorName, toNode.constructorName),
9704 _isEqualNodes(node.arguments, toNode.arguments))) {
9705 toNode.element = node.element;
9706 return true;
9707 }
9708 return false;
9709 }
9710
9711 @override
9712 bool visitArgumentList(ArgumentList node) {
9713 ArgumentList toNode = this._toNode as ArgumentList;
9714 return _and(
9715 _isEqualTokens(node.leftParenthesis, toNode.leftParenthesis),
9716 _isEqualNodeLists(node.arguments, toNode.arguments),
9717 _isEqualTokens(node.rightParenthesis, toNode.rightParenthesis));
9718 }
9719
9720 @override
9721 bool visitAsExpression(AsExpression node) {
9722 AsExpression toNode = this._toNode as AsExpression;
9723 if (_and(
9724 _isEqualNodes(node.expression, toNode.expression),
9725 _isEqualTokens(node.asOperator, toNode.asOperator),
9726 _isEqualNodes(node.type, toNode.type))) {
9727 toNode.propagatedType = node.propagatedType;
9728 toNode.staticType = node.staticType;
9729 return true;
9730 }
9731 return false;
9732 }
9733
9734 @override
9735 bool visitAssertStatement(AssertStatement node) {
9736 AssertStatement toNode = this._toNode as AssertStatement;
9737 return _and(
9738 _isEqualTokens(node.assertKeyword, toNode.assertKeyword),
9739 _isEqualTokens(node.leftParenthesis, toNode.leftParenthesis),
9740 _isEqualNodes(node.condition, toNode.condition),
9741 _isEqualTokens(node.rightParenthesis, toNode.rightParenthesis),
9742 _isEqualTokens(node.semicolon, toNode.semicolon));
9743 }
9744
9745 @override
9746 bool visitAssignmentExpression(AssignmentExpression node) {
9747 AssignmentExpression toNode = this._toNode as AssignmentExpression;
9748 if (_and(
9749 _isEqualNodes(node.leftHandSide, toNode.leftHandSide),
9750 _isEqualTokens(node.operator, toNode.operator),
9751 _isEqualNodes(node.rightHandSide, toNode.rightHandSide))) {
9752 toNode.propagatedElement = node.propagatedElement;
9753 toNode.propagatedType = node.propagatedType;
9754 toNode.staticElement = node.staticElement;
9755 toNode.staticType = node.staticType;
9756 return true;
9757 }
9758 return false;
9759 }
9760
9761 @override
9762 bool visitAwaitExpression(AwaitExpression node) {
9763 AwaitExpression toNode = this._toNode as AwaitExpression;
9764 if (_and(_isEqualTokens(node.awaitKeyword, toNode.awaitKeyword),
9765 _isEqualNodes(node.expression, toNode.expression))) {
9766 toNode.propagatedType = node.propagatedType;
9767 toNode.staticType = node.staticType;
9768 return true;
9769 }
9770 return false;
9771 }
9772
9773 @override
9774 bool visitBinaryExpression(BinaryExpression node) {
9775 BinaryExpression toNode = this._toNode as BinaryExpression;
9776 if (_and(
9777 _isEqualNodes(node.leftOperand, toNode.leftOperand),
9778 _isEqualTokens(node.operator, toNode.operator),
9779 _isEqualNodes(node.rightOperand, toNode.rightOperand))) {
9780 toNode.propagatedElement = node.propagatedElement;
9781 toNode.propagatedType = node.propagatedType;
9782 toNode.staticElement = node.staticElement;
9783 toNode.staticType = node.staticType;
9784 return true;
9785 }
9786 return false;
9787 }
9788
9789 @override
9790 bool visitBlock(Block node) {
9791 Block toNode = this._toNode as Block;
9792 return _and(
9793 _isEqualTokens(node.leftBracket, toNode.leftBracket),
9794 _isEqualNodeLists(node.statements, toNode.statements),
9795 _isEqualTokens(node.rightBracket, toNode.rightBracket));
9796 }
9797
9798 @override
9799 bool visitBlockFunctionBody(BlockFunctionBody node) {
9800 BlockFunctionBody toNode = this._toNode as BlockFunctionBody;
9801 return _isEqualNodes(node.block, toNode.block);
9802 }
9803
9804 @override
9805 bool visitBooleanLiteral(BooleanLiteral node) {
9806 BooleanLiteral toNode = this._toNode as BooleanLiteral;
9807 if (_and(_isEqualTokens(node.literal, toNode.literal),
9808 node.value == toNode.value)) {
9809 toNode.propagatedType = node.propagatedType;
9810 toNode.staticType = node.staticType;
9811 return true;
9812 }
9813 return false;
9814 }
9815
9816 @override
9817 bool visitBreakStatement(BreakStatement node) {
9818 BreakStatement toNode = this._toNode as BreakStatement;
9819 if (_and(
9820 _isEqualTokens(node.breakKeyword, toNode.breakKeyword),
9821 _isEqualNodes(node.label, toNode.label),
9822 _isEqualTokens(node.semicolon, toNode.semicolon))) {
9823 // TODO(paulberry): map node.target to toNode.target.
9824 return true;
9825 }
9826 return false;
9827 }
9828
9829 @override
9830 bool visitCascadeExpression(CascadeExpression node) {
9831 CascadeExpression toNode = this._toNode as CascadeExpression;
9832 if (_and(_isEqualNodes(node.target, toNode.target),
9833 _isEqualNodeLists(node.cascadeSections, toNode.cascadeSections))) {
9834 toNode.propagatedType = node.propagatedType;
9835 toNode.staticType = node.staticType;
9836 return true;
9837 }
9838 return false;
9839 }
9840
9841 @override
9842 bool visitCatchClause(CatchClause node) {
9843 CatchClause toNode = this._toNode as CatchClause;
9844 return _and(
9845 _isEqualTokens(node.onKeyword, toNode.onKeyword),
9846 _isEqualNodes(node.exceptionType, toNode.exceptionType),
9847 _isEqualTokens(node.catchKeyword, toNode.catchKeyword),
9848 _isEqualTokens(node.leftParenthesis, toNode.leftParenthesis),
9849 _isEqualNodes(node.exceptionParameter, toNode.exceptionParameter),
9850 _isEqualTokens(node.comma, toNode.comma),
9851 _isEqualNodes(node.stackTraceParameter, toNode.stackTraceParameter),
9852 _isEqualTokens(node.rightParenthesis, toNode.rightParenthesis),
9853 _isEqualNodes(node.body, toNode.body));
9854 }
9855
9856 @override
9857 bool visitClassDeclaration(ClassDeclaration node) {
9858 ClassDeclaration toNode = this._toNode as ClassDeclaration;
9859 return _and(
9860 _isEqualNodes(node.documentationComment, toNode.documentationComment),
9861 _isEqualNodeLists(node.metadata, toNode.metadata),
9862 _isEqualTokens(node.abstractKeyword, toNode.abstractKeyword),
9863 _isEqualTokens(node.classKeyword, toNode.classKeyword),
9864 _isEqualNodes(node.name, toNode.name),
9865 _isEqualNodes(node.typeParameters, toNode.typeParameters),
9866 _isEqualNodes(node.extendsClause, toNode.extendsClause),
9867 _isEqualNodes(node.withClause, toNode.withClause),
9868 _isEqualNodes(node.implementsClause, toNode.implementsClause),
9869 _isEqualTokens(node.leftBracket, toNode.leftBracket),
9870 _isEqualNodeLists(node.members, toNode.members),
9871 _isEqualTokens(node.rightBracket, toNode.rightBracket));
9872 }
9873
9874 @override
9875 bool visitClassTypeAlias(ClassTypeAlias node) {
9876 ClassTypeAlias toNode = this._toNode as ClassTypeAlias;
9877 return _and(
9878 _isEqualNodes(node.documentationComment, toNode.documentationComment),
9879 _isEqualNodeLists(node.metadata, toNode.metadata),
9880 _isEqualTokens(node.typedefKeyword, toNode.typedefKeyword),
9881 _isEqualNodes(node.name, toNode.name),
9882 _isEqualNodes(node.typeParameters, toNode.typeParameters),
9883 _isEqualTokens(node.equals, toNode.equals),
9884 _isEqualTokens(node.abstractKeyword, toNode.abstractKeyword),
9885 _isEqualNodes(node.superclass, toNode.superclass),
9886 _isEqualNodes(node.withClause, toNode.withClause),
9887 _isEqualNodes(node.implementsClause, toNode.implementsClause),
9888 _isEqualTokens(node.semicolon, toNode.semicolon));
9889 }
9890
9891 @override
9892 bool visitComment(Comment node) {
9893 Comment toNode = this._toNode as Comment;
9894 return _isEqualNodeLists(node.references, toNode.references);
9895 }
9896
9897 @override
9898 bool visitCommentReference(CommentReference node) {
9899 CommentReference toNode = this._toNode as CommentReference;
9900 return _and(_isEqualTokens(node.newKeyword, toNode.newKeyword),
9901 _isEqualNodes(node.identifier, toNode.identifier));
9902 }
9903
9904 @override
9905 bool visitCompilationUnit(CompilationUnit node) {
9906 CompilationUnit toNode = this._toNode as CompilationUnit;
9907 if (_and(
9908 _isEqualTokens(node.beginToken, toNode.beginToken),
9909 _isEqualNodes(node.scriptTag, toNode.scriptTag),
9910 _isEqualNodeLists(node.directives, toNode.directives),
9911 _isEqualNodeLists(node.declarations, toNode.declarations),
9912 _isEqualTokens(node.endToken, toNode.endToken))) {
9913 toNode.element = node.element;
9914 return true;
9915 }
9916 return false;
9917 }
9918
9919 @override
9920 bool visitConditionalExpression(ConditionalExpression node) {
9921 ConditionalExpression toNode = this._toNode as ConditionalExpression;
9922 if (_and(
9923 _isEqualNodes(node.condition, toNode.condition),
9924 _isEqualTokens(node.question, toNode.question),
9925 _isEqualNodes(node.thenExpression, toNode.thenExpression),
9926 _isEqualTokens(node.colon, toNode.colon),
9927 _isEqualNodes(node.elseExpression, toNode.elseExpression))) {
9928 toNode.propagatedType = node.propagatedType;
9929 toNode.staticType = node.staticType;
9930 return true;
9931 }
9932 return false;
9933 }
9934
9935 @override
9936 bool visitConstructorDeclaration(ConstructorDeclaration node) {
9937 ConstructorDeclaration toNode = this._toNode as ConstructorDeclaration;
9938 if (_and(
9939 _isEqualNodes(node.documentationComment, toNode.documentationComment),
9940 _isEqualNodeLists(node.metadata, toNode.metadata),
9941 _isEqualTokens(node.externalKeyword, toNode.externalKeyword),
9942 _isEqualTokens(node.constKeyword, toNode.constKeyword),
9943 _isEqualTokens(node.factoryKeyword, toNode.factoryKeyword),
9944 _isEqualNodes(node.returnType, toNode.returnType),
9945 _isEqualTokens(node.period, toNode.period),
9946 _isEqualNodes(node.name, toNode.name),
9947 _isEqualNodes(node.parameters, toNode.parameters),
9948 _isEqualTokens(node.separator, toNode.separator),
9949 _isEqualNodeLists(node.initializers, toNode.initializers),
9950 _isEqualNodes(node.redirectedConstructor, toNode.redirectedConstructor),
9951 _isEqualNodes(node.body, toNode.body))) {
9952 toNode.element = node.element;
9953 return true;
9954 }
9955 return false;
9956 }
9957
9958 @override
9959 bool visitConstructorFieldInitializer(ConstructorFieldInitializer node) {
9960 ConstructorFieldInitializer toNode =
9961 this._toNode as ConstructorFieldInitializer;
9962 return _and(
9963 _isEqualTokens(node.thisKeyword, toNode.thisKeyword),
9964 _isEqualTokens(node.period, toNode.period),
9965 _isEqualNodes(node.fieldName, toNode.fieldName),
9966 _isEqualTokens(node.equals, toNode.equals),
9967 _isEqualNodes(node.expression, toNode.expression));
9968 }
9969
9970 @override
9971 bool visitConstructorName(ConstructorName node) {
9972 ConstructorName toNode = this._toNode as ConstructorName;
9973 if (_and(
9974 _isEqualNodes(node.type, toNode.type),
9975 _isEqualTokens(node.period, toNode.period),
9976 _isEqualNodes(node.name, toNode.name))) {
9977 toNode.staticElement = node.staticElement;
9978 return true;
9979 }
9980 return false;
9981 }
9982
9983 @override
9984 bool visitContinueStatement(ContinueStatement node) {
9985 ContinueStatement toNode = this._toNode as ContinueStatement;
9986 if (_and(
9987 _isEqualTokens(node.continueKeyword, toNode.continueKeyword),
9988 _isEqualNodes(node.label, toNode.label),
9989 _isEqualTokens(node.semicolon, toNode.semicolon))) {
9990 // TODO(paulberry): map node.target to toNode.target.
9991 return true;
9992 }
9993 return false;
9994 }
9995
9996 @override
9997 bool visitDeclaredIdentifier(DeclaredIdentifier node) {
9998 DeclaredIdentifier toNode = this._toNode as DeclaredIdentifier;
9999 return _and(
10000 _isEqualNodes(node.documentationComment, toNode.documentationComment),
10001 _isEqualNodeLists(node.metadata, toNode.metadata),
10002 _isEqualTokens(node.keyword, toNode.keyword),
10003 _isEqualNodes(node.type, toNode.type),
10004 _isEqualNodes(node.identifier, toNode.identifier));
10005 }
10006
10007 @override
10008 bool visitDefaultFormalParameter(DefaultFormalParameter node) {
10009 DefaultFormalParameter toNode = this._toNode as DefaultFormalParameter;
10010 return _and(
10011 _isEqualNodes(node.parameter, toNode.parameter),
10012 node.kind == toNode.kind,
10013 _isEqualTokens(node.separator, toNode.separator),
10014 _isEqualNodes(node.defaultValue, toNode.defaultValue));
10015 }
10016
10017 @override
10018 bool visitDoStatement(DoStatement node) {
10019 DoStatement toNode = this._toNode as DoStatement;
10020 return _and(
10021 _isEqualTokens(node.doKeyword, toNode.doKeyword),
10022 _isEqualNodes(node.body, toNode.body),
10023 _isEqualTokens(node.whileKeyword, toNode.whileKeyword),
10024 _isEqualTokens(node.leftParenthesis, toNode.leftParenthesis),
10025 _isEqualNodes(node.condition, toNode.condition),
10026 _isEqualTokens(node.rightParenthesis, toNode.rightParenthesis),
10027 _isEqualTokens(node.semicolon, toNode.semicolon));
10028 }
10029
10030 @override
10031 bool visitDoubleLiteral(DoubleLiteral node) {
10032 DoubleLiteral toNode = this._toNode as DoubleLiteral;
10033 if (_and(_isEqualTokens(node.literal, toNode.literal),
10034 node.value == toNode.value)) {
10035 toNode.propagatedType = node.propagatedType;
10036 toNode.staticType = node.staticType;
10037 return true;
10038 }
10039 return false;
10040 }
10041
10042 @override
10043 bool visitEmptyFunctionBody(EmptyFunctionBody node) {
10044 EmptyFunctionBody toNode = this._toNode as EmptyFunctionBody;
10045 return _isEqualTokens(node.semicolon, toNode.semicolon);
10046 }
10047
10048 @override
10049 bool visitEmptyStatement(EmptyStatement node) {
10050 EmptyStatement toNode = this._toNode as EmptyStatement;
10051 return _isEqualTokens(node.semicolon, toNode.semicolon);
10052 }
10053
10054 @override
10055 bool visitEnumConstantDeclaration(EnumConstantDeclaration node) {
10056 EnumConstantDeclaration toNode = this._toNode as EnumConstantDeclaration;
10057 return _and(
10058 _isEqualNodes(node.documentationComment, toNode.documentationComment),
10059 _isEqualNodeLists(node.metadata, toNode.metadata),
10060 _isEqualNodes(node.name, toNode.name));
10061 }
10062
10063 @override
10064 bool visitEnumDeclaration(EnumDeclaration node) {
10065 EnumDeclaration toNode = this._toNode as EnumDeclaration;
10066 return _and(
10067 _isEqualNodes(node.documentationComment, toNode.documentationComment),
10068 _isEqualNodeLists(node.metadata, toNode.metadata),
10069 _isEqualTokens(node.enumKeyword, toNode.enumKeyword),
10070 _isEqualNodes(node.name, toNode.name),
10071 _isEqualTokens(node.leftBracket, toNode.leftBracket),
10072 _isEqualNodeLists(node.constants, toNode.constants),
10073 _isEqualTokens(node.rightBracket, toNode.rightBracket));
10074 }
10075
10076 @override
10077 bool visitExportDirective(ExportDirective node) {
10078 ExportDirective toNode = this._toNode as ExportDirective;
10079 if (_and(
10080 _isEqualNodes(node.documentationComment, toNode.documentationComment),
10081 _isEqualNodeLists(node.metadata, toNode.metadata),
10082 _isEqualTokens(node.keyword, toNode.keyword),
10083 _isEqualNodes(node.uri, toNode.uri),
10084 _isEqualNodeLists(node.combinators, toNode.combinators),
10085 _isEqualTokens(node.semicolon, toNode.semicolon))) {
10086 toNode.element = node.element;
10087 return true;
10088 }
10089 return false;
10090 }
10091
10092 @override
10093 bool visitExpressionFunctionBody(ExpressionFunctionBody node) {
10094 ExpressionFunctionBody toNode = this._toNode as ExpressionFunctionBody;
10095 return _and(
10096 _isEqualTokens(node.functionDefinition, toNode.functionDefinition),
10097 _isEqualNodes(node.expression, toNode.expression),
10098 _isEqualTokens(node.semicolon, toNode.semicolon));
10099 }
10100
10101 @override
10102 bool visitExpressionStatement(ExpressionStatement node) {
10103 ExpressionStatement toNode = this._toNode as ExpressionStatement;
10104 return _and(_isEqualNodes(node.expression, toNode.expression),
10105 _isEqualTokens(node.semicolon, toNode.semicolon));
10106 }
10107
10108 @override
10109 bool visitExtendsClause(ExtendsClause node) {
10110 ExtendsClause toNode = this._toNode as ExtendsClause;
10111 return _and(_isEqualTokens(node.extendsKeyword, toNode.extendsKeyword),
10112 _isEqualNodes(node.superclass, toNode.superclass));
10113 }
10114
10115 @override
10116 bool visitFieldDeclaration(FieldDeclaration node) {
10117 FieldDeclaration toNode = this._toNode as FieldDeclaration;
10118 return _and(
10119 _isEqualNodes(node.documentationComment, toNode.documentationComment),
10120 _isEqualNodeLists(node.metadata, toNode.metadata),
10121 _isEqualTokens(node.staticKeyword, toNode.staticKeyword),
10122 _isEqualNodes(node.fields, toNode.fields),
10123 _isEqualTokens(node.semicolon, toNode.semicolon));
10124 }
10125
10126 @override
10127 bool visitFieldFormalParameter(FieldFormalParameter node) {
10128 FieldFormalParameter toNode = this._toNode as FieldFormalParameter;
10129 return _and(
10130 _isEqualNodes(node.documentationComment, toNode.documentationComment),
10131 _isEqualNodeLists(node.metadata, toNode.metadata),
10132 _isEqualTokens(node.keyword, toNode.keyword),
10133 _isEqualNodes(node.type, toNode.type),
10134 _isEqualTokens(node.thisKeyword, toNode.thisKeyword),
10135 _isEqualTokens(node.period, toNode.period),
10136 _isEqualNodes(node.identifier, toNode.identifier));
10137 }
10138
10139 @override
10140 bool visitForEachStatement(ForEachStatement node) {
10141 ForEachStatement toNode = this._toNode as ForEachStatement;
10142 return _and(
10143 _isEqualTokens(node.forKeyword, toNode.forKeyword),
10144 _isEqualTokens(node.leftParenthesis, toNode.leftParenthesis),
10145 _isEqualNodes(node.loopVariable, toNode.loopVariable),
10146 _isEqualTokens(node.inKeyword, toNode.inKeyword),
10147 _isEqualNodes(node.iterable, toNode.iterable),
10148 _isEqualTokens(node.rightParenthesis, toNode.rightParenthesis),
10149 _isEqualNodes(node.body, toNode.body));
10150 }
10151
10152 @override
10153 bool visitFormalParameterList(FormalParameterList node) {
10154 FormalParameterList toNode = this._toNode as FormalParameterList;
10155 return _and(
10156 _isEqualTokens(node.leftParenthesis, toNode.leftParenthesis),
10157 _isEqualNodeLists(node.parameters, toNode.parameters),
10158 _isEqualTokens(node.leftDelimiter, toNode.leftDelimiter),
10159 _isEqualTokens(node.rightDelimiter, toNode.rightDelimiter),
10160 _isEqualTokens(node.rightParenthesis, toNode.rightParenthesis));
10161 }
10162
10163 @override
10164 bool visitForStatement(ForStatement node) {
10165 ForStatement toNode = this._toNode as ForStatement;
10166 return _and(
10167 _isEqualTokens(node.forKeyword, toNode.forKeyword),
10168 _isEqualTokens(node.leftParenthesis, toNode.leftParenthesis),
10169 _isEqualNodes(node.variables, toNode.variables),
10170 _isEqualNodes(node.initialization, toNode.initialization),
10171 _isEqualTokens(node.leftSeparator, toNode.leftSeparator),
10172 _isEqualNodes(node.condition, toNode.condition),
10173 _isEqualTokens(node.rightSeparator, toNode.rightSeparator),
10174 _isEqualNodeLists(node.updaters, toNode.updaters),
10175 _isEqualTokens(node.rightParenthesis, toNode.rightParenthesis),
10176 _isEqualNodes(node.body, toNode.body));
10177 }
10178
10179 @override
10180 bool visitFunctionDeclaration(FunctionDeclaration node) {
10181 FunctionDeclaration toNode = this._toNode as FunctionDeclaration;
10182 return _and(
10183 _isEqualNodes(node.documentationComment, toNode.documentationComment),
10184 _isEqualNodeLists(node.metadata, toNode.metadata),
10185 _isEqualTokens(node.externalKeyword, toNode.externalKeyword),
10186 _isEqualNodes(node.returnType, toNode.returnType),
10187 _isEqualTokens(node.propertyKeyword, toNode.propertyKeyword),
10188 _isEqualNodes(node.name, toNode.name),
10189 _isEqualNodes(node.functionExpression, toNode.functionExpression));
10190 }
10191
10192 @override
10193 bool visitFunctionDeclarationStatement(FunctionDeclarationStatement node) {
10194 FunctionDeclarationStatement toNode =
10195 this._toNode as FunctionDeclarationStatement;
10196 return _isEqualNodes(node.functionDeclaration, toNode.functionDeclaration);
10197 }
10198
10199 @override
10200 bool visitFunctionExpression(FunctionExpression node) {
10201 FunctionExpression toNode = this._toNode as FunctionExpression;
10202 if (_and(_isEqualNodes(node.parameters, toNode.parameters),
10203 _isEqualNodes(node.body, toNode.body))) {
10204 toNode.element = node.element;
10205 toNode.propagatedType = node.propagatedType;
10206 toNode.staticType = node.staticType;
10207 return true;
10208 }
10209 return false;
10210 }
10211
10212 @override
10213 bool visitFunctionExpressionInvocation(FunctionExpressionInvocation node) {
10214 FunctionExpressionInvocation toNode =
10215 this._toNode as FunctionExpressionInvocation;
10216 if (_and(_isEqualNodes(node.function, toNode.function),
10217 _isEqualNodes(node.argumentList, toNode.argumentList))) {
10218 toNode.propagatedElement = node.propagatedElement;
10219 toNode.propagatedType = node.propagatedType;
10220 toNode.staticElement = node.staticElement;
10221 toNode.staticType = node.staticType;
10222 return true;
10223 }
10224 return false;
10225 }
10226
10227 @override
10228 bool visitFunctionTypeAlias(FunctionTypeAlias node) {
10229 FunctionTypeAlias toNode = this._toNode as FunctionTypeAlias;
10230 return _and(
10231 _isEqualNodes(node.documentationComment, toNode.documentationComment),
10232 _isEqualNodeLists(node.metadata, toNode.metadata),
10233 _isEqualTokens(node.typedefKeyword, toNode.typedefKeyword),
10234 _isEqualNodes(node.returnType, toNode.returnType),
10235 _isEqualNodes(node.name, toNode.name),
10236 _isEqualNodes(node.typeParameters, toNode.typeParameters),
10237 _isEqualNodes(node.parameters, toNode.parameters),
10238 _isEqualTokens(node.semicolon, toNode.semicolon));
10239 }
10240
10241 @override
10242 bool visitFunctionTypedFormalParameter(FunctionTypedFormalParameter node) {
10243 FunctionTypedFormalParameter toNode =
10244 this._toNode as FunctionTypedFormalParameter;
10245 return _and(
10246 _isEqualNodes(node.documentationComment, toNode.documentationComment),
10247 _isEqualNodeLists(node.metadata, toNode.metadata),
10248 _isEqualNodes(node.returnType, toNode.returnType),
10249 _isEqualNodes(node.identifier, toNode.identifier),
10250 _isEqualNodes(node.parameters, toNode.parameters));
10251 }
10252
10253 @override
10254 bool visitHideCombinator(HideCombinator node) {
10255 HideCombinator toNode = this._toNode as HideCombinator;
10256 return _and(_isEqualTokens(node.keyword, toNode.keyword),
10257 _isEqualNodeLists(node.hiddenNames, toNode.hiddenNames));
10258 }
10259
10260 @override
10261 bool visitIfStatement(IfStatement node) {
10262 IfStatement toNode = this._toNode as IfStatement;
10263 return _and(
10264 _isEqualTokens(node.ifKeyword, toNode.ifKeyword),
10265 _isEqualTokens(node.leftParenthesis, toNode.leftParenthesis),
10266 _isEqualNodes(node.condition, toNode.condition),
10267 _isEqualTokens(node.rightParenthesis, toNode.rightParenthesis),
10268 _isEqualNodes(node.thenStatement, toNode.thenStatement),
10269 _isEqualTokens(node.elseKeyword, toNode.elseKeyword),
10270 _isEqualNodes(node.elseStatement, toNode.elseStatement));
10271 }
10272
10273 @override
10274 bool visitImplementsClause(ImplementsClause node) {
10275 ImplementsClause toNode = this._toNode as ImplementsClause;
10276 return _and(
10277 _isEqualTokens(node.implementsKeyword, toNode.implementsKeyword),
10278 _isEqualNodeLists(node.interfaces, toNode.interfaces));
10279 }
10280
10281 @override
10282 bool visitImportDirective(ImportDirective node) {
10283 ImportDirective toNode = this._toNode as ImportDirective;
10284 if (_and(
10285 _isEqualNodes(node.documentationComment, toNode.documentationComment),
10286 _isEqualNodeLists(node.metadata, toNode.metadata),
10287 _isEqualTokens(node.keyword, toNode.keyword),
10288 _isEqualNodes(node.uri, toNode.uri),
10289 _isEqualTokens(node.asKeyword, toNode.asKeyword),
10290 _isEqualNodes(node.prefix, toNode.prefix),
10291 _isEqualNodeLists(node.combinators, toNode.combinators),
10292 _isEqualTokens(node.semicolon, toNode.semicolon))) {
10293 toNode.element = node.element;
10294 return true;
10295 }
10296 return false;
10297 }
10298
10299 @override
10300 bool visitIndexExpression(IndexExpression node) {
10301 IndexExpression toNode = this._toNode as IndexExpression;
10302 if (_and(
10303 _isEqualNodes(node.target, toNode.target),
10304 _isEqualTokens(node.leftBracket, toNode.leftBracket),
10305 _isEqualNodes(node.index, toNode.index),
10306 _isEqualTokens(node.rightBracket, toNode.rightBracket))) {
10307 toNode.auxiliaryElements = node.auxiliaryElements;
10308 toNode.propagatedElement = node.propagatedElement;
10309 toNode.propagatedType = node.propagatedType;
10310 toNode.staticElement = node.staticElement;
10311 toNode.staticType = node.staticType;
10312 return true;
10313 }
10314 return false;
10315 }
10316
10317 @override
10318 bool visitInstanceCreationExpression(InstanceCreationExpression node) {
10319 InstanceCreationExpression toNode =
10320 this._toNode as InstanceCreationExpression;
10321 if (_and(
10322 _isEqualTokens(node.keyword, toNode.keyword),
10323 _isEqualNodes(node.constructorName, toNode.constructorName),
10324 _isEqualNodes(node.argumentList, toNode.argumentList))) {
10325 toNode.propagatedType = node.propagatedType;
10326 toNode.staticElement = node.staticElement;
10327 toNode.staticType = node.staticType;
10328 return true;
10329 }
10330 return false;
10331 }
10332
10333 @override
10334 bool visitIntegerLiteral(IntegerLiteral node) {
10335 IntegerLiteral toNode = this._toNode as IntegerLiteral;
10336 if (_and(_isEqualTokens(node.literal, toNode.literal),
10337 node.value == toNode.value)) {
10338 toNode.propagatedType = node.propagatedType;
10339 toNode.staticType = node.staticType;
10340 return true;
10341 }
10342 return false;
10343 }
10344
10345 @override
10346 bool visitInterpolationExpression(InterpolationExpression node) {
10347 InterpolationExpression toNode = this._toNode as InterpolationExpression;
10348 return _and(
10349 _isEqualTokens(node.leftBracket, toNode.leftBracket),
10350 _isEqualNodes(node.expression, toNode.expression),
10351 _isEqualTokens(node.rightBracket, toNode.rightBracket));
10352 }
10353
10354 @override
10355 bool visitInterpolationString(InterpolationString node) {
10356 InterpolationString toNode = this._toNode as InterpolationString;
10357 return _and(_isEqualTokens(node.contents, toNode.contents),
10358 node.value == toNode.value);
10359 }
10360
10361 @override
10362 bool visitIsExpression(IsExpression node) {
10363 IsExpression toNode = this._toNode as IsExpression;
10364 if (_and(
10365 _isEqualNodes(node.expression, toNode.expression),
10366 _isEqualTokens(node.isOperator, toNode.isOperator),
10367 _isEqualTokens(node.notOperator, toNode.notOperator),
10368 _isEqualNodes(node.type, toNode.type))) {
10369 toNode.propagatedType = node.propagatedType;
10370 toNode.staticType = node.staticType;
10371 return true;
10372 }
10373 return false;
10374 }
10375
10376 @override
10377 bool visitLabel(Label node) {
10378 Label toNode = this._toNode as Label;
10379 return _and(_isEqualNodes(node.label, toNode.label),
10380 _isEqualTokens(node.colon, toNode.colon));
10381 }
10382
10383 @override
10384 bool visitLabeledStatement(LabeledStatement node) {
10385 LabeledStatement toNode = this._toNode as LabeledStatement;
10386 return _and(_isEqualNodeLists(node.labels, toNode.labels),
10387 _isEqualNodes(node.statement, toNode.statement));
10388 }
10389
10390 @override
10391 bool visitLibraryDirective(LibraryDirective node) {
10392 LibraryDirective toNode = this._toNode as LibraryDirective;
10393 if (_and(
10394 _isEqualNodes(node.documentationComment, toNode.documentationComment),
10395 _isEqualNodeLists(node.metadata, toNode.metadata),
10396 _isEqualTokens(node.libraryKeyword, toNode.libraryKeyword),
10397 _isEqualNodes(node.name, toNode.name),
10398 _isEqualTokens(node.semicolon, toNode.semicolon))) {
10399 toNode.element = node.element;
10400 return true;
10401 }
10402 return false;
10403 }
10404
10405 @override
10406 bool visitLibraryIdentifier(LibraryIdentifier node) {
10407 LibraryIdentifier toNode = this._toNode as LibraryIdentifier;
10408 if (_isEqualNodeLists(node.components, toNode.components)) {
10409 toNode.propagatedType = node.propagatedType;
10410 toNode.staticType = node.staticType;
10411 return true;
10412 }
10413 return false;
10414 }
10415
10416 @override
10417 bool visitListLiteral(ListLiteral node) {
10418 ListLiteral toNode = this._toNode as ListLiteral;
10419 if (_and(
10420 _isEqualTokens(node.constKeyword, toNode.constKeyword),
10421 _isEqualNodes(node.typeArguments, toNode.typeArguments),
10422 _isEqualTokens(node.leftBracket, toNode.leftBracket),
10423 _isEqualNodeLists(node.elements, toNode.elements),
10424 _isEqualTokens(node.rightBracket, toNode.rightBracket))) {
10425 toNode.propagatedType = node.propagatedType;
10426 toNode.staticType = node.staticType;
10427 return true;
10428 }
10429 return false;
10430 }
10431
10432 @override
10433 bool visitMapLiteral(MapLiteral node) {
10434 MapLiteral toNode = this._toNode as MapLiteral;
10435 if (_and(
10436 _isEqualTokens(node.constKeyword, toNode.constKeyword),
10437 _isEqualNodes(node.typeArguments, toNode.typeArguments),
10438 _isEqualTokens(node.leftBracket, toNode.leftBracket),
10439 _isEqualNodeLists(node.entries, toNode.entries),
10440 _isEqualTokens(node.rightBracket, toNode.rightBracket))) {
10441 toNode.propagatedType = node.propagatedType;
10442 toNode.staticType = node.staticType;
10443 return true;
10444 }
10445 return false;
10446 }
10447
10448 @override
10449 bool visitMapLiteralEntry(MapLiteralEntry node) {
10450 MapLiteralEntry toNode = this._toNode as MapLiteralEntry;
10451 return _and(
10452 _isEqualNodes(node.key, toNode.key),
10453 _isEqualTokens(node.separator, toNode.separator),
10454 _isEqualNodes(node.value, toNode.value));
10455 }
10456
10457 @override
10458 bool visitMethodDeclaration(MethodDeclaration node) {
10459 MethodDeclaration toNode = this._toNode as MethodDeclaration;
10460 return _and(
10461 _isEqualNodes(node.documentationComment, toNode.documentationComment),
10462 _isEqualNodeLists(node.metadata, toNode.metadata),
10463 _isEqualTokens(node.externalKeyword, toNode.externalKeyword),
10464 _isEqualTokens(node.modifierKeyword, toNode.modifierKeyword),
10465 _isEqualNodes(node.returnType, toNode.returnType),
10466 _isEqualTokens(node.propertyKeyword, toNode.propertyKeyword),
10467 _isEqualTokens(node.propertyKeyword, toNode.propertyKeyword),
10468 _isEqualNodes(node.name, toNode.name),
10469 _isEqualNodes(node.parameters, toNode.parameters),
10470 _isEqualNodes(node.body, toNode.body));
10471 }
10472
10473 @override
10474 bool visitMethodInvocation(MethodInvocation node) {
10475 MethodInvocation toNode = this._toNode as MethodInvocation;
10476 if (_and(
10477 _isEqualNodes(node.target, toNode.target),
10478 _isEqualTokens(node.operator, toNode.operator),
10479 _isEqualNodes(node.methodName, toNode.methodName),
10480 _isEqualNodes(node.argumentList, toNode.argumentList))) {
10481 toNode.propagatedType = node.propagatedType;
10482 toNode.staticType = node.staticType;
10483 return true;
10484 }
10485 return false;
10486 }
10487
10488 @override
10489 bool visitNamedExpression(NamedExpression node) {
10490 NamedExpression toNode = this._toNode as NamedExpression;
10491 if (_and(_isEqualNodes(node.name, toNode.name),
10492 _isEqualNodes(node.expression, toNode.expression))) {
10493 toNode.propagatedType = node.propagatedType;
10494 toNode.staticType = node.staticType;
10495 return true;
10496 }
10497 return false;
10498 }
10499
10500 @override
10501 bool visitNativeClause(NativeClause node) {
10502 NativeClause toNode = this._toNode as NativeClause;
10503 return _and(_isEqualTokens(node.nativeKeyword, toNode.nativeKeyword),
10504 _isEqualNodes(node.name, toNode.name));
10505 }
10506
10507 @override
10508 bool visitNativeFunctionBody(NativeFunctionBody node) {
10509 NativeFunctionBody toNode = this._toNode as NativeFunctionBody;
10510 return _and(
10511 _isEqualTokens(node.nativeKeyword, toNode.nativeKeyword),
10512 _isEqualNodes(node.stringLiteral, toNode.stringLiteral),
10513 _isEqualTokens(node.semicolon, toNode.semicolon));
10514 }
10515
10516 @override
10517 bool visitNullLiteral(NullLiteral node) {
10518 NullLiteral toNode = this._toNode as NullLiteral;
10519 if (_isEqualTokens(node.literal, toNode.literal)) {
10520 toNode.propagatedType = node.propagatedType;
10521 toNode.staticType = node.staticType;
10522 return true;
10523 }
10524 return false;
10525 }
10526
10527 @override
10528 bool visitParenthesizedExpression(ParenthesizedExpression node) {
10529 ParenthesizedExpression toNode = this._toNode as ParenthesizedExpression;
10530 if (_and(
10531 _isEqualTokens(node.leftParenthesis, toNode.leftParenthesis),
10532 _isEqualNodes(node.expression, toNode.expression),
10533 _isEqualTokens(node.rightParenthesis, toNode.rightParenthesis))) {
10534 toNode.propagatedType = node.propagatedType;
10535 toNode.staticType = node.staticType;
10536 return true;
10537 }
10538 return false;
10539 }
10540
10541 @override
10542 bool visitPartDirective(PartDirective node) {
10543 PartDirective toNode = this._toNode as PartDirective;
10544 if (_and(
10545 _isEqualNodes(node.documentationComment, toNode.documentationComment),
10546 _isEqualNodeLists(node.metadata, toNode.metadata),
10547 _isEqualTokens(node.partKeyword, toNode.partKeyword),
10548 _isEqualNodes(node.uri, toNode.uri),
10549 _isEqualTokens(node.semicolon, toNode.semicolon))) {
10550 toNode.element = node.element;
10551 return true;
10552 }
10553 return false;
10554 }
10555
10556 @override
10557 bool visitPartOfDirective(PartOfDirective node) {
10558 PartOfDirective toNode = this._toNode as PartOfDirective;
10559 if (_and(
10560 _isEqualNodes(node.documentationComment, toNode.documentationComment),
10561 _isEqualNodeLists(node.metadata, toNode.metadata),
10562 _isEqualTokens(node.partKeyword, toNode.partKeyword),
10563 _isEqualTokens(node.ofKeyword, toNode.ofKeyword),
10564 _isEqualNodes(node.libraryName, toNode.libraryName),
10565 _isEqualTokens(node.semicolon, toNode.semicolon))) {
10566 toNode.element = node.element;
10567 return true;
10568 }
10569 return false;
10570 }
10571
10572 @override
10573 bool visitPostfixExpression(PostfixExpression node) {
10574 PostfixExpression toNode = this._toNode as PostfixExpression;
10575 if (_and(_isEqualNodes(node.operand, toNode.operand),
10576 _isEqualTokens(node.operator, toNode.operator))) {
10577 toNode.propagatedElement = node.propagatedElement;
10578 toNode.propagatedType = node.propagatedType;
10579 toNode.staticElement = node.staticElement;
10580 toNode.staticType = node.staticType;
10581 return true;
10582 }
10583 return false;
10584 }
10585
10586 @override
10587 bool visitPrefixedIdentifier(PrefixedIdentifier node) {
10588 PrefixedIdentifier toNode = this._toNode as PrefixedIdentifier;
10589 if (_and(
10590 _isEqualNodes(node.prefix, toNode.prefix),
10591 _isEqualTokens(node.period, toNode.period),
10592 _isEqualNodes(node.identifier, toNode.identifier))) {
10593 toNode.propagatedType = node.propagatedType;
10594 toNode.staticType = node.staticType;
10595 return true;
10596 }
10597 return false;
10598 }
10599
10600 @override
10601 bool visitPrefixExpression(PrefixExpression node) {
10602 PrefixExpression toNode = this._toNode as PrefixExpression;
10603 if (_and(_isEqualTokens(node.operator, toNode.operator),
10604 _isEqualNodes(node.operand, toNode.operand))) {
10605 toNode.propagatedElement = node.propagatedElement;
10606 toNode.propagatedType = node.propagatedType;
10607 toNode.staticElement = node.staticElement;
10608 toNode.staticType = node.staticType;
10609 return true;
10610 }
10611 return false;
10612 }
10613
10614 @override
10615 bool visitPropertyAccess(PropertyAccess node) {
10616 PropertyAccess toNode = this._toNode as PropertyAccess;
10617 if (_and(
10618 _isEqualNodes(node.target, toNode.target),
10619 _isEqualTokens(node.operator, toNode.operator),
10620 _isEqualNodes(node.propertyName, toNode.propertyName))) {
10621 toNode.propagatedType = node.propagatedType;
10622 toNode.staticType = node.staticType;
10623 return true;
10624 }
10625 return false;
10626 }
10627
10628 @override
10629 bool visitRedirectingConstructorInvocation(
10630 RedirectingConstructorInvocation node) {
10631 RedirectingConstructorInvocation toNode =
10632 this._toNode as RedirectingConstructorInvocation;
10633 if (_and(
10634 _isEqualTokens(node.thisKeyword, toNode.thisKeyword),
10635 _isEqualTokens(node.period, toNode.period),
10636 _isEqualNodes(node.constructorName, toNode.constructorName),
10637 _isEqualNodes(node.argumentList, toNode.argumentList))) {
10638 toNode.staticElement = node.staticElement;
10639 return true;
10640 }
10641 return false;
10642 }
10643
10644 @override
10645 bool visitRethrowExpression(RethrowExpression node) {
10646 RethrowExpression toNode = this._toNode as RethrowExpression;
10647 if (_isEqualTokens(node.rethrowKeyword, toNode.rethrowKeyword)) {
10648 toNode.propagatedType = node.propagatedType;
10649 toNode.staticType = node.staticType;
10650 return true;
10651 }
10652 return false;
10653 }
10654
10655 @override
10656 bool visitReturnStatement(ReturnStatement node) {
10657 ReturnStatement toNode = this._toNode as ReturnStatement;
10658 return _and(
10659 _isEqualTokens(node.returnKeyword, toNode.returnKeyword),
10660 _isEqualNodes(node.expression, toNode.expression),
10661 _isEqualTokens(node.semicolon, toNode.semicolon));
10662 }
10663
10664 @override
10665 bool visitScriptTag(ScriptTag node) {
10666 ScriptTag toNode = this._toNode as ScriptTag;
10667 return _isEqualTokens(node.scriptTag, toNode.scriptTag);
10668 }
10669
10670 @override
10671 bool visitShowCombinator(ShowCombinator node) {
10672 ShowCombinator toNode = this._toNode as ShowCombinator;
10673 return _and(_isEqualTokens(node.keyword, toNode.keyword),
10674 _isEqualNodeLists(node.shownNames, toNode.shownNames));
10675 }
10676
10677 @override
10678 bool visitSimpleFormalParameter(SimpleFormalParameter node) {
10679 SimpleFormalParameter toNode = this._toNode as SimpleFormalParameter;
10680 return _and(
10681 _isEqualNodes(node.documentationComment, toNode.documentationComment),
10682 _isEqualNodeLists(node.metadata, toNode.metadata),
10683 _isEqualTokens(node.keyword, toNode.keyword),
10684 _isEqualNodes(node.type, toNode.type),
10685 _isEqualNodes(node.identifier, toNode.identifier));
10686 }
10687
10688 @override
10689 bool visitSimpleIdentifier(SimpleIdentifier node) {
10690 SimpleIdentifier toNode = this._toNode as SimpleIdentifier;
10691 if (_isEqualTokens(node.token, toNode.token)) {
10692 toNode.staticElement = node.staticElement;
10693 toNode.staticType = node.staticType;
10694 toNode.propagatedElement = node.propagatedElement;
10695 toNode.propagatedType = node.propagatedType;
10696 toNode.auxiliaryElements = node.auxiliaryElements;
10697 return true;
10698 }
10699 return false;
10700 }
10701
10702 @override
10703 bool visitSimpleStringLiteral(SimpleStringLiteral node) {
10704 SimpleStringLiteral toNode = this._toNode as SimpleStringLiteral;
10705 if (_and(_isEqualTokens(node.literal, toNode.literal),
10706 node.value == toNode.value)) {
10707 toNode.propagatedType = node.propagatedType;
10708 toNode.staticType = node.staticType;
10709 return true;
10710 }
10711 return false;
10712 }
10713
10714 @override
10715 bool visitStringInterpolation(StringInterpolation node) {
10716 StringInterpolation toNode = this._toNode as StringInterpolation;
10717 if (_isEqualNodeLists(node.elements, toNode.elements)) {
10718 toNode.propagatedType = node.propagatedType;
10719 toNode.staticType = node.staticType;
10720 return true;
10721 }
10722 return false;
10723 }
10724
10725 @override
10726 bool visitSuperConstructorInvocation(SuperConstructorInvocation node) {
10727 SuperConstructorInvocation toNode =
10728 this._toNode as SuperConstructorInvocation;
10729 if (_and(
10730 _isEqualTokens(node.superKeyword, toNode.superKeyword),
10731 _isEqualTokens(node.period, toNode.period),
10732 _isEqualNodes(node.constructorName, toNode.constructorName),
10733 _isEqualNodes(node.argumentList, toNode.argumentList))) {
10734 toNode.staticElement = node.staticElement;
10735 return true;
10736 }
10737 return false;
10738 }
10739
10740 @override
10741 bool visitSuperExpression(SuperExpression node) {
10742 SuperExpression toNode = this._toNode as SuperExpression;
10743 if (_isEqualTokens(node.superKeyword, toNode.superKeyword)) {
10744 toNode.propagatedType = node.propagatedType;
10745 toNode.staticType = node.staticType;
10746 return true;
10747 }
10748 return false;
10749 }
10750
10751 @override
10752 bool visitSwitchCase(SwitchCase node) {
10753 SwitchCase toNode = this._toNode as SwitchCase;
10754 return _and(
10755 _isEqualNodeLists(node.labels, toNode.labels),
10756 _isEqualTokens(node.keyword, toNode.keyword),
10757 _isEqualNodes(node.expression, toNode.expression),
10758 _isEqualTokens(node.colon, toNode.colon),
10759 _isEqualNodeLists(node.statements, toNode.statements));
10760 }
10761
10762 @override
10763 bool visitSwitchDefault(SwitchDefault node) {
10764 SwitchDefault toNode = this._toNode as SwitchDefault;
10765 return _and(
10766 _isEqualNodeLists(node.labels, toNode.labels),
10767 _isEqualTokens(node.keyword, toNode.keyword),
10768 _isEqualTokens(node.colon, toNode.colon),
10769 _isEqualNodeLists(node.statements, toNode.statements));
10770 }
10771
10772 @override
10773 bool visitSwitchStatement(SwitchStatement node) {
10774 SwitchStatement toNode = this._toNode as SwitchStatement;
10775 return _and(
10776 _isEqualTokens(node.switchKeyword, toNode.switchKeyword),
10777 _isEqualTokens(node.leftParenthesis, toNode.leftParenthesis),
10778 _isEqualNodes(node.expression, toNode.expression),
10779 _isEqualTokens(node.rightParenthesis, toNode.rightParenthesis),
10780 _isEqualTokens(node.leftBracket, toNode.leftBracket),
10781 _isEqualNodeLists(node.members, toNode.members),
10782 _isEqualTokens(node.rightBracket, toNode.rightBracket));
10783 }
10784
10785 @override
10786 bool visitSymbolLiteral(SymbolLiteral node) {
10787 SymbolLiteral toNode = this._toNode as SymbolLiteral;
10788 if (_and(_isEqualTokens(node.poundSign, toNode.poundSign),
10789 _isEqualTokenLists(node.components, toNode.components))) {
10790 toNode.propagatedType = node.propagatedType;
10791 toNode.staticType = node.staticType;
10792 return true;
10793 }
10794 return false;
10795 }
10796
10797 @override
10798 bool visitThisExpression(ThisExpression node) {
10799 ThisExpression toNode = this._toNode as ThisExpression;
10800 if (_isEqualTokens(node.thisKeyword, toNode.thisKeyword)) {
10801 toNode.propagatedType = node.propagatedType;
10802 toNode.staticType = node.staticType;
10803 return true;
10804 }
10805 return false;
10806 }
10807
10808 @override
10809 bool visitThrowExpression(ThrowExpression node) {
10810 ThrowExpression toNode = this._toNode as ThrowExpression;
10811 if (_and(_isEqualTokens(node.throwKeyword, toNode.throwKeyword),
10812 _isEqualNodes(node.expression, toNode.expression))) {
10813 toNode.propagatedType = node.propagatedType;
10814 toNode.staticType = node.staticType;
10815 return true;
10816 }
10817 return false;
10818 }
10819
10820 @override
10821 bool visitTopLevelVariableDeclaration(TopLevelVariableDeclaration node) {
10822 TopLevelVariableDeclaration toNode =
10823 this._toNode as TopLevelVariableDeclaration;
10824 return _and(
10825 _isEqualNodes(node.documentationComment, toNode.documentationComment),
10826 _isEqualNodeLists(node.metadata, toNode.metadata),
10827 _isEqualNodes(node.variables, toNode.variables),
10828 _isEqualTokens(node.semicolon, toNode.semicolon));
10829 }
10830
10831 @override
10832 bool visitTryStatement(TryStatement node) {
10833 TryStatement toNode = this._toNode as TryStatement;
10834 return _and(
10835 _isEqualTokens(node.tryKeyword, toNode.tryKeyword),
10836 _isEqualNodes(node.body, toNode.body),
10837 _isEqualNodeLists(node.catchClauses, toNode.catchClauses),
10838 _isEqualTokens(node.finallyKeyword, toNode.finallyKeyword),
10839 _isEqualNodes(node.finallyBlock, toNode.finallyBlock));
10840 }
10841
10842 @override
10843 bool visitTypeArgumentList(TypeArgumentList node) {
10844 TypeArgumentList toNode = this._toNode as TypeArgumentList;
10845 return _and(
10846 _isEqualTokens(node.leftBracket, toNode.leftBracket),
10847 _isEqualNodeLists(node.arguments, toNode.arguments),
10848 _isEqualTokens(node.rightBracket, toNode.rightBracket));
10849 }
10850
10851 @override
10852 bool visitTypeName(TypeName node) {
10853 TypeName toNode = this._toNode as TypeName;
10854 if (_and(_isEqualNodes(node.name, toNode.name),
10855 _isEqualNodes(node.typeArguments, toNode.typeArguments))) {
10856 toNode.type = node.type;
10857 return true;
10858 }
10859 return false;
10860 }
10861
10862 @override
10863 bool visitTypeParameter(TypeParameter node) {
10864 TypeParameter toNode = this._toNode as TypeParameter;
10865 return _and(
10866 _isEqualNodes(node.documentationComment, toNode.documentationComment),
10867 _isEqualNodeLists(node.metadata, toNode.metadata),
10868 _isEqualNodes(node.name, toNode.name),
10869 _isEqualTokens(node.extendsKeyword, toNode.extendsKeyword),
10870 _isEqualNodes(node.bound, toNode.bound));
10871 }
10872
10873 @override
10874 bool visitTypeParameterList(TypeParameterList node) {
10875 TypeParameterList toNode = this._toNode as TypeParameterList;
10876 return _and(
10877 _isEqualTokens(node.leftBracket, toNode.leftBracket),
10878 _isEqualNodeLists(node.typeParameters, toNode.typeParameters),
10879 _isEqualTokens(node.rightBracket, toNode.rightBracket));
10880 }
10881
10882 @override
10883 bool visitVariableDeclaration(VariableDeclaration node) {
10884 VariableDeclaration toNode = this._toNode as VariableDeclaration;
10885 return _and(
10886 _isEqualNodes(node.documentationComment, toNode.documentationComment),
10887 _isEqualNodeLists(node.metadata, toNode.metadata),
10888 _isEqualNodes(node.name, toNode.name),
10889 _isEqualTokens(node.equals, toNode.equals),
10890 _isEqualNodes(node.initializer, toNode.initializer));
10891 }
10892
10893 @override
10894 bool visitVariableDeclarationList(VariableDeclarationList node) {
10895 VariableDeclarationList toNode = this._toNode as VariableDeclarationList;
10896 return _and(
10897 _isEqualNodes(node.documentationComment, toNode.documentationComment),
10898 _isEqualNodeLists(node.metadata, toNode.metadata),
10899 _isEqualTokens(node.keyword, toNode.keyword),
10900 _isEqualNodes(node.type, toNode.type),
10901 _isEqualNodeLists(node.variables, toNode.variables));
10902 }
10903
10904 @override
10905 bool visitVariableDeclarationStatement(VariableDeclarationStatement node) {
10906 VariableDeclarationStatement toNode =
10907 this._toNode as VariableDeclarationStatement;
10908 return _and(_isEqualNodes(node.variables, toNode.variables),
10909 _isEqualTokens(node.semicolon, toNode.semicolon));
10910 }
10911
10912 @override
10913 bool visitWhileStatement(WhileStatement node) {
10914 WhileStatement toNode = this._toNode as WhileStatement;
10915 return _and(
10916 _isEqualTokens(node.whileKeyword, toNode.whileKeyword),
10917 _isEqualTokens(node.leftParenthesis, toNode.leftParenthesis),
10918 _isEqualNodes(node.condition, toNode.condition),
10919 _isEqualTokens(node.rightParenthesis, toNode.rightParenthesis),
10920 _isEqualNodes(node.body, toNode.body));
10921 }
10922
10923 @override
10924 bool visitWithClause(WithClause node) {
10925 WithClause toNode = this._toNode as WithClause;
10926 return _and(_isEqualTokens(node.withKeyword, toNode.withKeyword),
10927 _isEqualNodeLists(node.mixinTypes, toNode.mixinTypes));
10928 }
10929
10930 @override
10931 bool visitYieldStatement(YieldStatement node) {
10932 YieldStatement toNode = this._toNode as YieldStatement;
10933 return _and(
10934 _isEqualTokens(node.yieldKeyword, toNode.yieldKeyword),
10935 _isEqualNodes(node.expression, toNode.expression),
10936 _isEqualTokens(node.semicolon, toNode.semicolon));
10937 }
10938
10939 /**
10940 * Return `true` if all of the parameters are `true`.
10941 */
10942 bool _and(bool b1, bool b2,
10943 [bool b3 = true,
10944 bool b4 = true,
10945 bool b5 = true,
10946 bool b6 = true,
10947 bool b7 = true,
10948 bool b8 = true,
10949 bool b9 = true,
10950 bool b10 = true,
10951 bool b11 = true,
10952 bool b12 = true,
10953 bool b13 = true]) {
10954 // TODO(brianwilkerson) Inline this method.
10955 return b1 &&
10956 b2 &&
10957 b3 &&
10958 b4 &&
10959 b5 &&
10960 b6 &&
10961 b7 &&
10962 b8 &&
10963 b9 &&
10964 b10 &&
10965 b11 &&
10966 b12 &&
10967 b13;
10968 }
10969
10970 /**
10971 * Return `true` if the [first] and [second] lists of AST nodes have the same
10972 * size and corresponding elements are equal.
10973 */
10974 bool _isEqualNodeLists(NodeList first, NodeList second) {
10975 if (first == null) {
10976 return second == null;
10977 } else if (second == null) {
10978 return false;
10979 }
10980 int size = first.length;
10981 if (second.length != size) {
10982 return false;
10983 }
10984 bool equal = true;
10985 for (int i = 0; i < size; i++) {
10986 if (!_isEqualNodes(first[i], second[i])) {
10987 equal = false;
10988 }
10989 }
10990 return equal;
10991 }
10992
10993 /**
10994 * Return `true` if the [fromNode] and [toNode] have the same structure. As a
10995 * side-effect, if the nodes do have the same structure, any resolution data
10996 * from the first node will be copied to the second node.
10997 */
10998 bool _isEqualNodes(AstNode fromNode, AstNode toNode) {
10999 if (fromNode == null) {
11000 return toNode == null;
11001 } else if (toNode == null) {
11002 return false;
11003 } else if (fromNode.runtimeType == toNode.runtimeType) {
11004 this._toNode = toNode;
11005 return fromNode.accept(this);
11006 }
11007 //
11008 // Check for a simple transformation caused by entering a period.
11009 //
11010 if (toNode is PrefixedIdentifier) {
11011 SimpleIdentifier prefix = toNode.prefix;
11012 if (fromNode.runtimeType == prefix.runtimeType) {
11013 this._toNode = prefix;
11014 return fromNode.accept(this);
11015 }
11016 } else if (toNode is PropertyAccess) {
11017 Expression target = toNode.target;
11018 if (fromNode.runtimeType == target.runtimeType) {
11019 this._toNode = target;
11020 return fromNode.accept(this);
11021 }
11022 }
11023 return false;
11024 }
11025
11026 /**
11027 * Return `true` if the [first] and [second] arrays of tokens have the same
11028 * length and corresponding elements are equal.
11029 */
11030 bool _isEqualTokenLists(List<Token> first, List<Token> second) {
11031 int length = first.length;
11032 if (second.length != length) {
11033 return false;
11034 }
11035 for (int i = 0; i < length; i++) {
11036 if (!_isEqualTokens(first[i], second[i])) {
11037 return false;
11038 }
11039 }
11040 return true;
11041 }
11042
11043 /**
11044 * Return `true` if the [first] and [second] tokens have the same structure.
11045 */
11046 bool _isEqualTokens(Token first, Token second) {
11047 if (first == null) {
11048 return second == null;
11049 } else if (second == null) {
11050 return false;
11051 }
11052 return first.lexeme == second.lexeme;
11053 }
11054
11055 /**
11056 * Copy resolution data from the [fromNode] to the [toNode].
11057 */
11058 static void copyResolutionData(AstNode fromNode, AstNode toNode) {
11059 ResolutionCopier copier = new ResolutionCopier();
11060 copier._isEqualNodes(fromNode, toNode);
11061 }
11062 }
OLDNEW
« no previous file with comments | « packages/analyzer/lib/src/generated/package.dart ('k') | packages/analyzer/lib/src/generated/resolver.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698