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

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

Issue 2356653003: Finish removing MethodTrampoline (Closed)
Patch Set: Created 4 years, 3 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
« no previous file with comments | « no previous file | pkg/analyzer/test/generated/parser_test.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 analyzer.src.generated.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 'package:analyzer/dart/ast/ast.dart'; 10 import 'package:analyzer/dart/ast/ast.dart';
11 import 'package:analyzer/dart/ast/token.dart'; 11 import 'package:analyzer/dart/ast/token.dart';
12 import 'package:analyzer/error/error.dart'; 12 import 'package:analyzer/error/error.dart';
13 import 'package:analyzer/error/listener.dart'; 13 import 'package:analyzer/error/listener.dart';
14 import 'package:analyzer/src/dart/ast/ast.dart'; 14 import 'package:analyzer/src/dart/ast/ast.dart';
15 import 'package:analyzer/src/dart/ast/token.dart'; 15 import 'package:analyzer/src/dart/ast/token.dart';
16 import 'package:analyzer/src/dart/scanner/reader.dart'; 16 import 'package:analyzer/src/dart/scanner/reader.dart';
17 import 'package:analyzer/src/dart/scanner/scanner.dart'; 17 import 'package:analyzer/src/dart/scanner/scanner.dart';
18 import 'package:analyzer/src/error/codes.dart'; 18 import 'package:analyzer/src/error/codes.dart';
19 import 'package:analyzer/src/generated/engine.dart' show AnalysisEngine; 19 import 'package:analyzer/src/generated/engine.dart' show AnalysisEngine;
20 import 'package:analyzer/src/generated/generated/shared_messages.dart' 20 import 'package:analyzer/src/generated/generated/shared_messages.dart'
21 as shared_messages; 21 as shared_messages;
22 import 'package:analyzer/src/generated/java_core.dart'; 22 import 'package:analyzer/src/generated/java_core.dart';
23 import 'package:analyzer/src/generated/java_engine.dart'; 23 import 'package:analyzer/src/generated/java_engine.dart';
24 import 'package:analyzer/src/generated/source.dart'; 24 import 'package:analyzer/src/generated/source.dart';
25 import 'package:analyzer/src/generated/utilities_dart.dart'; 25 import 'package:analyzer/src/generated/utilities_dart.dart';
26 26
27 export 'package:analyzer/src/dart/ast/utilities.dart' show ResolutionCopier; 27 export 'package:analyzer/src/dart/ast/utilities.dart' show ResolutionCopier;
28 28
29 Map<String, MethodTrampoline> methodTable_Parser = <String, MethodTrampoline>{
30 'parseCompilationUnit_1': new MethodTrampoline(
31 1, (Parser target, arg0) => target.parseCompilationUnit(arg0)),
32 'parseDirectives_1': new MethodTrampoline(
33 1, (Parser target, arg0) => target.parseDirectives(arg0)),
34 'parseExpression_1': new MethodTrampoline(
35 1, (Parser target, arg0) => target.parseExpression(arg0)),
36 'parseStatement_1': new MethodTrampoline(
37 1, (Parser target, arg0) => target.parseStatement(arg0)),
38 'parseStatements_1': new MethodTrampoline(
39 1, (Parser target, arg0) => target.parseStatements(arg0)),
40 'parseAnnotation_0':
41 new MethodTrampoline(0, (Parser target) => target.parseAnnotation()),
42 'parseArgument_0':
43 new MethodTrampoline(0, (Parser target) => target.parseArgument()),
44 'parseArgumentList_0':
45 new MethodTrampoline(0, (Parser target) => target.parseArgumentList()),
46 'parseBitwiseOrExpression_0': new MethodTrampoline(
47 0, (Parser target) => target.parseBitwiseOrExpression()),
48 'parseBlock_0':
49 new MethodTrampoline(0, (Parser target) => target.parseBlock()),
50 'parseClassMember_1': new MethodTrampoline(
51 1, (Parser target, arg0) => target.parseClassMember(arg0)),
52 'parseCompilationUnit_0': new MethodTrampoline(
53 0, (Parser target) => target.parseCompilationUnit2()),
54 'parseConditionalExpression_0': new MethodTrampoline(
55 0, (Parser target) => target.parseConditionalExpression()),
56 'parseConstructorName_0':
57 new MethodTrampoline(0, (Parser target) => target.parseConstructorName()),
58 'parseExpression_0':
59 new MethodTrampoline(0, (Parser target) => target.parseExpression2()),
60 'parseExpressionWithoutCascade_0': new MethodTrampoline(
61 0, (Parser target) => target.parseExpressionWithoutCascade()),
62 'parseExtendsClause_0':
63 new MethodTrampoline(0, (Parser target) => target.parseExtendsClause()),
64 'parseFormalParameterList_0': new MethodTrampoline(
65 0, (Parser target) => target.parseFormalParameterList()),
66 'parseFunctionExpression_0': new MethodTrampoline(
67 0, (Parser target) => target.parseFunctionExpression()),
68 'parseImplementsClause_0': new MethodTrampoline(
69 0, (Parser target) => target.parseImplementsClause()),
70 'parseLabel_0':
71 new MethodTrampoline(0, (Parser target) => target.parseLabel()),
72 'parseLibraryIdentifier_0': new MethodTrampoline(
73 0, (Parser target) => target.parseLibraryIdentifier()),
74 'parseLogicalOrExpression_0': new MethodTrampoline(
75 0, (Parser target) => target.parseLogicalOrExpression()),
76 'parseMapLiteralEntry_0':
77 new MethodTrampoline(0, (Parser target) => target.parseMapLiteralEntry()),
78 'parseNormalFormalParameter_0': new MethodTrampoline(
79 0, (Parser target) => target.parseNormalFormalParameter()),
80 'parsePrefixedIdentifier_0': new MethodTrampoline(
81 0, (Parser target) => target.parsePrefixedIdentifier()),
82 'parseReturnType_0':
83 new MethodTrampoline(0, (Parser target) => target.parseReturnType()),
84 'parseSimpleIdentifier_0': new MethodTrampoline(
85 0, (Parser target) => target.parseSimpleIdentifier()),
86 'parseStatement_0':
87 new MethodTrampoline(0, (Parser target) => target.parseStatement2()),
88 'parseStringLiteral_0':
89 new MethodTrampoline(0, (Parser target) => target.parseStringLiteral()),
90 'parseTypeArgumentList_0': new MethodTrampoline(
91 0, (Parser target) => target.parseTypeArgumentList()),
92 'parseTypeName_0':
93 new MethodTrampoline(0, (Parser target) => target.parseTypeName(false)),
94 'parseTypeParameter_0':
95 new MethodTrampoline(0, (Parser target) => target.parseTypeParameter()),
96 'parseTypeParameterList_0': new MethodTrampoline(
97 0, (Parser target) => target.parseTypeParameterList()),
98 'parseWithClause_0':
99 new MethodTrampoline(0, (Parser target) => target.parseWithClause()),
100 'advance_0': new MethodTrampoline(0, (Parser target) => target._advance()),
101 'appendScalarValue_5': new MethodTrampoline(
102 5,
103 (Parser target, arg0, arg1, arg2, arg3, arg4) =>
104 target._appendScalarValue(arg0, arg1, arg2, arg3, arg4)),
105 'convertToFunctionDeclaration_1': new MethodTrampoline(
106 1, (Parser target, arg0) => target._convertToFunctionDeclaration(arg0)),
107 'couldBeStartOfCompilationUnitMember_0': new MethodTrampoline(
108 0, (Parser target) => target._couldBeStartOfCompilationUnitMember()),
109 'createSyntheticIdentifier_0': new MethodTrampoline(
110 0, (Parser target) => target.createSyntheticIdentifier()),
111 'createSyntheticKeyword_1': new MethodTrampoline(
112 1, (Parser target, arg0) => target._createSyntheticKeyword(arg0)),
113 'createSyntheticStringLiteral_0': new MethodTrampoline(
114 0, (Parser target) => target.createSyntheticStringLiteral()),
115 'createSyntheticToken_1': new MethodTrampoline(
116 1, (Parser target, arg0) => target._createSyntheticToken(arg0)),
117 'ensureAssignable_1': new MethodTrampoline(
118 1, (Parser target, arg0) => target._ensureAssignable(arg0)),
119 'expect_1':
120 new MethodTrampoline(1, (Parser target, arg0) => target._expect(arg0)),
121 'expectGt_0': new MethodTrampoline(0, (Parser target) => target._expectGt()),
122 'expectKeyword_1': new MethodTrampoline(
123 1, (Parser target, arg0) => target._expectKeyword(arg0)),
124 'findRange_2': new MethodTrampoline(
125 2,
126 (Parser target, List<List<int>> arg0, int arg1) =>
127 target._findRange(arg0, arg1)),
128 'getCodeBlockRanges_1': new MethodTrampoline(
129 1, (Parser target, arg0) => target._getCodeBlockRanges(arg0)),
130 'getEndToken_1': new MethodTrampoline(
131 1, (Parser target, arg0) => target._getEndToken(arg0)),
132 'injectToken_1': new MethodTrampoline(
133 1, (Parser target, arg0) => target._injectToken(arg0)),
134 'isFunctionDeclaration_0': new MethodTrampoline(
135 0, (Parser target) => target.isFunctionDeclaration()),
136 'isFunctionExpression_1': new MethodTrampoline(
137 1, (Parser target, arg0) => target.isFunctionExpression(arg0)),
138 'isHexDigit_1': new MethodTrampoline(
139 1, (Parser target, arg0) => target._isHexDigit(arg0)),
140 'isInitializedVariableDeclaration_0': new MethodTrampoline(
141 0, (Parser target) => target.isInitializedVariableDeclaration()),
142 'isLinkText_2': new MethodTrampoline(
143 2, (Parser target, arg0, arg1) => target._isLinkText(arg0, arg1)),
144 'isOperator_1': new MethodTrampoline(
145 1, (Parser target, arg0) => target._isOperator(arg0)),
146 'isSwitchMember_0':
147 new MethodTrampoline(0, (Parser target) => target.isSwitchMember()),
148 'isTypedIdentifier_1': new MethodTrampoline(
149 1, (Parser target, arg0) => target._isTypedIdentifier(arg0)),
150 'lockErrorListener_0':
151 new MethodTrampoline(0, (Parser target) => target._lockErrorListener()),
152 'matches_1':
153 new MethodTrampoline(1, (Parser target, arg0) => target._matches(arg0)),
154 'matchesGt_0':
155 new MethodTrampoline(0, (Parser target) => target._matchesGt()),
156 'matchesIdentifier_0':
157 new MethodTrampoline(0, (Parser target) => target._matchesIdentifier()),
158 'matchesKeyword_1': new MethodTrampoline(
159 1, (Parser target, arg0) => target._matchesKeyword(arg0)),
160 'matchesString_1': new MethodTrampoline(
161 1, (Parser target, arg0) => target._matchesString(arg0)),
162 'optional_1':
163 new MethodTrampoline(1, (Parser target, arg0) => target._optional(arg0)),
164 'parseAdditiveExpression_0': new MethodTrampoline(
165 0, (Parser target) => target.parseAdditiveExpression()),
166 'parseAssertStatement_0':
167 new MethodTrampoline(0, (Parser target) => target.parseAssertStatement()),
168 'parseAssignableExpression_1': new MethodTrampoline(
169 1, (Parser target, arg0) => target.parseAssignableExpression(arg0)),
170 'parseAssignableSelector_2': new MethodTrampoline(
171 2,
172 (Parser target, arg0, arg1) =>
173 target._parseAssignableSelector(arg0, arg1)),
174 'parseAwaitExpression_0':
175 new MethodTrampoline(0, (Parser target) => target.parseAwaitExpression()),
176 'parseBitwiseAndExpression_0': new MethodTrampoline(
177 0, (Parser target) => target.parseBitwiseAndExpression()),
178 'parseBitwiseXorExpression_0': new MethodTrampoline(
179 0, (Parser target) => target.parseBitwiseXorExpression()),
180 'parseBreakStatement_0':
181 new MethodTrampoline(0, (Parser target) => target.parseBreakStatement()),
182 'parseCascadeSection_0':
183 new MethodTrampoline(0, (Parser target) => target.parseCascadeSection()),
184 'parseClassDeclaration_2': new MethodTrampoline(2,
185 (Parser target, arg0, arg1) => target.parseClassDeclaration(arg0, arg1)),
186 'parseClassMembers_2': new MethodTrampoline(
187 2, (Parser target, arg0, arg1) => target._parseClassMembers(arg0, arg1)),
188 'parseClassTypeAlias_3': new MethodTrampoline(
189 3,
190 (Parser target, arg0, arg1, arg2) =>
191 target.parseClassTypeAlias(arg0, arg1, arg2)),
192 'parseCombinator_0':
193 new MethodTrampoline(0, (Parser target) => target.parseCombinator()),
194 'parseCombinators_0':
195 new MethodTrampoline(0, (Parser target) => target.parseCombinators()),
196 'parseCommentAndMetadata_0': new MethodTrampoline(
197 0, (Parser target) => target.parseCommentAndMetadata()),
198 'parseCommentReference_2': new MethodTrampoline(2,
199 (Parser target, arg0, arg1) => target.parseCommentReference(arg0, arg1)),
200 'parseCommentReferences_1': new MethodTrampoline(
201 1,
202 (Parser target, List<DocumentationCommentToken> arg0) =>
203 target._parseCommentReferences(arg0)),
204 'parseCompilationUnitMember_1': new MethodTrampoline(
205 1, (Parser target, arg0) => target.parseCompilationUnitMember(arg0)),
206 'parseConfiguration_0':
207 new MethodTrampoline(0, (Parser target) => target.parseConfiguration()),
208 'parseConstExpression_0':
209 new MethodTrampoline(0, (Parser target) => target.parseConstExpression()),
210 'parseConstructor_8': new MethodTrampoline(
211 8,
212 (Parser target, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7) => target
213 ._parseConstructor(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7)),
214 'parseConstructorFieldInitializer_1': new MethodTrampoline(1,
215 (Parser target, arg0) => target._parseConstructorFieldInitializer(arg0)),
216 'parseContinueStatement_0': new MethodTrampoline(
217 0, (Parser target) => target.parseContinueStatement()),
218 'parseDirective_1': new MethodTrampoline(
219 1, (Parser target, arg0) => target._parseDirective(arg0)),
220 'parseDirectives_0':
221 new MethodTrampoline(0, (Parser target) => target.parseDirectives2()),
222 'parseDocumentationComment_0': new MethodTrampoline(0, (Parser target) {
223 List<DocumentationCommentToken> tokens =
224 target.parseDocumentationCommentTokens();
225 return target.parseDocumentationComment(tokens);
226 }),
227 'parseDoStatement_0':
228 new MethodTrampoline(0, (Parser target) => target.parseDoStatement()),
229 'parseDottedName_0':
230 new MethodTrampoline(0, (Parser target) => target.parseDottedName()),
231 'parseEmptyStatement_0':
232 new MethodTrampoline(0, (Parser target) => target.parseEmptyStatement()),
233 'parseEnumConstantDeclaration_0': new MethodTrampoline(
234 0, (Parser target) => target._parseEnumConstantDeclaration()),
235 'parseEnumDeclaration_1': new MethodTrampoline(
236 1, (Parser target, arg0) => target.parseEnumDeclaration(arg0)),
237 'parseEqualityExpression_0': new MethodTrampoline(
238 0, (Parser target) => target._parseEqualityExpression()),
239 'parseExportDirective_1': new MethodTrampoline(
240 1, (Parser target, arg0) => target._parseExportDirective(arg0)),
241 'parseExpressionList_0':
242 new MethodTrampoline(0, (Parser target) => target.parseExpressionList()),
243 'parseFinalConstVarOrType_1': new MethodTrampoline(
244 1, (Parser target, arg0) => target.parseFinalConstVarOrType(arg0)),
245 'parseFormalParameter_1': new MethodTrampoline(
246 1, (Parser target, arg0) => target._parseFormalParameter(arg0)),
247 'parseForStatement_0':
248 new MethodTrampoline(0, (Parser target) => target.parseForStatement()),
249 'parseFunctionBody_3': new MethodTrampoline(
250 3,
251 (Parser target, arg0, arg1, arg2) =>
252 target.parseFunctionBody(arg0, arg1, arg2)),
253 'parseFunctionDeclaration_3': new MethodTrampoline(
254 3,
255 (Parser target, arg0, arg1, arg2) =>
256 target._parseFunctionDeclaration(arg0, arg1, arg2)),
257 'parseFunctionDeclarationStatement_0': new MethodTrampoline(
258 0, (Parser target) => target.parseFunctionDeclarationStatement()),
259 'parseFunctionDeclarationStatementAfterReturnType_2': new MethodTrampoline(
260 2,
261 (Parser target, arg0, arg1) =>
262 target._parseFunctionDeclarationStatementAfterReturnType(arg0, arg1)),
263 'parseFunctionTypeAlias_2': new MethodTrampoline(
264 2,
265 (Parser target, arg0, arg1) =>
266 target._parseFunctionTypeAlias(arg0, arg1)),
267 'parseGetter_4': new MethodTrampoline(
268 4,
269 (Parser target, arg0, arg1, arg2, arg3) =>
270 target._parseGetter(arg0, arg1, arg2, arg3)),
271 'parseIdentifierList_0':
272 new MethodTrampoline(0, (Parser target) => target._parseIdentifierList()),
273 'parseIfStatement_0':
274 new MethodTrampoline(0, (Parser target) => target.parseIfStatement()),
275 'parseImportDirective_1': new MethodTrampoline(
276 1, (Parser target, arg0) => target._parseImportDirective(arg0)),
277 'parseInitializedIdentifierList_4': new MethodTrampoline(
278 4,
279 (Parser target, arg0, arg1, arg2, arg3) =>
280 target._parseInitializedIdentifierList(arg0, arg1, arg2, arg3)),
281 'parseInstanceCreationExpression_1': new MethodTrampoline(1,
282 (Parser target, arg0) => target._parseInstanceCreationExpression(arg0)),
283 'parseLibraryDirective_1': new MethodTrampoline(
284 1, (Parser target, arg0) => target._parseLibraryDirective(arg0)),
285 'parseLibraryName_2': new MethodTrampoline(
286 2, (Parser target, arg0, arg1) => target._parseLibraryName(arg0, arg1)),
287 'parseListLiteral_2': new MethodTrampoline(
288 2, (Parser target, arg0, arg1) => target._parseListLiteral(arg0, arg1)),
289 'parseListOrMapLiteral_1': new MethodTrampoline(
290 1, (Parser target, arg0) => target.parseListOrMapLiteral(arg0)),
291 'parseLogicalAndExpression_0': new MethodTrampoline(
292 0, (Parser target) => target._parseLogicalAndExpression()),
293 'parseMapLiteral_2': new MethodTrampoline(
294 2, (Parser target, arg0, arg1) => target._parseMapLiteral(arg0, arg1)),
295 'parseMethodDeclarationAfterParameters_7': new MethodTrampoline(
296 7,
297 (Parser target, arg0, arg1, arg2, arg3, arg4, arg5, arg6) =>
298 target._parseMethodDeclarationAfterParameters(
299 arg0, arg1, arg2, arg3, arg4, arg5, arg6)),
300 'parseMethodDeclarationAfterReturnType_4': new MethodTrampoline(
301 4,
302 (Parser target, arg0, arg1, arg2, arg3) => target
303 ._parseMethodDeclarationAfterReturnType(arg0, arg1, arg2, arg3)),
304 'parseModifiers_0':
305 new MethodTrampoline(0, (Parser target) => target._parseModifiers()),
306 'parseMultiplicativeExpression_0': new MethodTrampoline(
307 0, (Parser target) => target.parseMultiplicativeExpression()),
308 'parseNativeClause_0':
309 new MethodTrampoline(0, (Parser target) => target._parseNativeClause()),
310 'parseNewExpression_0':
311 new MethodTrampoline(0, (Parser target) => target._parseNewExpression()),
312 'parseNonLabeledStatement_0': new MethodTrampoline(
313 0, (Parser target) => target._parseNonLabeledStatement()),
314 'parseOperator_3': new MethodTrampoline(
315 3,
316 (Parser target, arg0, arg1, arg2) =>
317 target.parseOperator(arg0, arg1, arg2)),
318 'parseOptionalReturnType_0': new MethodTrampoline(
319 0, (Parser target) => target._parseOptionalReturnType()),
320 'parsePartDirective_1': new MethodTrampoline(
321 1, (Parser target, arg0) => target._parsePartOrPartOfDirective(arg0)),
322 'parsePostfixExpression_0': new MethodTrampoline(
323 0, (Parser target) => target._parsePostfixExpression()),
324 'parsePrimaryExpression_0': new MethodTrampoline(
325 0, (Parser target) => target.parsePrimaryExpression()),
326 'parseRedirectingConstructorInvocation_1': new MethodTrampoline(
327 1,
328 (Parser target, arg0) =>
329 target._parseRedirectingConstructorInvocation(arg0)),
330 'parseRelationalExpression_0': new MethodTrampoline(
331 0, (Parser target) => target.parseRelationalExpression()),
332 'parseRethrowExpression_0': new MethodTrampoline(
333 0, (Parser target) => target.parseRethrowExpression()),
334 'parseReturnStatement_0':
335 new MethodTrampoline(0, (Parser target) => target.parseReturnStatement()),
336 'parseSetter_4': new MethodTrampoline(
337 4,
338 (Parser target, arg0, arg1, arg2, arg3) =>
339 target._parseSetter(arg0, arg1, arg2, arg3)),
340 'parseShiftExpression_0':
341 new MethodTrampoline(0, (Parser target) => target.parseShiftExpression()),
342 'parseStatementList_0':
343 new MethodTrampoline(0, (Parser target) => target._parseStatementList()),
344 'parseStringInterpolation_1': new MethodTrampoline(
345 1, (Parser target, arg0) => target._parseStringInterpolation(arg0)),
346 'parseSuperConstructorInvocation_0': new MethodTrampoline(
347 0, (Parser target) => target.parseSuperConstructorInvocation()),
348 'parseSwitchStatement_0':
349 new MethodTrampoline(0, (Parser target) => target.parseSwitchStatement()),
350 'parseSymbolLiteral_0':
351 new MethodTrampoline(0, (Parser target) => target.parseSymbolLiteral()),
352 'parseThrowExpression_0':
353 new MethodTrampoline(0, (Parser target) => target.parseThrowExpression()),
354 'parseThrowExpressionWithoutCascade_0': new MethodTrampoline(
355 0, (Parser target) => target.parseThrowExpressionWithoutCascade()),
356 'parseTryStatement_0':
357 new MethodTrampoline(0, (Parser target) => target.parseTryStatement()),
358 'parseTypeAlias_1': new MethodTrampoline(
359 1, (Parser target, arg0) => target._parseTypeAlias(arg0)),
360 'parseUnaryExpression_0':
361 new MethodTrampoline(0, (Parser target) => target.parseUnaryExpression()),
362 'parseVariableDeclaration_0': new MethodTrampoline(
363 0, (Parser target) => target.parseVariableDeclaration()),
364 'parseVariableDeclarationListAfterMetadata_1': new MethodTrampoline(
365 1,
366 (Parser target, arg0) =>
367 target.parseVariableDeclarationListAfterMetadata(arg0)),
368 'parseVariableDeclarationListAfterType_3': new MethodTrampoline(
369 3,
370 (Parser target, arg0, arg1, arg2) =>
371 target.parseVariableDeclarationListAfterType(arg0, arg1, arg2)),
372 'parseVariableDeclarationStatementAfterMetadata_1': new MethodTrampoline(
373 1,
374 (Parser target, arg0) =>
375 target.parseVariableDeclarationStatementAfterMetadata(arg0)),
376 'parseVariableDeclarationStatementAfterType_3': new MethodTrampoline(
377 3,
378 (Parser target, arg0, arg1, arg2) =>
379 target._parseVariableDeclarationStatementAfterType(arg0, arg1, arg2)),
380 'parseWhileStatement_0':
381 new MethodTrampoline(0, (Parser target) => target.parseWhileStatement()),
382 'parseYieldStatement_0':
383 new MethodTrampoline(0, (Parser target) => target.parseYieldStatement()),
384 'peek_0': new MethodTrampoline(0, (Parser target) => target._peek()),
385 'peekAt_1':
386 new MethodTrampoline(1, (Parser target, arg0) => target._peekAt(arg0)),
387 'reportError_1': new MethodTrampoline(
388 1, (Parser target, arg0) => target._reportError(arg0)),
389 'reportErrorForCurrentToken_2': new MethodTrampoline(
390 2,
391 (Parser target, arg0, arg1) =>
392 target._reportErrorForCurrentToken(arg0, arg1)),
393 'reportErrorForNode_3': new MethodTrampoline(
394 3,
395 (Parser target, arg0, arg1, arg2) =>
396 target._reportErrorForNode(arg0, arg1, arg2)),
397 'reportErrorForToken_3': new MethodTrampoline(
398 3,
399 (Parser target, arg0, arg1, arg2) =>
400 target._reportErrorForToken(arg0, arg1, arg2)),
401 'skipBlock_0':
402 new MethodTrampoline(0, (Parser target) => target._skipBlock()),
403 'skipFinalConstVarOrType_1': new MethodTrampoline(
404 1, (Parser target, arg0) => target._skipFinalConstVarOrType(arg0)),
405 'skipFormalParameterList_1': new MethodTrampoline(
406 1, (Parser target, arg0) => target._skipFormalParameterList(arg0)),
407 'skipPastMatchingToken_1': new MethodTrampoline(
408 1, (Parser target, arg0) => target._skipPastMatchingToken(arg0)),
409 'skipPrefixedIdentifier_1': new MethodTrampoline(
410 1, (Parser target, arg0) => target.skipPrefixedIdentifier(arg0)),
411 'skipReturnType_1': new MethodTrampoline(
412 1, (Parser target, arg0) => target.skipReturnType(arg0)),
413 'skipSimpleIdentifier_1': new MethodTrampoline(
414 1, (Parser target, arg0) => target.skipSimpleIdentifier(arg0)),
415 'skipStringInterpolation_1': new MethodTrampoline(
416 1, (Parser target, arg0) => target._skipStringInterpolation(arg0)),
417 'skipStringLiteral_1': new MethodTrampoline(
418 1, (Parser target, arg0) => target.skipStringLiteral(arg0)),
419 'skipTypeArgumentList_1': new MethodTrampoline(
420 1, (Parser target, arg0) => target.skipTypeArgumentList(arg0)),
421 'skipTypeName_1': new MethodTrampoline(
422 1, (Parser target, arg0) => target.skipTypeName(arg0)),
423 'skipTypeParameterList_1': new MethodTrampoline(
424 1, (Parser target, arg0) => target._skipTypeParameterList(arg0)),
425 'tokenMatches_2': new MethodTrampoline(
426 2, (Parser target, arg0, arg1) => target._tokenMatches(arg0, arg1)),
427 'tokenMatchesIdentifier_1': new MethodTrampoline(
428 1, (Parser target, arg0) => target._tokenMatchesIdentifier(arg0)),
429 'tokenMatchesKeyword_2': new MethodTrampoline(2,
430 (Parser target, arg0, arg1) => target._tokenMatchesKeyword(arg0, arg1)),
431 'tokenMatchesString_2': new MethodTrampoline(
432 2, (Parser target, arg0, arg1) => target._tokenMatchesString(arg0, arg1)),
433 'unlockErrorListener_0':
434 new MethodTrampoline(0, (Parser target) => target._unlockErrorListener()),
435 'validateFormalParameterList_1': new MethodTrampoline(
436 1, (Parser target, arg0) => target._validateFormalParameterList(arg0)),
437 'validateModifiersForClass_1': new MethodTrampoline(
438 1, (Parser target, arg0) => target._validateModifiersForClass(arg0)),
439 'validateModifiersForConstructor_1': new MethodTrampoline(1,
440 (Parser target, arg0) => target._validateModifiersForConstructor(arg0)),
441 'validateModifiersForEnum_1': new MethodTrampoline(
442 1, (Parser target, arg0) => target._validateModifiersForEnum(arg0)),
443 'validateModifiersForField_1': new MethodTrampoline(
444 1, (Parser target, arg0) => target._validateModifiersForField(arg0)),
445 'validateModifiersForFunctionDeclarationStatement_1': new MethodTrampoline(
446 1,
447 (Parser target, arg0) =>
448 target._validateModifiersForFunctionDeclarationStatement(arg0)),
449 'validateModifiersForGetterOrSetterOrMethod_1': new MethodTrampoline(
450 1,
451 (Parser target, arg0) =>
452 target._validateModifiersForGetterOrSetterOrMethod(arg0)),
453 'validateModifiersForOperator_1': new MethodTrampoline(
454 1, (Parser target, arg0) => target._validateModifiersForOperator(arg0)),
455 'validateModifiersForTopLevelDeclaration_1': new MethodTrampoline(
456 1,
457 (Parser target, arg0) =>
458 target._validateModifiersForTopLevelDeclaration(arg0)),
459 'validateModifiersForTopLevelFunction_1': new MethodTrampoline(
460 1,
461 (Parser target, arg0) =>
462 target._validateModifiersForTopLevelFunction(arg0)),
463 'validateModifiersForTopLevelVariable_1': new MethodTrampoline(
464 1,
465 (Parser target, arg0) =>
466 target._validateModifiersForTopLevelVariable(arg0)),
467 'validateModifiersForTypedef_1': new MethodTrampoline(
468 1, (Parser target, arg0) => target._validateModifiersForTypedef(arg0)),
469 };
470
471 Object invokeParserMethodImpl(
472 Parser parser, String methodName, List<Object> objects) {
473 MethodTrampoline method =
474 methodTable_Parser['${methodName}_${objects.length}'];
475 if (method == null) {
476 throw new ArgumentError('There is no method named $methodName');
477 }
478 return method.invoke(parser, objects);
479 }
480
481 /** 29 /**
482 * 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.
483 */ 31 */
484 class CommentAndMetadata { 32 class CommentAndMetadata {
485 /** 33 /**
486 * 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.
487 */ 35 */
488 final Comment comment; 36 final Comment comment;
489 37
490 /** 38 /**
(...skipping 285 matching lines...) Expand 10 before | Expand all | Expand 10 after
776 * to match the given [enable] flag. 324 * to match the given [enable] flag.
777 */ 325 */
778 void set enableNnbd(bool enable) { 326 void set enableNnbd(bool enable) {
779 _enableNnbd = enable; 327 _enableNnbd = enable;
780 } 328 }
781 329
782 /** 330 /**
783 * Return `true` if the current token is the first token of a return type that 331 * Return `true` if the current token is the first token of a return type that
784 * is followed by an identifier, possibly followed by a list of type 332 * is followed by an identifier, possibly followed by a list of type
785 * parameters, followed by a left-parenthesis. This is used by 333 * parameters, followed by a left-parenthesis. This is used by
786 * [_parseTypeAlias] to determine whether or not to parse a return type. 334 * [parseTypeAlias] to determine whether or not to parse a return type.
787 */ 335 */
788 @deprecated 336 @deprecated
789 bool get hasReturnTypeInTypeAlias { 337 bool get hasReturnTypeInTypeAlias {
790 Token next = skipReturnType(_currentToken); 338 Token next = skipReturnType(_currentToken);
791 if (next == null) { 339 if (next == null) {
792 return false; 340 return false;
793 } 341 }
794 return _tokenMatchesIdentifier(next); 342 return _tokenMatchesIdentifier(next);
795 } 343 }
796 344
(...skipping 415 matching lines...) Expand 10 before | Expand all | Expand 10 after
1212 * expression is allowed to be a primary without any assignable selector. 760 * expression is allowed to be a primary without any assignable selector.
1213 * Return the assignable expression that was parsed. 761 * Return the assignable expression that was parsed.
1214 * 762 *
1215 * assignableExpression ::= 763 * assignableExpression ::=
1216 * primary (arguments* assignableSelector)+ 764 * primary (arguments* assignableSelector)+
1217 * | 'super' unconditionalAssignableSelector 765 * | 'super' unconditionalAssignableSelector
1218 * | identifier 766 * | identifier
1219 */ 767 */
1220 Expression parseAssignableExpression(bool primaryAllowed) { 768 Expression parseAssignableExpression(bool primaryAllowed) {
1221 if (_matchesKeyword(Keyword.SUPER)) { 769 if (_matchesKeyword(Keyword.SUPER)) {
1222 return _parseAssignableSelector( 770 return parseAssignableSelector(
1223 new SuperExpression(getAndAdvance()), false, 771 new SuperExpression(getAndAdvance()), false,
1224 allowConditional: false); 772 allowConditional: false);
1225 } 773 }
1226 return _parseAssignableExpressionNotStartingWithSuper(primaryAllowed); 774 return _parseAssignableExpressionNotStartingWithSuper(primaryAllowed);
1227 } 775 }
1228 776
1229 /** 777 /**
778 * Parse an assignable selector. The [prefix] is the expression preceding the
779 * selector. The [optional] is `true` if the selector is optional. Return the
780 * assignable selector that was parsed, or the original prefix if there was no
781 * assignable selector. If [allowConditional] is false, then the '?.'
782 * operator will still be parsed, but a parse error will be generated.
783 *
784 * unconditionalAssignableSelector ::=
785 * '[' expression ']'
786 * | '.' identifier
787 *
788 * assignableSelector ::=
789 * unconditionalAssignableSelector
790 * | '?.' identifier
791 */
792 Expression parseAssignableSelector(Expression prefix, bool optional,
793 {bool allowConditional: true}) {
794 TokenType type = _currentToken.type;
795 if (type == TokenType.OPEN_SQUARE_BRACKET) {
796 Token leftBracket = getAndAdvance();
797 bool wasInInitializer = _inInitializer;
798 _inInitializer = false;
799 try {
800 Expression index = parseExpression2();
801 Token rightBracket = _expect(TokenType.CLOSE_SQUARE_BRACKET);
802 return new IndexExpression.forTarget(
803 prefix, leftBracket, index, rightBracket);
804 } finally {
805 _inInitializer = wasInInitializer;
806 }
807 } else {
808 bool isQuestionPeriod = type == TokenType.QUESTION_PERIOD;
809 if (type == TokenType.PERIOD || isQuestionPeriod) {
810 if (isQuestionPeriod && !allowConditional) {
811 _reportErrorForCurrentToken(
812 ParserErrorCode.INVALID_OPERATOR_FOR_SUPER,
813 [_currentToken.lexeme]);
814 }
815 Token operator = getAndAdvance();
816 return new PropertyAccess(prefix, operator, parseSimpleIdentifier());
817 } else {
818 if (!optional) {
819 // Report the missing selector.
820 _reportErrorForCurrentToken(
821 ParserErrorCode.MISSING_ASSIGNABLE_SELECTOR);
822 }
823 return prefix;
824 }
825 }
826 }
827
828 /**
1230 * Parse a await expression. Return the await expression that was parsed. 829 * Parse a await expression. Return the await expression that was parsed.
1231 * 830 *
1232 * This method assumes that the current token matches `_AWAIT`. 831 * This method assumes that the current token matches `_AWAIT`.
1233 * 832 *
1234 * awaitExpression ::= 833 * awaitExpression ::=
1235 * 'await' unaryExpression 834 * 'await' unaryExpression
1236 */ 835 */
1237 AwaitExpression parseAwaitExpression() { 836 AwaitExpression parseAwaitExpression() {
1238 Token awaitToken = getAndAdvance(); 837 Token awaitToken = getAndAdvance();
1239 Expression expression = parseUnaryExpression(); 838 Expression expression = parseUnaryExpression();
(...skipping 190 matching lines...) Expand 10 before | Expand all | Expand 10 after
1430 } 1029 }
1431 } while (_isLikelyArgumentList()); 1030 } while (_isLikelyArgumentList());
1432 } else if (functionName != null) { 1031 } else if (functionName != null) {
1433 expression = new PropertyAccess(expression, period, functionName); 1032 expression = new PropertyAccess(expression, period, functionName);
1434 period = null; 1033 period = null;
1435 } 1034 }
1436 assert(expression != null); 1035 assert(expression != null);
1437 bool progress = true; 1036 bool progress = true;
1438 while (progress) { 1037 while (progress) {
1439 progress = false; 1038 progress = false;
1440 Expression selector = _parseAssignableSelector(expression, true); 1039 Expression selector = parseAssignableSelector(expression, true);
1441 if (!identical(selector, expression)) { 1040 if (!identical(selector, expression)) {
1442 expression = selector; 1041 expression = selector;
1443 progress = true; 1042 progress = true;
1444 while (_isLikelyArgumentList()) { 1043 while (_isLikelyArgumentList()) {
1445 TypeArgumentList typeArguments = _parseOptionalTypeArguments(); 1044 TypeArgumentList typeArguments = _parseOptionalTypeArguments();
1446 Expression currentExpression = expression; 1045 Expression currentExpression = expression;
1447 if (currentExpression is PropertyAccess) { 1046 if (currentExpression is PropertyAccess) {
1448 expression = new MethodInvocation( 1047 expression = new MethodInvocation(
1449 currentExpression.target, 1048 currentExpression.target,
1450 currentExpression.operator, 1049 currentExpression.operator,
(...skipping 153 matching lines...) Expand 10 before | Expand all | Expand 10 after
1604 * Parse a class member. The [className] is the name of the class containing 1203 * Parse a class member. The [className] is the name of the class containing
1605 * the member being parsed. Return the class member that was parsed, or `null` 1204 * the member being parsed. Return the class member that was parsed, or `null`
1606 * if what was found was not a valid class member. 1205 * if what was found was not a valid class member.
1607 * 1206 *
1608 * classMemberDefinition ::= 1207 * classMemberDefinition ::=
1609 * declaration ';' 1208 * declaration ';'
1610 * | methodSignature functionBody 1209 * | methodSignature functionBody
1611 */ 1210 */
1612 ClassMember parseClassMember(String className) { 1211 ClassMember parseClassMember(String className) {
1613 CommentAndMetadata commentAndMetadata = parseCommentAndMetadata(); 1212 CommentAndMetadata commentAndMetadata = parseCommentAndMetadata();
1614 Modifiers modifiers = _parseModifiers(); 1213 Modifiers modifiers = parseModifiers();
1615 Keyword keyword = _currentToken.keyword; 1214 Keyword keyword = _currentToken.keyword;
1616 if (keyword == Keyword.VOID) { 1215 if (keyword == Keyword.VOID) {
1617 TypeName returnType = 1216 TypeName returnType =
1618 new TypeName(new SimpleIdentifier(getAndAdvance()), null); 1217 new TypeName(new SimpleIdentifier(getAndAdvance()), null);
1619 keyword = _currentToken.keyword; 1218 keyword = _currentToken.keyword;
1620 Token next = _peek(); 1219 Token next = _peek();
1621 bool isFollowedByIdentifier = _tokenMatchesIdentifier(next); 1220 bool isFollowedByIdentifier = _tokenMatchesIdentifier(next);
1622 if (keyword == Keyword.GET && isFollowedByIdentifier) { 1221 if (keyword == Keyword.GET && isFollowedByIdentifier) {
1623 _validateModifiersForGetterOrSetterOrMethod(modifiers); 1222 _validateModifiersForGetterOrSetterOrMethod(modifiers);
1624 return _parseGetter(commentAndMetadata, modifiers.externalKeyword, 1223 return parseGetter(commentAndMetadata, modifiers.externalKeyword,
1625 modifiers.staticKeyword, returnType); 1224 modifiers.staticKeyword, returnType);
1626 } else if (keyword == Keyword.SET && isFollowedByIdentifier) { 1225 } else if (keyword == Keyword.SET && isFollowedByIdentifier) {
1627 _validateModifiersForGetterOrSetterOrMethod(modifiers); 1226 _validateModifiersForGetterOrSetterOrMethod(modifiers);
1628 return _parseSetter(commentAndMetadata, modifiers.externalKeyword, 1227 return parseSetter(commentAndMetadata, modifiers.externalKeyword,
1629 modifiers.staticKeyword, returnType); 1228 modifiers.staticKeyword, returnType);
1630 } else if (keyword == Keyword.OPERATOR && _isOperator(next)) { 1229 } else if (keyword == Keyword.OPERATOR && _isOperator(next)) {
1631 _validateModifiersForOperator(modifiers); 1230 _validateModifiersForOperator(modifiers);
1632 return _parseOperatorAfterKeyword(commentAndMetadata, 1231 return _parseOperatorAfterKeyword(commentAndMetadata,
1633 modifiers.externalKeyword, returnType, getAndAdvance()); 1232 modifiers.externalKeyword, returnType, getAndAdvance());
1634 } else if (_matchesIdentifier() && 1233 } else if (_matchesIdentifier() &&
1635 _peek().matchesAny(const <TokenType>[ 1234 _peek().matchesAny(const <TokenType>[
1636 TokenType.OPEN_PAREN, 1235 TokenType.OPEN_PAREN,
1637 TokenType.OPEN_CURLY_BRACKET, 1236 TokenType.OPEN_CURLY_BRACKET,
1638 TokenType.FUNCTION, 1237 TokenType.FUNCTION,
1639 TokenType.LT 1238 TokenType.LT
1640 ])) { 1239 ])) {
1641 _validateModifiersForGetterOrSetterOrMethod(modifiers); 1240 _validateModifiersForGetterOrSetterOrMethod(modifiers);
1642 return _parseMethodDeclarationAfterReturnType(commentAndMetadata, 1241 return _parseMethodDeclarationAfterReturnType(commentAndMetadata,
1643 modifiers.externalKeyword, modifiers.staticKeyword, returnType); 1242 modifiers.externalKeyword, modifiers.staticKeyword, returnType);
1644 } else { 1243 } else {
1645 // 1244 //
1646 // We have found an error of some kind. Try to recover. 1245 // We have found an error of some kind. Try to recover.
1647 // 1246 //
1648 if (_matchesIdentifier()) { 1247 if (_matchesIdentifier()) {
1649 if (_peek().matchesAny(const <TokenType>[ 1248 if (_peek().matchesAny(const <TokenType>[
1650 TokenType.EQ, 1249 TokenType.EQ,
1651 TokenType.COMMA, 1250 TokenType.COMMA,
1652 TokenType.SEMICOLON 1251 TokenType.SEMICOLON
1653 ])) { 1252 ])) {
1654 // 1253 //
1655 // We appear to have a variable declaration with a type of "void". 1254 // We appear to have a variable declaration with a type of "void".
1656 // 1255 //
1657 _reportErrorForNode(ParserErrorCode.VOID_VARIABLE, returnType); 1256 _reportErrorForNode(ParserErrorCode.VOID_VARIABLE, returnType);
1658 return _parseInitializedIdentifierList( 1257 return parseInitializedIdentifierList(
1659 commentAndMetadata, 1258 commentAndMetadata,
1660 modifiers.staticKeyword, 1259 modifiers.staticKeyword,
1661 _validateModifiersForField(modifiers), 1260 _validateModifiersForField(modifiers),
1662 returnType); 1261 returnType);
1663 } 1262 }
1664 } 1263 }
1665 if (_isOperator(_currentToken)) { 1264 if (_isOperator(_currentToken)) {
1666 // 1265 //
1667 // We appear to have found an operator declaration without the 1266 // We appear to have found an operator declaration without the
1668 // 'operator' keyword. 1267 // 'operator' keyword.
1669 // 1268 //
1670 _validateModifiersForOperator(modifiers); 1269 _validateModifiersForOperator(modifiers);
1671 return parseOperator( 1270 return parseOperator(
1672 commentAndMetadata, modifiers.externalKeyword, returnType); 1271 commentAndMetadata, modifiers.externalKeyword, returnType);
1673 } 1272 }
1674 _reportErrorForToken( 1273 _reportErrorForToken(
1675 ParserErrorCode.EXPECTED_EXECUTABLE, _currentToken); 1274 ParserErrorCode.EXPECTED_EXECUTABLE, _currentToken);
1676 return null; 1275 return null;
1677 } 1276 }
1678 } 1277 }
1679 Token next = _peek(); 1278 Token next = _peek();
1680 bool isFollowedByIdentifier = _tokenMatchesIdentifier(next); 1279 bool isFollowedByIdentifier = _tokenMatchesIdentifier(next);
1681 if (keyword == Keyword.GET && isFollowedByIdentifier) { 1280 if (keyword == Keyword.GET && isFollowedByIdentifier) {
1682 _validateModifiersForGetterOrSetterOrMethod(modifiers); 1281 _validateModifiersForGetterOrSetterOrMethod(modifiers);
1683 return _parseGetter(commentAndMetadata, modifiers.externalKeyword, 1282 return parseGetter(commentAndMetadata, modifiers.externalKeyword,
1684 modifiers.staticKeyword, null); 1283 modifiers.staticKeyword, null);
1685 } else if (keyword == Keyword.SET && isFollowedByIdentifier) { 1284 } else if (keyword == Keyword.SET && isFollowedByIdentifier) {
1686 _validateModifiersForGetterOrSetterOrMethod(modifiers); 1285 _validateModifiersForGetterOrSetterOrMethod(modifiers);
1687 return _parseSetter(commentAndMetadata, modifiers.externalKeyword, 1286 return parseSetter(commentAndMetadata, modifiers.externalKeyword,
1688 modifiers.staticKeyword, null); 1287 modifiers.staticKeyword, null);
1689 } else if (keyword == Keyword.OPERATOR && _isOperator(next)) { 1288 } else if (keyword == Keyword.OPERATOR && _isOperator(next)) {
1690 _validateModifiersForOperator(modifiers); 1289 _validateModifiersForOperator(modifiers);
1691 return _parseOperatorAfterKeyword( 1290 return _parseOperatorAfterKeyword(
1692 commentAndMetadata, modifiers.externalKeyword, null, getAndAdvance()); 1291 commentAndMetadata, modifiers.externalKeyword, null, getAndAdvance());
1693 } else if (!_matchesIdentifier()) { 1292 } else if (!_matchesIdentifier()) {
1694 // 1293 //
1695 // Recover from an error. 1294 // Recover from an error.
1696 // 1295 //
1697 if (_matchesKeyword(Keyword.CLASS)) { 1296 if (_matchesKeyword(Keyword.CLASS)) {
(...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after
1813 TokenType.EQ, 1412 TokenType.EQ,
1814 TokenType.COMMA, 1413 TokenType.COMMA,
1815 TokenType.SEMICOLON 1414 TokenType.SEMICOLON
1816 ])) { 1415 ])) {
1817 if (modifiers.constKeyword == null && 1416 if (modifiers.constKeyword == null &&
1818 modifiers.finalKeyword == null && 1417 modifiers.finalKeyword == null &&
1819 modifiers.varKeyword == null) { 1418 modifiers.varKeyword == null) {
1820 _reportErrorForCurrentToken( 1419 _reportErrorForCurrentToken(
1821 ParserErrorCode.MISSING_CONST_FINAL_VAR_OR_TYPE); 1420 ParserErrorCode.MISSING_CONST_FINAL_VAR_OR_TYPE);
1822 } 1421 }
1823 return _parseInitializedIdentifierList(commentAndMetadata, 1422 return parseInitializedIdentifierList(commentAndMetadata,
1824 modifiers.staticKeyword, _validateModifiersForField(modifiers), null); 1423 modifiers.staticKeyword, _validateModifiersForField(modifiers), null);
1825 } else if (keyword == Keyword.TYPEDEF) { 1424 } else if (keyword == Keyword.TYPEDEF) {
1826 _reportErrorForCurrentToken(ParserErrorCode.TYPEDEF_IN_CLASS); 1425 _reportErrorForCurrentToken(ParserErrorCode.TYPEDEF_IN_CLASS);
1827 // TODO(brianwilkerson) We don't currently have any way to capture the 1426 // TODO(brianwilkerson) We don't currently have any way to capture the
1828 // function type alias that was parsed. 1427 // function type alias that was parsed.
1829 _parseFunctionTypeAlias(commentAndMetadata, getAndAdvance()); 1428 _parseFunctionTypeAlias(commentAndMetadata, getAndAdvance());
1830 return null; 1429 return null;
1831 } else if (parseGenericMethods) { 1430 } else if (parseGenericMethods) {
1832 Token token = _skipTypeParameterList(_peek()); 1431 Token token = _skipTypeParameterList(_peek());
1833 if (token != null && _tokenMatches(token, TokenType.OPEN_PAREN)) { 1432 if (token != null && _tokenMatches(token, TokenType.OPEN_PAREN)) {
1834 return _parseMethodDeclarationAfterReturnType(commentAndMetadata, 1433 return _parseMethodDeclarationAfterReturnType(commentAndMetadata,
1835 modifiers.externalKeyword, modifiers.staticKeyword, null); 1434 modifiers.externalKeyword, modifiers.staticKeyword, null);
1836 } 1435 }
1837 } 1436 }
1838 TypeName type = _parseTypeNameAfterIdentifier(); 1437 TypeName type = _parseTypeNameAfterIdentifier();
1839 keyword = _currentToken.keyword; 1438 keyword = _currentToken.keyword;
1840 next = _peek(); 1439 next = _peek();
1841 isFollowedByIdentifier = _tokenMatchesIdentifier(next); 1440 isFollowedByIdentifier = _tokenMatchesIdentifier(next);
1842 if (keyword == Keyword.GET && isFollowedByIdentifier) { 1441 if (keyword == Keyword.GET && isFollowedByIdentifier) {
1843 _validateModifiersForGetterOrSetterOrMethod(modifiers); 1442 _validateModifiersForGetterOrSetterOrMethod(modifiers);
1844 return _parseGetter(commentAndMetadata, modifiers.externalKeyword, 1443 return parseGetter(commentAndMetadata, modifiers.externalKeyword,
1845 modifiers.staticKeyword, type); 1444 modifiers.staticKeyword, type);
1846 } else if (keyword == Keyword.SET && isFollowedByIdentifier) { 1445 } else if (keyword == Keyword.SET && isFollowedByIdentifier) {
1847 _validateModifiersForGetterOrSetterOrMethod(modifiers); 1446 _validateModifiersForGetterOrSetterOrMethod(modifiers);
1848 return _parseSetter(commentAndMetadata, modifiers.externalKeyword, 1447 return parseSetter(commentAndMetadata, modifiers.externalKeyword,
1849 modifiers.staticKeyword, type); 1448 modifiers.staticKeyword, type);
1850 } else if (keyword == Keyword.OPERATOR && _isOperator(next)) { 1449 } else if (keyword == Keyword.OPERATOR && _isOperator(next)) {
1851 _validateModifiersForOperator(modifiers); 1450 _validateModifiersForOperator(modifiers);
1852 return _parseOperatorAfterKeyword( 1451 return _parseOperatorAfterKeyword(
1853 commentAndMetadata, modifiers.externalKeyword, type, getAndAdvance()); 1452 commentAndMetadata, modifiers.externalKeyword, type, getAndAdvance());
1854 } else if (!_matchesIdentifier()) { 1453 } else if (!_matchesIdentifier()) {
1855 if (_matches(TokenType.CLOSE_CURLY_BRACKET)) { 1454 if (_matches(TokenType.CLOSE_CURLY_BRACKET)) {
1856 // 1455 //
1857 // We appear to have found an incomplete declaration at the end of the 1456 // We appear to have found an incomplete declaration at the end of the
1858 // class. At this point it consists of a type name, so we'll treat it as 1457 // class. At this point it consists of a type name, so we'll treat it as
1859 // a field declaration with a missing field name and semicolon. 1458 // a field declaration with a missing field name and semicolon.
1860 // 1459 //
1861 return _parseInitializedIdentifierList( 1460 return parseInitializedIdentifierList(
1862 commentAndMetadata, 1461 commentAndMetadata,
1863 modifiers.staticKeyword, 1462 modifiers.staticKeyword,
1864 _validateModifiersForField(modifiers), 1463 _validateModifiersForField(modifiers),
1865 type); 1464 type);
1866 } 1465 }
1867 if (_isOperator(_currentToken)) { 1466 if (_isOperator(_currentToken)) {
1868 // 1467 //
1869 // We appear to have found an operator declaration without the 1468 // We appear to have found an operator declaration without the
1870 // 'operator' keyword. 1469 // 'operator' keyword.
1871 // 1470 //
1872 _validateModifiersForOperator(modifiers); 1471 _validateModifiersForOperator(modifiers);
1873 return parseOperator( 1472 return parseOperator(
1874 commentAndMetadata, modifiers.externalKeyword, type); 1473 commentAndMetadata, modifiers.externalKeyword, type);
1875 } 1474 }
1876 // 1475 //
1877 // We appear to have found an incomplete declaration before another 1476 // We appear to have found an incomplete declaration before another
1878 // declaration. At this point it consists of a type name, so we'll treat 1477 // declaration. At this point it consists of a type name, so we'll treat
1879 // it as a field declaration with a missing field name and semicolon. 1478 // it as a field declaration with a missing field name and semicolon.
1880 // 1479 //
1881 _reportErrorForToken( 1480 _reportErrorForToken(
1882 ParserErrorCode.EXPECTED_CLASS_MEMBER, _currentToken); 1481 ParserErrorCode.EXPECTED_CLASS_MEMBER, _currentToken);
1883 try { 1482 try {
1884 _lockErrorListener(); 1483 _lockErrorListener();
1885 return _parseInitializedIdentifierList( 1484 return parseInitializedIdentifierList(
1886 commentAndMetadata, 1485 commentAndMetadata,
1887 modifiers.staticKeyword, 1486 modifiers.staticKeyword,
1888 _validateModifiersForField(modifiers), 1487 _validateModifiersForField(modifiers),
1889 type); 1488 type);
1890 } finally { 1489 } finally {
1891 _unlockErrorListener(); 1490 _unlockErrorListener();
1892 } 1491 }
1893 } else if (_tokenMatches(next, TokenType.OPEN_PAREN)) { 1492 } else if (_tokenMatches(next, TokenType.OPEN_PAREN)) {
1894 SimpleIdentifier methodName = 1493 SimpleIdentifier methodName =
1895 _parseSimpleIdentifierUnchecked(isDeclaration: true); 1494 _parseSimpleIdentifierUnchecked(isDeclaration: true);
(...skipping 24 matching lines...) Expand all
1920 } else if (parseGenericMethods && _tokenMatches(next, TokenType.LT)) { 1519 } else if (parseGenericMethods && _tokenMatches(next, TokenType.LT)) {
1921 return _parseMethodDeclarationAfterReturnType(commentAndMetadata, 1520 return _parseMethodDeclarationAfterReturnType(commentAndMetadata,
1922 modifiers.externalKeyword, modifiers.staticKeyword, type); 1521 modifiers.externalKeyword, modifiers.staticKeyword, type);
1923 } else if (_tokenMatches(next, TokenType.OPEN_CURLY_BRACKET)) { 1522 } else if (_tokenMatches(next, TokenType.OPEN_CURLY_BRACKET)) {
1924 // We have found "TypeName identifier {", and are guessing that this is a 1523 // We have found "TypeName identifier {", and are guessing that this is a
1925 // getter without the keyword 'get'. 1524 // getter without the keyword 'get'.
1926 _validateModifiersForGetterOrSetterOrMethod(modifiers); 1525 _validateModifiersForGetterOrSetterOrMethod(modifiers);
1927 _reportErrorForCurrentToken(ParserErrorCode.MISSING_GET); 1526 _reportErrorForCurrentToken(ParserErrorCode.MISSING_GET);
1928 _currentToken = _injectToken( 1527 _currentToken = _injectToken(
1929 new Parser_SyntheticKeywordToken(Keyword.GET, _currentToken.offset)); 1528 new Parser_SyntheticKeywordToken(Keyword.GET, _currentToken.offset));
1930 return _parseGetter(commentAndMetadata, modifiers.externalKeyword, 1529 return parseGetter(commentAndMetadata, modifiers.externalKeyword,
1931 modifiers.staticKeyword, type); 1530 modifiers.staticKeyword, type);
1932 } 1531 }
1933 return _parseInitializedIdentifierList(commentAndMetadata, 1532 return parseInitializedIdentifierList(commentAndMetadata,
1934 modifiers.staticKeyword, _validateModifiersForField(modifiers), type); 1533 modifiers.staticKeyword, _validateModifiersForField(modifiers), type);
1935 } 1534 }
1936 1535
1937 /** 1536 /**
1938 * Parse a class type alias. The [commentAndMetadata] is the metadata to be 1537 * Parse a class type alias. The [commentAndMetadata] is the metadata to be
1939 * associated with the member. The [abstractKeyword] is the token representing 1538 * associated with the member. The [abstractKeyword] is the token representing
1940 * the 'abstract' keyword. The [classKeyword] is the token representing the 1539 * the 'abstract' keyword. The [classKeyword] is the token representing the
1941 * 'class' keyword. Return the class type alias that was parsed. 1540 * 'class' keyword. Return the class type alias that was parsed.
1942 * 1541 *
1943 * This method assumes that the current token matches an identifier. 1542 * This method assumes that the current token matches an identifier.
(...skipping 19 matching lines...) Expand all
1963 /** 1562 /**
1964 * Parse a single combinator. Return the combinator that was parsed, or `null` 1563 * Parse a single combinator. Return the combinator that was parsed, or `null`
1965 * if no combinator is found. 1564 * if no combinator is found.
1966 * 1565 *
1967 * combinator ::= 1566 * combinator ::=
1968 * 'show' identifier (',' identifier)* 1567 * 'show' identifier (',' identifier)*
1969 * | 'hide' identifier (',' identifier)* 1568 * | 'hide' identifier (',' identifier)*
1970 */ 1569 */
1971 Combinator parseCombinator() { 1570 Combinator parseCombinator() {
1972 if (_matchesString(_SHOW)) { 1571 if (_matchesString(_SHOW)) {
1973 return new ShowCombinator(getAndAdvance(), _parseIdentifierList()); 1572 return new ShowCombinator(getAndAdvance(), parseIdentifierList());
1974 } else if (_matchesString(_HIDE)) { 1573 } else if (_matchesString(_HIDE)) {
1975 return new HideCombinator(getAndAdvance(), _parseIdentifierList()); 1574 return new HideCombinator(getAndAdvance(), parseIdentifierList());
1976 } 1575 }
1977 return null; 1576 return null;
1978 } 1577 }
1979 1578
1980 /** 1579 /**
1981 * Parse a list of combinators in a directive. Return the combinators that 1580 * Parse a list of combinators in a directive. Return the combinators that
1982 * were parsed, or `null` if there are no combinators. 1581 * were parsed, or `null` if there are no combinators.
1983 * 1582 *
1984 * combinator ::= 1583 * combinator ::=
1985 * 'show' identifier (',' identifier)* 1584 * 'show' identifier (',' identifier)*
(...skipping 141 matching lines...) Expand 10 before | Expand all | Expand 10 after
2127 return null; 1726 return null;
2128 } 1727 }
2129 } 1728 }
2130 } catch (exception) { 1729 } catch (exception) {
2131 // Ignored because we assume that it wasn't a real comment reference. 1730 // Ignored because we assume that it wasn't a real comment reference.
2132 } 1731 }
2133 return null; 1732 return null;
2134 } 1733 }
2135 1734
2136 /** 1735 /**
1736 * Parse all of the comment references occurring in the given array of
1737 * documentation comments. The [tokens] are the comment tokens representing
1738 * the documentation comments to be parsed. Return the comment references that
1739 * were parsed.
1740 *
1741 * commentReference ::=
1742 * '[' 'new'? qualified ']' libraryReference?
1743 *
1744 * libraryReference ::=
1745 * '(' stringLiteral ')'
1746 */
1747 List<CommentReference> parseCommentReferences(
1748 List<DocumentationCommentToken> tokens) {
1749 List<CommentReference> references = <CommentReference>[];
1750 bool isInGitHubCodeBlock = false;
1751 for (DocumentationCommentToken token in tokens) {
1752 String comment = token.lexeme;
1753 // Skip GitHub code blocks.
1754 // https://help.github.com/articles/creating-and-highlighting-code-blocks/
1755 if (tokens.length != 1) {
1756 if (comment.indexOf('```') != -1) {
1757 isInGitHubCodeBlock = !isInGitHubCodeBlock;
1758 }
1759 if (isInGitHubCodeBlock) {
1760 continue;
1761 }
1762 }
1763 // Remove GitHub include code.
1764 comment = _removeGitHubInlineCode(comment);
1765 // Find references.
1766 int length = comment.length;
1767 List<List<int>> codeBlockRanges = _getCodeBlockRanges(comment);
1768 int leftIndex = comment.indexOf('[');
1769 while (leftIndex >= 0 && leftIndex + 1 < length) {
1770 List<int> range = _findRange(codeBlockRanges, leftIndex);
1771 if (range == null) {
1772 int nameOffset = token.offset + leftIndex + 1;
1773 int rightIndex = comment.indexOf(']', leftIndex);
1774 if (rightIndex >= 0) {
1775 int firstChar = comment.codeUnitAt(leftIndex + 1);
1776 if (firstChar != 0x27 && firstChar != 0x22) {
1777 if (_isLinkText(comment, rightIndex)) {
1778 // TODO(brianwilkerson) Handle the case where there's a library
1779 // URI in the link text.
1780 } else {
1781 CommentReference reference = parseCommentReference(
1782 comment.substring(leftIndex + 1, rightIndex), nameOffset);
1783 if (reference != null) {
1784 references.add(reference);
1785 token.references.add(reference.beginToken);
1786 }
1787 }
1788 }
1789 } else {
1790 // terminating ']' is not typed yet
1791 int charAfterLeft = comment.codeUnitAt(leftIndex + 1);
1792 Token nameToken;
1793 if (Character.isLetterOrDigit(charAfterLeft)) {
1794 int nameEnd = StringUtilities.indexOfFirstNotLetterDigit(
1795 comment, leftIndex + 1);
1796 String name = comment.substring(leftIndex + 1, nameEnd);
1797 nameToken =
1798 new StringToken(TokenType.IDENTIFIER, name, nameOffset);
1799 } else {
1800 nameToken = new SyntheticStringToken(
1801 TokenType.IDENTIFIER, '', nameOffset);
1802 }
1803 nameToken.setNext(new SimpleToken(TokenType.EOF, nameToken.end));
1804 references.add(
1805 new CommentReference(null, new SimpleIdentifier(nameToken)));
1806 token.references.add(nameToken);
1807 // next character
1808 rightIndex = leftIndex + 1;
1809 }
1810 leftIndex = comment.indexOf('[', rightIndex);
1811 } else {
1812 leftIndex = comment.indexOf('[', range[1]);
1813 }
1814 }
1815 }
1816 return references;
1817 }
1818
1819 /**
2137 * Parse a compilation unit, starting with the given [token]. Return the 1820 * Parse a compilation unit, starting with the given [token]. Return the
2138 * compilation unit that was parsed. 1821 * compilation unit that was parsed.
2139 */ 1822 */
2140 CompilationUnit parseCompilationUnit(Token token) { 1823 CompilationUnit parseCompilationUnit(Token token) {
2141 _currentToken = token; 1824 _currentToken = token;
2142 return parseCompilationUnit2(); 1825 return parseCompilationUnit2();
2143 } 1826 }
2144 1827
2145 /** 1828 /**
2146 * Parse a compilation unit. Return the compilation unit that was parsed. 1829 * Parse a compilation unit. Return the compilation unit that was parsed.
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
2188 keyword == Keyword.PART) && 1871 keyword == Keyword.PART) &&
2189 nextType != TokenType.PERIOD && 1872 nextType != TokenType.PERIOD &&
2190 nextType != TokenType.LT && 1873 nextType != TokenType.LT &&
2191 nextType != TokenType.OPEN_PAREN) { 1874 nextType != TokenType.OPEN_PAREN) {
2192 Directive parseDirective() { 1875 Directive parseDirective() {
2193 if (keyword == Keyword.IMPORT) { 1876 if (keyword == Keyword.IMPORT) {
2194 if (partDirectiveFound) { 1877 if (partDirectiveFound) {
2195 _reportErrorForCurrentToken( 1878 _reportErrorForCurrentToken(
2196 ParserErrorCode.IMPORT_DIRECTIVE_AFTER_PART_DIRECTIVE); 1879 ParserErrorCode.IMPORT_DIRECTIVE_AFTER_PART_DIRECTIVE);
2197 } 1880 }
2198 return _parseImportDirective(commentAndMetadata); 1881 return parseImportDirective(commentAndMetadata);
2199 } else if (keyword == Keyword.EXPORT) { 1882 } else if (keyword == Keyword.EXPORT) {
2200 if (partDirectiveFound) { 1883 if (partDirectiveFound) {
2201 _reportErrorForCurrentToken( 1884 _reportErrorForCurrentToken(
2202 ParserErrorCode.EXPORT_DIRECTIVE_AFTER_PART_DIRECTIVE); 1885 ParserErrorCode.EXPORT_DIRECTIVE_AFTER_PART_DIRECTIVE);
2203 } 1886 }
2204 return _parseExportDirective(commentAndMetadata); 1887 return parseExportDirective(commentAndMetadata);
2205 } else if (keyword == Keyword.LIBRARY) { 1888 } else if (keyword == Keyword.LIBRARY) {
2206 if (libraryDirectiveFound) { 1889 if (libraryDirectiveFound) {
2207 _reportErrorForCurrentToken( 1890 _reportErrorForCurrentToken(
2208 ParserErrorCode.MULTIPLE_LIBRARY_DIRECTIVES); 1891 ParserErrorCode.MULTIPLE_LIBRARY_DIRECTIVES);
2209 } else { 1892 } else {
2210 if (directives.length > 0) { 1893 if (directives.length > 0) {
2211 _reportErrorForCurrentToken( 1894 _reportErrorForCurrentToken(
2212 ParserErrorCode.LIBRARY_DIRECTIVE_NOT_FIRST); 1895 ParserErrorCode.LIBRARY_DIRECTIVE_NOT_FIRST);
2213 } 1896 }
2214 libraryDirectiveFound = true; 1897 libraryDirectiveFound = true;
2215 } 1898 }
2216 return _parseLibraryDirective(commentAndMetadata); 1899 return parseLibraryDirective(commentAndMetadata);
2217 } else if (keyword == Keyword.PART) { 1900 } else if (keyword == Keyword.PART) {
2218 if (_tokenMatchesString(_peek(), _OF)) { 1901 if (_tokenMatchesString(_peek(), _OF)) {
2219 partOfDirectiveFound = true; 1902 partOfDirectiveFound = true;
2220 return _parsePartOfDirective(commentAndMetadata); 1903 return _parsePartOfDirective(commentAndMetadata);
2221 } else { 1904 } else {
2222 partDirectiveFound = true; 1905 partDirectiveFound = true;
2223 return _parsePartDirective(commentAndMetadata); 1906 return _parsePartDirective(commentAndMetadata);
2224 } 1907 }
2225 } else { 1908 } else {
2226 // Internal error: this method should not have been invoked if the 1909 // Internal error: this method should not have been invoked if the
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after
2310 * | external functionSignature 1993 * | external functionSignature
2311 * | external getterSignature 1994 * | external getterSignature
2312 * | external setterSignature 1995 * | external setterSignature
2313 * | functionSignature functionBody 1996 * | functionSignature functionBody
2314 * | returnType? getOrSet identifier formalParameterList functionBody 1997 * | returnType? getOrSet identifier formalParameterList functionBody
2315 * | (final | const) type? staticFinalDeclarationList ';' 1998 * | (final | const) type? staticFinalDeclarationList ';'
2316 * | variableDeclaration ';' 1999 * | variableDeclaration ';'
2317 */ 2000 */
2318 CompilationUnitMember parseCompilationUnitMember( 2001 CompilationUnitMember parseCompilationUnitMember(
2319 CommentAndMetadata commentAndMetadata) { 2002 CommentAndMetadata commentAndMetadata) {
2320 Modifiers modifiers = _parseModifiers(); 2003 Modifiers modifiers = parseModifiers();
2321 Keyword keyword = _currentToken.keyword; 2004 Keyword keyword = _currentToken.keyword;
2322 if (keyword == Keyword.CLASS) { 2005 if (keyword == Keyword.CLASS) {
2323 return parseClassDeclaration( 2006 return parseClassDeclaration(
2324 commentAndMetadata, _validateModifiersForClass(modifiers)); 2007 commentAndMetadata, _validateModifiersForClass(modifiers));
2325 } 2008 }
2326 Token next = _peek(); 2009 Token next = _peek();
2327 TokenType nextType = next.type; 2010 TokenType nextType = next.type;
2328 if (keyword == Keyword.TYPEDEF && 2011 if (keyword == Keyword.TYPEDEF &&
2329 nextType != TokenType.PERIOD && 2012 nextType != TokenType.PERIOD &&
2330 nextType != TokenType.LT && 2013 nextType != TokenType.LT &&
2331 nextType != TokenType.OPEN_PAREN) { 2014 nextType != TokenType.OPEN_PAREN) {
2332 _validateModifiersForTypedef(modifiers); 2015 _validateModifiersForTypedef(modifiers);
2333 return _parseTypeAlias(commentAndMetadata); 2016 return parseTypeAlias(commentAndMetadata);
2334 } else if (keyword == Keyword.ENUM) { 2017 } else if (keyword == Keyword.ENUM) {
2335 _validateModifiersForEnum(modifiers); 2018 _validateModifiersForEnum(modifiers);
2336 return parseEnumDeclaration(commentAndMetadata); 2019 return parseEnumDeclaration(commentAndMetadata);
2337 } else if (keyword == Keyword.VOID) { 2020 } else if (keyword == Keyword.VOID) {
2338 TypeName returnType = 2021 TypeName returnType =
2339 new TypeName(new SimpleIdentifier(getAndAdvance()), null); 2022 new TypeName(new SimpleIdentifier(getAndAdvance()), null);
2340 keyword = _currentToken.keyword; 2023 keyword = _currentToken.keyword;
2341 next = _peek(); 2024 next = _peek();
2342 if ((keyword == Keyword.GET || keyword == Keyword.SET) && 2025 if ((keyword == Keyword.GET || keyword == Keyword.SET) &&
2343 _tokenMatchesIdentifier(next)) { 2026 _tokenMatchesIdentifier(next)) {
2344 _validateModifiersForTopLevelFunction(modifiers); 2027 _validateModifiersForTopLevelFunction(modifiers);
2345 return _parseFunctionDeclaration( 2028 return parseFunctionDeclaration(
2346 commentAndMetadata, modifiers.externalKeyword, returnType); 2029 commentAndMetadata, modifiers.externalKeyword, returnType);
2347 } else if (keyword == Keyword.OPERATOR && _isOperator(next)) { 2030 } else if (keyword == Keyword.OPERATOR && _isOperator(next)) {
2348 _reportErrorForToken(ParserErrorCode.TOP_LEVEL_OPERATOR, _currentToken); 2031 _reportErrorForToken(ParserErrorCode.TOP_LEVEL_OPERATOR, _currentToken);
2349 return _convertToFunctionDeclaration(_parseOperatorAfterKeyword( 2032 return _convertToFunctionDeclaration(_parseOperatorAfterKeyword(
2350 commentAndMetadata, 2033 commentAndMetadata,
2351 modifiers.externalKeyword, 2034 modifiers.externalKeyword,
2352 returnType, 2035 returnType,
2353 getAndAdvance())); 2036 getAndAdvance()));
2354 } else if (_matchesIdentifier() && 2037 } else if (_matchesIdentifier() &&
2355 next.matchesAny(const <TokenType>[ 2038 next.matchesAny(const <TokenType>[
2356 TokenType.OPEN_PAREN, 2039 TokenType.OPEN_PAREN,
2357 TokenType.OPEN_CURLY_BRACKET, 2040 TokenType.OPEN_CURLY_BRACKET,
2358 TokenType.FUNCTION, 2041 TokenType.FUNCTION,
2359 TokenType.LT 2042 TokenType.LT
2360 ])) { 2043 ])) {
2361 _validateModifiersForTopLevelFunction(modifiers); 2044 _validateModifiersForTopLevelFunction(modifiers);
2362 return _parseFunctionDeclaration( 2045 return parseFunctionDeclaration(
2363 commentAndMetadata, modifiers.externalKeyword, returnType); 2046 commentAndMetadata, modifiers.externalKeyword, returnType);
2364 } else { 2047 } else {
2365 // 2048 //
2366 // We have found an error of some kind. Try to recover. 2049 // We have found an error of some kind. Try to recover.
2367 // 2050 //
2368 if (_matchesIdentifier()) { 2051 if (_matchesIdentifier()) {
2369 if (next.matchesAny(const <TokenType>[ 2052 if (next.matchesAny(const <TokenType>[
2370 TokenType.EQ, 2053 TokenType.EQ,
2371 TokenType.COMMA, 2054 TokenType.COMMA,
2372 TokenType.SEMICOLON 2055 TokenType.SEMICOLON
(...skipping 10 matching lines...) Expand all
2383 _expect(TokenType.SEMICOLON)); 2066 _expect(TokenType.SEMICOLON));
2384 } 2067 }
2385 } 2068 }
2386 _reportErrorForToken( 2069 _reportErrorForToken(
2387 ParserErrorCode.EXPECTED_EXECUTABLE, _currentToken); 2070 ParserErrorCode.EXPECTED_EXECUTABLE, _currentToken);
2388 return null; 2071 return null;
2389 } 2072 }
2390 } else if ((keyword == Keyword.GET || keyword == Keyword.SET) && 2073 } else if ((keyword == Keyword.GET || keyword == Keyword.SET) &&
2391 _tokenMatchesIdentifier(next)) { 2074 _tokenMatchesIdentifier(next)) {
2392 _validateModifiersForTopLevelFunction(modifiers); 2075 _validateModifiersForTopLevelFunction(modifiers);
2393 return _parseFunctionDeclaration( 2076 return parseFunctionDeclaration(
2394 commentAndMetadata, modifiers.externalKeyword, null); 2077 commentAndMetadata, modifiers.externalKeyword, null);
2395 } else if (keyword == Keyword.OPERATOR && _isOperator(next)) { 2078 } else if (keyword == Keyword.OPERATOR && _isOperator(next)) {
2396 _reportErrorForToken(ParserErrorCode.TOP_LEVEL_OPERATOR, _currentToken); 2079 _reportErrorForToken(ParserErrorCode.TOP_LEVEL_OPERATOR, _currentToken);
2397 return _convertToFunctionDeclaration(_parseOperatorAfterKeyword( 2080 return _convertToFunctionDeclaration(_parseOperatorAfterKeyword(
2398 commentAndMetadata, 2081 commentAndMetadata,
2399 modifiers.externalKeyword, 2082 modifiers.externalKeyword,
2400 null, 2083 null,
2401 getAndAdvance())); 2084 getAndAdvance()));
2402 } else if (!_matchesIdentifier()) { 2085 } else if (!_matchesIdentifier()) {
2403 Token keyword = modifiers.varKeyword; 2086 Token keyword = modifiers.varKeyword;
(...skipping 13 matching lines...) Expand all
2417 List<VariableDeclaration> variables = <VariableDeclaration>[variable]; 2100 List<VariableDeclaration> variables = <VariableDeclaration>[variable];
2418 return new TopLevelVariableDeclaration( 2101 return new TopLevelVariableDeclaration(
2419 commentAndMetadata.comment, 2102 commentAndMetadata.comment,
2420 commentAndMetadata.metadata, 2103 commentAndMetadata.metadata,
2421 new VariableDeclarationList(null, null, keyword, null, variables), 2104 new VariableDeclarationList(null, null, keyword, null, variables),
2422 _expect(TokenType.SEMICOLON)); 2105 _expect(TokenType.SEMICOLON));
2423 } 2106 }
2424 _reportErrorForToken(ParserErrorCode.EXPECTED_EXECUTABLE, _currentToken); 2107 _reportErrorForToken(ParserErrorCode.EXPECTED_EXECUTABLE, _currentToken);
2425 return null; 2108 return null;
2426 } else if (_isPeekGenericTypeParametersAndOpenParen()) { 2109 } else if (_isPeekGenericTypeParametersAndOpenParen()) {
2427 return _parseFunctionDeclaration( 2110 return parseFunctionDeclaration(
2428 commentAndMetadata, modifiers.externalKeyword, null); 2111 commentAndMetadata, modifiers.externalKeyword, null);
2429 } else if (_tokenMatches(next, TokenType.OPEN_PAREN)) { 2112 } else if (_tokenMatches(next, TokenType.OPEN_PAREN)) {
2430 TypeName returnType = _parseOptionalTypeNameComment(); 2113 TypeName returnType = _parseOptionalTypeNameComment();
2431 _validateModifiersForTopLevelFunction(modifiers); 2114 _validateModifiersForTopLevelFunction(modifiers);
2432 return _parseFunctionDeclaration( 2115 return parseFunctionDeclaration(
2433 commentAndMetadata, modifiers.externalKeyword, returnType); 2116 commentAndMetadata, modifiers.externalKeyword, returnType);
2434 } else if (next.matchesAny(const <TokenType>[ 2117 } else if (next.matchesAny(const <TokenType>[
2435 TokenType.EQ, 2118 TokenType.EQ,
2436 TokenType.COMMA, 2119 TokenType.COMMA,
2437 TokenType.SEMICOLON 2120 TokenType.SEMICOLON
2438 ])) { 2121 ])) {
2439 if (modifiers.constKeyword == null && 2122 if (modifiers.constKeyword == null &&
2440 modifiers.finalKeyword == null && 2123 modifiers.finalKeyword == null &&
2441 modifiers.varKeyword == null) { 2124 modifiers.varKeyword == null) {
2442 _reportErrorForCurrentToken( 2125 _reportErrorForCurrentToken(
2443 ParserErrorCode.MISSING_CONST_FINAL_VAR_OR_TYPE); 2126 ParserErrorCode.MISSING_CONST_FINAL_VAR_OR_TYPE);
2444 } 2127 }
2445 return new TopLevelVariableDeclaration( 2128 return new TopLevelVariableDeclaration(
2446 commentAndMetadata.comment, 2129 commentAndMetadata.comment,
2447 commentAndMetadata.metadata, 2130 commentAndMetadata.metadata,
2448 parseVariableDeclarationListAfterType( 2131 parseVariableDeclarationListAfterType(
2449 null, _validateModifiersForTopLevelVariable(modifiers), null), 2132 null, _validateModifiersForTopLevelVariable(modifiers), null),
2450 _expect(TokenType.SEMICOLON)); 2133 _expect(TokenType.SEMICOLON));
2451 } 2134 }
2452 TypeName returnType = parseReturnType(); 2135 TypeName returnType = parseReturnType();
2453 keyword = _currentToken.keyword; 2136 keyword = _currentToken.keyword;
2454 next = _peek(); 2137 next = _peek();
2455 if ((keyword == Keyword.GET || keyword == Keyword.SET) && 2138 if ((keyword == Keyword.GET || keyword == Keyword.SET) &&
2456 _tokenMatchesIdentifier(next)) { 2139 _tokenMatchesIdentifier(next)) {
2457 _validateModifiersForTopLevelFunction(modifiers); 2140 _validateModifiersForTopLevelFunction(modifiers);
2458 return _parseFunctionDeclaration( 2141 return parseFunctionDeclaration(
2459 commentAndMetadata, modifiers.externalKeyword, returnType); 2142 commentAndMetadata, modifiers.externalKeyword, returnType);
2460 } else if (keyword == Keyword.OPERATOR && _isOperator(next)) { 2143 } else if (keyword == Keyword.OPERATOR && _isOperator(next)) {
2461 _reportErrorForToken(ParserErrorCode.TOP_LEVEL_OPERATOR, _currentToken); 2144 _reportErrorForToken(ParserErrorCode.TOP_LEVEL_OPERATOR, _currentToken);
2462 return _convertToFunctionDeclaration(_parseOperatorAfterKeyword( 2145 return _convertToFunctionDeclaration(_parseOperatorAfterKeyword(
2463 commentAndMetadata, 2146 commentAndMetadata,
2464 modifiers.externalKeyword, 2147 modifiers.externalKeyword,
2465 returnType, 2148 returnType,
2466 getAndAdvance())); 2149 getAndAdvance()));
2467 } else if (_matches(TokenType.AT)) { 2150 } else if (_matches(TokenType.AT)) {
2468 return new TopLevelVariableDeclaration( 2151 return new TopLevelVariableDeclaration(
(...skipping 20 matching lines...) Expand all
2489 commentAndMetadata.metadata, 2172 commentAndMetadata.metadata,
2490 new VariableDeclarationList(null, null, null, returnType, variables), 2173 new VariableDeclarationList(null, null, null, returnType, variables),
2491 semicolon); 2174 semicolon);
2492 } else if (next.matchesAny(const <TokenType>[ 2175 } else if (next.matchesAny(const <TokenType>[
2493 TokenType.OPEN_PAREN, 2176 TokenType.OPEN_PAREN,
2494 TokenType.FUNCTION, 2177 TokenType.FUNCTION,
2495 TokenType.OPEN_CURLY_BRACKET, 2178 TokenType.OPEN_CURLY_BRACKET,
2496 TokenType.LT 2179 TokenType.LT
2497 ])) { 2180 ])) {
2498 _validateModifiersForTopLevelFunction(modifiers); 2181 _validateModifiersForTopLevelFunction(modifiers);
2499 return _parseFunctionDeclaration( 2182 return parseFunctionDeclaration(
2500 commentAndMetadata, modifiers.externalKeyword, returnType); 2183 commentAndMetadata, modifiers.externalKeyword, returnType);
2501 } 2184 }
2502 return new TopLevelVariableDeclaration( 2185 return new TopLevelVariableDeclaration(
2503 commentAndMetadata.comment, 2186 commentAndMetadata.comment,
2504 commentAndMetadata.metadata, 2187 commentAndMetadata.metadata,
2505 parseVariableDeclarationListAfterType( 2188 parseVariableDeclarationListAfterType(
2506 null, _validateModifiersForTopLevelVariable(modifiers), returnType), 2189 null, _validateModifiersForTopLevelVariable(modifiers), returnType),
2507 _expect(TokenType.SEMICOLON)); 2190 _expect(TokenType.SEMICOLON));
2508 } 2191 }
2509 2192
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after
2571 * | listLiteral 2254 * | listLiteral
2572 * | mapLiteral 2255 * | mapLiteral
2573 */ 2256 */
2574 Expression parseConstExpression() { 2257 Expression parseConstExpression() {
2575 Token keyword = getAndAdvance(); 2258 Token keyword = getAndAdvance();
2576 TokenType type = _currentToken.type; 2259 TokenType type = _currentToken.type;
2577 if (type == TokenType.LT || _injectGenericCommentTypeList()) { 2260 if (type == TokenType.LT || _injectGenericCommentTypeList()) {
2578 return parseListOrMapLiteral(keyword); 2261 return parseListOrMapLiteral(keyword);
2579 } else if (type == TokenType.OPEN_SQUARE_BRACKET || 2262 } else if (type == TokenType.OPEN_SQUARE_BRACKET ||
2580 type == TokenType.INDEX) { 2263 type == TokenType.INDEX) {
2581 return _parseListLiteral(keyword, null); 2264 return parseListLiteral(keyword, null);
2582 } else if (type == TokenType.OPEN_CURLY_BRACKET) { 2265 } else if (type == TokenType.OPEN_CURLY_BRACKET) {
2583 return _parseMapLiteral(keyword, null); 2266 return parseMapLiteral(keyword, null);
2584 } 2267 }
2585 return _parseInstanceCreationExpression(keyword); 2268 return parseInstanceCreationExpression(keyword);
2586 } 2269 }
2587 2270
2588 /** 2271 /**
2272 * Parse a field initializer within a constructor. The flag [hasThis] should
2273 * be true if the current token is `this`. Return the field initializer that
2274 * was parsed.
2275 *
2276 * fieldInitializer:
2277 * ('this' '.')? identifier '=' conditionalExpression cascadeSection*
2278 */
2279 ConstructorFieldInitializer parseConstructorFieldInitializer(bool hasThis) {
2280 Token keywordToken = null;
2281 Token period = null;
2282 if (hasThis) {
2283 keywordToken = getAndAdvance();
2284 period = _expect(TokenType.PERIOD);
2285 }
2286 SimpleIdentifier fieldName = parseSimpleIdentifier();
2287 Token equals = null;
2288 TokenType type = _currentToken.type;
2289 if (type == TokenType.EQ) {
2290 equals = getAndAdvance();
2291 } else {
2292 _reportErrorForCurrentToken(
2293 ParserErrorCode.MISSING_ASSIGNMENT_IN_INITIALIZER);
2294 Keyword keyword = _currentToken.keyword;
2295 if (keyword != Keyword.THIS &&
2296 keyword != Keyword.SUPER &&
2297 type != TokenType.OPEN_CURLY_BRACKET &&
2298 type != TokenType.FUNCTION) {
2299 equals = _createSyntheticToken(TokenType.EQ);
2300 } else {
2301 return new ConstructorFieldInitializer(keywordToken, period, fieldName,
2302 _createSyntheticToken(TokenType.EQ), createSyntheticIdentifier());
2303 }
2304 }
2305 bool wasInInitializer = _inInitializer;
2306 _inInitializer = true;
2307 try {
2308 Expression expression = parseConditionalExpression();
2309 if (_matches(TokenType.PERIOD_PERIOD)) {
2310 List<Expression> cascadeSections = <Expression>[];
2311 do {
2312 Expression section = parseCascadeSection();
2313 if (section != null) {
2314 cascadeSections.add(section);
2315 }
2316 } while (_matches(TokenType.PERIOD_PERIOD));
2317 expression = new CascadeExpression(expression, cascadeSections);
2318 }
2319 return new ConstructorFieldInitializer(
2320 keywordToken, period, fieldName, equals, expression);
2321 } finally {
2322 _inInitializer = wasInInitializer;
2323 }
2324 }
2325
2326 /**
2589 * Parse the name of a constructor. Return the constructor name that was 2327 * Parse the name of a constructor. Return the constructor name that was
2590 * parsed. 2328 * parsed.
2591 * 2329 *
2592 * constructorName: 2330 * constructorName:
2593 * type ('.' identifier)? 2331 * type ('.' identifier)?
2594 */ 2332 */
2595 ConstructorName parseConstructorName() { 2333 ConstructorName parseConstructorName() {
2596 TypeName type = parseTypeName(false); 2334 TypeName type = parseTypeName(false);
2597 Token period = null; 2335 Token period = null;
2598 SimpleIdentifier name = null; 2336 SimpleIdentifier name = null;
(...skipping 24 matching lines...) Expand all
2623 } 2361 }
2624 if (_inSwitch && !_inLoop && label == null) { 2362 if (_inSwitch && !_inLoop && label == null) {
2625 _reportErrorForToken( 2363 _reportErrorForToken(
2626 ParserErrorCode.CONTINUE_WITHOUT_LABEL_IN_CASE, continueKeyword); 2364 ParserErrorCode.CONTINUE_WITHOUT_LABEL_IN_CASE, continueKeyword);
2627 } 2365 }
2628 Token semicolon = _expect(TokenType.SEMICOLON); 2366 Token semicolon = _expect(TokenType.SEMICOLON);
2629 return new ContinueStatement(continueKeyword, label, semicolon); 2367 return new ContinueStatement(continueKeyword, label, semicolon);
2630 } 2368 }
2631 2369
2632 /** 2370 /**
2371 * Parse a directive. The [commentAndMetadata] is the metadata to be
2372 * associated with the directive. Return the directive that was parsed.
2373 *
2374 * directive ::=
2375 * exportDirective
2376 * | libraryDirective
2377 * | importDirective
2378 * | partDirective
2379 */
2380 Directive parseDirective(CommentAndMetadata commentAndMetadata) {
2381 if (_matchesKeyword(Keyword.IMPORT)) {
2382 return parseImportDirective(commentAndMetadata);
2383 } else if (_matchesKeyword(Keyword.EXPORT)) {
2384 return parseExportDirective(commentAndMetadata);
2385 } else if (_matchesKeyword(Keyword.LIBRARY)) {
2386 return parseLibraryDirective(commentAndMetadata);
2387 } else if (_matchesKeyword(Keyword.PART)) {
2388 return parsePartOrPartOfDirective(commentAndMetadata);
2389 } else {
2390 // Internal error: this method should not have been invoked if the current
2391 // token was something other than one of the above.
2392 throw new StateError(
2393 "parseDirective invoked in an invalid state; currentToken = $_currentT oken");
2394 }
2395 }
2396
2397 /**
2633 * Parse the script tag and directives in a compilation unit, starting with 2398 * Parse the script tag and directives in a compilation unit, starting with
2634 * the given [token], until the first non-directive is encountered. The 2399 * the given [token], until the first non-directive is encountered. The
2635 * remainder of the compilation unit will not be parsed. Specifically, if 2400 * remainder of the compilation unit will not be parsed. Specifically, if
2636 * there are directives later in the file, they will not be parsed. Return the 2401 * there are directives later in the file, they will not be parsed. Return the
2637 * compilation unit that was parsed. 2402 * compilation unit that was parsed.
2638 */ 2403 */
2639 CompilationUnit parseDirectives(Token token) { 2404 CompilationUnit parseDirectives(Token token) {
2640 _currentToken = token; 2405 _currentToken = token;
2641 return parseDirectives2(); 2406 return parseDirectives2();
2642 } 2407 }
(...skipping 16 matching lines...) Expand all
2659 CommentAndMetadata commentAndMetadata = parseCommentAndMetadata(); 2424 CommentAndMetadata commentAndMetadata = parseCommentAndMetadata();
2660 Keyword keyword = _currentToken.keyword; 2425 Keyword keyword = _currentToken.keyword;
2661 TokenType type = _peek().type; 2426 TokenType type = _peek().type;
2662 if ((keyword == Keyword.IMPORT || 2427 if ((keyword == Keyword.IMPORT ||
2663 keyword == Keyword.EXPORT || 2428 keyword == Keyword.EXPORT ||
2664 keyword == Keyword.LIBRARY || 2429 keyword == Keyword.LIBRARY ||
2665 keyword == Keyword.PART) && 2430 keyword == Keyword.PART) &&
2666 type != TokenType.PERIOD && 2431 type != TokenType.PERIOD &&
2667 type != TokenType.LT && 2432 type != TokenType.LT &&
2668 type != TokenType.OPEN_PAREN) { 2433 type != TokenType.OPEN_PAREN) {
2669 directives.add(_parseDirective(commentAndMetadata)); 2434 directives.add(parseDirective(commentAndMetadata));
2670 } else if (_matches(TokenType.SEMICOLON)) { 2435 } else if (_matches(TokenType.SEMICOLON)) {
2671 _advance(); 2436 _advance();
2672 } else { 2437 } else {
2673 while (!_matches(TokenType.EOF)) { 2438 while (!_matches(TokenType.EOF)) {
2674 _advance(); 2439 _advance();
2675 } 2440 }
2676 return new CompilationUnit( 2441 return new CompilationUnit(
2677 firstToken, scriptTag, directives, null, _currentToken); 2442 firstToken, scriptTag, directives, null, _currentToken);
2678 } 2443 }
2679 } 2444 }
2680 return new CompilationUnit( 2445 return new CompilationUnit(
2681 firstToken, scriptTag, directives, null, _currentToken); 2446 firstToken, scriptTag, directives, null, _currentToken);
2682 } 2447 }
2683 2448
2684 /** 2449 /**
2685 * Parse a documentation comment based on the given list of documentation 2450 * Parse a documentation comment based on the given list of documentation
2686 * comment tokens. Return the documentation comment that was parsed, or `null` 2451 * comment tokens. Return the documentation comment that was parsed, or `null`
2687 * if there was no comment. 2452 * if there was no comment.
2688 * 2453 *
2689 * documentationComment ::= 2454 * documentationComment ::=
2690 * multiLineComment? 2455 * multiLineComment?
2691 * | singleLineComment* 2456 * | singleLineComment*
2692 */ 2457 */
2693 Comment parseDocumentationComment(List<DocumentationCommentToken> tokens) { 2458 Comment parseDocumentationComment(List<DocumentationCommentToken> tokens) {
2694 if (tokens == null) { 2459 if (tokens == null) {
2695 return null; 2460 return null;
2696 } 2461 }
2697 List<CommentReference> references = _parseCommentReferences(tokens); 2462 List<CommentReference> references = parseCommentReferences(tokens);
2698 return Comment.createDocumentationCommentWithReferences(tokens, references); 2463 return Comment.createDocumentationCommentWithReferences(tokens, references);
2699 } 2464 }
2700 2465
2701 /** 2466 /**
2702 * Parse a documentation comment. Return the documentation comment that was 2467 * Parse a documentation comment. Return the documentation comment that was
2703 * parsed, or `null` if there was no comment. 2468 * parsed, or `null` if there was no comment.
2704 * 2469 *
2705 * documentationComment ::= 2470 * documentationComment ::=
2706 * multiLineComment? 2471 * multiLineComment?
2707 * | singleLineComment* 2472 * | singleLineComment*
(...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after
2822 commentAndMetadata.comment, 2587 commentAndMetadata.comment,
2823 commentAndMetadata.metadata, 2588 commentAndMetadata.metadata,
2824 keyword, 2589 keyword,
2825 name, 2590 name,
2826 leftBracket, 2591 leftBracket,
2827 constants, 2592 constants,
2828 rightBracket); 2593 rightBracket);
2829 } 2594 }
2830 2595
2831 /** 2596 /**
2597 * Parse an equality expression. Return the equality expression that was
2598 * parsed.
2599 *
2600 * equalityExpression ::=
2601 * relationalExpression (equalityOperator relationalExpression)?
2602 * | 'super' equalityOperator relationalExpression
2603 */
2604 Expression parseEqualityExpression() {
2605 Expression expression;
2606 if (_currentToken.keyword == Keyword.SUPER &&
2607 _currentToken.next.type.isEqualityOperator) {
2608 expression = new SuperExpression(getAndAdvance());
2609 } else {
2610 expression = parseRelationalExpression();
2611 }
2612 bool leftEqualityExpression = false;
2613 while (_currentToken.type.isEqualityOperator) {
2614 if (leftEqualityExpression) {
2615 _reportErrorForNode(
2616 ParserErrorCode.EQUALITY_CANNOT_BE_EQUALITY_OPERAND, expression);
2617 }
2618 expression = new BinaryExpression(
2619 expression, getAndAdvance(), parseRelationalExpression());
2620 leftEqualityExpression = true;
2621 }
2622 return expression;
2623 }
2624
2625 /**
2626 * Parse an export directive. The [commentAndMetadata] is the metadata to be
2627 * associated with the directive. Return the export directive that was parsed.
2628 *
2629 * This method assumes that the current token matches `Keyword.EXPORT`.
2630 *
2631 * exportDirective ::=
2632 * metadata 'export' stringLiteral configuration* combinator*';'
2633 */
2634 ExportDirective parseExportDirective(CommentAndMetadata commentAndMetadata) {
2635 Token exportKeyword = getAndAdvance();
2636 StringLiteral libraryUri = _parseUri();
2637 List<Configuration> configurations = _parseConfigurations();
2638 List<Combinator> combinators = parseCombinators();
2639 Token semicolon = _expect(TokenType.SEMICOLON);
2640 return new ExportDirective(
2641 commentAndMetadata.comment,
2642 commentAndMetadata.metadata,
2643 exportKeyword,
2644 libraryUri,
2645 configurations,
2646 combinators,
2647 semicolon);
2648 }
2649
2650 /**
2832 * Parse an expression, starting with the given [token]. Return the expression 2651 * Parse an expression, starting with the given [token]. Return the expression
2833 * that was parsed, or `null` if the tokens do not represent a recognizable 2652 * that was parsed, or `null` if the tokens do not represent a recognizable
2834 * expression. 2653 * expression.
2835 */ 2654 */
2836 Expression parseExpression(Token token) { 2655 Expression parseExpression(Token token) {
2837 _currentToken = token; 2656 _currentToken = token;
2838 return parseExpression2(); 2657 return parseExpression2();
2839 } 2658 }
2840 2659
2841 /** 2660 /**
(...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after
2978 ParserErrorCode.MISSING_CONST_FINAL_VAR_OR_TYPE); 2797 ParserErrorCode.MISSING_CONST_FINAL_VAR_OR_TYPE);
2979 } else { 2798 } else {
2980 // Support parameters such as `(/*=K*/ key, /*=V*/ value)` 2799 // Support parameters such as `(/*=K*/ key, /*=V*/ value)`
2981 // This is not supported if the type is required. 2800 // This is not supported if the type is required.
2982 type = _parseOptionalTypeNameComment(); 2801 type = _parseOptionalTypeNameComment();
2983 } 2802 }
2984 return new FinalConstVarOrType(keywordToken, type); 2803 return new FinalConstVarOrType(keywordToken, type);
2985 } 2804 }
2986 2805
2987 /** 2806 /**
2807 * Parse a formal parameter. At most one of `isOptional` and `isNamed` can be
2808 * `true`. The [kind] is the kind of parameter being expected based on the
2809 * presence or absence of group delimiters. Return the formal parameter that
2810 * was parsed.
2811 *
2812 * defaultFormalParameter ::=
2813 * normalFormalParameter ('=' expression)?
2814 *
2815 * defaultNamedParameter ::=
2816 * normalFormalParameter (':' expression)?
2817 */
2818 FormalParameter parseFormalParameter(ParameterKind kind) {
2819 NormalFormalParameter parameter = parseNormalFormalParameter();
2820 TokenType type = _currentToken.type;
2821 if (type == TokenType.EQ) {
2822 Token separator = getAndAdvance();
2823 Expression defaultValue = parseExpression2();
2824 if (kind == ParameterKind.NAMED) {
2825 _reportErrorForToken(
2826 ParserErrorCode.WRONG_SEPARATOR_FOR_NAMED_PARAMETER, separator);
2827 } else if (kind == ParameterKind.REQUIRED) {
2828 _reportErrorForNode(
2829 ParserErrorCode.POSITIONAL_PARAMETER_OUTSIDE_GROUP, parameter);
2830 }
2831 return new DefaultFormalParameter(
2832 parameter, kind, separator, defaultValue);
2833 } else if (type == TokenType.COLON) {
2834 Token separator = getAndAdvance();
2835 Expression defaultValue = parseExpression2();
2836 if (kind == ParameterKind.POSITIONAL) {
2837 _reportErrorForToken(
2838 ParserErrorCode.WRONG_SEPARATOR_FOR_POSITIONAL_PARAMETER,
2839 separator);
2840 } else if (kind == ParameterKind.REQUIRED) {
2841 _reportErrorForNode(
2842 ParserErrorCode.NAMED_PARAMETER_OUTSIDE_GROUP, parameter);
2843 }
2844 return new DefaultFormalParameter(
2845 parameter, kind, separator, defaultValue);
2846 } else if (kind != ParameterKind.REQUIRED) {
2847 return new DefaultFormalParameter(parameter, kind, null, null);
2848 }
2849 return parameter;
2850 }
2851
2852 /**
2988 * Parse a list of formal parameters. Return the formal parameters that were 2853 * Parse a list of formal parameters. Return the formal parameters that were
2989 * parsed. 2854 * parsed.
2990 * 2855 *
2991 * formalParameterList ::= 2856 * formalParameterList ::=
2992 * '(' ')' 2857 * '(' ')'
2993 * | '(' normalFormalParameters (',' optionalFormalParameters)? ')' 2858 * | '(' normalFormalParameters (',' optionalFormalParameters)? ')'
2994 * | '(' optionalFormalParameters ')' 2859 * | '(' optionalFormalParameters ')'
2995 * 2860 *
2996 * normalFormalParameters ::= 2861 * normalFormalParameters ::=
2997 * normalFormalParameter (',' normalFormalParameter)* 2862 * normalFormalParameter (',' normalFormalParameter)*
(...skipping 284 matching lines...) Expand 10 before | Expand all | Expand 10 after
3282 } 3147 }
3283 } finally { 3148 } finally {
3284 _inAsync = wasInAsync; 3149 _inAsync = wasInAsync;
3285 _inGenerator = wasInGenerator; 3150 _inGenerator = wasInGenerator;
3286 _inLoop = wasInLoop; 3151 _inLoop = wasInLoop;
3287 _inSwitch = wasInSwitch; 3152 _inSwitch = wasInSwitch;
3288 } 3153 }
3289 } 3154 }
3290 3155
3291 /** 3156 /**
3157 * Parse a function declaration. The [commentAndMetadata] is the documentation
3158 * comment and metadata to be associated with the declaration. The
3159 * [externalKeyword] is the 'external' keyword, or `null` if the function is
3160 * not external. The [returnType] is the return type, or `null` if there is no
3161 * return type. The [isStatement] is `true` if the function declaration is
3162 * being parsed as a statement. Return the function declaration that was
3163 * parsed.
3164 *
3165 * functionDeclaration ::=
3166 * functionSignature functionBody
3167 * | returnType? getOrSet identifier formalParameterList functionBody
3168 */
3169 FunctionDeclaration parseFunctionDeclaration(
3170 CommentAndMetadata commentAndMetadata,
3171 Token externalKeyword,
3172 TypeName returnType) {
3173 Token keywordToken = null;
3174 bool isGetter = false;
3175 Keyword keyword = _currentToken.keyword;
3176 SimpleIdentifier name = null;
3177 if (keyword == Keyword.GET) {
3178 keywordToken = getAndAdvance();
3179 isGetter = true;
3180 } else if (keyword == Keyword.SET) {
3181 keywordToken = getAndAdvance();
3182 }
3183 if (keywordToken != null && _matches(TokenType.OPEN_PAREN)) {
3184 name = new SimpleIdentifier(keywordToken, isDeclaration: true);
3185 keywordToken = null;
3186 isGetter = false;
3187 } else {
3188 name = parseSimpleIdentifier(isDeclaration: true);
3189 }
3190 TypeParameterList typeParameters = _parseGenericMethodTypeParameters();
3191 FormalParameterList parameters = null;
3192 if (!isGetter) {
3193 if (_matches(TokenType.OPEN_PAREN)) {
3194 parameters = _parseFormalParameterListUnchecked();
3195 _validateFormalParameterList(parameters);
3196 } else {
3197 _reportErrorForCurrentToken(
3198 ParserErrorCode.MISSING_FUNCTION_PARAMETERS);
3199 parameters = new FormalParameterList(
3200 _createSyntheticToken(TokenType.OPEN_PAREN),
3201 null,
3202 null,
3203 null,
3204 _createSyntheticToken(TokenType.CLOSE_PAREN));
3205 }
3206 } else if (_matches(TokenType.OPEN_PAREN)) {
3207 _reportErrorForCurrentToken(ParserErrorCode.GETTER_WITH_PARAMETERS);
3208 _parseFormalParameterListUnchecked();
3209 }
3210 FunctionBody body;
3211 if (externalKeyword == null) {
3212 body = parseFunctionBody(
3213 false, ParserErrorCode.MISSING_FUNCTION_BODY, false);
3214 } else {
3215 body = new EmptyFunctionBody(_expect(TokenType.SEMICOLON));
3216 }
3217 // if (!isStatement && matches(TokenType.SEMICOLON)) {
3218 // // TODO(brianwilkerson) Improve this error message.
3219 // reportError(ParserErrorCode.UNEXPECTED_TOKEN, currentToken.getLexeme ());
3220 // advance();
3221 // }
3222 return new FunctionDeclaration(
3223 commentAndMetadata.comment,
3224 commentAndMetadata.metadata,
3225 externalKeyword,
3226 returnType,
3227 keywordToken,
3228 name,
3229 new FunctionExpression(typeParameters, parameters, body));
3230 }
3231
3232 /**
3292 * Parse a function declaration statement. Return the function declaration 3233 * Parse a function declaration statement. Return the function declaration
3293 * statement that was parsed. 3234 * statement that was parsed.
3294 * 3235 *
3295 * functionDeclarationStatement ::= 3236 * functionDeclarationStatement ::=
3296 * functionSignature functionBody 3237 * functionSignature functionBody
3297 */ 3238 */
3298 Statement parseFunctionDeclarationStatement() { 3239 Statement parseFunctionDeclarationStatement() {
3299 Modifiers modifiers = _parseModifiers(); 3240 Modifiers modifiers = parseModifiers();
3300 _validateModifiersForFunctionDeclarationStatement(modifiers); 3241 _validateModifiersForFunctionDeclarationStatement(modifiers);
3301 return _parseFunctionDeclarationStatementAfterReturnType( 3242 return _parseFunctionDeclarationStatementAfterReturnType(
3302 parseCommentAndMetadata(), _parseOptionalReturnType()); 3243 parseCommentAndMetadata(), _parseOptionalReturnType());
3303 } 3244 }
3304 3245
3305 /** 3246 /**
3306 * Parse a function expression. Return the function expression that was 3247 * Parse a function expression. Return the function expression that was
3307 * parsed. 3248 * parsed.
3308 * 3249 *
3309 * functionExpression ::= 3250 * functionExpression ::=
3310 * typeParameters? formalParameterList functionExpressionBody 3251 * typeParameters? formalParameterList functionExpressionBody
3311 */ 3252 */
3312 FunctionExpression parseFunctionExpression() { 3253 FunctionExpression parseFunctionExpression() {
3313 TypeParameterList typeParameters = _parseGenericMethodTypeParameters(); 3254 TypeParameterList typeParameters = _parseGenericMethodTypeParameters();
3314 FormalParameterList parameters = parseFormalParameterList(); 3255 FormalParameterList parameters = parseFormalParameterList();
3315 _validateFormalParameterList(parameters); 3256 _validateFormalParameterList(parameters);
3316 FunctionBody body = 3257 FunctionBody body =
3317 parseFunctionBody(false, ParserErrorCode.MISSING_FUNCTION_BODY, true); 3258 parseFunctionBody(false, ParserErrorCode.MISSING_FUNCTION_BODY, true);
3318 return new FunctionExpression(typeParameters, parameters, body); 3259 return new FunctionExpression(typeParameters, parameters, body);
3319 } 3260 }
3320 3261
3321 /** 3262 /**
3263 * Parse a getter. The [commentAndMetadata] is the documentation comment and
3264 * metadata to be associated with the declaration. The externalKeyword] is the
3265 * 'external' token. The staticKeyword] is the static keyword, or `null` if
3266 * the getter is not static. The [returnType] the return type that has already
3267 * been parsed, or `null` if there was no return type. Return the getter that
3268 * was parsed.
3269 *
3270 * This method assumes that the current token matches `Keyword.GET`.
3271 *
3272 * getter ::=
3273 * getterSignature functionBody?
3274 *
3275 * getterSignature ::=
3276 * 'external'? 'static'? returnType? 'get' identifier
3277 */
3278 MethodDeclaration parseGetter(CommentAndMetadata commentAndMetadata,
3279 Token externalKeyword, Token staticKeyword, TypeName returnType) {
3280 Token propertyKeyword = getAndAdvance();
3281 SimpleIdentifier name = parseSimpleIdentifier(isDeclaration: true);
3282 if (_matches(TokenType.OPEN_PAREN) &&
3283 _tokenMatches(_peek(), TokenType.CLOSE_PAREN)) {
3284 _reportErrorForCurrentToken(ParserErrorCode.GETTER_WITH_PARAMETERS);
3285 _advance();
3286 _advance();
3287 }
3288 FunctionBody body = parseFunctionBody(
3289 externalKeyword != null || staticKeyword == null,
3290 ParserErrorCode.STATIC_GETTER_WITHOUT_BODY,
3291 false);
3292 if (externalKeyword != null && body is! EmptyFunctionBody) {
3293 _reportErrorForCurrentToken(ParserErrorCode.EXTERNAL_GETTER_WITH_BODY);
3294 }
3295 return new MethodDeclaration(
3296 commentAndMetadata.comment,
3297 commentAndMetadata.metadata,
3298 externalKeyword,
3299 staticKeyword,
3300 returnType,
3301 propertyKeyword,
3302 null,
3303 name,
3304 null,
3305 null,
3306 body);
3307 }
3308
3309 /**
3310 * Parse a list of identifiers. Return the list of identifiers that were
3311 * parsed.
3312 *
3313 * identifierList ::=
3314 * identifier (',' identifier)*
3315 */
3316 List<SimpleIdentifier> parseIdentifierList() {
3317 List<SimpleIdentifier> identifiers = <SimpleIdentifier>[
3318 parseSimpleIdentifier()
3319 ];
3320 while (_optional(TokenType.COMMA)) {
3321 identifiers.add(parseSimpleIdentifier());
3322 }
3323 return identifiers;
3324 }
3325
3326 /**
3322 * Parse an if-null expression. Return the if-null expression that was 3327 * Parse an if-null expression. Return the if-null expression that was
3323 * parsed. 3328 * parsed.
3324 * 3329 *
3325 * ifNullExpression ::= logicalOrExpression ('??' logicalOrExpression)* 3330 * ifNullExpression ::= logicalOrExpression ('??' logicalOrExpression)*
3326 */ 3331 */
3327 Expression parseIfNullExpression() { 3332 Expression parseIfNullExpression() {
3328 Expression expression = parseLogicalOrExpression(); 3333 Expression expression = parseLogicalOrExpression();
3329 while (_currentToken.type == TokenType.QUESTION_QUESTION) { 3334 while (_currentToken.type == TokenType.QUESTION_QUESTION) {
3330 expression = new BinaryExpression( 3335 expression = new BinaryExpression(
3331 expression, getAndAdvance(), parseLogicalOrExpression()); 3336 expression, getAndAdvance(), parseLogicalOrExpression());
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
3369 Token keyword = getAndAdvance(); 3374 Token keyword = getAndAdvance();
3370 List<TypeName> interfaces = <TypeName>[]; 3375 List<TypeName> interfaces = <TypeName>[];
3371 interfaces.add(parseTypeName(false)); 3376 interfaces.add(parseTypeName(false));
3372 while (_optional(TokenType.COMMA)) { 3377 while (_optional(TokenType.COMMA)) {
3373 interfaces.add(parseTypeName(false)); 3378 interfaces.add(parseTypeName(false));
3374 } 3379 }
3375 return new ImplementsClause(keyword, interfaces); 3380 return new ImplementsClause(keyword, interfaces);
3376 } 3381 }
3377 3382
3378 /** 3383 /**
3384 * Parse an import directive. The [commentAndMetadata] is the metadata to be
3385 * associated with the directive. Return the import directive that was parsed.
3386 *
3387 * This method assumes that the current token matches `Keyword.IMPORT`.
3388 *
3389 * importDirective ::=
3390 * metadata 'import' stringLiteral configuration* (deferred)? ('as' id entifier)? combinator*';'
3391 */
3392 ImportDirective parseImportDirective(CommentAndMetadata commentAndMetadata) {
3393 Token importKeyword = getAndAdvance();
3394 StringLiteral libraryUri = _parseUri();
3395 List<Configuration> configurations = _parseConfigurations();
3396 Token deferredToken = null;
3397 Token asToken = null;
3398 SimpleIdentifier prefix = null;
3399 if (_matchesKeyword(Keyword.DEFERRED)) {
3400 deferredToken = getAndAdvance();
3401 }
3402 if (_matchesKeyword(Keyword.AS)) {
3403 asToken = getAndAdvance();
3404 prefix = parseSimpleIdentifier(isDeclaration: true);
3405 } else if (deferredToken != null) {
3406 _reportErrorForCurrentToken(
3407 ParserErrorCode.MISSING_PREFIX_IN_DEFERRED_IMPORT);
3408 } else if (!_matches(TokenType.SEMICOLON) &&
3409 !_matchesString(_SHOW) &&
3410 !_matchesString(_HIDE)) {
3411 Token nextToken = _peek();
3412 if (_tokenMatchesKeyword(nextToken, Keyword.AS) ||
3413 _tokenMatchesString(nextToken, _SHOW) ||
3414 _tokenMatchesString(nextToken, _HIDE)) {
3415 _reportErrorForCurrentToken(
3416 ParserErrorCode.UNEXPECTED_TOKEN, [_currentToken]);
3417 _advance();
3418 if (_matchesKeyword(Keyword.AS)) {
3419 asToken = getAndAdvance();
3420 prefix = parseSimpleIdentifier(isDeclaration: true);
3421 }
3422 }
3423 }
3424 List<Combinator> combinators = parseCombinators();
3425 Token semicolon = _expect(TokenType.SEMICOLON);
3426 return new ImportDirective(
3427 commentAndMetadata.comment,
3428 commentAndMetadata.metadata,
3429 importKeyword,
3430 libraryUri,
3431 configurations,
3432 deferredToken,
3433 asToken,
3434 prefix,
3435 combinators,
3436 semicolon);
3437 }
3438
3439 /**
3440 * Parse a list of initialized identifiers. The [commentAndMetadata] is the
3441 * documentation comment and metadata to be associated with the declaration.
3442 * The [staticKeyword] is the static keyword, or `null` if the getter is not
3443 * static. The [keyword] is the token representing the 'final', 'const' or
3444 * 'var' keyword, or `null` if there is no keyword. The [type] is the type
3445 * that has already been parsed, or `null` if 'var' was provided. Return the
3446 * getter that was parsed.
3447 *
3448 * ?? ::=
3449 * 'static'? ('var' | type) initializedIdentifierList ';'
3450 * | 'final' type? initializedIdentifierList ';'
3451 *
3452 * initializedIdentifierList ::=
3453 * initializedIdentifier (',' initializedIdentifier)*
3454 *
3455 * initializedIdentifier ::=
3456 * identifier ('=' expression)?
3457 */
3458 FieldDeclaration parseInitializedIdentifierList(
3459 CommentAndMetadata commentAndMetadata,
3460 Token staticKeyword,
3461 Token keyword,
3462 TypeName type) {
3463 VariableDeclarationList fieldList =
3464 parseVariableDeclarationListAfterType(null, keyword, type);
3465 return new FieldDeclaration(
3466 commentAndMetadata.comment,
3467 commentAndMetadata.metadata,
3468 staticKeyword,
3469 fieldList,
3470 _expect(TokenType.SEMICOLON));
3471 }
3472
3473 /**
3474 * Parse an instance creation expression. The [keyword] is the 'new' or
3475 * 'const' keyword that introduces the expression. Return the instance
3476 * creation expression that was parsed.
3477 *
3478 * instanceCreationExpression ::=
3479 * ('new' | 'const') type ('.' identifier)? argumentList
3480 */
3481 InstanceCreationExpression parseInstanceCreationExpression(Token keyword) {
3482 ConstructorName constructorName = parseConstructorName();
3483 ArgumentList argumentList = _parseArgumentListChecked();
3484 return new InstanceCreationExpression(
3485 keyword, constructorName, argumentList);
3486 }
3487
3488 /**
3379 * Parse a label. Return the label that was parsed. 3489 * Parse a label. Return the label that was parsed.
3380 * 3490 *
3381 * This method assumes that the current token matches an identifier and that 3491 * This method assumes that the current token matches an identifier and that
3382 * the following token matches `TokenType.COLON`. 3492 * the following token matches `TokenType.COLON`.
3383 * 3493 *
3384 * label ::= 3494 * label ::=
3385 * identifier ':' 3495 * identifier ':'
3386 */ 3496 */
3387 Label parseLabel({bool isDeclaration: false}) { 3497 Label parseLabel({bool isDeclaration: false}) {
3388 SimpleIdentifier label = 3498 SimpleIdentifier label =
3389 _parseSimpleIdentifierUnchecked(isDeclaration: isDeclaration); 3499 _parseSimpleIdentifierUnchecked(isDeclaration: isDeclaration);
3390 Token colon = getAndAdvance(); 3500 Token colon = getAndAdvance();
3391 return new Label(label, colon); 3501 return new Label(label, colon);
3392 } 3502 }
3393 3503
3394 /** 3504 /**
3505 * Parse a library directive. The [commentAndMetadata] is the metadata to be
3506 * associated with the directive. Return the library directive that was
3507 * parsed.
3508 *
3509 * This method assumes that the current token matches `Keyword.LIBRARY`.
3510 *
3511 * libraryDirective ::=
3512 * metadata 'library' identifier ';'
3513 */
3514 LibraryDirective parseLibraryDirective(
3515 CommentAndMetadata commentAndMetadata) {
3516 Token keyword = getAndAdvance();
3517 LibraryIdentifier libraryName = _parseLibraryName(
3518 ParserErrorCode.MISSING_NAME_IN_LIBRARY_DIRECTIVE, keyword);
3519 Token semicolon = _expect(TokenType.SEMICOLON);
3520 return new LibraryDirective(commentAndMetadata.comment,
3521 commentAndMetadata.metadata, keyword, libraryName, semicolon);
3522 }
3523
3524 /**
3395 * Parse a library identifier. Return the library identifier that was parsed. 3525 * Parse a library identifier. Return the library identifier that was parsed.
3396 * 3526 *
3397 * libraryIdentifier ::= 3527 * libraryIdentifier ::=
3398 * identifier ('.' identifier)* 3528 * identifier ('.' identifier)*
3399 */ 3529 */
3400 LibraryIdentifier parseLibraryIdentifier() { 3530 LibraryIdentifier parseLibraryIdentifier() {
3401 List<SimpleIdentifier> components = <SimpleIdentifier>[]; 3531 List<SimpleIdentifier> components = <SimpleIdentifier>[];
3402 components.add(parseSimpleIdentifier()); 3532 components.add(parseSimpleIdentifier());
3403 while (_optional(TokenType.PERIOD)) { 3533 while (_optional(TokenType.PERIOD)) {
3404 components.add(parseSimpleIdentifier()); 3534 components.add(parseSimpleIdentifier());
3405 } 3535 }
3406 return new LibraryIdentifier(components); 3536 return new LibraryIdentifier(components);
3407 } 3537 }
3408 3538
3409 /** 3539 /**
3540 * Parse a list literal. The [modifier] is the 'const' modifier appearing
3541 * before the literal, or `null` if there is no modifier. The [typeArguments]
3542 * is the type arguments appearing before the literal, or `null` if there are
3543 * no type arguments. Return the list literal that was parsed.
3544 *
3545 * This method assumes that the current token matches either
3546 * `TokenType.OPEN_SQUARE_BRACKET` or `TokenType.INDEX`.
3547 *
3548 * listLiteral ::=
3549 * 'const'? typeArguments? '[' (expressionList ','?)? ']'
3550 */
3551 ListLiteral parseListLiteral(Token modifier, TypeArgumentList typeArguments) {
3552 if (_matches(TokenType.INDEX)) {
3553 // Split the token into two separate tokens.
3554 BeginToken leftBracket = _createToken(
3555 _currentToken, TokenType.OPEN_SQUARE_BRACKET,
3556 isBegin: true);
3557 Token rightBracket =
3558 new Token(TokenType.CLOSE_SQUARE_BRACKET, _currentToken.offset + 1);
3559 leftBracket.endToken = rightBracket;
3560 rightBracket.setNext(_currentToken.next);
3561 leftBracket.setNext(rightBracket);
3562 _currentToken.previous.setNext(leftBracket);
3563 _currentToken = _currentToken.next;
3564 return new ListLiteral(
3565 modifier, typeArguments, leftBracket, null, rightBracket);
3566 }
3567 Token leftBracket = getAndAdvance();
3568 if (_matches(TokenType.CLOSE_SQUARE_BRACKET)) {
3569 return new ListLiteral(
3570 modifier, typeArguments, leftBracket, null, getAndAdvance());
3571 }
3572 bool wasInInitializer = _inInitializer;
3573 _inInitializer = false;
3574 try {
3575 List<Expression> elements = <Expression>[parseExpression2()];
3576 while (_optional(TokenType.COMMA)) {
3577 if (_matches(TokenType.CLOSE_SQUARE_BRACKET)) {
3578 return new ListLiteral(
3579 modifier, typeArguments, leftBracket, elements, getAndAdvance());
3580 }
3581 elements.add(parseExpression2());
3582 }
3583 Token rightBracket = _expect(TokenType.CLOSE_SQUARE_BRACKET);
3584 return new ListLiteral(
3585 modifier, typeArguments, leftBracket, elements, rightBracket);
3586 } finally {
3587 _inInitializer = wasInInitializer;
3588 }
3589 }
3590
3591 /**
3410 * Parse a list or map literal. The [modifier] is the 'const' modifier 3592 * Parse a list or map literal. The [modifier] is the 'const' modifier
3411 * appearing before the literal, or `null` if there is no modifier. Return the 3593 * appearing before the literal, or `null` if there is no modifier. Return the
3412 * list or map literal that was parsed. 3594 * list or map literal that was parsed.
3413 * 3595 *
3414 * listOrMapLiteral ::= 3596 * listOrMapLiteral ::=
3415 * listLiteral 3597 * listLiteral
3416 * | mapLiteral 3598 * | mapLiteral
3417 */ 3599 */
3418 TypedLiteral parseListOrMapLiteral(Token modifier) { 3600 TypedLiteral parseListOrMapLiteral(Token modifier) {
3419 TypeArgumentList typeArguments = _parseOptionalTypeArguments(); 3601 TypeArgumentList typeArguments = _parseOptionalTypeArguments();
3420 if (_matches(TokenType.OPEN_CURLY_BRACKET)) { 3602 if (_matches(TokenType.OPEN_CURLY_BRACKET)) {
3421 return _parseMapLiteral(modifier, typeArguments); 3603 return parseMapLiteral(modifier, typeArguments);
3422 } else if (_matches(TokenType.OPEN_SQUARE_BRACKET) || 3604 } else if (_matches(TokenType.OPEN_SQUARE_BRACKET) ||
3423 _matches(TokenType.INDEX)) { 3605 _matches(TokenType.INDEX)) {
3424 return _parseListLiteral(modifier, typeArguments); 3606 return parseListLiteral(modifier, typeArguments);
3425 } 3607 }
3426 _reportErrorForCurrentToken(ParserErrorCode.EXPECTED_LIST_OR_MAP_LITERAL); 3608 _reportErrorForCurrentToken(ParserErrorCode.EXPECTED_LIST_OR_MAP_LITERAL);
3427 return new ListLiteral( 3609 return new ListLiteral(
3428 modifier, 3610 modifier,
3429 typeArguments, 3611 typeArguments,
3430 _createSyntheticToken(TokenType.OPEN_SQUARE_BRACKET), 3612 _createSyntheticToken(TokenType.OPEN_SQUARE_BRACKET),
3431 null, 3613 null,
3432 _createSyntheticToken(TokenType.CLOSE_SQUARE_BRACKET)); 3614 _createSyntheticToken(TokenType.CLOSE_SQUARE_BRACKET));
3433 } 3615 }
3434 3616
3435 /** 3617 /**
3618 * Parse a logical and expression. Return the logical and expression that was
3619 * parsed.
3620 *
3621 * logicalAndExpression ::=
3622 * equalityExpression ('&&' equalityExpression)*
3623 */
3624 Expression parseLogicalAndExpression() {
3625 Expression expression = parseEqualityExpression();
3626 while (_currentToken.type == TokenType.AMPERSAND_AMPERSAND) {
3627 expression = new BinaryExpression(
3628 expression, getAndAdvance(), parseEqualityExpression());
3629 }
3630 return expression;
3631 }
3632
3633 /**
3436 * Parse a logical or expression. Return the logical or expression that was 3634 * Parse a logical or expression. Return the logical or expression that was
3437 * parsed. 3635 * parsed.
3438 * 3636 *
3439 * logicalOrExpression ::= 3637 * logicalOrExpression ::=
3440 * logicalAndExpression ('||' logicalAndExpression)* 3638 * logicalAndExpression ('||' logicalAndExpression)*
3441 */ 3639 */
3442 Expression parseLogicalOrExpression() { 3640 Expression parseLogicalOrExpression() {
3443 Expression expression = _parseLogicalAndExpression(); 3641 Expression expression = parseLogicalAndExpression();
3444 while (_currentToken.type == TokenType.BAR_BAR) { 3642 while (_currentToken.type == TokenType.BAR_BAR) {
3445 expression = new BinaryExpression( 3643 expression = new BinaryExpression(
3446 expression, getAndAdvance(), _parseLogicalAndExpression()); 3644 expression, getAndAdvance(), parseLogicalAndExpression());
3447 } 3645 }
3448 return expression; 3646 return expression;
3449 } 3647 }
3450 3648
3451 /** 3649 /**
3650 * Parse a map literal. The [modifier] is the 'const' modifier appearing
3651 * before the literal, or `null` if there is no modifier. The [typeArguments]
3652 * is the type arguments that were declared, or `null` if there are no type
3653 * arguments. Return the map literal that was parsed.
3654 *
3655 * This method assumes that the current token matches
3656 * `TokenType.OPEN_CURLY_BRACKET`.
3657 *
3658 * mapLiteral ::=
3659 * 'const'? typeArguments? '{' (mapLiteralEntry (',' mapLiteralEntry)* ','?)? '}'
3660 */
3661 MapLiteral parseMapLiteral(Token modifier, TypeArgumentList typeArguments) {
3662 Token leftBracket = getAndAdvance();
3663 if (_matches(TokenType.CLOSE_CURLY_BRACKET)) {
3664 return new MapLiteral(
3665 modifier, typeArguments, leftBracket, null, getAndAdvance());
3666 }
3667 bool wasInInitializer = _inInitializer;
3668 _inInitializer = false;
3669 try {
3670 List<MapLiteralEntry> entries = <MapLiteralEntry>[parseMapLiteralEntry()];
3671 while (_optional(TokenType.COMMA)) {
3672 if (_matches(TokenType.CLOSE_CURLY_BRACKET)) {
3673 return new MapLiteral(
3674 modifier, typeArguments, leftBracket, entries, getAndAdvance());
3675 }
3676 entries.add(parseMapLiteralEntry());
3677 }
3678 Token rightBracket = _expect(TokenType.CLOSE_CURLY_BRACKET);
3679 return new MapLiteral(
3680 modifier, typeArguments, leftBracket, entries, rightBracket);
3681 } finally {
3682 _inInitializer = wasInInitializer;
3683 }
3684 }
3685
3686 /**
3452 * Parse a map literal entry. Return the map literal entry that was parsed. 3687 * Parse a map literal entry. Return the map literal entry that was parsed.
3453 * 3688 *
3454 * mapLiteralEntry ::= 3689 * mapLiteralEntry ::=
3455 * expression ':' expression 3690 * expression ':' expression
3456 */ 3691 */
3457 MapLiteralEntry parseMapLiteralEntry() { 3692 MapLiteralEntry parseMapLiteralEntry() {
3458 Expression key = parseExpression2(); 3693 Expression key = parseExpression2();
3459 Token separator = _expect(TokenType.COLON); 3694 Token separator = _expect(TokenType.COLON);
3460 Expression value = parseExpression2(); 3695 Expression value = parseExpression2();
3461 return new MapLiteralEntry(key, separator, value); 3696 return new MapLiteralEntry(key, separator, value);
3462 } 3697 }
3463 3698
3464 /** 3699 /**
3465 * Parse a multiplicative expression. Return the multiplicative expression
3466 * that was parsed.
3467 *
3468 * multiplicativeExpression ::=
3469 * unaryExpression (multiplicativeOperator unaryExpression)*
3470 * | 'super' (multiplicativeOperator unaryExpression)+
3471 */
3472 Expression parseMultiplicativeExpression() {
3473 Expression expression;
3474 if (_currentToken.keyword == Keyword.SUPER &&
3475 _currentToken.next.type.isMultiplicativeOperator) {
3476 expression = new SuperExpression(getAndAdvance());
3477 } else {
3478 expression = parseUnaryExpression();
3479 }
3480 while (_currentToken.type.isMultiplicativeOperator) {
3481 expression = new BinaryExpression(
3482 expression, getAndAdvance(), parseUnaryExpression());
3483 }
3484 return expression;
3485 }
3486
3487 /**
3488 * Parse a normal formal parameter. Return the normal formal parameter that
3489 * was parsed.
3490 *
3491 * normalFormalParameter ::=
3492 * functionSignature
3493 * | fieldFormalParameter
3494 * | simpleFormalParameter
3495 *
3496 * functionSignature:
3497 * metadata returnType? identifier typeParameters? formalParameterList
3498 *
3499 * fieldFormalParameter ::=
3500 * metadata finalConstVarOrType? 'this' '.' identifier
3501 *
3502 * simpleFormalParameter ::=
3503 * declaredIdentifier
3504 * | metadata identifier
3505 */
3506 NormalFormalParameter parseNormalFormalParameter() {
3507 CommentAndMetadata commentAndMetadata = parseCommentAndMetadata();
3508 FinalConstVarOrType holder = parseFinalConstVarOrType(true);
3509 Token thisKeyword = null;
3510 Token period = null;
3511 if (_matchesKeyword(Keyword.THIS)) {
3512 thisKeyword = getAndAdvance();
3513 period = _expect(TokenType.PERIOD);
3514 }
3515 SimpleIdentifier identifier = parseSimpleIdentifier();
3516 TypeParameterList typeParameters = _parseGenericMethodTypeParameters();
3517 if (_matches(TokenType.OPEN_PAREN)) {
3518 FormalParameterList parameters = _parseFormalParameterListUnchecked();
3519 if (thisKeyword == null) {
3520 if (holder.keyword != null) {
3521 _reportErrorForToken(
3522 ParserErrorCode.FUNCTION_TYPED_PARAMETER_VAR, holder.keyword);
3523 }
3524 Token question = null;
3525 if (enableNnbd && _matches(TokenType.QUESTION)) {
3526 question = getAndAdvance();
3527 }
3528 return new FunctionTypedFormalParameter(
3529 commentAndMetadata.comment,
3530 commentAndMetadata.metadata,
3531 holder.type,
3532 new SimpleIdentifier(identifier.token, isDeclaration: true),
3533 typeParameters,
3534 parameters,
3535 question: question);
3536 } else {
3537 return new FieldFormalParameter(
3538 commentAndMetadata.comment,
3539 commentAndMetadata.metadata,
3540 holder.keyword,
3541 holder.type,
3542 thisKeyword,
3543 period,
3544 identifier,
3545 typeParameters,
3546 parameters);
3547 }
3548 } else if (typeParameters != null) {
3549 // TODO(brianwilkerson) Report an error. It looks like a function-typed
3550 // parameter with no parameter list.
3551 //_reportErrorForToken(ParserErrorCode.MISSING_PARAMETERS, typeParameters. endToken);
3552 }
3553 TypeName type = holder.type;
3554 if (type != null) {
3555 if (_tokenMatchesKeyword(type.name.beginToken, Keyword.VOID)) {
3556 _reportErrorForToken(
3557 ParserErrorCode.VOID_PARAMETER, type.name.beginToken);
3558 } else if (holder.keyword != null &&
3559 _tokenMatchesKeyword(holder.keyword, Keyword.VAR)) {
3560 _reportErrorForToken(ParserErrorCode.VAR_AND_TYPE, holder.keyword);
3561 }
3562 }
3563 if (thisKeyword != null) {
3564 // TODO(brianwilkerson) If there are type parameters but no parameters,
3565 // should we create a synthetic empty parameter list here so we can
3566 // capture the type parameters?
3567 return new FieldFormalParameter(
3568 commentAndMetadata.comment,
3569 commentAndMetadata.metadata,
3570 holder.keyword,
3571 holder.type,
3572 thisKeyword,
3573 period,
3574 identifier,
3575 null,
3576 null);
3577 }
3578 return new SimpleFormalParameter(
3579 commentAndMetadata.comment,
3580 commentAndMetadata.metadata,
3581 holder.keyword,
3582 holder.type,
3583 new SimpleIdentifier(identifier.token, isDeclaration: true));
3584 }
3585
3586 /**
3587 * Parse an operator declaration. The [commentAndMetadata] is the
3588 * documentation comment and metadata to be associated with the declaration.
3589 * The [externalKeyword] is the 'external' token. The [returnType] is the
3590 * return type that has already been parsed, or `null` if there was no return
3591 * type. Return the operator declaration that was parsed.
3592 *
3593 * operatorDeclaration ::=
3594 * operatorSignature (';' | functionBody)
3595 *
3596 * operatorSignature ::=
3597 * 'external'? returnType? 'operator' operator formalParameterList
3598 */
3599 MethodDeclaration parseOperator(CommentAndMetadata commentAndMetadata,
3600 Token externalKeyword, TypeName returnType) {
3601 Token operatorKeyword;
3602 if (_matchesKeyword(Keyword.OPERATOR)) {
3603 operatorKeyword = getAndAdvance();
3604 } else {
3605 _reportErrorForToken(
3606 ParserErrorCode.MISSING_KEYWORD_OPERATOR, _currentToken);
3607 operatorKeyword = _createSyntheticKeyword(Keyword.OPERATOR);
3608 }
3609 return _parseOperatorAfterKeyword(
3610 commentAndMetadata, externalKeyword, returnType, operatorKeyword);
3611 }
3612
3613 /**
3614 * Parse a prefixed identifier. Return the prefixed identifier that was
3615 * parsed.
3616 *
3617 * prefixedIdentifier ::=
3618 * identifier ('.' identifier)?
3619 */
3620 Identifier parsePrefixedIdentifier() {
3621 return _parsePrefixedIdentifierAfterIdentifier(parseSimpleIdentifier());
3622 }
3623
3624 /**
3625 * Parse a primary expression. Return the primary expression that was parsed.
3626 *
3627 * primary ::=
3628 * thisExpression
3629 * | 'super' unconditionalAssignableSelector
3630 * | functionExpression
3631 * | literal
3632 * | identifier
3633 * | newExpression
3634 * | constObjectExpression
3635 * | '(' expression ')'
3636 * | argumentDefinitionTest
3637 *
3638 * literal ::=
3639 * nullLiteral
3640 * | booleanLiteral
3641 * | numericLiteral
3642 * | stringLiteral
3643 * | symbolLiteral
3644 * | mapLiteral
3645 * | listLiteral
3646 */
3647 Expression parsePrimaryExpression() {
3648 if (_matchesIdentifier()) {
3649 // TODO(brianwilkerson) The code below was an attempt to recover from an
3650 // error case, but it needs to be applied as a recovery only after we
3651 // know that parsing it as an identifier doesn't work. Leaving the code as
3652 // a reminder of how to recover.
3653 // if (isFunctionExpression(_peek())) {
3654 // //
3655 // // Function expressions were allowed to have names at one point, but t his is now illegal.
3656 // //
3657 // reportError(ParserErrorCode.NAMED_FUNCTION_EXPRESSION, getAndAdvance() );
3658 // return parseFunctionExpression();
3659 // }
3660 return _parsePrefixedIdentifierUnchecked();
3661 }
3662 TokenType type = _currentToken.type;
3663 if (type == TokenType.STRING) {
3664 return parseStringLiteral();
3665 } else if (type == TokenType.INT) {
3666 Token token = getAndAdvance();
3667 int value = null;
3668 try {
3669 value = int.parse(token.lexeme);
3670 } on FormatException {
3671 // The invalid format should have been reported by the scanner.
3672 }
3673 return new IntegerLiteral(token, value);
3674 }
3675 Keyword keyword = _currentToken.keyword;
3676 if (keyword == Keyword.NULL) {
3677 return new NullLiteral(getAndAdvance());
3678 } else if (keyword == Keyword.NEW) {
3679 return _parseNewExpression();
3680 } else if (keyword == Keyword.THIS) {
3681 return new ThisExpression(getAndAdvance());
3682 } else if (keyword == Keyword.SUPER) {
3683 // TODO(paulberry): verify with Gilad that "super" must be followed by
3684 // unconditionalAssignableSelector in this case.
3685 return _parseAssignableSelector(
3686 new SuperExpression(getAndAdvance()), false,
3687 allowConditional: false);
3688 } else if (keyword == Keyword.FALSE) {
3689 return new BooleanLiteral(getAndAdvance(), false);
3690 } else if (keyword == Keyword.TRUE) {
3691 return new BooleanLiteral(getAndAdvance(), true);
3692 }
3693 if (type == TokenType.DOUBLE) {
3694 Token token = getAndAdvance();
3695 double value = 0.0;
3696 try {
3697 value = double.parse(token.lexeme);
3698 } on FormatException {
3699 // The invalid format should have been reported by the scanner.
3700 }
3701 return new DoubleLiteral(token, value);
3702 } else if (type == TokenType.HEXADECIMAL) {
3703 Token token = getAndAdvance();
3704 int value = null;
3705 try {
3706 value = int.parse(token.lexeme.substring(2), radix: 16);
3707 } on FormatException {
3708 // The invalid format should have been reported by the scanner.
3709 }
3710 return new IntegerLiteral(token, value);
3711 } else if (keyword == Keyword.CONST) {
3712 return parseConstExpression();
3713 } else if (type == TokenType.OPEN_PAREN) {
3714 if (isFunctionExpression(_currentToken)) {
3715 return parseFunctionExpression();
3716 }
3717 Token leftParenthesis = getAndAdvance();
3718 bool wasInInitializer = _inInitializer;
3719 _inInitializer = false;
3720 try {
3721 Expression expression = parseExpression2();
3722 Token rightParenthesis = _expect(TokenType.CLOSE_PAREN);
3723 return new ParenthesizedExpression(
3724 leftParenthesis, expression, rightParenthesis);
3725 } finally {
3726 _inInitializer = wasInInitializer;
3727 }
3728 } else if (type == TokenType.LT || _injectGenericCommentTypeList()) {
3729 return parseListOrMapLiteral(null);
3730 } else if (type == TokenType.OPEN_CURLY_BRACKET) {
3731 return _parseMapLiteral(null, null);
3732 } else if (type == TokenType.OPEN_SQUARE_BRACKET ||
3733 type == TokenType.INDEX) {
3734 return _parseListLiteral(null, null);
3735 } else if (type == TokenType.QUESTION &&
3736 _tokenMatches(_peek(), TokenType.IDENTIFIER)) {
3737 _reportErrorForCurrentToken(
3738 ParserErrorCode.UNEXPECTED_TOKEN, [_currentToken.lexeme]);
3739 _advance();
3740 return parsePrimaryExpression();
3741 } else if (keyword == Keyword.VOID) {
3742 //
3743 // Recover from having a return type of "void" where a return type is not
3744 // expected.
3745 //
3746 // TODO(brianwilkerson) Improve this error message.
3747 _reportErrorForCurrentToken(
3748 ParserErrorCode.UNEXPECTED_TOKEN, [_currentToken.lexeme]);
3749 _advance();
3750 return parsePrimaryExpression();
3751 } else if (type == TokenType.HASH) {
3752 return parseSymbolLiteral();
3753 } else {
3754 _reportErrorForCurrentToken(ParserErrorCode.MISSING_IDENTIFIER);
3755 return createSyntheticIdentifier();
3756 }
3757 }
3758
3759 /**
3760 * Parse a relational expression. Return the relational expression that was
3761 * parsed.
3762 *
3763 * relationalExpression ::=
3764 * bitwiseOrExpression ('is' '!'? type | 'as' type | relationalOperato r bitwiseOrExpression)?
3765 * | 'super' relationalOperator bitwiseOrExpression
3766 */
3767 Expression parseRelationalExpression() {
3768 if (_currentToken.keyword == Keyword.SUPER &&
3769 _currentToken.next.type.isRelationalOperator) {
3770 Expression expression = new SuperExpression(getAndAdvance());
3771 Token operator = getAndAdvance();
3772 return new BinaryExpression(
3773 expression, operator, parseBitwiseOrExpression());
3774 }
3775 Expression expression = parseBitwiseOrExpression();
3776 Keyword keyword = _currentToken.keyword;
3777 if (keyword == Keyword.AS) {
3778 Token asOperator = getAndAdvance();
3779 return new AsExpression(expression, asOperator, parseTypeName(true));
3780 } else if (keyword == Keyword.IS) {
3781 Token isOperator = getAndAdvance();
3782 Token notOperator = null;
3783 if (_matches(TokenType.BANG)) {
3784 notOperator = getAndAdvance();
3785 }
3786 return new IsExpression(
3787 expression, isOperator, notOperator, parseTypeName(true));
3788 } else if (_currentToken.type.isRelationalOperator) {
3789 Token operator = getAndAdvance();
3790 return new BinaryExpression(
3791 expression, operator, parseBitwiseOrExpression());
3792 }
3793 return expression;
3794 }
3795
3796 /**
3797 * Parse a rethrow expression. Return the rethrow expression that was parsed.
3798 *
3799 * This method assumes that the current token matches `Keyword.RETHROW`.
3800 *
3801 * rethrowExpression ::=
3802 * 'rethrow'
3803 */
3804 Expression parseRethrowExpression() => new RethrowExpression(getAndAdvance());
3805
3806 /**
3807 * Parse a return statement. Return the return statement that was parsed.
3808 *
3809 * This method assumes that the current token matches `Keyword.RETURN`.
3810 *
3811 * returnStatement ::=
3812 * 'return' expression? ';'
3813 */
3814 Statement parseReturnStatement() {
3815 Token returnKeyword = getAndAdvance();
3816 if (_matches(TokenType.SEMICOLON)) {
3817 return new ReturnStatement(returnKeyword, null, getAndAdvance());
3818 }
3819 Expression expression = parseExpression2();
3820 Token semicolon = _expect(TokenType.SEMICOLON);
3821 return new ReturnStatement(returnKeyword, expression, semicolon);
3822 }
3823
3824 /**
3825 * Parse a return type. Return the return type that was parsed.
3826 *
3827 * returnType ::=
3828 * 'void'
3829 * | type
3830 */
3831 TypeName parseReturnType() {
3832 if (_currentToken.keyword == Keyword.VOID) {
3833 return new TypeName(new SimpleIdentifier(getAndAdvance()), null);
3834 } else {
3835 return parseTypeName(false);
3836 }
3837 }
3838
3839 /**
3840 * Parse a shift expression. Return the shift expression that was parsed.
3841 *
3842 * shiftExpression ::=
3843 * additiveExpression (shiftOperator additiveExpression)*
3844 * | 'super' (shiftOperator additiveExpression)+
3845 */
3846 Expression parseShiftExpression() {
3847 Expression expression;
3848 if (_currentToken.keyword == Keyword.SUPER &&
3849 _currentToken.next.type.isShiftOperator) {
3850 expression = new SuperExpression(getAndAdvance());
3851 } else {
3852 expression = parseAdditiveExpression();
3853 }
3854 while (_currentToken.type.isShiftOperator) {
3855 expression = new BinaryExpression(
3856 expression, getAndAdvance(), parseAdditiveExpression());
3857 }
3858 return expression;
3859 }
3860
3861 /**
3862 * Parse a simple identifier. Return the simple identifier that was parsed.
3863 *
3864 * identifier ::=
3865 * IDENTIFIER
3866 */
3867 SimpleIdentifier parseSimpleIdentifier({bool isDeclaration: false}) {
3868 if (_matchesIdentifier()) {
3869 return _parseSimpleIdentifierUnchecked(isDeclaration: isDeclaration);
3870 }
3871 _reportErrorForCurrentToken(ParserErrorCode.MISSING_IDENTIFIER);
3872 return createSyntheticIdentifier(isDeclaration: isDeclaration);
3873 }
3874
3875 /**
3876 * Parse a statement, starting with the given [token]. Return the statement
3877 * that was parsed, or `null` if the tokens do not represent a recognizable
3878 * statement.
3879 */
3880 Statement parseStatement(Token token) {
3881 _currentToken = token;
3882 return parseStatement2();
3883 }
3884
3885 /**
3886 * Parse a statement. Return the statement that was parsed.
3887 *
3888 * statement ::=
3889 * label* nonLabeledStatement
3890 */
3891 Statement parseStatement2() {
3892 List<Label> labels = null;
3893 while (_matchesIdentifier() && _currentToken.next.type == TokenType.COLON) {
3894 Label label = parseLabel(isDeclaration: true);
3895 if (labels == null) {
3896 labels = <Label>[label];
3897 } else {
3898 labels.add(label);
3899 }
3900 }
3901 Statement statement = _parseNonLabeledStatement();
3902 if (labels == null) {
3903 return statement;
3904 }
3905 return new LabeledStatement(labels, statement);
3906 }
3907
3908 /**
3909 * Parse a sequence of statements, starting with the given [token]. Return the
3910 * statements that were parsed, or `null` if the tokens do not represent a
3911 * recognizable sequence of statements.
3912 */
3913 List<Statement> parseStatements(Token token) {
3914 _currentToken = token;
3915 return _parseStatementList();
3916 }
3917
3918 /**
3919 * Parse a string literal. Return the string literal that was parsed.
3920 *
3921 * stringLiteral ::=
3922 * MULTI_LINE_STRING+
3923 * | SINGLE_LINE_STRING+
3924 */
3925 StringLiteral parseStringLiteral() {
3926 if (_matches(TokenType.STRING)) {
3927 return _parseStringLiteralUnchecked();
3928 }
3929 _reportErrorForCurrentToken(ParserErrorCode.EXPECTED_STRING_LITERAL);
3930 return createSyntheticStringLiteral();
3931 }
3932
3933 /**
3934 * Parse a super constructor invocation. Return the super constructor
3935 * invocation that was parsed.
3936 *
3937 * This method assumes that the current token matches [Keyword.SUPER].
3938 *
3939 * superConstructorInvocation ::=
3940 * 'super' ('.' identifier)? arguments
3941 */
3942 SuperConstructorInvocation parseSuperConstructorInvocation() {
3943 Token keyword = getAndAdvance();
3944 Token period = null;
3945 SimpleIdentifier constructorName = null;
3946 if (_matches(TokenType.PERIOD)) {
3947 period = getAndAdvance();
3948 constructorName = parseSimpleIdentifier();
3949 }
3950 ArgumentList argumentList = _parseArgumentListChecked();
3951 return new SuperConstructorInvocation(
3952 keyword, period, constructorName, argumentList);
3953 }
3954
3955 /**
3956 * Parse a switch statement. Return the switch statement that was parsed.
3957 *
3958 * switchStatement ::=
3959 * 'switch' '(' expression ')' '{' switchCase* defaultCase? '}'
3960 *
3961 * switchCase ::=
3962 * label* ('case' expression ':') statements
3963 *
3964 * defaultCase ::=
3965 * label* 'default' ':' statements
3966 */
3967 SwitchStatement parseSwitchStatement() {
3968 bool wasInSwitch = _inSwitch;
3969 _inSwitch = true;
3970 try {
3971 HashSet<String> definedLabels = new HashSet<String>();
3972 Token keyword = _expectKeyword(Keyword.SWITCH);
3973 Token leftParenthesis = _expect(TokenType.OPEN_PAREN);
3974 Expression expression = parseExpression2();
3975 Token rightParenthesis = _expect(TokenType.CLOSE_PAREN);
3976 Token leftBracket = _expect(TokenType.OPEN_CURLY_BRACKET);
3977 Token defaultKeyword = null;
3978 List<SwitchMember> members = <SwitchMember>[];
3979 TokenType type = _currentToken.type;
3980 while (type != TokenType.EOF && type != TokenType.CLOSE_CURLY_BRACKET) {
3981 List<Label> labels = <Label>[];
3982 while (
3983 _matchesIdentifier() && _tokenMatches(_peek(), TokenType.COLON)) {
3984 SimpleIdentifier identifier =
3985 _parseSimpleIdentifierUnchecked(isDeclaration: true);
3986 String label = identifier.token.lexeme;
3987 if (definedLabels.contains(label)) {
3988 _reportErrorForToken(
3989 ParserErrorCode.DUPLICATE_LABEL_IN_SWITCH_STATEMENT,
3990 identifier.token,
3991 [label]);
3992 } else {
3993 definedLabels.add(label);
3994 }
3995 Token colon = getAndAdvance();
3996 labels.add(new Label(identifier, colon));
3997 }
3998 Keyword keyword = _currentToken.keyword;
3999 if (keyword == Keyword.CASE) {
4000 Token caseKeyword = getAndAdvance();
4001 Expression caseExpression = parseExpression2();
4002 Token colon = _expect(TokenType.COLON);
4003 members.add(new SwitchCase(labels, caseKeyword, caseExpression, colon,
4004 _parseStatementList()));
4005 if (defaultKeyword != null) {
4006 _reportErrorForToken(
4007 ParserErrorCode.SWITCH_HAS_CASE_AFTER_DEFAULT_CASE,
4008 caseKeyword);
4009 }
4010 } else if (keyword == Keyword.DEFAULT) {
4011 if (defaultKeyword != null) {
4012 _reportErrorForToken(
4013 ParserErrorCode.SWITCH_HAS_MULTIPLE_DEFAULT_CASES, _peek());
4014 }
4015 defaultKeyword = getAndAdvance();
4016 Token colon = _expect(TokenType.COLON);
4017 members.add(new SwitchDefault(
4018 labels, defaultKeyword, colon, _parseStatementList()));
4019 } else {
4020 // We need to advance, otherwise we could end up in an infinite loop,
4021 // but this could be a lot smarter about recovering from the error.
4022 _reportErrorForCurrentToken(ParserErrorCode.EXPECTED_CASE_OR_DEFAULT);
4023 bool atEndOrNextMember() {
4024 TokenType type = _currentToken.type;
4025 if (type == TokenType.EOF ||
4026 type == TokenType.CLOSE_CURLY_BRACKET) {
4027 return true;
4028 }
4029 Keyword keyword = _currentToken.keyword;
4030 return keyword == Keyword.CASE || keyword == Keyword.DEFAULT;
4031 }
4032
4033 while (!atEndOrNextMember()) {
4034 _advance();
4035 }
4036 }
4037 type = _currentToken.type;
4038 }
4039 Token rightBracket = _expect(TokenType.CLOSE_CURLY_BRACKET);
4040 return new SwitchStatement(keyword, leftParenthesis, expression,
4041 rightParenthesis, leftBracket, members, rightBracket);
4042 } finally {
4043 _inSwitch = wasInSwitch;
4044 }
4045 }
4046
4047 /**
4048 * Parse a symbol literal. Return the symbol literal that was parsed.
4049 *
4050 * This method assumes that the current token matches [TokenType.HASH].
4051 *
4052 * symbolLiteral ::=
4053 * '#' identifier ('.' identifier)*
4054 */
4055 SymbolLiteral parseSymbolLiteral() {
4056 Token poundSign = getAndAdvance();
4057 List<Token> components = <Token>[];
4058 if (_matchesIdentifier()) {
4059 components.add(getAndAdvance());
4060 while (_optional(TokenType.PERIOD)) {
4061 if (_matchesIdentifier()) {
4062 components.add(getAndAdvance());
4063 } else {
4064 _reportErrorForCurrentToken(ParserErrorCode.MISSING_IDENTIFIER);
4065 components.add(_createSyntheticToken(TokenType.IDENTIFIER));
4066 break;
4067 }
4068 }
4069 } else if (_currentToken.isOperator) {
4070 components.add(getAndAdvance());
4071 } else if (_matchesKeyword(Keyword.VOID)) {
4072 components.add(getAndAdvance());
4073 } else {
4074 _reportErrorForCurrentToken(ParserErrorCode.MISSING_IDENTIFIER);
4075 components.add(_createSyntheticToken(TokenType.IDENTIFIER));
4076 }
4077 return new SymbolLiteral(poundSign, components);
4078 }
4079
4080 /**
4081 * Parse a throw expression. Return the throw expression that was parsed.
4082 *
4083 * This method assumes that the current token matches [Keyword.THROW].
4084 *
4085 * throwExpression ::=
4086 * 'throw' expression
4087 */
4088 Expression parseThrowExpression() {
4089 Token keyword = getAndAdvance();
4090 TokenType type = _currentToken.type;
4091 if (type == TokenType.SEMICOLON || type == TokenType.CLOSE_PAREN) {
4092 _reportErrorForToken(
4093 ParserErrorCode.MISSING_EXPRESSION_IN_THROW, _currentToken);
4094 return new ThrowExpression(keyword, createSyntheticIdentifier());
4095 }
4096 Expression expression = parseExpression2();
4097 return new ThrowExpression(keyword, expression);
4098 }
4099
4100 /**
4101 * Parse a throw expression. Return the throw expression that was parsed.
4102 *
4103 * This method assumes that the current token matches [Keyword.THROW].
4104 *
4105 * throwExpressionWithoutCascade ::=
4106 * 'throw' expressionWithoutCascade
4107 */
4108 Expression parseThrowExpressionWithoutCascade() {
4109 Token keyword = getAndAdvance();
4110 TokenType type = _currentToken.type;
4111 if (type == TokenType.SEMICOLON || type == TokenType.CLOSE_PAREN) {
4112 _reportErrorForToken(
4113 ParserErrorCode.MISSING_EXPRESSION_IN_THROW, _currentToken);
4114 return new ThrowExpression(keyword, createSyntheticIdentifier());
4115 }
4116 Expression expression = parseExpressionWithoutCascade();
4117 return new ThrowExpression(keyword, expression);
4118 }
4119
4120 /**
4121 * Parse a try statement. Return the try statement that was parsed.
4122 *
4123 * This method assumes that the current token matches [Keyword.TRY].
4124 *
4125 * tryStatement ::=
4126 * 'try' block (onPart+ finallyPart? | finallyPart)
4127 *
4128 * onPart ::=
4129 * catchPart block
4130 * | 'on' type catchPart? block
4131 *
4132 * catchPart ::=
4133 * 'catch' '(' identifier (',' identifier)? ')'
4134 *
4135 * finallyPart ::=
4136 * 'finally' block
4137 */
4138 Statement parseTryStatement() {
4139 Token tryKeyword = getAndAdvance();
4140 Block body = _parseBlockChecked();
4141 List<CatchClause> catchClauses = <CatchClause>[];
4142 Block finallyClause = null;
4143 while (_matchesString(_ON) || _matchesKeyword(Keyword.CATCH)) {
4144 Token onKeyword = null;
4145 TypeName exceptionType = null;
4146 if (_matchesString(_ON)) {
4147 onKeyword = getAndAdvance();
4148 exceptionType = parseTypeName(false);
4149 }
4150 Token catchKeyword = null;
4151 Token leftParenthesis = null;
4152 SimpleIdentifier exceptionParameter = null;
4153 Token comma = null;
4154 SimpleIdentifier stackTraceParameter = null;
4155 Token rightParenthesis = null;
4156 if (_matchesKeyword(Keyword.CATCH)) {
4157 catchKeyword = getAndAdvance();
4158 leftParenthesis = _expect(TokenType.OPEN_PAREN);
4159 exceptionParameter = parseSimpleIdentifier(isDeclaration: true);
4160 if (_matches(TokenType.COMMA)) {
4161 comma = getAndAdvance();
4162 stackTraceParameter = parseSimpleIdentifier(isDeclaration: true);
4163 }
4164 rightParenthesis = _expect(TokenType.CLOSE_PAREN);
4165 }
4166 Block catchBody = _parseBlockChecked();
4167 catchClauses.add(new CatchClause(
4168 onKeyword,
4169 exceptionType,
4170 catchKeyword,
4171 leftParenthesis,
4172 exceptionParameter,
4173 comma,
4174 stackTraceParameter,
4175 rightParenthesis,
4176 catchBody));
4177 }
4178 Token finallyKeyword = null;
4179 if (_matchesKeyword(Keyword.FINALLY)) {
4180 finallyKeyword = getAndAdvance();
4181 finallyClause = _parseBlockChecked();
4182 } else if (catchClauses.isEmpty) {
4183 _reportErrorForCurrentToken(ParserErrorCode.MISSING_CATCH_OR_FINALLY);
4184 }
4185 return new TryStatement(
4186 tryKeyword, body, catchClauses, finallyKeyword, finallyClause);
4187 }
4188
4189 /**
4190 * Parse a list of type arguments. Return the type argument list that was
4191 * parsed.
4192 *
4193 * This method assumes that the current token matches `TokenType.LT`.
4194 *
4195 * typeArguments ::=
4196 * '<' typeList '>'
4197 *
4198 * typeList ::=
4199 * type (',' type)*
4200 */
4201 TypeArgumentList parseTypeArgumentList() {
4202 Token leftBracket = getAndAdvance();
4203 List<TypeName> arguments = <TypeName>[parseTypeName(false)];
4204 while (_optional(TokenType.COMMA)) {
4205 arguments.add(parseTypeName(false));
4206 }
4207 Token rightBracket = _expectGt();
4208 return new TypeArgumentList(leftBracket, arguments, rightBracket);
4209 }
4210
4211 /**
4212 * Parse a type name. Return the type name that was parsed.
4213 *
4214 * type ::=
4215 * qualified typeArguments?
4216 */
4217 TypeName parseTypeName(bool inExpression) {
4218 TypeName realType = _parseTypeName(inExpression);
4219 // If this is followed by a generic method type comment, allow the comment
4220 // type to replace the real type name.
4221 // TODO(jmesserly): this feels like a big hammer. Can we restrict it to
4222 // only work inside generic methods?
4223 TypeName typeFromComment = _parseOptionalTypeNameComment();
4224 return typeFromComment ?? realType;
4225 }
4226
4227 /**
4228 * Parse a type parameter. Return the type parameter that was parsed.
4229 *
4230 * typeParameter ::=
4231 * metadata name ('extends' bound)?
4232 */
4233 TypeParameter parseTypeParameter() {
4234 CommentAndMetadata commentAndMetadata = parseCommentAndMetadata();
4235 SimpleIdentifier name = parseSimpleIdentifier(isDeclaration: true);
4236 if (_matchesKeyword(Keyword.EXTENDS)) {
4237 Token keyword = getAndAdvance();
4238 TypeName bound = parseTypeName(false);
4239 return new TypeParameter(commentAndMetadata.comment,
4240 commentAndMetadata.metadata, name, keyword, bound);
4241 }
4242 return new TypeParameter(commentAndMetadata.comment,
4243 commentAndMetadata.metadata, name, null, null);
4244 }
4245
4246 /**
4247 * Parse a list of type parameters. Return the list of type parameters that
4248 * were parsed.
4249 *
4250 * This method assumes that the current token matches `TokenType.LT`.
4251 *
4252 * typeParameterList ::=
4253 * '<' typeParameter (',' typeParameter)* '>'
4254 */
4255 TypeParameterList parseTypeParameterList() {
4256 Token leftBracket = getAndAdvance();
4257 List<TypeParameter> typeParameters = <TypeParameter>[parseTypeParameter()];
4258 while (_optional(TokenType.COMMA)) {
4259 typeParameters.add(parseTypeParameter());
4260 }
4261 Token rightBracket = _expectGt();
4262 return new TypeParameterList(leftBracket, typeParameters, rightBracket);
4263 }
4264
4265 /**
4266 * Parse a unary expression. Return the unary expression that was parsed.
4267 *
4268 * unaryExpression ::=
4269 * prefixOperator unaryExpression
4270 * | awaitExpression
4271 * | postfixExpression
4272 * | unaryOperator 'super'
4273 * | '-' 'super'
4274 * | incrementOperator assignableExpression
4275 */
4276 Expression parseUnaryExpression() {
4277 TokenType type = _currentToken.type;
4278 if (type == TokenType.MINUS ||
4279 type == TokenType.BANG ||
4280 type == TokenType.TILDE) {
4281 Token operator = getAndAdvance();
4282 if (_matchesKeyword(Keyword.SUPER)) {
4283 TokenType nextType = _peek().type;
4284 if (nextType == TokenType.OPEN_SQUARE_BRACKET ||
4285 nextType == TokenType.PERIOD) {
4286 // "prefixOperator unaryExpression"
4287 // --> "prefixOperator postfixExpression"
4288 // --> "prefixOperator primary selector*"
4289 // --> "prefixOperator 'super' assignableSelector selector*"
4290 return new PrefixExpression(operator, parseUnaryExpression());
4291 }
4292 return new PrefixExpression(
4293 operator, new SuperExpression(getAndAdvance()));
4294 }
4295 return new PrefixExpression(operator, parseUnaryExpression());
4296 } else if (_currentToken.type.isIncrementOperator) {
4297 Token operator = getAndAdvance();
4298 if (_matchesKeyword(Keyword.SUPER)) {
4299 TokenType nextType = _peek().type;
4300 if (nextType == TokenType.OPEN_SQUARE_BRACKET ||
4301 nextType == TokenType.PERIOD) {
4302 // --> "prefixOperator 'super' assignableSelector selector*"
4303 return new PrefixExpression(operator, parseUnaryExpression());
4304 }
4305 //
4306 // Even though it is not valid to use an incrementing operator
4307 // ('++' or '--') before 'super', we can (and therefore must) interpret
4308 // "--super" as semantically equivalent to "-(-super)". Unfortunately,
4309 // we cannot do the same for "++super" because "+super" is also not
4310 // valid.
4311 //
4312 if (type == TokenType.MINUS_MINUS) {
4313 Token firstOperator = _createToken(operator, TokenType.MINUS);
4314 Token secondOperator =
4315 new Token(TokenType.MINUS, operator.offset + 1);
4316 secondOperator.setNext(_currentToken);
4317 firstOperator.setNext(secondOperator);
4318 operator.previous.setNext(firstOperator);
4319 return new PrefixExpression(
4320 firstOperator,
4321 new PrefixExpression(
4322 secondOperator, new SuperExpression(getAndAdvance())));
4323 }
4324 // Invalid operator before 'super'
4325 _reportErrorForCurrentToken(
4326 ParserErrorCode.INVALID_OPERATOR_FOR_SUPER, [operator.lexeme]);
4327 return new PrefixExpression(
4328 operator, new SuperExpression(getAndAdvance()));
4329 }
4330 return new PrefixExpression(
4331 operator, _parseAssignableExpressionNotStartingWithSuper(false));
4332 } else if (type == TokenType.PLUS) {
4333 _reportErrorForCurrentToken(ParserErrorCode.MISSING_IDENTIFIER);
4334 return createSyntheticIdentifier();
4335 } else if (_inAsync && _matchesString(_AWAIT)) {
4336 return parseAwaitExpression();
4337 }
4338 return _parsePostfixExpression();
4339 }
4340
4341 /**
4342 * Parse a variable declaration. Return the variable declaration that was
4343 * parsed.
4344 *
4345 * variableDeclaration ::=
4346 * identifier ('=' expression)?
4347 */
4348 VariableDeclaration parseVariableDeclaration() {
4349 // TODO(paulberry): prior to the fix for bug 23204, we permitted
4350 // annotations before variable declarations (e.g. "String @deprecated s;").
4351 // Although such constructions are prohibited by the spec, we may want to
4352 // consider handling them anyway to allow for better parser recovery in the
4353 // event that the user erroneously tries to use them. However, as a
4354 // counterargument, this would likely degrade parser recovery in the event
4355 // of a construct like "class C { int @deprecated foo() {} }" (i.e. the
4356 // user is in the middle of inserting "int bar;" prior to
4357 // "@deprecated foo() {}").
4358 SimpleIdentifier name = parseSimpleIdentifier(isDeclaration: true);
4359 Token equals = null;
4360 Expression initializer = null;
4361 if (_matches(TokenType.EQ)) {
4362 equals = getAndAdvance();
4363 initializer = parseExpression2();
4364 }
4365 return new VariableDeclaration(name, equals, initializer);
4366 }
4367
4368 /**
4369 * Parse a variable declaration list. The [commentAndMetadata] is the metadata
4370 * to be associated with the variable declaration list. Return the variable
4371 * declaration list that was parsed.
4372 *
4373 * variableDeclarationList ::=
4374 * finalConstVarOrType variableDeclaration (',' variableDeclaration)*
4375 */
4376 VariableDeclarationList parseVariableDeclarationListAfterMetadata(
4377 CommentAndMetadata commentAndMetadata) {
4378 FinalConstVarOrType holder = parseFinalConstVarOrType(false);
4379 return parseVariableDeclarationListAfterType(
4380 commentAndMetadata, holder.keyword, holder.type);
4381 }
4382
4383 /**
4384 * Parse a variable declaration list. The [commentAndMetadata] is the metadata
4385 * to be associated with the variable declaration list, or `null` if there is
4386 * no attempt at parsing the comment and metadata. The [keyword] is the token
4387 * representing the 'final', 'const' or 'var' keyword, or `null` if there is
4388 * no keyword. The [type] is the type of the variables in the list. Return the
4389 * variable declaration list that was parsed.
4390 *
4391 * variableDeclarationList ::=
4392 * finalConstVarOrType variableDeclaration (',' variableDeclaration)*
4393 */
4394 VariableDeclarationList parseVariableDeclarationListAfterType(
4395 CommentAndMetadata commentAndMetadata, Token keyword, TypeName type) {
4396 if (type != null &&
4397 keyword != null &&
4398 _tokenMatchesKeyword(keyword, Keyword.VAR)) {
4399 _reportErrorForToken(ParserErrorCode.VAR_AND_TYPE, keyword);
4400 }
4401 List<VariableDeclaration> variables = <VariableDeclaration>[
4402 parseVariableDeclaration()
4403 ];
4404 while (_optional(TokenType.COMMA)) {
4405 variables.add(parseVariableDeclaration());
4406 }
4407 return new VariableDeclarationList(commentAndMetadata?.comment,
4408 commentAndMetadata?.metadata, keyword, type, variables);
4409 }
4410
4411 /**
4412 * Parse a variable declaration statement. The [commentAndMetadata] is the
4413 * metadata to be associated with the variable declaration statement, or
4414 * `null` if there is no attempt at parsing the comment and metadata. Return
4415 * the variable declaration statement that was parsed.
4416 *
4417 * variableDeclarationStatement ::=
4418 * variableDeclarationList ';'
4419 */
4420 VariableDeclarationStatement parseVariableDeclarationStatementAfterMetadata(
4421 CommentAndMetadata commentAndMetadata) {
4422 // Token startToken = currentToken;
4423 VariableDeclarationList variableList =
4424 parseVariableDeclarationListAfterMetadata(commentAndMetadata);
4425 // if (!matches(TokenType.SEMICOLON)) {
4426 // if (matches(startToken, Keyword.VAR) && isTypedIdentifier(startToken .getNext())) {
4427 // // TODO(brianwilkerson) This appears to be of the form "var type v ariable". We should do
4428 // // a better job of recovering in this case.
4429 // }
4430 // }
4431 Token semicolon = _expect(TokenType.SEMICOLON);
4432 return new VariableDeclarationStatement(variableList, semicolon);
4433 }
4434
4435 /**
4436 * Parse a while statement. Return the while statement that was parsed.
4437 *
4438 * This method assumes that the current token matches [Keyword.WHILE].
4439 *
4440 * whileStatement ::=
4441 * 'while' '(' expression ')' statement
4442 */
4443 Statement parseWhileStatement() {
4444 bool wasInLoop = _inLoop;
4445 _inLoop = true;
4446 try {
4447 Token keyword = getAndAdvance();
4448 Token leftParenthesis = _expect(TokenType.OPEN_PAREN);
4449 Expression condition = parseExpression2();
4450 Token rightParenthesis = _expect(TokenType.CLOSE_PAREN);
4451 Statement body = parseStatement2();
4452 return new WhileStatement(
4453 keyword, leftParenthesis, condition, rightParenthesis, body);
4454 } finally {
4455 _inLoop = wasInLoop;
4456 }
4457 }
4458
4459 /**
4460 * Parse a with clause. Return the with clause that was parsed.
4461 *
4462 * This method assumes that the current token matches `Keyword.WITH`.
4463 *
4464 * withClause ::=
4465 * 'with' typeName (',' typeName)*
4466 */
4467 WithClause parseWithClause() {
4468 Token withKeyword = getAndAdvance();
4469 List<TypeName> types = <TypeName>[parseTypeName(false)];
4470 while (_optional(TokenType.COMMA)) {
4471 types.add(parseTypeName(false));
4472 }
4473 return new WithClause(withKeyword, types);
4474 }
4475
4476 /**
4477 * Parse a yield statement. Return the yield statement that was parsed.
4478 *
4479 * This method assumes that the current token matches [Keyword.YIELD].
4480 *
4481 * yieldStatement ::=
4482 * 'yield' '*'? expression ';'
4483 */
4484 YieldStatement parseYieldStatement() {
4485 Token yieldToken = getAndAdvance();
4486 Token star = null;
4487 if (_matches(TokenType.STAR)) {
4488 star = getAndAdvance();
4489 }
4490 Expression expression = parseExpression2();
4491 Token semicolon = _expect(TokenType.SEMICOLON);
4492 return new YieldStatement(yieldToken, star, expression, semicolon);
4493 }
4494
4495 /**
4496 * Parse a prefixed identifier, starting at the [startToken], without actually
4497 * creating a prefixed identifier or changing the current token. Return the
4498 * token following the prefixed identifier that was parsed, or `null` if the
4499 * given token is not the first token in a valid prefixed identifier.
4500 *
4501 * This method must be kept in sync with [parsePrefixedIdentifier].
4502 *
4503 * prefixedIdentifier ::=
4504 * identifier ('.' identifier)?
4505 */
4506 Token skipPrefixedIdentifier(Token startToken) {
4507 Token token = skipSimpleIdentifier(startToken);
4508 if (token == null) {
4509 return null;
4510 } else if (!_tokenMatches(token, TokenType.PERIOD)) {
4511 return token;
4512 }
4513 token = token.next;
4514 Token nextToken = skipSimpleIdentifier(token);
4515 if (nextToken != null) {
4516 return nextToken;
4517 } else if (_tokenMatches(token, TokenType.CLOSE_PAREN) ||
4518 _tokenMatches(token, TokenType.COMMA)) {
4519 // If the `id.` is followed by something that cannot produce a valid
4520 // structure then assume this is a prefixed identifier but missing the
4521 // trailing identifier
4522 return token;
4523 }
4524 return null;
4525 }
4526
4527 /**
4528 * Parse a return type, starting at the [startToken], without actually
4529 * creating a return type or changing the current token. Return the token
4530 * following the return type that was parsed, or `null` if the given token is
4531 * not the first token in a valid return type.
4532 *
4533 * This method must be kept in sync with [parseReturnType].
4534 *
4535 * returnType ::=
4536 * 'void'
4537 * | type
4538 */
4539 Token skipReturnType(Token startToken) {
4540 if (_tokenMatchesKeyword(startToken, Keyword.VOID)) {
4541 return startToken.next;
4542 } else {
4543 return skipTypeName(startToken);
4544 }
4545 }
4546
4547 /**
4548 * Parse a simple identifier, starting at the [startToken], without actually
4549 * creating a simple identifier or changing the current token. Return the
4550 * token following the simple identifier that was parsed, or `null` if the
4551 * given token is not the first token in a valid simple identifier.
4552 *
4553 * This method must be kept in sync with [parseSimpleIdentifier].
4554 *
4555 * identifier ::=
4556 * IDENTIFIER
4557 */
4558 Token skipSimpleIdentifier(Token startToken) {
4559 if (_tokenMatches(startToken, TokenType.IDENTIFIER) ||
4560 _tokenMatchesPseudoKeyword(startToken)) {
4561 return startToken.next;
4562 }
4563 return null;
4564 }
4565
4566 /**
4567 * Parse a string literal, starting at the [startToken], without actually
4568 * creating a string literal or changing the current token. Return the token
4569 * following the string literal that was parsed, or `null` if the given token
4570 * is not the first token in a valid string literal.
4571 *
4572 * This method must be kept in sync with [parseStringLiteral].
4573 *
4574 * stringLiteral ::=
4575 * MULTI_LINE_STRING+
4576 * | SINGLE_LINE_STRING+
4577 */
4578 Token skipStringLiteral(Token startToken) {
4579 Token token = startToken;
4580 while (token != null && _tokenMatches(token, TokenType.STRING)) {
4581 token = token.next;
4582 TokenType type = token.type;
4583 if (type == TokenType.STRING_INTERPOLATION_EXPRESSION ||
4584 type == TokenType.STRING_INTERPOLATION_IDENTIFIER) {
4585 token = _skipStringInterpolation(token);
4586 }
4587 }
4588 if (identical(token, startToken)) {
4589 return null;
4590 }
4591 return token;
4592 }
4593
4594 /**
4595 * Parse a list of type arguments, starting at the [startToken], without
4596 * actually creating a type argument list or changing the current token.
4597 * Return the token following the type argument list that was parsed, or
4598 * `null` if the given token is not the first token in a valid type argument
4599 * list.
4600 *
4601 * This method must be kept in sync with [parseTypeArgumentList].
4602 *
4603 * typeArguments ::=
4604 * '<' typeList '>'
4605 *
4606 * typeList ::=
4607 * type (',' type)*
4608 */
4609 Token skipTypeArgumentList(Token startToken) {
4610 Token token = startToken;
4611 if (!_tokenMatches(token, TokenType.LT) &&
4612 !_injectGenericCommentTypeList()) {
4613 return null;
4614 }
4615 token = skipTypeName(token.next);
4616 if (token == null) {
4617 // If the start token '<' is followed by '>'
4618 // then assume this should be type argument list but is missing a type
4619 token = startToken.next;
4620 if (_tokenMatches(token, TokenType.GT)) {
4621 return token.next;
4622 }
4623 return null;
4624 }
4625 while (_tokenMatches(token, TokenType.COMMA)) {
4626 token = skipTypeName(token.next);
4627 if (token == null) {
4628 return null;
4629 }
4630 }
4631 if (token.type == TokenType.GT) {
4632 return token.next;
4633 } else if (token.type == TokenType.GT_GT) {
4634 Token second = new Token(TokenType.GT, token.offset + 1);
4635 second.setNextWithoutSettingPrevious(token.next);
4636 return second;
4637 }
4638 return null;
4639 }
4640
4641 /**
4642 * Parse a type name, starting at the [startToken], without actually creating
4643 * a type name or changing the current token. Return the token following the
4644 * type name that was parsed, or `null` if the given token is not the first
4645 * token in a valid type name.
4646 *
4647 * This method must be kept in sync with [parseTypeName].
4648 *
4649 * type ::=
4650 * qualified typeArguments?
4651 */
4652 Token skipTypeName(Token startToken) {
4653 Token token = skipPrefixedIdentifier(startToken);
4654 if (token == null) {
4655 return null;
4656 }
4657 if (_tokenMatches(token, TokenType.LT)) {
4658 token = skipTypeArgumentList(token);
4659 }
4660 return token;
4661 }
4662
4663 /**
4664 * Advance to the next token in the token stream.
4665 */
4666 void _advance() {
4667 _currentToken = _currentToken.next;
4668 }
4669
4670 /**
4671 * Append the character equivalent of the given [scalarValue] to the given
4672 * [builder]. Use the [startIndex] and [endIndex] to report an error, and
4673 * don't append anything to the builder, if the scalar value is invalid. The
4674 * [escapeSequence] is the escape sequence that was parsed to produce the
4675 * scalar value (used for error reporting).
4676 */
4677 void _appendScalarValue(StringBuffer buffer, String escapeSequence,
4678 int scalarValue, int startIndex, int endIndex) {
4679 if (scalarValue < 0 ||
4680 scalarValue > Character.MAX_CODE_POINT ||
4681 (scalarValue >= 0xD800 && scalarValue <= 0xDFFF)) {
4682 _reportErrorForCurrentToken(
4683 ParserErrorCode.INVALID_CODE_POINT, [escapeSequence]);
4684 return;
4685 }
4686 if (scalarValue < Character.MAX_VALUE) {
4687 buffer.writeCharCode(scalarValue);
4688 } else {
4689 buffer.write(Character.toChars(scalarValue));
4690 }
4691 }
4692
4693 /**
4694 * Clone all token starting from the given [token] up to the end of the token
4695 * stream, and return the first token in the new token stream.
4696 */
4697 Token _cloneTokens(Token token) {
4698 if (token == null) {
4699 return null;
4700 }
4701 token = token is CommentToken ? token.parent : token;
4702 Token head = new Token(TokenType.EOF, -1);
4703 head.setNext(head);
4704 Token current = head;
4705 while (token.type != TokenType.EOF) {
4706 Token clone = token.copy();
4707 current.setNext(clone);
4708 current = clone;
4709 token = token.next;
4710 }
4711 Token tail = new Token(TokenType.EOF, 0);
4712 tail.setNext(tail);
4713 current.setNext(tail);
4714 return head.next;
4715 }
4716
4717 /**
4718 * Convert the given [method] declaration into the nearest valid top-level
4719 * function declaration (that is, the function declaration that most closely
4720 * captures the components of the given method declaration).
4721 */
4722 FunctionDeclaration _convertToFunctionDeclaration(MethodDeclaration method) =>
4723 new FunctionDeclaration(
4724 method.documentationComment,
4725 method.metadata,
4726 method.externalKeyword,
4727 method.returnType,
4728 method.propertyKeyword,
4729 method.name,
4730 new FunctionExpression(
4731 method.typeParameters, method.parameters, method.body));
4732
4733 /**
4734 * Return `true` if the current token could be the start of a compilation unit
4735 * member. This method is used for recovery purposes to decide when to stop
4736 * skipping tokens after finding an error while parsing a compilation unit
4737 * member.
4738 */
4739 bool _couldBeStartOfCompilationUnitMember() {
4740 Keyword keyword = _currentToken.keyword;
4741 Token next = _currentToken.next;
4742 TokenType nextType = next.type;
4743 if ((keyword == Keyword.IMPORT ||
4744 keyword == Keyword.EXPORT ||
4745 keyword == Keyword.LIBRARY ||
4746 keyword == Keyword.PART) &&
4747 nextType != TokenType.PERIOD &&
4748 nextType != TokenType.LT) {
4749 // This looks like the start of a directive
4750 return true;
4751 } else if (keyword == Keyword.CLASS) {
4752 // This looks like the start of a class definition
4753 return true;
4754 } else if (keyword == Keyword.TYPEDEF &&
4755 nextType != TokenType.PERIOD &&
4756 nextType != TokenType.LT) {
4757 // This looks like the start of a typedef
4758 return true;
4759 } else if (keyword == Keyword.VOID ||
4760 ((keyword == Keyword.GET || keyword == Keyword.SET) &&
4761 _tokenMatchesIdentifier(next)) ||
4762 (keyword == Keyword.OPERATOR && _isOperator(next))) {
4763 // This looks like the start of a function
4764 return true;
4765 } else if (_matchesIdentifier()) {
4766 if (nextType == TokenType.OPEN_PAREN) {
4767 // This looks like the start of a function
4768 return true;
4769 }
4770 Token token = skipReturnType(_currentToken);
4771 if (token == null) {
4772 return false;
4773 }
4774 // TODO(brianwilkerson) This looks wrong; should we be checking 'token'?
4775 if (keyword == Keyword.GET ||
4776 keyword == Keyword.SET ||
4777 (keyword == Keyword.OPERATOR && _isOperator(next)) ||
4778 _matchesIdentifier()) {
4779 return true;
4780 }
4781 }
4782 return false;
4783 }
4784
4785 /**
4786 * Return a synthetic token representing the given [keyword].
4787 */
4788 Token _createSyntheticKeyword(Keyword keyword) => _injectToken(
4789 new Parser_SyntheticKeywordToken(keyword, _currentToken.offset));
4790
4791 /**
4792 * Return a synthetic token with the given [type].
4793 */
4794 Token _createSyntheticToken(TokenType type) =>
4795 _injectToken(new StringToken(type, "", _currentToken.offset));
4796
4797 /**
4798 * Create and return a new token with the given [type]. The token will replace
4799 * the first portion of the given [token], so it will have the same offset and
4800 * will have any comments that might have preceeded the token.
4801 */
4802 Token _createToken(Token token, TokenType type, {bool isBegin: false}) {
4803 CommentToken comments = token.precedingComments;
4804 if (comments == null) {
4805 if (isBegin) {
4806 return new BeginToken(type, token.offset);
4807 }
4808 return new Token(type, token.offset);
4809 } else if (isBegin) {
4810 return new BeginTokenWithComment(type, token.offset, comments);
4811 }
4812 return new TokenWithComment(type, token.offset, comments);
4813 }
4814
4815 /**
4816 * Check that the given [expression] is assignable and report an error if it
4817 * isn't.
4818 *
4819 * assignableExpression ::=
4820 * primary (arguments* assignableSelector)+
4821 * | 'super' unconditionalAssignableSelector
4822 * | identifier
4823 *
4824 * unconditionalAssignableSelector ::=
4825 * '[' expression ']'
4826 * | '.' identifier
4827 *
4828 * assignableSelector ::=
4829 * unconditionalAssignableSelector
4830 * | '?.' identifier
4831 */
4832 void _ensureAssignable(Expression expression) {
4833 if (expression != null && !expression.isAssignable) {
4834 _reportErrorForCurrentToken(
4835 ParserErrorCode.ILLEGAL_ASSIGNMENT_TO_NON_ASSIGNABLE);
4836 }
4837 }
4838
4839 /**
4840 * If the current token has the expected type, return it after advancing to
4841 * the next token. Otherwise report an error and return the current token
4842 * without advancing.
4843 *
4844 * Note that the method [_expectGt] should be used if the argument to this
4845 * method would be [TokenType.GT].
4846 *
4847 * The [type] is the type of token that is expected.
4848 */
4849 Token _expect(TokenType type) {
4850 if (_matches(type)) {
4851 return getAndAdvance();
4852 }
4853 // Remove uses of this method in favor of matches?
4854 // Pass in the error code to use to report the error?
4855 if (type == TokenType.SEMICOLON) {
4856 if (_tokenMatches(_currentToken.next, TokenType.SEMICOLON)) {
4857 _reportErrorForCurrentToken(
4858 ParserErrorCode.UNEXPECTED_TOKEN, [_currentToken.lexeme]);
4859 _advance();
4860 return getAndAdvance();
4861 }
4862 _reportErrorForToken(ParserErrorCode.EXPECTED_TOKEN,
4863 _currentToken.previous, [type.lexeme]);
4864 return _createSyntheticToken(TokenType.SEMICOLON);
4865 }
4866 _reportErrorForCurrentToken(ParserErrorCode.EXPECTED_TOKEN, [type.lexeme]);
4867 return _createSyntheticToken(type);
4868 }
4869
4870 /**
4871 * If the current token has the type [TokenType.GT], return it after advancing
4872 * to the next token. Otherwise report an error and create a synthetic token.
4873 */
4874 Token _expectGt() {
4875 if (_matchesGt()) {
4876 return getAndAdvance();
4877 }
4878 _reportErrorForCurrentToken(
4879 ParserErrorCode.EXPECTED_TOKEN, [TokenType.GT.lexeme]);
4880 return _createSyntheticToken(TokenType.GT);
4881 }
4882
4883 /**
4884 * If the current token is a keyword matching the given [keyword], return it
4885 * after advancing to the next token. Otherwise report an error and return the
4886 * current token without advancing.
4887 */
4888 Token _expectKeyword(Keyword keyword) {
4889 if (_matchesKeyword(keyword)) {
4890 return getAndAdvance();
4891 }
4892 // Remove uses of this method in favor of matches?
4893 // Pass in the error code to use to report the error?
4894 _reportErrorForCurrentToken(
4895 ParserErrorCode.EXPECTED_TOKEN, [keyword.syntax]);
4896 return _currentToken;
4897 }
4898
4899 /**
4900 * Search the given list of [ranges] for a range that contains the given
4901 * [index]. Return the range that was found, or `null` if none of the ranges
4902 * contain the index.
4903 */
4904 List<int> _findRange(List<List<int>> ranges, int index) {
4905 int rangeCount = ranges.length;
4906 for (int i = 0; i < rangeCount; i++) {
4907 List<int> range = ranges[i];
4908 if (range[0] <= index && index <= range[1]) {
4909 return range;
4910 } else if (index < range[0]) {
4911 return null;
4912 }
4913 }
4914 return null;
4915 }
4916
4917 /**
4918 * Return a list of the ranges of characters in the given [comment] that
4919 * should be treated as code blocks.
4920 */
4921 List<List<int>> _getCodeBlockRanges(String comment) {
4922 List<List<int>> ranges = <List<int>>[];
4923 int length = comment.length;
4924 if (length < 3) {
4925 return ranges;
4926 }
4927 int index = 0;
4928 int firstChar = comment.codeUnitAt(0);
4929 if (firstChar == 0x2F) {
4930 int secondChar = comment.codeUnitAt(1);
4931 int thirdChar = comment.codeUnitAt(2);
4932 if ((secondChar == 0x2A && thirdChar == 0x2A) ||
4933 (secondChar == 0x2F && thirdChar == 0x2F)) {
4934 index = 3;
4935 }
4936 }
4937 if (StringUtilities.startsWith4(comment, index, 0x20, 0x20, 0x20, 0x20)) {
4938 int end = index + 4;
4939 while (end < length &&
4940 comment.codeUnitAt(end) != 0xD &&
4941 comment.codeUnitAt(end) != 0xA) {
4942 end = end + 1;
4943 }
4944 ranges.add(<int>[index, end]);
4945 index = end;
4946 }
4947 while (index < length) {
4948 int currentChar = comment.codeUnitAt(index);
4949 if (currentChar == 0xD || currentChar == 0xA) {
4950 index = index + 1;
4951 while (index < length &&
4952 Character.isWhitespace(comment.codeUnitAt(index))) {
4953 index = index + 1;
4954 }
4955 if (StringUtilities.startsWith6(
4956 comment, index, 0x2A, 0x20, 0x20, 0x20, 0x20, 0x20)) {
4957 int end = index + 6;
4958 while (end < length &&
4959 comment.codeUnitAt(end) != 0xD &&
4960 comment.codeUnitAt(end) != 0xA) {
4961 end = end + 1;
4962 }
4963 ranges.add(<int>[index, end]);
4964 index = end;
4965 }
4966 } else if (index + 1 < length &&
4967 currentChar == 0x5B &&
4968 comment.codeUnitAt(index + 1) == 0x3A) {
4969 int end = StringUtilities.indexOf2(comment, index + 2, 0x3A, 0x5D);
4970 if (end < 0) {
4971 end = length;
4972 }
4973 ranges.add(<int>[index, end]);
4974 index = end + 1;
4975 } else {
4976 index = index + 1;
4977 }
4978 }
4979 return ranges;
4980 }
4981
4982 /**
4983 * Return the end token associated with the given [beginToken], or `null` if
4984 * either the given token is not a begin token or it does not have an end
4985 * token associated with it.
4986 */
4987 Token _getEndToken(Token beginToken) {
4988 if (beginToken is BeginToken) {
4989 return beginToken.endToken;
4990 }
4991 return null;
4992 }
4993
4994 bool _injectGenericComment(TokenType type, int prefixLen) {
4995 if (parseGenericMethodComments) {
4996 CommentToken t = _currentToken.precedingComments;
4997 for (; t != null; t = t.next) {
4998 if (t.type == type) {
4999 String comment = t.lexeme.substring(prefixLen, t.lexeme.length - 2);
5000 Token list = _scanGenericMethodComment(comment, t.offset + prefixLen);
5001 if (list != null) {
5002 // Remove the token from the comment stream.
5003 t.remove();
5004 // Insert the tokens into the stream.
5005 _injectTokenList(list);
5006 return true;
5007 }
5008 }
5009 }
5010 }
5011 return false;
5012 }
5013
5014 /**
5015 * Matches a generic comment type substitution and injects it into the token
5016 * stream. Returns true if a match was injected, otherwise false.
5017 *
5018 * These comments are of the form `/*=T*/`, in other words, a [TypeName]
5019 * inside a slash-star comment, preceded by equals sign.
5020 */
5021 bool _injectGenericCommentTypeAssign() {
5022 return _injectGenericComment(TokenType.GENERIC_METHOD_TYPE_ASSIGN, 3);
5023 }
5024
5025 /**
5026 * Matches a generic comment type parameters and injects them into the token
5027 * stream. Returns true if a match was injected, otherwise false.
5028 *
5029 * These comments are of the form `/*<K, V>*/`, in other words, a
5030 * [TypeParameterList] or [TypeArgumentList] inside a slash-star comment.
5031 */
5032 bool _injectGenericCommentTypeList() {
5033 return _injectGenericComment(TokenType.GENERIC_METHOD_TYPE_LIST, 2);
5034 }
5035
5036 /**
5037 * Inject the given [token] into the token stream immediately before the
5038 * current token.
5039 */
5040 Token _injectToken(Token token) {
5041 Token previous = _currentToken.previous;
5042 token.setNext(_currentToken);
5043 previous.setNext(token);
5044 return token;
5045 }
5046
5047 void _injectTokenList(Token firstToken) {
5048 // Scanner creates a cyclic EOF token.
5049 Token lastToken = firstToken;
5050 while (lastToken.next.type != TokenType.EOF) {
5051 lastToken = lastToken.next;
5052 }
5053 // Inject these new tokens into the stream.
5054 Token previous = _currentToken.previous;
5055 lastToken.setNext(_currentToken);
5056 previous.setNext(firstToken);
5057 _currentToken = firstToken;
5058 }
5059
5060 /**
5061 * Return `true` if the current token could be the question mark in a
5062 * condition expression. The current token is assumed to be a question mark.
5063 */
5064 bool _isConditionalOperator() {
5065 void parseOperation(Parser parser) {
5066 parser.parseExpressionWithoutCascade();
5067 }
5068
5069 Token token = _skip(_currentToken.next, parseOperation);
5070 if (token == null || !_tokenMatches(token, TokenType.COLON)) {
5071 return false;
5072 }
5073 token = _skip(token.next, parseOperation);
5074 return token != null;
5075 }
5076
5077 /**
5078 * Return `true` if the given [character] is a valid hexadecimal digit.
5079 */
5080 bool _isHexDigit(int character) =>
5081 (0x30 <= character && character <= 0x39) ||
5082 (0x41 <= character && character <= 0x46) ||
5083 (0x61 <= character && character <= 0x66);
5084
5085 bool _isLikelyArgumentList() {
5086 // Try to reduce the amount of lookahead required here before enabling
5087 // generic methods.
5088 if (_matches(TokenType.OPEN_PAREN)) {
5089 return true;
5090 }
5091 if (!parseGenericMethods) {
5092 return false;
5093 }
5094 Token token = skipTypeArgumentList(_currentToken);
5095 return token != null && _tokenMatches(token, TokenType.OPEN_PAREN);
5096 }
5097
5098 /**
5099 * Given that we have just found bracketed text within the given [comment],
5100 * look to see whether that text is (a) followed by a parenthesized link
5101 * address, (b) followed by a colon, or (c) followed by optional whitespace
5102 * and another square bracket. The [rightIndex] is the index of the right
5103 * bracket. Return `true` if the bracketed text is followed by a link address.
5104 *
5105 * This method uses the syntax described by the
5106 * <a href="http://daringfireball.net/projects/markdown/syntax">markdown</a>
5107 * project.
5108 */
5109 bool _isLinkText(String comment, int rightIndex) {
5110 int length = comment.length;
5111 int index = rightIndex + 1;
5112 if (index >= length) {
5113 return false;
5114 }
5115 int nextChar = comment.codeUnitAt(index);
5116 if (nextChar == 0x28 || nextChar == 0x3A) {
5117 return true;
5118 }
5119 while (Character.isWhitespace(nextChar)) {
5120 index = index + 1;
5121 if (index >= length) {
5122 return false;
5123 }
5124 nextChar = comment.codeUnitAt(index);
5125 }
5126 return nextChar == 0x5B;
5127 }
5128
5129 /**
5130 * Return `true` if the given [startToken] appears to be the beginning of an
5131 * operator declaration.
5132 */
5133 bool _isOperator(Token startToken) {
5134 // Accept any operator here, even if it is not user definable.
5135 if (!startToken.isOperator) {
5136 return false;
5137 }
5138 // Token "=" means that it is actually a field initializer.
5139 if (startToken.type == TokenType.EQ) {
5140 return false;
5141 }
5142 // Consume all operator tokens.
5143 Token token = startToken.next;
5144 while (token.isOperator) {
5145 token = token.next;
5146 }
5147 // Formal parameter list is expect now.
5148 return _tokenMatches(token, TokenType.OPEN_PAREN);
5149 }
5150
5151 bool _isPeekGenericTypeParametersAndOpenParen() {
5152 if (!parseGenericMethods) {
5153 return false;
5154 }
5155 Token token = _skipTypeParameterList(_peek());
5156 return token != null && _tokenMatches(token, TokenType.OPEN_PAREN);
5157 }
5158
5159 /**
5160 * Return `true` if the [startToken] appears to be the first token of a type
5161 * name that is followed by a variable or field formal parameter.
5162 */
5163 bool _isTypedIdentifier(Token startToken) {
5164 Token token = skipReturnType(startToken);
5165 if (token == null) {
5166 return false;
5167 } else if (_tokenMatchesIdentifier(token)) {
5168 return true;
5169 } else if (_tokenMatchesKeyword(token, Keyword.THIS) &&
5170 _tokenMatches(token.next, TokenType.PERIOD) &&
5171 _tokenMatchesIdentifier(token.next.next)) {
5172 return true;
5173 } else if (_tokenMatchesKeyword(startToken, Keyword.VOID)) {
5174 // The keyword 'void' isn't a valid identifier, so it should be assumed to
5175 // be a type name.
5176 return true;
5177 } else if (startToken.next != token &&
5178 !_tokenMatches(token, TokenType.OPEN_PAREN)) {
5179 // The type is more than a simple identifier, so it should be assumed to
5180 // be a type name.
5181 return true;
5182 }
5183 return false;
5184 }
5185
5186 /**
5187 * Increments the error reporting lock level. If level is more than `0`, then
5188 * [reportError] wont report any error.
5189 */
5190 void _lockErrorListener() {
5191 _errorListenerLock++;
5192 }
5193
5194 /**
5195 * Return `true` if the current token has the given [type]. Note that the
5196 * method [_matchesGt] should be used if the argument to this method would be
5197 * [TokenType.GT].
5198 */
5199 bool _matches(TokenType type) => _currentToken.type == type;
5200
5201 /**
5202 * Return `true` if the current token has a type of [TokenType.GT]. Note that
5203 * this method, unlike other variants, will modify the token stream if
5204 * possible to match desired type. In particular, if the next token is either
5205 * a '>>' or '>>>', the token stream will be re-written and `true` will be
5206 * returned.
5207 */
5208 bool _matchesGt() {
5209 TokenType currentType = _currentToken.type;
5210 if (currentType == TokenType.GT) {
5211 return true;
5212 } else if (currentType == TokenType.GT_GT) {
5213 Token first = _createToken(_currentToken, TokenType.GT);
5214 Token second = new Token(TokenType.GT, _currentToken.offset + 1);
5215 second.setNext(_currentToken.next);
5216 first.setNext(second);
5217 _currentToken.previous.setNext(first);
5218 _currentToken = first;
5219 return true;
5220 } else if (currentType == TokenType.GT_EQ) {
5221 Token first = _createToken(_currentToken, TokenType.GT);
5222 Token second = new Token(TokenType.EQ, _currentToken.offset + 1);
5223 second.setNext(_currentToken.next);
5224 first.setNext(second);
5225 _currentToken.previous.setNext(first);
5226 _currentToken = first;
5227 return true;
5228 } else if (currentType == TokenType.GT_GT_EQ) {
5229 int offset = _currentToken.offset;
5230 Token first = _createToken(_currentToken, TokenType.GT);
5231 Token second = new Token(TokenType.GT, offset + 1);
5232 Token third = new Token(TokenType.EQ, offset + 2);
5233 third.setNext(_currentToken.next);
5234 second.setNext(third);
5235 first.setNext(second);
5236 _currentToken.previous.setNext(first);
5237 _currentToken = first;
5238 return true;
5239 }
5240 return false;
5241 }
5242
5243 /**
5244 * Return `true` if the current token is a valid identifier. Valid identifiers
5245 * include built-in identifiers (pseudo-keywords).
5246 */
5247 bool _matchesIdentifier() => _tokenMatchesIdentifier(_currentToken);
5248
5249 /**
5250 * Return `true` if the current token matches the given [keyword].
5251 */
5252 bool _matchesKeyword(Keyword keyword) =>
5253 _tokenMatchesKeyword(_currentToken, keyword);
5254
5255 /**
5256 * Return `true` if the current token matches the given [identifier].
5257 */
5258 bool _matchesString(String identifier) =>
5259 _currentToken.type == TokenType.IDENTIFIER &&
5260 _currentToken.lexeme == identifier;
5261
5262 /**
5263 * If the current token has the given [type], then advance to the next token
5264 * and return `true`. Otherwise, return `false` without advancing. This method
5265 * should not be invoked with an argument value of [TokenType.GT].
5266 */
5267 bool _optional(TokenType type) {
5268 if (_currentToken.type == type) {
5269 _advance();
5270 return true;
5271 }
5272 return false;
5273 }
5274
5275 /**
5276 * Parse an argument list when we need to check for an open paren and recover
5277 * when there isn't one. Return the argument list that was parsed.
5278 */
5279 ArgumentList _parseArgumentListChecked() {
5280 if (_matches(TokenType.OPEN_PAREN)) {
5281 return parseArgumentList();
5282 }
5283 _reportErrorForCurrentToken(
5284 ParserErrorCode.EXPECTED_TOKEN, [TokenType.OPEN_PAREN.lexeme]);
5285 // Recovery: Look to see whether there is a close paren that isn't matched
5286 // to an open paren and if so parse the list of arguments as normal.
5287 return new ArgumentList(_createSyntheticToken(TokenType.OPEN_PAREN), null,
5288 _createSyntheticToken(TokenType.CLOSE_PAREN));
5289 }
5290
5291 /**
5292 * Parse an assert within a constructor's initializer list. Return the assert.
5293 *
5294 * This method assumes that the current token matches `Keyword.ASSERT`.
5295 *
5296 * assertInitializer ::=
5297 * 'assert' '(' expression [',' expression] ')'
5298 */
5299 void _parseAssertInitializer() {
5300 // TODO(brianwilkerson) Capture the syntax in the AST using a new class,
5301 // such as AssertInitializer
5302 Token keyword = getAndAdvance();
5303 Token leftParen = _expect(TokenType.OPEN_PAREN);
5304 Expression expression = parseExpression2();
5305 Token comma;
5306 Expression message;
5307 if (_matches(TokenType.COMMA)) {
5308 comma = getAndAdvance();
5309 message = parseExpression2();
5310 }
5311 Token rightParen = _expect(TokenType.CLOSE_PAREN);
5312 // return new AssertInitializer(
5313 // keyword, leftParen, expression, comma, message, rightParen);
5314 }
5315
5316 /**
5317 * Parse an assignable expression given that the current token is not 'super'.
5318 * The [primaryAllowed] is `true` if the expression is allowed to be a primary
5319 * without any assignable selector. Return the assignable expression that was
5320 * parsed.
5321 */
5322 Expression _parseAssignableExpressionNotStartingWithSuper(
5323 bool primaryAllowed) {
5324 //
5325 // A primary expression can start with an identifier. We resolve the
5326 // ambiguity by determining whether the primary consists of anything other
5327 // than an identifier and/or is followed by an assignableSelector.
5328 //
5329 Expression expression = parsePrimaryExpression();
5330 bool isOptional = primaryAllowed || expression is SimpleIdentifier;
5331 while (true) {
5332 while (_isLikelyArgumentList()) {
5333 TypeArgumentList typeArguments = _parseOptionalTypeArguments();
5334 ArgumentList argumentList = parseArgumentList();
5335 Expression currentExpression = expression;
5336 if (currentExpression is SimpleIdentifier) {
5337 expression = new MethodInvocation(
5338 null, null, currentExpression, typeArguments, argumentList);
5339 } else if (currentExpression is PrefixedIdentifier) {
5340 expression = new MethodInvocation(
5341 currentExpression.prefix,
5342 currentExpression.period,
5343 currentExpression.identifier,
5344 typeArguments,
5345 argumentList);
5346 } else if (currentExpression is PropertyAccess) {
5347 expression = new MethodInvocation(
5348 currentExpression.target,
5349 currentExpression.operator,
5350 currentExpression.propertyName,
5351 typeArguments,
5352 argumentList);
5353 } else {
5354 expression = new FunctionExpressionInvocation(
5355 expression, typeArguments, argumentList);
5356 }
5357 if (!primaryAllowed) {
5358 isOptional = false;
5359 }
5360 }
5361 Expression selectorExpression = _parseAssignableSelector(
5362 expression, isOptional || (expression is PrefixedIdentifier));
5363 if (identical(selectorExpression, expression)) {
5364 if (!isOptional && (expression is PrefixedIdentifier)) {
5365 PrefixedIdentifier identifier = expression as PrefixedIdentifier;
5366 expression = new PropertyAccess(
5367 identifier.prefix, identifier.period, identifier.identifier);
5368 }
5369 return expression;
5370 }
5371 expression = selectorExpression;
5372 isOptional = true;
5373 }
5374 }
5375
5376 /**
5377 * Parse an assignable selector. The [prefix] is the expression preceding the
5378 * selector. The [optional] is `true` if the selector is optional. Return the
5379 * assignable selector that was parsed, or the original prefix if there was no
5380 * assignable selector. If [allowConditional] is false, then the '?.'
5381 * operator will still be parsed, but a parse error will be generated.
5382 *
5383 * unconditionalAssignableSelector ::=
5384 * '[' expression ']'
5385 * | '.' identifier
5386 *
5387 * assignableSelector ::=
5388 * unconditionalAssignableSelector
5389 * | '?.' identifier
5390 */
5391 Expression _parseAssignableSelector(Expression prefix, bool optional,
5392 {bool allowConditional: true}) {
5393 TokenType type = _currentToken.type;
5394 if (type == TokenType.OPEN_SQUARE_BRACKET) {
5395 Token leftBracket = getAndAdvance();
5396 bool wasInInitializer = _inInitializer;
5397 _inInitializer = false;
5398 try {
5399 Expression index = parseExpression2();
5400 Token rightBracket = _expect(TokenType.CLOSE_SQUARE_BRACKET);
5401 return new IndexExpression.forTarget(
5402 prefix, leftBracket, index, rightBracket);
5403 } finally {
5404 _inInitializer = wasInInitializer;
5405 }
5406 } else {
5407 bool isQuestionPeriod = type == TokenType.QUESTION_PERIOD;
5408 if (type == TokenType.PERIOD || isQuestionPeriod) {
5409 if (isQuestionPeriod && !allowConditional) {
5410 _reportErrorForCurrentToken(
5411 ParserErrorCode.INVALID_OPERATOR_FOR_SUPER,
5412 [_currentToken.lexeme]);
5413 }
5414 Token operator = getAndAdvance();
5415 return new PropertyAccess(prefix, operator, parseSimpleIdentifier());
5416 } else {
5417 if (!optional) {
5418 // Report the missing selector.
5419 _reportErrorForCurrentToken(
5420 ParserErrorCode.MISSING_ASSIGNABLE_SELECTOR);
5421 }
5422 return prefix;
5423 }
5424 }
5425 }
5426
5427 /**
5428 * Parse a block when we need to check for an open curly brace and recover
5429 * when there isn't one. Return the block that was parsed.
5430 *
5431 * block ::=
5432 * '{' statements '}'
5433 */
5434 Block _parseBlockChecked() {
5435 if (_matches(TokenType.OPEN_CURLY_BRACKET)) {
5436 return parseBlock();
5437 }
5438 // TODO(brianwilkerson) Improve the error message.
5439 _reportErrorForCurrentToken(
5440 ParserErrorCode.EXPECTED_TOKEN, [TokenType.OPEN_CURLY_BRACKET.lexeme]);
5441 // Recovery: Check for an unmatched closing curly bracket and parse
5442 // statements until it is reached.
5443 return new Block(_createSyntheticToken(TokenType.OPEN_CURLY_BRACKET), null,
5444 _createSyntheticToken(TokenType.CLOSE_CURLY_BRACKET));
5445 }
5446
5447 /**
5448 * Parse a list of class members. The [className] is the name of the class
5449 * whose members are being parsed. The [closingBracket] is the closing bracket
5450 * for the class, or `null` if the closing bracket is missing. Return the list
5451 * of class members that were parsed.
5452 *
5453 * classMembers ::=
5454 * (metadata memberDefinition)*
5455 */
5456 List<ClassMember> _parseClassMembers(String className, Token closingBracket) {
5457 List<ClassMember> members = <ClassMember>[];
5458 Token memberStart = _currentToken;
5459 TokenType type = _currentToken.type;
5460 Keyword keyword = _currentToken.keyword;
5461 while (type != TokenType.EOF &&
5462 type != TokenType.CLOSE_CURLY_BRACKET &&
5463 (closingBracket != null ||
5464 (keyword != Keyword.CLASS && keyword != Keyword.TYPEDEF))) {
5465 if (type == TokenType.SEMICOLON) {
5466 _reportErrorForToken(ParserErrorCode.UNEXPECTED_TOKEN, _currentToken,
5467 [_currentToken.lexeme]);
5468 _advance();
5469 } else {
5470 ClassMember member = parseClassMember(className);
5471 if (member != null) {
5472 members.add(member);
5473 }
5474 }
5475 if (identical(_currentToken, memberStart)) {
5476 _reportErrorForToken(ParserErrorCode.UNEXPECTED_TOKEN, _currentToken,
5477 [_currentToken.lexeme]);
5478 _advance();
5479 }
5480 memberStart = _currentToken;
5481 type = _currentToken.type;
5482 keyword = _currentToken.keyword;
5483 }
5484 return members;
5485 }
5486
5487 /**
5488 * Parse a class type alias. The [commentAndMetadata] is the metadata to be
5489 * associated with the member. The [abstractKeyword] is the token representing
5490 * the 'abstract' keyword. The [classKeyword] is the token representing the
5491 * 'class' keyword. The [className] is the name of the alias, and the
5492 * [typeParameters] are the type parameters following the name. Return the
5493 * class type alias that was parsed.
5494 *
5495 * classTypeAlias ::=
5496 * identifier typeParameters? '=' 'abstract'? mixinApplication
5497 *
5498 * mixinApplication ::=
5499 * type withClause implementsClause? ';'
5500 */
5501 ClassTypeAlias _parseClassTypeAliasAfterName(
5502 CommentAndMetadata commentAndMetadata,
5503 Token abstractKeyword,
5504 Token classKeyword,
5505 SimpleIdentifier className,
5506 TypeParameterList typeParameters) {
5507 Token equals = _expect(TokenType.EQ);
5508 TypeName superclass = parseTypeName(false);
5509 WithClause withClause = null;
5510 if (_matchesKeyword(Keyword.WITH)) {
5511 withClause = parseWithClause();
5512 } else {
5513 _reportErrorForCurrentToken(
5514 ParserErrorCode.EXPECTED_TOKEN, [Keyword.WITH.syntax]);
5515 }
5516 ImplementsClause implementsClause = null;
5517 if (_matchesKeyword(Keyword.IMPLEMENTS)) {
5518 implementsClause = parseImplementsClause();
5519 }
5520 Token semicolon;
5521 if (_matches(TokenType.SEMICOLON)) {
5522 semicolon = getAndAdvance();
5523 } else {
5524 if (_matches(TokenType.OPEN_CURLY_BRACKET)) {
5525 _reportErrorForCurrentToken(
5526 ParserErrorCode.EXPECTED_TOKEN, [TokenType.SEMICOLON.lexeme]);
5527 Token leftBracket = getAndAdvance();
5528 _parseClassMembers(className.name, _getEndToken(leftBracket));
5529 _expect(TokenType.CLOSE_CURLY_BRACKET);
5530 } else {
5531 _reportErrorForToken(ParserErrorCode.EXPECTED_TOKEN,
5532 _currentToken.previous, [TokenType.SEMICOLON.lexeme]);
5533 }
5534 semicolon = _createSyntheticToken(TokenType.SEMICOLON);
5535 }
5536 return new ClassTypeAlias(
5537 commentAndMetadata.comment,
5538 commentAndMetadata.metadata,
5539 classKeyword,
5540 className,
5541 typeParameters,
5542 equals,
5543 abstractKeyword,
5544 superclass,
5545 withClause,
5546 implementsClause,
5547 semicolon);
5548 }
5549
5550 /**
5551 * Parse all of the comment references occurring in the given array of
5552 * documentation comments. The [tokens] are the comment tokens representing
5553 * the documentation comments to be parsed. Return the comment references that
5554 * were parsed.
5555 *
5556 * commentReference ::=
5557 * '[' 'new'? qualified ']' libraryReference?
5558 *
5559 * libraryReference ::=
5560 * '(' stringLiteral ')'
5561 */
5562 List<CommentReference> _parseCommentReferences(
5563 List<DocumentationCommentToken> tokens) {
5564 List<CommentReference> references = <CommentReference>[];
5565 bool isInGitHubCodeBlock = false;
5566 for (DocumentationCommentToken token in tokens) {
5567 String comment = token.lexeme;
5568 // Skip GitHub code blocks.
5569 // https://help.github.com/articles/creating-and-highlighting-code-blocks/
5570 if (tokens.length != 1) {
5571 if (comment.indexOf('```') != -1) {
5572 isInGitHubCodeBlock = !isInGitHubCodeBlock;
5573 }
5574 if (isInGitHubCodeBlock) {
5575 continue;
5576 }
5577 }
5578 // Remove GitHub include code.
5579 comment = _removeGitHubInlineCode(comment);
5580 // Find references.
5581 int length = comment.length;
5582 List<List<int>> codeBlockRanges = _getCodeBlockRanges(comment);
5583 int leftIndex = comment.indexOf('[');
5584 while (leftIndex >= 0 && leftIndex + 1 < length) {
5585 List<int> range = _findRange(codeBlockRanges, leftIndex);
5586 if (range == null) {
5587 int nameOffset = token.offset + leftIndex + 1;
5588 int rightIndex = comment.indexOf(']', leftIndex);
5589 if (rightIndex >= 0) {
5590 int firstChar = comment.codeUnitAt(leftIndex + 1);
5591 if (firstChar != 0x27 && firstChar != 0x22) {
5592 if (_isLinkText(comment, rightIndex)) {
5593 // TODO(brianwilkerson) Handle the case where there's a library
5594 // URI in the link text.
5595 } else {
5596 CommentReference reference = parseCommentReference(
5597 comment.substring(leftIndex + 1, rightIndex), nameOffset);
5598 if (reference != null) {
5599 references.add(reference);
5600 token.references.add(reference.beginToken);
5601 }
5602 }
5603 }
5604 } else {
5605 // terminating ']' is not typed yet
5606 int charAfterLeft = comment.codeUnitAt(leftIndex + 1);
5607 Token nameToken;
5608 if (Character.isLetterOrDigit(charAfterLeft)) {
5609 int nameEnd = StringUtilities.indexOfFirstNotLetterDigit(
5610 comment, leftIndex + 1);
5611 String name = comment.substring(leftIndex + 1, nameEnd);
5612 nameToken =
5613 new StringToken(TokenType.IDENTIFIER, name, nameOffset);
5614 } else {
5615 nameToken = new SyntheticStringToken(
5616 TokenType.IDENTIFIER, '', nameOffset);
5617 }
5618 nameToken.setNext(new SimpleToken(TokenType.EOF, nameToken.end));
5619 references.add(
5620 new CommentReference(null, new SimpleIdentifier(nameToken)));
5621 token.references.add(nameToken);
5622 // next character
5623 rightIndex = leftIndex + 1;
5624 }
5625 leftIndex = comment.indexOf('[', rightIndex);
5626 } else {
5627 leftIndex = comment.indexOf('[', range[1]);
5628 }
5629 }
5630 }
5631 return references;
5632 }
5633
5634 /**
5635 * Parse a list of configurations. Return the configurations that were parsed,
5636 * or `null` if there are no configurations.
5637 */
5638 List<Configuration> _parseConfigurations() {
5639 List<Configuration> configurations = null;
5640 while (_matchesKeyword(Keyword.IF)) {
5641 configurations ??= <Configuration>[];
5642 configurations.add(parseConfiguration());
5643 }
5644 return configurations;
5645 }
5646
5647 ConstructorDeclaration _parseConstructor(
5648 CommentAndMetadata commentAndMetadata,
5649 Token externalKeyword,
5650 Token constKeyword,
5651 Token factoryKeyword,
5652 SimpleIdentifier returnType,
5653 Token period,
5654 SimpleIdentifier name,
5655 FormalParameterList parameters) {
5656 bool bodyAllowed = externalKeyword == null;
5657 Token separator = null;
5658 List<ConstructorInitializer> initializers = null;
5659 if (_matches(TokenType.COLON)) {
5660 separator = getAndAdvance();
5661 initializers = <ConstructorInitializer>[];
5662 do {
5663 Keyword keyword = _currentToken.keyword;
5664 if (keyword == Keyword.THIS) {
5665 TokenType nextType = _peek().type;
5666 if (nextType == TokenType.OPEN_PAREN) {
5667 bodyAllowed = false;
5668 initializers.add(_parseRedirectingConstructorInvocation(false));
5669 } else if (nextType == TokenType.PERIOD &&
5670 _tokenMatches(_peekAt(3), TokenType.OPEN_PAREN)) {
5671 bodyAllowed = false;
5672 initializers.add(_parseRedirectingConstructorInvocation(true));
5673 } else {
5674 initializers.add(_parseConstructorFieldInitializer(true));
5675 }
5676 } else if (keyword == Keyword.SUPER) {
5677 initializers.add(parseSuperConstructorInvocation());
5678 } else if (_matches(TokenType.OPEN_CURLY_BRACKET) ||
5679 _matches(TokenType.FUNCTION)) {
5680 _reportErrorForCurrentToken(ParserErrorCode.MISSING_INITIALIZER);
5681 } else if (_enableAssertInitializer &&
5682 _matchesKeyword(Keyword.ASSERT)) {
5683 _parseAssertInitializer();
5684 } else {
5685 initializers.add(_parseConstructorFieldInitializer(false));
5686 }
5687 } while (_optional(TokenType.COMMA));
5688 if (factoryKeyword != null) {
5689 _reportErrorForToken(
5690 ParserErrorCode.FACTORY_WITH_INITIALIZERS, factoryKeyword);
5691 }
5692 }
5693 ConstructorName redirectedConstructor = null;
5694 FunctionBody body;
5695 if (_matches(TokenType.EQ)) {
5696 separator = getAndAdvance();
5697 redirectedConstructor = parseConstructorName();
5698 body = new EmptyFunctionBody(_expect(TokenType.SEMICOLON));
5699 if (factoryKeyword == null) {
5700 _reportErrorForNode(
5701 ParserErrorCode.REDIRECTION_IN_NON_FACTORY_CONSTRUCTOR,
5702 redirectedConstructor);
5703 }
5704 } else {
5705 body =
5706 parseFunctionBody(true, ParserErrorCode.MISSING_FUNCTION_BODY, false);
5707 if (constKeyword != null &&
5708 factoryKeyword != null &&
5709 externalKeyword == null) {
5710 _reportErrorForToken(ParserErrorCode.CONST_FACTORY, factoryKeyword);
5711 } else if (body is EmptyFunctionBody) {
5712 if (factoryKeyword != null &&
5713 externalKeyword == null &&
5714 _parseFunctionBodies) {
5715 _reportErrorForToken(
5716 ParserErrorCode.FACTORY_WITHOUT_BODY, factoryKeyword);
5717 }
5718 } else {
5719 if (constKeyword != null) {
5720 _reportErrorForNode(
5721 ParserErrorCode.CONST_CONSTRUCTOR_WITH_BODY, body);
5722 } else if (externalKeyword != null) {
5723 _reportErrorForNode(
5724 ParserErrorCode.EXTERNAL_CONSTRUCTOR_WITH_BODY, body);
5725 } else if (!bodyAllowed) {
5726 _reportErrorForNode(
5727 ParserErrorCode.REDIRECTING_CONSTRUCTOR_WITH_BODY, body);
5728 }
5729 }
5730 }
5731 return new ConstructorDeclaration(
5732 commentAndMetadata.comment,
5733 commentAndMetadata.metadata,
5734 externalKeyword,
5735 constKeyword,
5736 factoryKeyword,
5737 returnType,
5738 period,
5739 name,
5740 parameters,
5741 separator,
5742 initializers,
5743 redirectedConstructor,
5744 body);
5745 }
5746
5747 /**
5748 * Parse a field initializer within a constructor. The flag [hasThis] should
5749 * be true if the current token is `this`. Return the field initializer that
5750 * was parsed.
5751 *
5752 * fieldInitializer:
5753 * ('this' '.')? identifier '=' conditionalExpression cascadeSection*
5754 */
5755 ConstructorFieldInitializer _parseConstructorFieldInitializer(bool hasThis) {
5756 Token keywordToken = null;
5757 Token period = null;
5758 if (hasThis) {
5759 keywordToken = getAndAdvance();
5760 period = _expect(TokenType.PERIOD);
5761 }
5762 SimpleIdentifier fieldName = parseSimpleIdentifier();
5763 Token equals = null;
5764 TokenType type = _currentToken.type;
5765 if (type == TokenType.EQ) {
5766 equals = getAndAdvance();
5767 } else {
5768 _reportErrorForCurrentToken(
5769 ParserErrorCode.MISSING_ASSIGNMENT_IN_INITIALIZER);
5770 Keyword keyword = _currentToken.keyword;
5771 if (keyword != Keyword.THIS &&
5772 keyword != Keyword.SUPER &&
5773 type != TokenType.OPEN_CURLY_BRACKET &&
5774 type != TokenType.FUNCTION) {
5775 equals = _createSyntheticToken(TokenType.EQ);
5776 } else {
5777 return new ConstructorFieldInitializer(keywordToken, period, fieldName,
5778 _createSyntheticToken(TokenType.EQ), createSyntheticIdentifier());
5779 }
5780 }
5781 bool wasInInitializer = _inInitializer;
5782 _inInitializer = true;
5783 try {
5784 Expression expression = parseConditionalExpression();
5785 if (_matches(TokenType.PERIOD_PERIOD)) {
5786 List<Expression> cascadeSections = <Expression>[];
5787 do {
5788 Expression section = parseCascadeSection();
5789 if (section != null) {
5790 cascadeSections.add(section);
5791 }
5792 } while (_matches(TokenType.PERIOD_PERIOD));
5793 expression = new CascadeExpression(expression, cascadeSections);
5794 }
5795 return new ConstructorFieldInitializer(
5796 keywordToken, period, fieldName, equals, expression);
5797 } finally {
5798 _inInitializer = wasInInitializer;
5799 }
5800 }
5801
5802 /**
5803 * Parse a directive. The [commentAndMetadata] is the metadata to be
5804 * associated with the directive. Return the directive that was parsed.
5805 *
5806 * directive ::=
5807 * exportDirective
5808 * | libraryDirective
5809 * | importDirective
5810 * | partDirective
5811 */
5812 Directive _parseDirective(CommentAndMetadata commentAndMetadata) {
5813 if (_matchesKeyword(Keyword.IMPORT)) {
5814 return _parseImportDirective(commentAndMetadata);
5815 } else if (_matchesKeyword(Keyword.EXPORT)) {
5816 return _parseExportDirective(commentAndMetadata);
5817 } else if (_matchesKeyword(Keyword.LIBRARY)) {
5818 return _parseLibraryDirective(commentAndMetadata);
5819 } else if (_matchesKeyword(Keyword.PART)) {
5820 return _parsePartOrPartOfDirective(commentAndMetadata);
5821 } else {
5822 // Internal error: this method should not have been invoked if the current
5823 // token was something other than one of the above.
5824 throw new StateError(
5825 "parseDirective invoked in an invalid state; currentToken = $_currentT oken");
5826 }
5827 }
5828
5829 /**
5830 * Parse an enum constant declaration. Return the enum constant declaration
5831 * that was parsed.
5832 *
5833 * Specified:
5834 *
5835 * enumConstant ::=
5836 * id
5837 *
5838 * Actual:
5839 *
5840 * enumConstant ::=
5841 * metadata id
5842 */
5843 EnumConstantDeclaration _parseEnumConstantDeclaration() {
5844 CommentAndMetadata commentAndMetadata = parseCommentAndMetadata();
5845 SimpleIdentifier name;
5846 if (_matchesIdentifier()) {
5847 name = _parseSimpleIdentifierUnchecked(isDeclaration: true);
5848 } else {
5849 name = createSyntheticIdentifier();
5850 }
5851 if (commentAndMetadata.hasMetadata) {
5852 _reportErrorForNode(ParserErrorCode.ANNOTATION_ON_ENUM_CONSTANT,
5853 commentAndMetadata.metadata[0]);
5854 }
5855 return new EnumConstantDeclaration(
5856 commentAndMetadata.comment, commentAndMetadata.metadata, name);
5857 }
5858
5859 /**
5860 * Parse an equality expression. Return the equality expression that was
5861 * parsed.
5862 *
5863 * equalityExpression ::=
5864 * relationalExpression (equalityOperator relationalExpression)?
5865 * | 'super' equalityOperator relationalExpression
5866 */
5867 Expression _parseEqualityExpression() {
5868 Expression expression;
5869 if (_currentToken.keyword == Keyword.SUPER &&
5870 _currentToken.next.type.isEqualityOperator) {
5871 expression = new SuperExpression(getAndAdvance());
5872 } else {
5873 expression = parseRelationalExpression();
5874 }
5875 bool leftEqualityExpression = false;
5876 while (_currentToken.type.isEqualityOperator) {
5877 if (leftEqualityExpression) {
5878 _reportErrorForNode(
5879 ParserErrorCode.EQUALITY_CANNOT_BE_EQUALITY_OPERAND, expression);
5880 }
5881 expression = new BinaryExpression(
5882 expression, getAndAdvance(), parseRelationalExpression());
5883 leftEqualityExpression = true;
5884 }
5885 return expression;
5886 }
5887
5888 /**
5889 * Parse an export directive. The [commentAndMetadata] is the metadata to be
5890 * associated with the directive. Return the export directive that was parsed.
5891 *
5892 * This method assumes that the current token matches `Keyword.EXPORT`.
5893 *
5894 * exportDirective ::=
5895 * metadata 'export' stringLiteral configuration* combinator*';'
5896 */
5897 ExportDirective _parseExportDirective(CommentAndMetadata commentAndMetadata) {
5898 Token exportKeyword = getAndAdvance();
5899 StringLiteral libraryUri = _parseUri();
5900 List<Configuration> configurations = _parseConfigurations();
5901 List<Combinator> combinators = parseCombinators();
5902 Token semicolon = _expect(TokenType.SEMICOLON);
5903 return new ExportDirective(
5904 commentAndMetadata.comment,
5905 commentAndMetadata.metadata,
5906 exportKeyword,
5907 libraryUri,
5908 configurations,
5909 combinators,
5910 semicolon);
5911 }
5912
5913 /**
5914 * Parse a formal parameter. At most one of `isOptional` and `isNamed` can be
5915 * `true`. The [kind] is the kind of parameter being expected based on the
5916 * presence or absence of group delimiters. Return the formal parameter that
5917 * was parsed.
5918 *
5919 * defaultFormalParameter ::=
5920 * normalFormalParameter ('=' expression)?
5921 *
5922 * defaultNamedParameter ::=
5923 * normalFormalParameter (':' expression)?
5924 */
5925 FormalParameter _parseFormalParameter(ParameterKind kind) {
5926 NormalFormalParameter parameter = parseNormalFormalParameter();
5927 TokenType type = _currentToken.type;
5928 if (type == TokenType.EQ) {
5929 Token separator = getAndAdvance();
5930 Expression defaultValue = parseExpression2();
5931 if (kind == ParameterKind.NAMED) {
5932 _reportErrorForToken(
5933 ParserErrorCode.WRONG_SEPARATOR_FOR_NAMED_PARAMETER, separator);
5934 } else if (kind == ParameterKind.REQUIRED) {
5935 _reportErrorForNode(
5936 ParserErrorCode.POSITIONAL_PARAMETER_OUTSIDE_GROUP, parameter);
5937 }
5938 return new DefaultFormalParameter(
5939 parameter, kind, separator, defaultValue);
5940 } else if (type == TokenType.COLON) {
5941 Token separator = getAndAdvance();
5942 Expression defaultValue = parseExpression2();
5943 if (kind == ParameterKind.POSITIONAL) {
5944 _reportErrorForToken(
5945 ParserErrorCode.WRONG_SEPARATOR_FOR_POSITIONAL_PARAMETER,
5946 separator);
5947 } else if (kind == ParameterKind.REQUIRED) {
5948 _reportErrorForNode(
5949 ParserErrorCode.NAMED_PARAMETER_OUTSIDE_GROUP, parameter);
5950 }
5951 return new DefaultFormalParameter(
5952 parameter, kind, separator, defaultValue);
5953 } else if (kind != ParameterKind.REQUIRED) {
5954 return new DefaultFormalParameter(parameter, kind, null, null);
5955 }
5956 return parameter;
5957 }
5958
5959 /**
5960 * Parse a list of formal parameters given that the list starts with the given
5961 * [leftParenthesis]. Return the formal parameters that were parsed.
5962 */
5963 FormalParameterList _parseFormalParameterListAfterParen(
5964 Token leftParenthesis) {
5965 if (_matches(TokenType.CLOSE_PAREN)) {
5966 return new FormalParameterList(
5967 leftParenthesis, null, null, null, getAndAdvance());
5968 }
5969 //
5970 // Even though it is invalid to have default parameters outside of brackets,
5971 // required parameters inside of brackets, or multiple groups of default and
5972 // named parameters, we allow all of these cases so that we can recover
5973 // better.
5974 //
5975 List<FormalParameter> parameters = <FormalParameter>[];
5976 Token leftSquareBracket = null;
5977 Token rightSquareBracket = null;
5978 Token leftCurlyBracket = null;
5979 Token rightCurlyBracket = null;
5980 ParameterKind kind = ParameterKind.REQUIRED;
5981 bool firstParameter = true;
5982 bool reportedMultiplePositionalGroups = false;
5983 bool reportedMultipleNamedGroups = false;
5984 bool reportedMixedGroups = false;
5985 bool wasOptionalParameter = false;
5986 Token initialToken = null;
5987 do {
5988 if (firstParameter) {
5989 firstParameter = false;
5990 } else if (!_optional(TokenType.COMMA)) {
5991 // TODO(brianwilkerson) The token is wrong, we need to recover from this
5992 // case.
5993 if (_getEndToken(leftParenthesis) != null) {
5994 _reportErrorForCurrentToken(
5995 ParserErrorCode.EXPECTED_TOKEN, [TokenType.COMMA.lexeme]);
5996 } else {
5997 _reportErrorForToken(ParserErrorCode.MISSING_CLOSING_PARENTHESIS,
5998 _currentToken.previous);
5999 break;
6000 }
6001 }
6002 initialToken = _currentToken;
6003 //
6004 // Handle the beginning of parameter groups.
6005 //
6006 TokenType type = _currentToken.type;
6007 if (type == TokenType.OPEN_SQUARE_BRACKET) {
6008 wasOptionalParameter = true;
6009 if (leftSquareBracket != null && !reportedMultiplePositionalGroups) {
6010 _reportErrorForCurrentToken(
6011 ParserErrorCode.MULTIPLE_POSITIONAL_PARAMETER_GROUPS);
6012 reportedMultiplePositionalGroups = true;
6013 }
6014 if (leftCurlyBracket != null && !reportedMixedGroups) {
6015 _reportErrorForCurrentToken(ParserErrorCode.MIXED_PARAMETER_GROUPS);
6016 reportedMixedGroups = true;
6017 }
6018 leftSquareBracket = getAndAdvance();
6019 kind = ParameterKind.POSITIONAL;
6020 } else if (type == TokenType.OPEN_CURLY_BRACKET) {
6021 wasOptionalParameter = true;
6022 if (leftCurlyBracket != null && !reportedMultipleNamedGroups) {
6023 _reportErrorForCurrentToken(
6024 ParserErrorCode.MULTIPLE_NAMED_PARAMETER_GROUPS);
6025 reportedMultipleNamedGroups = true;
6026 }
6027 if (leftSquareBracket != null && !reportedMixedGroups) {
6028 _reportErrorForCurrentToken(ParserErrorCode.MIXED_PARAMETER_GROUPS);
6029 reportedMixedGroups = true;
6030 }
6031 leftCurlyBracket = getAndAdvance();
6032 kind = ParameterKind.NAMED;
6033 }
6034 //
6035 // Parse and record the parameter.
6036 //
6037 FormalParameter parameter = _parseFormalParameter(kind);
6038 parameters.add(parameter);
6039 if (kind == ParameterKind.REQUIRED && wasOptionalParameter) {
6040 _reportErrorForNode(
6041 ParserErrorCode.NORMAL_BEFORE_OPTIONAL_PARAMETERS, parameter);
6042 }
6043 //
6044 // Handle the end of parameter groups.
6045 //
6046 // TODO(brianwilkerson) Improve the detection and reporting of missing and
6047 // mismatched delimiters.
6048 type = _currentToken.type;
6049
6050 // Advance past trailing commas as appropriate.
6051 if (type == TokenType.COMMA) {
6052 // Only parse commas trailing normal (non-positional/named) params.
6053 if (rightSquareBracket == null && rightCurlyBracket == null) {
6054 Token next = _peek();
6055 if (next.type == TokenType.CLOSE_PAREN ||
6056 next.type == TokenType.CLOSE_CURLY_BRACKET ||
6057 next.type == TokenType.CLOSE_SQUARE_BRACKET) {
6058 _advance();
6059 type = _currentToken.type;
6060 }
6061 }
6062 }
6063
6064 if (type == TokenType.CLOSE_SQUARE_BRACKET) {
6065 rightSquareBracket = getAndAdvance();
6066 if (leftSquareBracket == null) {
6067 if (leftCurlyBracket != null) {
6068 _reportErrorForCurrentToken(
6069 ParserErrorCode.WRONG_TERMINATOR_FOR_PARAMETER_GROUP, ["}"]);
6070 rightCurlyBracket = rightSquareBracket;
6071 rightSquareBracket = null;
6072 } else {
6073 _reportErrorForCurrentToken(
6074 ParserErrorCode.UNEXPECTED_TERMINATOR_FOR_PARAMETER_GROUP,
6075 ["["]);
6076 }
6077 }
6078 kind = ParameterKind.REQUIRED;
6079 } else if (type == TokenType.CLOSE_CURLY_BRACKET) {
6080 rightCurlyBracket = getAndAdvance();
6081 if (leftCurlyBracket == null) {
6082 if (leftSquareBracket != null) {
6083 _reportErrorForCurrentToken(
6084 ParserErrorCode.WRONG_TERMINATOR_FOR_PARAMETER_GROUP, ["]"]);
6085 rightSquareBracket = rightCurlyBracket;
6086 rightCurlyBracket = null;
6087 } else {
6088 _reportErrorForCurrentToken(
6089 ParserErrorCode.UNEXPECTED_TERMINATOR_FOR_PARAMETER_GROUP,
6090 ["{"]);
6091 }
6092 }
6093 kind = ParameterKind.REQUIRED;
6094 }
6095 } while (!_matches(TokenType.CLOSE_PAREN) &&
6096 !identical(initialToken, _currentToken));
6097 Token rightParenthesis = _expect(TokenType.CLOSE_PAREN);
6098 //
6099 // Check that the groups were closed correctly.
6100 //
6101 if (leftSquareBracket != null && rightSquareBracket == null) {
6102 _reportErrorForCurrentToken(
6103 ParserErrorCode.MISSING_TERMINATOR_FOR_PARAMETER_GROUP, ["]"]);
6104 }
6105 if (leftCurlyBracket != null && rightCurlyBracket == null) {
6106 _reportErrorForCurrentToken(
6107 ParserErrorCode.MISSING_TERMINATOR_FOR_PARAMETER_GROUP, ["}"]);
6108 }
6109 //
6110 // Build the parameter list.
6111 //
6112 leftSquareBracket ??= leftCurlyBracket;
6113 rightSquareBracket ??= rightCurlyBracket;
6114 return new FormalParameterList(leftParenthesis, parameters,
6115 leftSquareBracket, rightSquareBracket, rightParenthesis);
6116 }
6117
6118 /**
6119 * Parse a list of formal parameters. Return the formal parameters that were
6120 * parsed.
6121 *
6122 * This method assumes that the current token matches `TokenType.OPEN_PAREN`.
6123 */
6124 FormalParameterList _parseFormalParameterListUnchecked() {
6125 return _parseFormalParameterListAfterParen(getAndAdvance());
6126 }
6127
6128 /**
6129 * Parse a function declaration. The [commentAndMetadata] is the documentation
6130 * comment and metadata to be associated with the declaration. The
6131 * [externalKeyword] is the 'external' keyword, or `null` if the function is
6132 * not external. The [returnType] is the return type, or `null` if there is no
6133 * return type. The [isStatement] is `true` if the function declaration is
6134 * being parsed as a statement. Return the function declaration that was
6135 * parsed.
6136 *
6137 * functionDeclaration ::=
6138 * functionSignature functionBody
6139 * | returnType? getOrSet identifier formalParameterList functionBody
6140 */
6141 FunctionDeclaration _parseFunctionDeclaration(
6142 CommentAndMetadata commentAndMetadata,
6143 Token externalKeyword,
6144 TypeName returnType) {
6145 Token keywordToken = null;
6146 bool isGetter = false;
6147 Keyword keyword = _currentToken.keyword;
6148 SimpleIdentifier name = null;
6149 if (keyword == Keyword.GET) {
6150 keywordToken = getAndAdvance();
6151 isGetter = true;
6152 } else if (keyword == Keyword.SET) {
6153 keywordToken = getAndAdvance();
6154 }
6155 if (keywordToken != null && _matches(TokenType.OPEN_PAREN)) {
6156 name = new SimpleIdentifier(keywordToken, isDeclaration: true);
6157 keywordToken = null;
6158 isGetter = false;
6159 } else {
6160 name = parseSimpleIdentifier(isDeclaration: true);
6161 }
6162 TypeParameterList typeParameters = _parseGenericMethodTypeParameters();
6163 FormalParameterList parameters = null;
6164 if (!isGetter) {
6165 if (_matches(TokenType.OPEN_PAREN)) {
6166 parameters = _parseFormalParameterListUnchecked();
6167 _validateFormalParameterList(parameters);
6168 } else {
6169 _reportErrorForCurrentToken(
6170 ParserErrorCode.MISSING_FUNCTION_PARAMETERS);
6171 parameters = new FormalParameterList(
6172 _createSyntheticToken(TokenType.OPEN_PAREN),
6173 null,
6174 null,
6175 null,
6176 _createSyntheticToken(TokenType.CLOSE_PAREN));
6177 }
6178 } else if (_matches(TokenType.OPEN_PAREN)) {
6179 _reportErrorForCurrentToken(ParserErrorCode.GETTER_WITH_PARAMETERS);
6180 _parseFormalParameterListUnchecked();
6181 }
6182 FunctionBody body;
6183 if (externalKeyword == null) {
6184 body = parseFunctionBody(
6185 false, ParserErrorCode.MISSING_FUNCTION_BODY, false);
6186 } else {
6187 body = new EmptyFunctionBody(_expect(TokenType.SEMICOLON));
6188 }
6189 // if (!isStatement && matches(TokenType.SEMICOLON)) {
6190 // // TODO(brianwilkerson) Improve this error message.
6191 // reportError(ParserErrorCode.UNEXPECTED_TOKEN, currentToken.getLexeme ());
6192 // advance();
6193 // }
6194 return new FunctionDeclaration(
6195 commentAndMetadata.comment,
6196 commentAndMetadata.metadata,
6197 externalKeyword,
6198 returnType,
6199 keywordToken,
6200 name,
6201 new FunctionExpression(typeParameters, parameters, body));
6202 }
6203
6204 /**
6205 * Parse a function declaration statement. The [commentAndMetadata] is the
6206 * documentation comment and metadata to be associated with the declaration.
6207 * The [returnType] is the return type, or `null` if there is no return type.
6208 * Return the function declaration statement that was parsed.
6209 *
6210 * functionDeclarationStatement ::=
6211 * functionSignature functionBody
6212 */
6213 Statement _parseFunctionDeclarationStatementAfterReturnType(
6214 CommentAndMetadata commentAndMetadata, TypeName returnType) {
6215 FunctionDeclaration declaration =
6216 _parseFunctionDeclaration(commentAndMetadata, null, returnType);
6217 Token propertyKeyword = declaration.propertyKeyword;
6218 if (propertyKeyword != null) {
6219 if (propertyKeyword.keyword == Keyword.GET) {
6220 _reportErrorForToken(
6221 ParserErrorCode.GETTER_IN_FUNCTION, propertyKeyword);
6222 } else {
6223 _reportErrorForToken(
6224 ParserErrorCode.SETTER_IN_FUNCTION, propertyKeyword);
6225 }
6226 }
6227 return new FunctionDeclarationStatement(declaration);
6228 }
6229
6230 /**
6231 * Parse a function type alias. The [commentAndMetadata] is the metadata to be
6232 * associated with the member. The [keyword] is the token representing the
6233 * 'typedef' keyword. Return the function type alias that was parsed.
6234 *
6235 * functionTypeAlias ::=
6236 * functionPrefix typeParameterList? formalParameterList ';'
6237 *
6238 * functionPrefix ::=
6239 * returnType? name
6240 */
6241 FunctionTypeAlias _parseFunctionTypeAlias(
6242 CommentAndMetadata commentAndMetadata, Token keyword) {
6243 TypeName returnType = null;
6244 if (hasReturnTypeInTypeAlias) {
6245 returnType = parseReturnType();
6246 }
6247 SimpleIdentifier name = parseSimpleIdentifier(isDeclaration: true);
6248 TypeParameterList typeParameters = null;
6249 if (_matches(TokenType.LT)) {
6250 typeParameters = parseTypeParameterList();
6251 }
6252 TokenType type = _currentToken.type;
6253 if (type == TokenType.SEMICOLON || type == TokenType.EOF) {
6254 _reportErrorForCurrentToken(ParserErrorCode.MISSING_TYPEDEF_PARAMETERS);
6255 FormalParameterList parameters = new FormalParameterList(
6256 _createSyntheticToken(TokenType.OPEN_PAREN),
6257 null,
6258 null,
6259 null,
6260 _createSyntheticToken(TokenType.CLOSE_PAREN));
6261 Token semicolon = _expect(TokenType.SEMICOLON);
6262 return new FunctionTypeAlias(
6263 commentAndMetadata.comment,
6264 commentAndMetadata.metadata,
6265 keyword,
6266 returnType,
6267 name,
6268 typeParameters,
6269 parameters,
6270 semicolon);
6271 } else if (type == TokenType.OPEN_PAREN) {
6272 FormalParameterList parameters = _parseFormalParameterListUnchecked();
6273 _validateFormalParameterList(parameters);
6274 Token semicolon = _expect(TokenType.SEMICOLON);
6275 return new FunctionTypeAlias(
6276 commentAndMetadata.comment,
6277 commentAndMetadata.metadata,
6278 keyword,
6279 returnType,
6280 name,
6281 typeParameters,
6282 parameters,
6283 semicolon);
6284 } else {
6285 _reportErrorForCurrentToken(ParserErrorCode.MISSING_TYPEDEF_PARAMETERS);
6286 // Recovery: At the very least we should skip to the start of the next
6287 // valid compilation unit member, allowing for the possibility of finding
6288 // the typedef parameters before that point.
6289 return new FunctionTypeAlias(
6290 commentAndMetadata.comment,
6291 commentAndMetadata.metadata,
6292 keyword,
6293 returnType,
6294 name,
6295 typeParameters,
6296 new FormalParameterList(_createSyntheticToken(TokenType.OPEN_PAREN),
6297 null, null, null, _createSyntheticToken(TokenType.CLOSE_PAREN)),
6298 _createSyntheticToken(TokenType.SEMICOLON));
6299 }
6300 }
6301
6302 /**
6303 * Parses generic type parameters from a comment.
6304 *
6305 * Normally this is handled by [_parseGenericMethodTypeParameters], but if the
6306 * code already handles the normal generic type parameters, the comment
6307 * matcher can be called directly. For example, we may have already tried
6308 * matching `<` (less than sign) in a method declaration, and be currently
6309 * on the `(` (open paren) because we didn't find it. In that case, this
6310 * function will parse the preceding comment such as `/*<T, R>*/`.
6311 */
6312 TypeParameterList _parseGenericCommentTypeParameters() {
6313 if (_injectGenericCommentTypeList()) {
6314 return parseTypeParameterList();
6315 }
6316 return null;
6317 }
6318
6319 /**
6320 * Parse the generic method or function's type parameters.
6321 *
6322 * For backwards compatibility this can optionally use comments.
6323 * See [parseGenericMethodComments].
6324 */
6325 TypeParameterList _parseGenericMethodTypeParameters() {
6326 if (parseGenericMethods && _matches(TokenType.LT) ||
6327 _injectGenericCommentTypeList()) {
6328 return parseTypeParameterList();
6329 }
6330 return null;
6331 }
6332
6333 /**
6334 * Parse a getter. The [commentAndMetadata] is the documentation comment and
6335 * metadata to be associated with the declaration. The externalKeyword] is the
6336 * 'external' token. The staticKeyword] is the static keyword, or `null` if
6337 * the getter is not static. The [returnType] the return type that has already
6338 * been parsed, or `null` if there was no return type. Return the getter that
6339 * was parsed.
6340 *
6341 * This method assumes that the current token matches `Keyword.GET`.
6342 *
6343 * getter ::=
6344 * getterSignature functionBody?
6345 *
6346 * getterSignature ::=
6347 * 'external'? 'static'? returnType? 'get' identifier
6348 */
6349 MethodDeclaration _parseGetter(CommentAndMetadata commentAndMetadata,
6350 Token externalKeyword, Token staticKeyword, TypeName returnType) {
6351 Token propertyKeyword = getAndAdvance();
6352 SimpleIdentifier name = parseSimpleIdentifier(isDeclaration: true);
6353 if (_matches(TokenType.OPEN_PAREN) &&
6354 _tokenMatches(_peek(), TokenType.CLOSE_PAREN)) {
6355 _reportErrorForCurrentToken(ParserErrorCode.GETTER_WITH_PARAMETERS);
6356 _advance();
6357 _advance();
6358 }
6359 FunctionBody body = parseFunctionBody(
6360 externalKeyword != null || staticKeyword == null,
6361 ParserErrorCode.STATIC_GETTER_WITHOUT_BODY,
6362 false);
6363 if (externalKeyword != null && body is! EmptyFunctionBody) {
6364 _reportErrorForCurrentToken(ParserErrorCode.EXTERNAL_GETTER_WITH_BODY);
6365 }
6366 return new MethodDeclaration(
6367 commentAndMetadata.comment,
6368 commentAndMetadata.metadata,
6369 externalKeyword,
6370 staticKeyword,
6371 returnType,
6372 propertyKeyword,
6373 null,
6374 name,
6375 null,
6376 null,
6377 body);
6378 }
6379
6380 /**
6381 * Parse a list of identifiers. Return the list of identifiers that were
6382 * parsed.
6383 *
6384 * identifierList ::=
6385 * identifier (',' identifier)*
6386 */
6387 List<SimpleIdentifier> _parseIdentifierList() {
6388 List<SimpleIdentifier> identifiers = <SimpleIdentifier>[
6389 parseSimpleIdentifier()
6390 ];
6391 while (_optional(TokenType.COMMA)) {
6392 identifiers.add(parseSimpleIdentifier());
6393 }
6394 return identifiers;
6395 }
6396
6397 /**
6398 * Parse an import directive. The [commentAndMetadata] is the metadata to be
6399 * associated with the directive. Return the import directive that was parsed.
6400 *
6401 * This method assumes that the current token matches `Keyword.IMPORT`.
6402 *
6403 * importDirective ::=
6404 * metadata 'import' stringLiteral configuration* (deferred)? ('as' id entifier)? combinator*';'
6405 */
6406 ImportDirective _parseImportDirective(CommentAndMetadata commentAndMetadata) {
6407 Token importKeyword = getAndAdvance();
6408 StringLiteral libraryUri = _parseUri();
6409 List<Configuration> configurations = _parseConfigurations();
6410 Token deferredToken = null;
6411 Token asToken = null;
6412 SimpleIdentifier prefix = null;
6413 if (_matchesKeyword(Keyword.DEFERRED)) {
6414 deferredToken = getAndAdvance();
6415 }
6416 if (_matchesKeyword(Keyword.AS)) {
6417 asToken = getAndAdvance();
6418 prefix = parseSimpleIdentifier(isDeclaration: true);
6419 } else if (deferredToken != null) {
6420 _reportErrorForCurrentToken(
6421 ParserErrorCode.MISSING_PREFIX_IN_DEFERRED_IMPORT);
6422 } else if (!_matches(TokenType.SEMICOLON) &&
6423 !_matchesString(_SHOW) &&
6424 !_matchesString(_HIDE)) {
6425 Token nextToken = _peek();
6426 if (_tokenMatchesKeyword(nextToken, Keyword.AS) ||
6427 _tokenMatchesString(nextToken, _SHOW) ||
6428 _tokenMatchesString(nextToken, _HIDE)) {
6429 _reportErrorForCurrentToken(
6430 ParserErrorCode.UNEXPECTED_TOKEN, [_currentToken]);
6431 _advance();
6432 if (_matchesKeyword(Keyword.AS)) {
6433 asToken = getAndAdvance();
6434 prefix = parseSimpleIdentifier(isDeclaration: true);
6435 }
6436 }
6437 }
6438 List<Combinator> combinators = parseCombinators();
6439 Token semicolon = _expect(TokenType.SEMICOLON);
6440 return new ImportDirective(
6441 commentAndMetadata.comment,
6442 commentAndMetadata.metadata,
6443 importKeyword,
6444 libraryUri,
6445 configurations,
6446 deferredToken,
6447 asToken,
6448 prefix,
6449 combinators,
6450 semicolon);
6451 }
6452
6453 /**
6454 * Parse a list of initialized identifiers. The [commentAndMetadata] is the
6455 * documentation comment and metadata to be associated with the declaration.
6456 * The [staticKeyword] is the static keyword, or `null` if the getter is not
6457 * static. The [keyword] is the token representing the 'final', 'const' or
6458 * 'var' keyword, or `null` if there is no keyword. The [type] is the type
6459 * that has already been parsed, or `null` if 'var' was provided. Return the
6460 * getter that was parsed.
6461 *
6462 * ?? ::=
6463 * 'static'? ('var' | type) initializedIdentifierList ';'
6464 * | 'final' type? initializedIdentifierList ';'
6465 *
6466 * initializedIdentifierList ::=
6467 * initializedIdentifier (',' initializedIdentifier)*
6468 *
6469 * initializedIdentifier ::=
6470 * identifier ('=' expression)?
6471 */
6472 FieldDeclaration _parseInitializedIdentifierList(
6473 CommentAndMetadata commentAndMetadata,
6474 Token staticKeyword,
6475 Token keyword,
6476 TypeName type) {
6477 VariableDeclarationList fieldList =
6478 parseVariableDeclarationListAfterType(null, keyword, type);
6479 return new FieldDeclaration(
6480 commentAndMetadata.comment,
6481 commentAndMetadata.metadata,
6482 staticKeyword,
6483 fieldList,
6484 _expect(TokenType.SEMICOLON));
6485 }
6486
6487 /**
6488 * Parse an instance creation expression. The [keyword] is the 'new' or
6489 * 'const' keyword that introduces the expression. Return the instance
6490 * creation expression that was parsed.
6491 *
6492 * instanceCreationExpression ::=
6493 * ('new' | 'const') type ('.' identifier)? argumentList
6494 */
6495 InstanceCreationExpression _parseInstanceCreationExpression(Token keyword) {
6496 ConstructorName constructorName = parseConstructorName();
6497 ArgumentList argumentList = _parseArgumentListChecked();
6498 return new InstanceCreationExpression(
6499 keyword, constructorName, argumentList);
6500 }
6501
6502 /**
6503 * Parse a library directive. The [commentAndMetadata] is the metadata to be
6504 * associated with the directive. Return the library directive that was
6505 * parsed.
6506 *
6507 * This method assumes that the current token matches `Keyword.LIBRARY`.
6508 *
6509 * libraryDirective ::=
6510 * metadata 'library' identifier ';'
6511 */
6512 LibraryDirective _parseLibraryDirective(
6513 CommentAndMetadata commentAndMetadata) {
6514 Token keyword = getAndAdvance();
6515 LibraryIdentifier libraryName = _parseLibraryName(
6516 ParserErrorCode.MISSING_NAME_IN_LIBRARY_DIRECTIVE, keyword);
6517 Token semicolon = _expect(TokenType.SEMICOLON);
6518 return new LibraryDirective(commentAndMetadata.comment,
6519 commentAndMetadata.metadata, keyword, libraryName, semicolon);
6520 }
6521
6522 /**
6523 * Parse a library name. The [missingNameError] is the error code to be used
6524 * if the library name is missing. The [missingNameToken] is the token
6525 * associated with the error produced if the library name is missing. Return
6526 * the library name that was parsed.
6527 *
6528 * libraryName ::=
6529 * libraryIdentifier
6530 */
6531 LibraryIdentifier _parseLibraryName(
6532 ParserErrorCode missingNameError, Token missingNameToken) {
6533 if (_matchesIdentifier()) {
6534 return parseLibraryIdentifier();
6535 } else if (_matches(TokenType.STRING)) {
6536 // Recovery: This should be extended to handle arbitrary tokens until we
6537 // can find a token that can start a compilation unit member.
6538 StringLiteral string = parseStringLiteral();
6539 _reportErrorForNode(ParserErrorCode.NON_IDENTIFIER_LIBRARY_NAME, string);
6540 } else {
6541 _reportErrorForToken(missingNameError, missingNameToken);
6542 }
6543 return new LibraryIdentifier(
6544 <SimpleIdentifier>[createSyntheticIdentifier()]);
6545 }
6546
6547 /**
6548 * Parse a list literal. The [modifier] is the 'const' modifier appearing
6549 * before the literal, or `null` if there is no modifier. The [typeArguments]
6550 * is the type arguments appearing before the literal, or `null` if there are
6551 * no type arguments. Return the list literal that was parsed.
6552 *
6553 * This method assumes that the current token matches either
6554 * `TokenType.OPEN_SQUARE_BRACKET` or `TokenType.INDEX`.
6555 *
6556 * listLiteral ::=
6557 * 'const'? typeArguments? '[' (expressionList ','?)? ']'
6558 */
6559 ListLiteral _parseListLiteral(
6560 Token modifier, TypeArgumentList typeArguments) {
6561 if (_matches(TokenType.INDEX)) {
6562 // Split the token into two separate tokens.
6563 BeginToken leftBracket = _createToken(
6564 _currentToken, TokenType.OPEN_SQUARE_BRACKET,
6565 isBegin: true);
6566 Token rightBracket =
6567 new Token(TokenType.CLOSE_SQUARE_BRACKET, _currentToken.offset + 1);
6568 leftBracket.endToken = rightBracket;
6569 rightBracket.setNext(_currentToken.next);
6570 leftBracket.setNext(rightBracket);
6571 _currentToken.previous.setNext(leftBracket);
6572 _currentToken = _currentToken.next;
6573 return new ListLiteral(
6574 modifier, typeArguments, leftBracket, null, rightBracket);
6575 }
6576 Token leftBracket = getAndAdvance();
6577 if (_matches(TokenType.CLOSE_SQUARE_BRACKET)) {
6578 return new ListLiteral(
6579 modifier, typeArguments, leftBracket, null, getAndAdvance());
6580 }
6581 bool wasInInitializer = _inInitializer;
6582 _inInitializer = false;
6583 try {
6584 List<Expression> elements = <Expression>[parseExpression2()];
6585 while (_optional(TokenType.COMMA)) {
6586 if (_matches(TokenType.CLOSE_SQUARE_BRACKET)) {
6587 return new ListLiteral(
6588 modifier, typeArguments, leftBracket, elements, getAndAdvance());
6589 }
6590 elements.add(parseExpression2());
6591 }
6592 Token rightBracket = _expect(TokenType.CLOSE_SQUARE_BRACKET);
6593 return new ListLiteral(
6594 modifier, typeArguments, leftBracket, elements, rightBracket);
6595 } finally {
6596 _inInitializer = wasInInitializer;
6597 }
6598 }
6599
6600 /**
6601 * Parse a logical and expression. Return the logical and expression that was
6602 * parsed.
6603 *
6604 * logicalAndExpression ::=
6605 * equalityExpression ('&&' equalityExpression)*
6606 */
6607 Expression _parseLogicalAndExpression() {
6608 Expression expression = _parseEqualityExpression();
6609 while (_currentToken.type == TokenType.AMPERSAND_AMPERSAND) {
6610 expression = new BinaryExpression(
6611 expression, getAndAdvance(), _parseEqualityExpression());
6612 }
6613 return expression;
6614 }
6615
6616 /**
6617 * Parse a map literal. The [modifier] is the 'const' modifier appearing
6618 * before the literal, or `null` if there is no modifier. The [typeArguments]
6619 * is the type arguments that were declared, or `null` if there are no type
6620 * arguments. Return the map literal that was parsed.
6621 *
6622 * This method assumes that the current token matches
6623 * `TokenType.OPEN_CURLY_BRACKET`.
6624 *
6625 * mapLiteral ::=
6626 * 'const'? typeArguments? '{' (mapLiteralEntry (',' mapLiteralEntry)* ','?)? '}'
6627 */
6628 MapLiteral _parseMapLiteral(Token modifier, TypeArgumentList typeArguments) {
6629 Token leftBracket = getAndAdvance();
6630 if (_matches(TokenType.CLOSE_CURLY_BRACKET)) {
6631 return new MapLiteral(
6632 modifier, typeArguments, leftBracket, null, getAndAdvance());
6633 }
6634 bool wasInInitializer = _inInitializer;
6635 _inInitializer = false;
6636 try {
6637 List<MapLiteralEntry> entries = <MapLiteralEntry>[parseMapLiteralEntry()];
6638 while (_optional(TokenType.COMMA)) {
6639 if (_matches(TokenType.CLOSE_CURLY_BRACKET)) {
6640 return new MapLiteral(
6641 modifier, typeArguments, leftBracket, entries, getAndAdvance());
6642 }
6643 entries.add(parseMapLiteralEntry());
6644 }
6645 Token rightBracket = _expect(TokenType.CLOSE_CURLY_BRACKET);
6646 return new MapLiteral(
6647 modifier, typeArguments, leftBracket, entries, rightBracket);
6648 } finally {
6649 _inInitializer = wasInInitializer;
6650 }
6651 }
6652
6653 /**
6654 * Parse a method declaration. The [commentAndMetadata] is the documentation
6655 * comment and metadata to be associated with the declaration. The
6656 * [externalKeyword] is the 'external' token. The [staticKeyword] is the
6657 * static keyword, or `null` if the getter is not static. The [returnType] is
6658 * the return type of the method. The [name] is the name of the method. The
6659 * [parameters] is the parameters to the method. Return the method declaration
6660 * that was parsed.
6661 *
6662 * functionDeclaration ::=
6663 * ('external' 'static'?)? functionSignature functionBody
6664 * | 'external'? functionSignature ';'
6665 */
6666 MethodDeclaration _parseMethodDeclarationAfterParameters(
6667 CommentAndMetadata commentAndMetadata,
6668 Token externalKeyword,
6669 Token staticKeyword,
6670 TypeName returnType,
6671 SimpleIdentifier name,
6672 TypeParameterList typeParameters,
6673 FormalParameterList parameters) {
6674 FunctionBody body = parseFunctionBody(
6675 externalKeyword != null || staticKeyword == null,
6676 ParserErrorCode.MISSING_FUNCTION_BODY,
6677 false);
6678 if (externalKeyword != null) {
6679 if (body is! EmptyFunctionBody) {
6680 _reportErrorForNode(ParserErrorCode.EXTERNAL_METHOD_WITH_BODY, body);
6681 }
6682 } else if (staticKeyword != null) {
6683 if (body is EmptyFunctionBody && _parseFunctionBodies) {
6684 _reportErrorForNode(ParserErrorCode.ABSTRACT_STATIC_METHOD, body);
6685 }
6686 }
6687 return new MethodDeclaration(
6688 commentAndMetadata.comment,
6689 commentAndMetadata.metadata,
6690 externalKeyword,
6691 staticKeyword,
6692 returnType,
6693 null,
6694 null,
6695 name,
6696 typeParameters,
6697 parameters,
6698 body);
6699 }
6700
6701 /**
6702 * Parse a method declaration. The [commentAndMetadata] is the documentation
6703 * comment and metadata to be associated with the declaration. The
6704 * [externalKeyword] is the 'external' token. The [staticKeyword] is the
6705 * static keyword, or `null` if the getter is not static. The [returnType] is
6706 * the return type of the method. Return the method declaration that was
6707 * parsed.
6708 *
6709 * functionDeclaration ::=
6710 * 'external'? 'static'? functionSignature functionBody
6711 * | 'external'? functionSignature ';'
6712 */
6713 MethodDeclaration _parseMethodDeclarationAfterReturnType(
6714 CommentAndMetadata commentAndMetadata,
6715 Token externalKeyword,
6716 Token staticKeyword,
6717 TypeName returnType) {
6718 SimpleIdentifier methodName = parseSimpleIdentifier(isDeclaration: true);
6719 TypeParameterList typeParameters = _parseGenericMethodTypeParameters();
6720 FormalParameterList parameters;
6721 TokenType type = _currentToken.type;
6722 // TODO(brianwilkerson) Figure out why we care what the current token is if
6723 // it isn't a paren.
6724 if (type != TokenType.OPEN_PAREN &&
6725 (type == TokenType.OPEN_CURLY_BRACKET || type == TokenType.FUNCTION)) {
6726 _reportErrorForToken(
6727 ParserErrorCode.MISSING_METHOD_PARAMETERS, _currentToken.previous);
6728 parameters = new FormalParameterList(
6729 _createSyntheticToken(TokenType.OPEN_PAREN),
6730 null,
6731 null,
6732 null,
6733 _createSyntheticToken(TokenType.CLOSE_PAREN));
6734 } else {
6735 parameters = parseFormalParameterList();
6736 }
6737 _validateFormalParameterList(parameters);
6738 return _parseMethodDeclarationAfterParameters(
6739 commentAndMetadata,
6740 externalKeyword,
6741 staticKeyword,
6742 returnType,
6743 methodName,
6744 typeParameters,
6745 parameters);
6746 }
6747
6748 /**
6749 * Parse the modifiers preceding a declaration. This method allows the 3700 * Parse the modifiers preceding a declaration. This method allows the
6750 * modifiers to appear in any order but does generate errors for duplicated 3701 * modifiers to appear in any order but does generate errors for duplicated
6751 * modifiers. Checks for other problems, such as having the modifiers appear 3702 * modifiers. Checks for other problems, such as having the modifiers appear
6752 * in the wrong order or specifying both 'const' and 'final', are reported in 3703 * in the wrong order or specifying both 'const' and 'final', are reported in
6753 * one of the methods whose name is prefixed with `validateModifiersFor`. 3704 * one of the methods whose name is prefixed with `validateModifiersFor`.
6754 * Return the modifiers that were parsed. 3705 * Return the modifiers that were parsed.
6755 * 3706 *
6756 * modifiers ::= 3707 * modifiers ::=
6757 * ('abstract' | 'const' | 'external' | 'factory' | 'final' | 'static' | 'var')* 3708 * ('abstract' | 'const' | 'external' | 'factory' | 'final' | 'static' | 'var')*
6758 */ 3709 */
6759 Modifiers _parseModifiers() { 3710 Modifiers parseModifiers() {
6760 Modifiers modifiers = new Modifiers(); 3711 Modifiers modifiers = new Modifiers();
6761 bool progress = true; 3712 bool progress = true;
6762 while (progress) { 3713 while (progress) {
6763 TokenType nextType = _peek().type; 3714 TokenType nextType = _peek().type;
6764 if (nextType == TokenType.PERIOD || 3715 if (nextType == TokenType.PERIOD ||
6765 nextType == TokenType.LT || 3716 nextType == TokenType.LT ||
6766 nextType == TokenType.OPEN_PAREN) { 3717 nextType == TokenType.OPEN_PAREN) {
6767 return modifiers; 3718 return modifiers;
6768 } 3719 }
6769 Keyword keyword = _currentToken.keyword; 3720 Keyword keyword = _currentToken.keyword;
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after
6824 modifiers.varKeyword = getAndAdvance(); 3775 modifiers.varKeyword = getAndAdvance();
6825 } 3776 }
6826 } else { 3777 } else {
6827 progress = false; 3778 progress = false;
6828 } 3779 }
6829 } 3780 }
6830 return modifiers; 3781 return modifiers;
6831 } 3782 }
6832 3783
6833 /** 3784 /**
6834 * Parse a class native clause. Return the native clause that was parsed. 3785 * Parse a multiplicative expression. Return the multiplicative expression
6835 * 3786 * that was parsed.
6836 * This method assumes that the current token matches `_NATIVE`. 3787 *
6837 * 3788 * multiplicativeExpression ::=
6838 * classNativeClause ::= 3789 * unaryExpression (multiplicativeOperator unaryExpression)*
6839 * 'native' name 3790 * | 'super' (multiplicativeOperator unaryExpression)+
6840 */ 3791 */
6841 NativeClause _parseNativeClause() { 3792 Expression parseMultiplicativeExpression() {
6842 Token keyword = getAndAdvance(); 3793 Expression expression;
6843 StringLiteral name = parseStringLiteral(); 3794 if (_currentToken.keyword == Keyword.SUPER &&
6844 return new NativeClause(keyword, name); 3795 _currentToken.next.type.isMultiplicativeOperator) {
3796 expression = new SuperExpression(getAndAdvance());
3797 } else {
3798 expression = parseUnaryExpression();
3799 }
3800 while (_currentToken.type.isMultiplicativeOperator) {
3801 expression = new BinaryExpression(
3802 expression, getAndAdvance(), parseUnaryExpression());
3803 }
3804 return expression;
6845 } 3805 }
6846 3806
6847 /** 3807 /**
6848 * Parse a new expression. Return the new expression that was parsed. 3808 * Parse a new expression. Return the new expression that was parsed.
6849 * 3809 *
6850 * This method assumes that the current token matches `Keyword.NEW`. 3810 * This method assumes that the current token matches `Keyword.NEW`.
6851 * 3811 *
6852 * newExpression ::= 3812 * newExpression ::=
6853 * instanceCreationExpression 3813 * instanceCreationExpression
6854 */ 3814 */
6855 InstanceCreationExpression _parseNewExpression() => 3815 InstanceCreationExpression parseNewExpression() =>
6856 _parseInstanceCreationExpression(getAndAdvance()); 3816 parseInstanceCreationExpression(getAndAdvance());
6857 3817
6858 /** 3818 /**
6859 * Parse a non-labeled statement. Return the non-labeled statement that was 3819 * Parse a non-labeled statement. Return the non-labeled statement that was
6860 * parsed. 3820 * parsed.
6861 * 3821 *
6862 * nonLabeledStatement ::= 3822 * nonLabeledStatement ::=
6863 * block 3823 * block
6864 * | assertStatement 3824 * | assertStatement
6865 * | breakStatement 3825 * | breakStatement
6866 * | continueStatement 3826 * | continueStatement
6867 * | doStatement 3827 * | doStatement
6868 * | forStatement 3828 * | forStatement
6869 * | ifStatement 3829 * | ifStatement
6870 * | returnStatement 3830 * | returnStatement
6871 * | switchStatement 3831 * | switchStatement
6872 * | tryStatement 3832 * | tryStatement
6873 * | whileStatement 3833 * | whileStatement
6874 * | variableDeclarationList ';' 3834 * | variableDeclarationList ';'
6875 * | expressionStatement 3835 * | expressionStatement
6876 * | functionSignature functionBody 3836 * | functionSignature functionBody
6877 */ 3837 */
6878 Statement _parseNonLabeledStatement() { 3838 Statement parseNonLabeledStatement() {
6879 // TODO(brianwilkerson) Pass the comment and metadata on where appropriate. 3839 // TODO(brianwilkerson) Pass the comment and metadata on where appropriate.
6880 CommentAndMetadata commentAndMetadata = parseCommentAndMetadata(); 3840 CommentAndMetadata commentAndMetadata = parseCommentAndMetadata();
6881 TokenType type = _currentToken.type; 3841 TokenType type = _currentToken.type;
6882 if (type == TokenType.OPEN_CURLY_BRACKET) { 3842 if (type == TokenType.OPEN_CURLY_BRACKET) {
6883 if (_tokenMatches(_peek(), TokenType.STRING)) { 3843 if (_tokenMatches(_peek(), TokenType.STRING)) {
6884 Token afterString = skipStringLiteral(_currentToken.next); 3844 Token afterString = skipStringLiteral(_currentToken.next);
6885 if (afterString != null && afterString.type == TokenType.COLON) { 3845 if (afterString != null && afterString.type == TokenType.COLON) {
6886 return new ExpressionStatement( 3846 return new ExpressionStatement(
6887 parseExpression2(), _expect(TokenType.SEMICOLON)); 3847 parseExpression2(), _expect(TokenType.SEMICOLON));
6888 } 3848 }
(...skipping 140 matching lines...) Expand 10 before | Expand all | Expand 10 after
7029 } else if (type == TokenType.CLOSE_CURLY_BRACKET) { 3989 } else if (type == TokenType.CLOSE_CURLY_BRACKET) {
7030 _reportErrorForCurrentToken(ParserErrorCode.MISSING_STATEMENT); 3990 _reportErrorForCurrentToken(ParserErrorCode.MISSING_STATEMENT);
7031 return new EmptyStatement(_createSyntheticToken(TokenType.SEMICOLON)); 3991 return new EmptyStatement(_createSyntheticToken(TokenType.SEMICOLON));
7032 } else { 3992 } else {
7033 return new ExpressionStatement( 3993 return new ExpressionStatement(
7034 parseExpression2(), _expect(TokenType.SEMICOLON)); 3994 parseExpression2(), _expect(TokenType.SEMICOLON));
7035 } 3995 }
7036 } 3996 }
7037 3997
7038 /** 3998 /**
3999 * Parse a normal formal parameter. Return the normal formal parameter that
4000 * was parsed.
4001 *
4002 * normalFormalParameter ::=
4003 * functionSignature
4004 * | fieldFormalParameter
4005 * | simpleFormalParameter
4006 *
4007 * functionSignature:
4008 * metadata returnType? identifier typeParameters? formalParameterList
4009 *
4010 * fieldFormalParameter ::=
4011 * metadata finalConstVarOrType? 'this' '.' identifier
4012 *
4013 * simpleFormalParameter ::=
4014 * declaredIdentifier
4015 * | metadata identifier
4016 */
4017 NormalFormalParameter parseNormalFormalParameter() {
4018 CommentAndMetadata commentAndMetadata = parseCommentAndMetadata();
4019 FinalConstVarOrType holder = parseFinalConstVarOrType(true);
4020 Token thisKeyword = null;
4021 Token period = null;
4022 if (_matchesKeyword(Keyword.THIS)) {
4023 thisKeyword = getAndAdvance();
4024 period = _expect(TokenType.PERIOD);
4025 }
4026 SimpleIdentifier identifier = parseSimpleIdentifier();
4027 TypeParameterList typeParameters = _parseGenericMethodTypeParameters();
4028 if (_matches(TokenType.OPEN_PAREN)) {
4029 FormalParameterList parameters = _parseFormalParameterListUnchecked();
4030 if (thisKeyword == null) {
4031 if (holder.keyword != null) {
4032 _reportErrorForToken(
4033 ParserErrorCode.FUNCTION_TYPED_PARAMETER_VAR, holder.keyword);
4034 }
4035 Token question = null;
4036 if (enableNnbd && _matches(TokenType.QUESTION)) {
4037 question = getAndAdvance();
4038 }
4039 return new FunctionTypedFormalParameter(
4040 commentAndMetadata.comment,
4041 commentAndMetadata.metadata,
4042 holder.type,
4043 new SimpleIdentifier(identifier.token, isDeclaration: true),
4044 typeParameters,
4045 parameters,
4046 question: question);
4047 } else {
4048 return new FieldFormalParameter(
4049 commentAndMetadata.comment,
4050 commentAndMetadata.metadata,
4051 holder.keyword,
4052 holder.type,
4053 thisKeyword,
4054 period,
4055 identifier,
4056 typeParameters,
4057 parameters);
4058 }
4059 } else if (typeParameters != null) {
4060 // TODO(brianwilkerson) Report an error. It looks like a function-typed
4061 // parameter with no parameter list.
4062 //_reportErrorForToken(ParserErrorCode.MISSING_PARAMETERS, typeParameters. endToken);
4063 }
4064 TypeName type = holder.type;
4065 if (type != null) {
4066 if (_tokenMatchesKeyword(type.name.beginToken, Keyword.VOID)) {
4067 _reportErrorForToken(
4068 ParserErrorCode.VOID_PARAMETER, type.name.beginToken);
4069 } else if (holder.keyword != null &&
4070 _tokenMatchesKeyword(holder.keyword, Keyword.VAR)) {
4071 _reportErrorForToken(ParserErrorCode.VAR_AND_TYPE, holder.keyword);
4072 }
4073 }
4074 if (thisKeyword != null) {
4075 // TODO(brianwilkerson) If there are type parameters but no parameters,
4076 // should we create a synthetic empty parameter list here so we can
4077 // capture the type parameters?
4078 return new FieldFormalParameter(
4079 commentAndMetadata.comment,
4080 commentAndMetadata.metadata,
4081 holder.keyword,
4082 holder.type,
4083 thisKeyword,
4084 period,
4085 identifier,
4086 null,
4087 null);
4088 }
4089 return new SimpleFormalParameter(
4090 commentAndMetadata.comment,
4091 commentAndMetadata.metadata,
4092 holder.keyword,
4093 holder.type,
4094 new SimpleIdentifier(identifier.token, isDeclaration: true));
4095 }
4096
4097 /**
4098 * Parse an operator declaration. The [commentAndMetadata] is the
4099 * documentation comment and metadata to be associated with the declaration.
4100 * The [externalKeyword] is the 'external' token. The [returnType] is the
4101 * return type that has already been parsed, or `null` if there was no return
4102 * type. Return the operator declaration that was parsed.
4103 *
4104 * operatorDeclaration ::=
4105 * operatorSignature (';' | functionBody)
4106 *
4107 * operatorSignature ::=
4108 * 'external'? returnType? 'operator' operator formalParameterList
4109 */
4110 MethodDeclaration parseOperator(CommentAndMetadata commentAndMetadata,
4111 Token externalKeyword, TypeName returnType) {
4112 Token operatorKeyword;
4113 if (_matchesKeyword(Keyword.OPERATOR)) {
4114 operatorKeyword = getAndAdvance();
4115 } else {
4116 _reportErrorForToken(
4117 ParserErrorCode.MISSING_KEYWORD_OPERATOR, _currentToken);
4118 operatorKeyword = _createSyntheticKeyword(Keyword.OPERATOR);
4119 }
4120 return _parseOperatorAfterKeyword(
4121 commentAndMetadata, externalKeyword, returnType, operatorKeyword);
4122 }
4123
4124 /**
4125 * Parse a part or part-of directive. The [commentAndMetadata] is the metadata
4126 * to be associated with the directive. Return the part or part-of directive
4127 * that was parsed.
4128 *
4129 * This method assumes that the current token matches `Keyword.PART`.
4130 *
4131 * partDirective ::=
4132 * metadata 'part' stringLiteral ';'
4133 *
4134 * partOfDirective ::=
4135 * metadata 'part' 'of' identifier ';'
4136 */
4137 Directive parsePartOrPartOfDirective(CommentAndMetadata commentAndMetadata) {
4138 if (_tokenMatchesString(_peek(), _OF)) {
4139 return _parsePartOfDirective(commentAndMetadata);
4140 }
4141 return _parsePartDirective(commentAndMetadata);
4142 }
4143
4144 /**
4145 * Parse a postfix expression. Return the postfix expression that was parsed.
4146 *
4147 * postfixExpression ::=
4148 * assignableExpression postfixOperator
4149 * | primary selector*
4150 *
4151 * selector ::=
4152 * assignableSelector
4153 * | argumentList
4154 */
4155 Expression parsePostfixExpression() {
4156 Expression operand = parseAssignableExpression(true);
4157 TokenType type = _currentToken.type;
4158 if (type == TokenType.OPEN_SQUARE_BRACKET ||
4159 type == TokenType.PERIOD ||
4160 type == TokenType.QUESTION_PERIOD ||
4161 type == TokenType.OPEN_PAREN ||
4162 (parseGenericMethods && type == TokenType.LT)) {
4163 do {
4164 if (_isLikelyArgumentList()) {
4165 TypeArgumentList typeArguments = _parseOptionalTypeArguments();
4166 ArgumentList argumentList = parseArgumentList();
4167 Expression currentOperand = operand;
4168 if (currentOperand is PropertyAccess) {
4169 operand = new MethodInvocation(
4170 currentOperand.target,
4171 currentOperand.operator,
4172 currentOperand.propertyName,
4173 typeArguments,
4174 argumentList);
4175 } else {
4176 operand = new FunctionExpressionInvocation(
4177 operand, typeArguments, argumentList);
4178 }
4179 } else {
4180 operand = parseAssignableSelector(operand, true);
4181 }
4182 type = _currentToken.type;
4183 } while (type == TokenType.OPEN_SQUARE_BRACKET ||
4184 type == TokenType.PERIOD ||
4185 type == TokenType.QUESTION_PERIOD ||
4186 type == TokenType.OPEN_PAREN);
4187 return operand;
4188 }
4189 if (!_currentToken.type.isIncrementOperator) {
4190 return operand;
4191 }
4192 _ensureAssignable(operand);
4193 Token operator = getAndAdvance();
4194 return new PostfixExpression(operand, operator);
4195 }
4196
4197 /**
4198 * Parse a prefixed identifier. Return the prefixed identifier that was
4199 * parsed.
4200 *
4201 * prefixedIdentifier ::=
4202 * identifier ('.' identifier)?
4203 */
4204 Identifier parsePrefixedIdentifier() {
4205 return _parsePrefixedIdentifierAfterIdentifier(parseSimpleIdentifier());
4206 }
4207
4208 /**
4209 * Parse a primary expression. Return the primary expression that was parsed.
4210 *
4211 * primary ::=
4212 * thisExpression
4213 * | 'super' unconditionalAssignableSelector
4214 * | functionExpression
4215 * | literal
4216 * | identifier
4217 * | newExpression
4218 * | constObjectExpression
4219 * | '(' expression ')'
4220 * | argumentDefinitionTest
4221 *
4222 * literal ::=
4223 * nullLiteral
4224 * | booleanLiteral
4225 * | numericLiteral
4226 * | stringLiteral
4227 * | symbolLiteral
4228 * | mapLiteral
4229 * | listLiteral
4230 */
4231 Expression parsePrimaryExpression() {
4232 if (_matchesIdentifier()) {
4233 // TODO(brianwilkerson) The code below was an attempt to recover from an
4234 // error case, but it needs to be applied as a recovery only after we
4235 // know that parsing it as an identifier doesn't work. Leaving the code as
4236 // a reminder of how to recover.
4237 // if (isFunctionExpression(_peek())) {
4238 // //
4239 // // Function expressions were allowed to have names at one point, but t his is now illegal.
4240 // //
4241 // reportError(ParserErrorCode.NAMED_FUNCTION_EXPRESSION, getAndAdvance() );
4242 // return parseFunctionExpression();
4243 // }
4244 return _parsePrefixedIdentifierUnchecked();
4245 }
4246 TokenType type = _currentToken.type;
4247 if (type == TokenType.STRING) {
4248 return parseStringLiteral();
4249 } else if (type == TokenType.INT) {
4250 Token token = getAndAdvance();
4251 int value = null;
4252 try {
4253 value = int.parse(token.lexeme);
4254 } on FormatException {
4255 // The invalid format should have been reported by the scanner.
4256 }
4257 return new IntegerLiteral(token, value);
4258 }
4259 Keyword keyword = _currentToken.keyword;
4260 if (keyword == Keyword.NULL) {
4261 return new NullLiteral(getAndAdvance());
4262 } else if (keyword == Keyword.NEW) {
4263 return parseNewExpression();
4264 } else if (keyword == Keyword.THIS) {
4265 return new ThisExpression(getAndAdvance());
4266 } else if (keyword == Keyword.SUPER) {
4267 // TODO(paulberry): verify with Gilad that "super" must be followed by
4268 // unconditionalAssignableSelector in this case.
4269 return parseAssignableSelector(
4270 new SuperExpression(getAndAdvance()), false,
4271 allowConditional: false);
4272 } else if (keyword == Keyword.FALSE) {
4273 return new BooleanLiteral(getAndAdvance(), false);
4274 } else if (keyword == Keyword.TRUE) {
4275 return new BooleanLiteral(getAndAdvance(), true);
4276 }
4277 if (type == TokenType.DOUBLE) {
4278 Token token = getAndAdvance();
4279 double value = 0.0;
4280 try {
4281 value = double.parse(token.lexeme);
4282 } on FormatException {
4283 // The invalid format should have been reported by the scanner.
4284 }
4285 return new DoubleLiteral(token, value);
4286 } else if (type == TokenType.HEXADECIMAL) {
4287 Token token = getAndAdvance();
4288 int value = null;
4289 try {
4290 value = int.parse(token.lexeme.substring(2), radix: 16);
4291 } on FormatException {
4292 // The invalid format should have been reported by the scanner.
4293 }
4294 return new IntegerLiteral(token, value);
4295 } else if (keyword == Keyword.CONST) {
4296 return parseConstExpression();
4297 } else if (type == TokenType.OPEN_PAREN) {
4298 if (isFunctionExpression(_currentToken)) {
4299 return parseFunctionExpression();
4300 }
4301 Token leftParenthesis = getAndAdvance();
4302 bool wasInInitializer = _inInitializer;
4303 _inInitializer = false;
4304 try {
4305 Expression expression = parseExpression2();
4306 Token rightParenthesis = _expect(TokenType.CLOSE_PAREN);
4307 return new ParenthesizedExpression(
4308 leftParenthesis, expression, rightParenthesis);
4309 } finally {
4310 _inInitializer = wasInInitializer;
4311 }
4312 } else if (type == TokenType.LT || _injectGenericCommentTypeList()) {
4313 return parseListOrMapLiteral(null);
4314 } else if (type == TokenType.OPEN_CURLY_BRACKET) {
4315 return parseMapLiteral(null, null);
4316 } else if (type == TokenType.OPEN_SQUARE_BRACKET ||
4317 type == TokenType.INDEX) {
4318 return parseListLiteral(null, null);
4319 } else if (type == TokenType.QUESTION &&
4320 _tokenMatches(_peek(), TokenType.IDENTIFIER)) {
4321 _reportErrorForCurrentToken(
4322 ParserErrorCode.UNEXPECTED_TOKEN, [_currentToken.lexeme]);
4323 _advance();
4324 return parsePrimaryExpression();
4325 } else if (keyword == Keyword.VOID) {
4326 //
4327 // Recover from having a return type of "void" where a return type is not
4328 // expected.
4329 //
4330 // TODO(brianwilkerson) Improve this error message.
4331 _reportErrorForCurrentToken(
4332 ParserErrorCode.UNEXPECTED_TOKEN, [_currentToken.lexeme]);
4333 _advance();
4334 return parsePrimaryExpression();
4335 } else if (type == TokenType.HASH) {
4336 return parseSymbolLiteral();
4337 } else {
4338 _reportErrorForCurrentToken(ParserErrorCode.MISSING_IDENTIFIER);
4339 return createSyntheticIdentifier();
4340 }
4341 }
4342
4343 /**
4344 * Parse a redirecting constructor invocation. The flag [hasPeriod] should be
4345 * `true` if the `this` is followed by a period. Return the redirecting
4346 * constructor invocation that was parsed.
4347 *
4348 * This method assumes that the current token matches `Keyword.THIS`.
4349 *
4350 * redirectingConstructorInvocation ::=
4351 * 'this' ('.' identifier)? arguments
4352 */
4353 RedirectingConstructorInvocation parseRedirectingConstructorInvocation(
4354 bool hasPeriod) {
4355 Token keyword = getAndAdvance();
4356 Token period = null;
4357 SimpleIdentifier constructorName = null;
4358 if (hasPeriod) {
4359 period = getAndAdvance();
4360 if (_matchesIdentifier()) {
4361 constructorName = _parseSimpleIdentifierUnchecked(isDeclaration: false);
4362 } else {
4363 _reportErrorForCurrentToken(ParserErrorCode.MISSING_IDENTIFIER);
4364 constructorName = createSyntheticIdentifier(isDeclaration: false);
4365 _advance();
4366 }
4367 }
4368 ArgumentList argumentList = _parseArgumentListChecked();
4369 return new RedirectingConstructorInvocation(
4370 keyword, period, constructorName, argumentList);
4371 }
4372
4373 /**
4374 * Parse a relational expression. Return the relational expression that was
4375 * parsed.
4376 *
4377 * relationalExpression ::=
4378 * bitwiseOrExpression ('is' '!'? type | 'as' type | relationalOperato r bitwiseOrExpression)?
4379 * | 'super' relationalOperator bitwiseOrExpression
4380 */
4381 Expression parseRelationalExpression() {
4382 if (_currentToken.keyword == Keyword.SUPER &&
4383 _currentToken.next.type.isRelationalOperator) {
4384 Expression expression = new SuperExpression(getAndAdvance());
4385 Token operator = getAndAdvance();
4386 return new BinaryExpression(
4387 expression, operator, parseBitwiseOrExpression());
4388 }
4389 Expression expression = parseBitwiseOrExpression();
4390 Keyword keyword = _currentToken.keyword;
4391 if (keyword == Keyword.AS) {
4392 Token asOperator = getAndAdvance();
4393 return new AsExpression(expression, asOperator, parseTypeName(true));
4394 } else if (keyword == Keyword.IS) {
4395 Token isOperator = getAndAdvance();
4396 Token notOperator = null;
4397 if (_matches(TokenType.BANG)) {
4398 notOperator = getAndAdvance();
4399 }
4400 return new IsExpression(
4401 expression, isOperator, notOperator, parseTypeName(true));
4402 } else if (_currentToken.type.isRelationalOperator) {
4403 Token operator = getAndAdvance();
4404 return new BinaryExpression(
4405 expression, operator, parseBitwiseOrExpression());
4406 }
4407 return expression;
4408 }
4409
4410 /**
4411 * Parse a rethrow expression. Return the rethrow expression that was parsed.
4412 *
4413 * This method assumes that the current token matches `Keyword.RETHROW`.
4414 *
4415 * rethrowExpression ::=
4416 * 'rethrow'
4417 */
4418 Expression parseRethrowExpression() => new RethrowExpression(getAndAdvance());
4419
4420 /**
4421 * Parse a return statement. Return the return statement that was parsed.
4422 *
4423 * This method assumes that the current token matches `Keyword.RETURN`.
4424 *
4425 * returnStatement ::=
4426 * 'return' expression? ';'
4427 */
4428 Statement parseReturnStatement() {
4429 Token returnKeyword = getAndAdvance();
4430 if (_matches(TokenType.SEMICOLON)) {
4431 return new ReturnStatement(returnKeyword, null, getAndAdvance());
4432 }
4433 Expression expression = parseExpression2();
4434 Token semicolon = _expect(TokenType.SEMICOLON);
4435 return new ReturnStatement(returnKeyword, expression, semicolon);
4436 }
4437
4438 /**
4439 * Parse a return type. Return the return type that was parsed.
4440 *
4441 * returnType ::=
4442 * 'void'
4443 * | type
4444 */
4445 TypeName parseReturnType() {
4446 if (_currentToken.keyword == Keyword.VOID) {
4447 return new TypeName(new SimpleIdentifier(getAndAdvance()), null);
4448 } else {
4449 return parseTypeName(false);
4450 }
4451 }
4452
4453 /**
4454 * Parse a setter. The [commentAndMetadata] is the documentation comment and
4455 * metadata to be associated with the declaration. The [externalKeyword] is
4456 * the 'external' token. The [staticKeyword] is the static keyword, or `null`
4457 * if the setter is not static. The [returnType] is the return type that has
4458 * already been parsed, or `null` if there was no return type. Return the
4459 * setter that was parsed.
4460 *
4461 * This method assumes that the current token matches `Keyword.SET`.
4462 *
4463 * setter ::=
4464 * setterSignature functionBody?
4465 *
4466 * setterSignature ::=
4467 * 'external'? 'static'? returnType? 'set' identifier formalParameterL ist
4468 */
4469 MethodDeclaration parseSetter(CommentAndMetadata commentAndMetadata,
4470 Token externalKeyword, Token staticKeyword, TypeName returnType) {
4471 Token propertyKeyword = getAndAdvance();
4472 SimpleIdentifier name = parseSimpleIdentifier(isDeclaration: true);
4473 FormalParameterList parameters = parseFormalParameterList();
4474 _validateFormalParameterList(parameters);
4475 FunctionBody body = parseFunctionBody(
4476 externalKeyword != null || staticKeyword == null,
4477 ParserErrorCode.STATIC_SETTER_WITHOUT_BODY,
4478 false);
4479 if (externalKeyword != null && body is! EmptyFunctionBody) {
4480 _reportErrorForCurrentToken(ParserErrorCode.EXTERNAL_SETTER_WITH_BODY);
4481 }
4482 return new MethodDeclaration(
4483 commentAndMetadata.comment,
4484 commentAndMetadata.metadata,
4485 externalKeyword,
4486 staticKeyword,
4487 returnType,
4488 propertyKeyword,
4489 null,
4490 name,
4491 null,
4492 parameters,
4493 body);
4494 }
4495
4496 /**
4497 * Parse a shift expression. Return the shift expression that was parsed.
4498 *
4499 * shiftExpression ::=
4500 * additiveExpression (shiftOperator additiveExpression)*
4501 * | 'super' (shiftOperator additiveExpression)+
4502 */
4503 Expression parseShiftExpression() {
4504 Expression expression;
4505 if (_currentToken.keyword == Keyword.SUPER &&
4506 _currentToken.next.type.isShiftOperator) {
4507 expression = new SuperExpression(getAndAdvance());
4508 } else {
4509 expression = parseAdditiveExpression();
4510 }
4511 while (_currentToken.type.isShiftOperator) {
4512 expression = new BinaryExpression(
4513 expression, getAndAdvance(), parseAdditiveExpression());
4514 }
4515 return expression;
4516 }
4517
4518 /**
4519 * Parse a simple identifier. Return the simple identifier that was parsed.
4520 *
4521 * identifier ::=
4522 * IDENTIFIER
4523 */
4524 SimpleIdentifier parseSimpleIdentifier({bool isDeclaration: false}) {
4525 if (_matchesIdentifier()) {
4526 return _parseSimpleIdentifierUnchecked(isDeclaration: isDeclaration);
4527 }
4528 _reportErrorForCurrentToken(ParserErrorCode.MISSING_IDENTIFIER);
4529 return createSyntheticIdentifier(isDeclaration: isDeclaration);
4530 }
4531
4532 /**
4533 * Parse a statement, starting with the given [token]. Return the statement
4534 * that was parsed, or `null` if the tokens do not represent a recognizable
4535 * statement.
4536 */
4537 Statement parseStatement(Token token) {
4538 _currentToken = token;
4539 return parseStatement2();
4540 }
4541
4542 /**
4543 * Parse a statement. Return the statement that was parsed.
4544 *
4545 * statement ::=
4546 * label* nonLabeledStatement
4547 */
4548 Statement parseStatement2() {
4549 List<Label> labels = null;
4550 while (_matchesIdentifier() && _currentToken.next.type == TokenType.COLON) {
4551 Label label = parseLabel(isDeclaration: true);
4552 if (labels == null) {
4553 labels = <Label>[label];
4554 } else {
4555 labels.add(label);
4556 }
4557 }
4558 Statement statement = parseNonLabeledStatement();
4559 if (labels == null) {
4560 return statement;
4561 }
4562 return new LabeledStatement(labels, statement);
4563 }
4564
4565 /**
4566 * Parse a sequence of statements, starting with the given [token]. Return the
4567 * statements that were parsed, or `null` if the tokens do not represent a
4568 * recognizable sequence of statements.
4569 */
4570 List<Statement> parseStatements(Token token) {
4571 _currentToken = token;
4572 return _parseStatementList();
4573 }
4574
4575 /**
4576 * Parse a string literal. Return the string literal that was parsed.
4577 *
4578 * stringLiteral ::=
4579 * MULTI_LINE_STRING+
4580 * | SINGLE_LINE_STRING+
4581 */
4582 StringLiteral parseStringLiteral() {
4583 if (_matches(TokenType.STRING)) {
4584 return _parseStringLiteralUnchecked();
4585 }
4586 _reportErrorForCurrentToken(ParserErrorCode.EXPECTED_STRING_LITERAL);
4587 return createSyntheticStringLiteral();
4588 }
4589
4590 /**
4591 * Parse a super constructor invocation. Return the super constructor
4592 * invocation that was parsed.
4593 *
4594 * This method assumes that the current token matches [Keyword.SUPER].
4595 *
4596 * superConstructorInvocation ::=
4597 * 'super' ('.' identifier)? arguments
4598 */
4599 SuperConstructorInvocation parseSuperConstructorInvocation() {
4600 Token keyword = getAndAdvance();
4601 Token period = null;
4602 SimpleIdentifier constructorName = null;
4603 if (_matches(TokenType.PERIOD)) {
4604 period = getAndAdvance();
4605 constructorName = parseSimpleIdentifier();
4606 }
4607 ArgumentList argumentList = _parseArgumentListChecked();
4608 return new SuperConstructorInvocation(
4609 keyword, period, constructorName, argumentList);
4610 }
4611
4612 /**
4613 * Parse a switch statement. Return the switch statement that was parsed.
4614 *
4615 * switchStatement ::=
4616 * 'switch' '(' expression ')' '{' switchCase* defaultCase? '}'
4617 *
4618 * switchCase ::=
4619 * label* ('case' expression ':') statements
4620 *
4621 * defaultCase ::=
4622 * label* 'default' ':' statements
4623 */
4624 SwitchStatement parseSwitchStatement() {
4625 bool wasInSwitch = _inSwitch;
4626 _inSwitch = true;
4627 try {
4628 HashSet<String> definedLabels = new HashSet<String>();
4629 Token keyword = _expectKeyword(Keyword.SWITCH);
4630 Token leftParenthesis = _expect(TokenType.OPEN_PAREN);
4631 Expression expression = parseExpression2();
4632 Token rightParenthesis = _expect(TokenType.CLOSE_PAREN);
4633 Token leftBracket = _expect(TokenType.OPEN_CURLY_BRACKET);
4634 Token defaultKeyword = null;
4635 List<SwitchMember> members = <SwitchMember>[];
4636 TokenType type = _currentToken.type;
4637 while (type != TokenType.EOF && type != TokenType.CLOSE_CURLY_BRACKET) {
4638 List<Label> labels = <Label>[];
4639 while (
4640 _matchesIdentifier() && _tokenMatches(_peek(), TokenType.COLON)) {
4641 SimpleIdentifier identifier =
4642 _parseSimpleIdentifierUnchecked(isDeclaration: true);
4643 String label = identifier.token.lexeme;
4644 if (definedLabels.contains(label)) {
4645 _reportErrorForToken(
4646 ParserErrorCode.DUPLICATE_LABEL_IN_SWITCH_STATEMENT,
4647 identifier.token,
4648 [label]);
4649 } else {
4650 definedLabels.add(label);
4651 }
4652 Token colon = getAndAdvance();
4653 labels.add(new Label(identifier, colon));
4654 }
4655 Keyword keyword = _currentToken.keyword;
4656 if (keyword == Keyword.CASE) {
4657 Token caseKeyword = getAndAdvance();
4658 Expression caseExpression = parseExpression2();
4659 Token colon = _expect(TokenType.COLON);
4660 members.add(new SwitchCase(labels, caseKeyword, caseExpression, colon,
4661 _parseStatementList()));
4662 if (defaultKeyword != null) {
4663 _reportErrorForToken(
4664 ParserErrorCode.SWITCH_HAS_CASE_AFTER_DEFAULT_CASE,
4665 caseKeyword);
4666 }
4667 } else if (keyword == Keyword.DEFAULT) {
4668 if (defaultKeyword != null) {
4669 _reportErrorForToken(
4670 ParserErrorCode.SWITCH_HAS_MULTIPLE_DEFAULT_CASES, _peek());
4671 }
4672 defaultKeyword = getAndAdvance();
4673 Token colon = _expect(TokenType.COLON);
4674 members.add(new SwitchDefault(
4675 labels, defaultKeyword, colon, _parseStatementList()));
4676 } else {
4677 // We need to advance, otherwise we could end up in an infinite loop,
4678 // but this could be a lot smarter about recovering from the error.
4679 _reportErrorForCurrentToken(ParserErrorCode.EXPECTED_CASE_OR_DEFAULT);
4680 bool atEndOrNextMember() {
4681 TokenType type = _currentToken.type;
4682 if (type == TokenType.EOF ||
4683 type == TokenType.CLOSE_CURLY_BRACKET) {
4684 return true;
4685 }
4686 Keyword keyword = _currentToken.keyword;
4687 return keyword == Keyword.CASE || keyword == Keyword.DEFAULT;
4688 }
4689
4690 while (!atEndOrNextMember()) {
4691 _advance();
4692 }
4693 }
4694 type = _currentToken.type;
4695 }
4696 Token rightBracket = _expect(TokenType.CLOSE_CURLY_BRACKET);
4697 return new SwitchStatement(keyword, leftParenthesis, expression,
4698 rightParenthesis, leftBracket, members, rightBracket);
4699 } finally {
4700 _inSwitch = wasInSwitch;
4701 }
4702 }
4703
4704 /**
4705 * Parse a symbol literal. Return the symbol literal that was parsed.
4706 *
4707 * This method assumes that the current token matches [TokenType.HASH].
4708 *
4709 * symbolLiteral ::=
4710 * '#' identifier ('.' identifier)*
4711 */
4712 SymbolLiteral parseSymbolLiteral() {
4713 Token poundSign = getAndAdvance();
4714 List<Token> components = <Token>[];
4715 if (_matchesIdentifier()) {
4716 components.add(getAndAdvance());
4717 while (_optional(TokenType.PERIOD)) {
4718 if (_matchesIdentifier()) {
4719 components.add(getAndAdvance());
4720 } else {
4721 _reportErrorForCurrentToken(ParserErrorCode.MISSING_IDENTIFIER);
4722 components.add(_createSyntheticToken(TokenType.IDENTIFIER));
4723 break;
4724 }
4725 }
4726 } else if (_currentToken.isOperator) {
4727 components.add(getAndAdvance());
4728 } else if (_matchesKeyword(Keyword.VOID)) {
4729 components.add(getAndAdvance());
4730 } else {
4731 _reportErrorForCurrentToken(ParserErrorCode.MISSING_IDENTIFIER);
4732 components.add(_createSyntheticToken(TokenType.IDENTIFIER));
4733 }
4734 return new SymbolLiteral(poundSign, components);
4735 }
4736
4737 /**
4738 * Parse a throw expression. Return the throw expression that was parsed.
4739 *
4740 * This method assumes that the current token matches [Keyword.THROW].
4741 *
4742 * throwExpression ::=
4743 * 'throw' expression
4744 */
4745 Expression parseThrowExpression() {
4746 Token keyword = getAndAdvance();
4747 TokenType type = _currentToken.type;
4748 if (type == TokenType.SEMICOLON || type == TokenType.CLOSE_PAREN) {
4749 _reportErrorForToken(
4750 ParserErrorCode.MISSING_EXPRESSION_IN_THROW, _currentToken);
4751 return new ThrowExpression(keyword, createSyntheticIdentifier());
4752 }
4753 Expression expression = parseExpression2();
4754 return new ThrowExpression(keyword, expression);
4755 }
4756
4757 /**
4758 * Parse a throw expression. Return the throw expression that was parsed.
4759 *
4760 * This method assumes that the current token matches [Keyword.THROW].
4761 *
4762 * throwExpressionWithoutCascade ::=
4763 * 'throw' expressionWithoutCascade
4764 */
4765 Expression parseThrowExpressionWithoutCascade() {
4766 Token keyword = getAndAdvance();
4767 TokenType type = _currentToken.type;
4768 if (type == TokenType.SEMICOLON || type == TokenType.CLOSE_PAREN) {
4769 _reportErrorForToken(
4770 ParserErrorCode.MISSING_EXPRESSION_IN_THROW, _currentToken);
4771 return new ThrowExpression(keyword, createSyntheticIdentifier());
4772 }
4773 Expression expression = parseExpressionWithoutCascade();
4774 return new ThrowExpression(keyword, expression);
4775 }
4776
4777 /**
4778 * Parse a try statement. Return the try statement that was parsed.
4779 *
4780 * This method assumes that the current token matches [Keyword.TRY].
4781 *
4782 * tryStatement ::=
4783 * 'try' block (onPart+ finallyPart? | finallyPart)
4784 *
4785 * onPart ::=
4786 * catchPart block
4787 * | 'on' type catchPart? block
4788 *
4789 * catchPart ::=
4790 * 'catch' '(' identifier (',' identifier)? ')'
4791 *
4792 * finallyPart ::=
4793 * 'finally' block
4794 */
4795 Statement parseTryStatement() {
4796 Token tryKeyword = getAndAdvance();
4797 Block body = _parseBlockChecked();
4798 List<CatchClause> catchClauses = <CatchClause>[];
4799 Block finallyClause = null;
4800 while (_matchesString(_ON) || _matchesKeyword(Keyword.CATCH)) {
4801 Token onKeyword = null;
4802 TypeName exceptionType = null;
4803 if (_matchesString(_ON)) {
4804 onKeyword = getAndAdvance();
4805 exceptionType = parseTypeName(false);
4806 }
4807 Token catchKeyword = null;
4808 Token leftParenthesis = null;
4809 SimpleIdentifier exceptionParameter = null;
4810 Token comma = null;
4811 SimpleIdentifier stackTraceParameter = null;
4812 Token rightParenthesis = null;
4813 if (_matchesKeyword(Keyword.CATCH)) {
4814 catchKeyword = getAndAdvance();
4815 leftParenthesis = _expect(TokenType.OPEN_PAREN);
4816 exceptionParameter = parseSimpleIdentifier(isDeclaration: true);
4817 if (_matches(TokenType.COMMA)) {
4818 comma = getAndAdvance();
4819 stackTraceParameter = parseSimpleIdentifier(isDeclaration: true);
4820 }
4821 rightParenthesis = _expect(TokenType.CLOSE_PAREN);
4822 }
4823 Block catchBody = _parseBlockChecked();
4824 catchClauses.add(new CatchClause(
4825 onKeyword,
4826 exceptionType,
4827 catchKeyword,
4828 leftParenthesis,
4829 exceptionParameter,
4830 comma,
4831 stackTraceParameter,
4832 rightParenthesis,
4833 catchBody));
4834 }
4835 Token finallyKeyword = null;
4836 if (_matchesKeyword(Keyword.FINALLY)) {
4837 finallyKeyword = getAndAdvance();
4838 finallyClause = _parseBlockChecked();
4839 } else if (catchClauses.isEmpty) {
4840 _reportErrorForCurrentToken(ParserErrorCode.MISSING_CATCH_OR_FINALLY);
4841 }
4842 return new TryStatement(
4843 tryKeyword, body, catchClauses, finallyKeyword, finallyClause);
4844 }
4845
4846 /**
4847 * Parse a type alias. The [commentAndMetadata] is the metadata to be
4848 * associated with the member. Return the type alias that was parsed.
4849 *
4850 * This method assumes that the current token matches [Keyword.TYPEDEF].
4851 *
4852 * typeAlias ::=
4853 * 'typedef' typeAliasBody
4854 *
4855 * typeAliasBody ::=
4856 * classTypeAlias
4857 * | functionTypeAlias
4858 *
4859 * classTypeAlias ::=
4860 * identifier typeParameters? '=' 'abstract'? mixinApplication
4861 *
4862 * mixinApplication ::=
4863 * qualified withClause implementsClause? ';'
4864 *
4865 * functionTypeAlias ::=
4866 * functionPrefix typeParameterList? formalParameterList ';'
4867 *
4868 * functionPrefix ::=
4869 * returnType? name
4870 */
4871 TypeAlias parseTypeAlias(CommentAndMetadata commentAndMetadata) {
4872 Token keyword = getAndAdvance();
4873 if (_matchesIdentifier()) {
4874 Token next = _peek();
4875 if (_tokenMatches(next, TokenType.LT)) {
4876 next = _skipTypeParameterList(next);
4877 if (next != null && _tokenMatches(next, TokenType.EQ)) {
4878 TypeAlias typeAlias =
4879 parseClassTypeAlias(commentAndMetadata, null, keyword);
4880 _reportErrorForToken(
4881 ParserErrorCode.DEPRECATED_CLASS_TYPE_ALIAS, keyword);
4882 return typeAlias;
4883 }
4884 } else if (_tokenMatches(next, TokenType.EQ)) {
4885 TypeAlias typeAlias =
4886 parseClassTypeAlias(commentAndMetadata, null, keyword);
4887 _reportErrorForToken(
4888 ParserErrorCode.DEPRECATED_CLASS_TYPE_ALIAS, keyword);
4889 return typeAlias;
4890 }
4891 }
4892 return _parseFunctionTypeAlias(commentAndMetadata, keyword);
4893 }
4894
4895 /**
4896 * Parse a list of type arguments. Return the type argument list that was
4897 * parsed.
4898 *
4899 * This method assumes that the current token matches `TokenType.LT`.
4900 *
4901 * typeArguments ::=
4902 * '<' typeList '>'
4903 *
4904 * typeList ::=
4905 * type (',' type)*
4906 */
4907 TypeArgumentList parseTypeArgumentList() {
4908 Token leftBracket = getAndAdvance();
4909 List<TypeName> arguments = <TypeName>[parseTypeName(false)];
4910 while (_optional(TokenType.COMMA)) {
4911 arguments.add(parseTypeName(false));
4912 }
4913 Token rightBracket = _expectGt();
4914 return new TypeArgumentList(leftBracket, arguments, rightBracket);
4915 }
4916
4917 /**
4918 * Parse a type name. Return the type name that was parsed.
4919 *
4920 * type ::=
4921 * qualified typeArguments?
4922 */
4923 TypeName parseTypeName(bool inExpression) {
4924 TypeName realType = _parseTypeName(inExpression);
4925 // If this is followed by a generic method type comment, allow the comment
4926 // type to replace the real type name.
4927 // TODO(jmesserly): this feels like a big hammer. Can we restrict it to
4928 // only work inside generic methods?
4929 TypeName typeFromComment = _parseOptionalTypeNameComment();
4930 return typeFromComment ?? realType;
4931 }
4932
4933 /**
4934 * Parse a type parameter. Return the type parameter that was parsed.
4935 *
4936 * typeParameter ::=
4937 * metadata name ('extends' bound)?
4938 */
4939 TypeParameter parseTypeParameter() {
4940 CommentAndMetadata commentAndMetadata = parseCommentAndMetadata();
4941 SimpleIdentifier name = parseSimpleIdentifier(isDeclaration: true);
4942 if (_matchesKeyword(Keyword.EXTENDS)) {
4943 Token keyword = getAndAdvance();
4944 TypeName bound = parseTypeName(false);
4945 return new TypeParameter(commentAndMetadata.comment,
4946 commentAndMetadata.metadata, name, keyword, bound);
4947 }
4948 return new TypeParameter(commentAndMetadata.comment,
4949 commentAndMetadata.metadata, name, null, null);
4950 }
4951
4952 /**
4953 * Parse a list of type parameters. Return the list of type parameters that
4954 * were parsed.
4955 *
4956 * This method assumes that the current token matches `TokenType.LT`.
4957 *
4958 * typeParameterList ::=
4959 * '<' typeParameter (',' typeParameter)* '>'
4960 */
4961 TypeParameterList parseTypeParameterList() {
4962 Token leftBracket = getAndAdvance();
4963 List<TypeParameter> typeParameters = <TypeParameter>[parseTypeParameter()];
4964 while (_optional(TokenType.COMMA)) {
4965 typeParameters.add(parseTypeParameter());
4966 }
4967 Token rightBracket = _expectGt();
4968 return new TypeParameterList(leftBracket, typeParameters, rightBracket);
4969 }
4970
4971 /**
4972 * Parse a unary expression. Return the unary expression that was parsed.
4973 *
4974 * unaryExpression ::=
4975 * prefixOperator unaryExpression
4976 * | awaitExpression
4977 * | postfixExpression
4978 * | unaryOperator 'super'
4979 * | '-' 'super'
4980 * | incrementOperator assignableExpression
4981 */
4982 Expression parseUnaryExpression() {
4983 TokenType type = _currentToken.type;
4984 if (type == TokenType.MINUS ||
4985 type == TokenType.BANG ||
4986 type == TokenType.TILDE) {
4987 Token operator = getAndAdvance();
4988 if (_matchesKeyword(Keyword.SUPER)) {
4989 TokenType nextType = _peek().type;
4990 if (nextType == TokenType.OPEN_SQUARE_BRACKET ||
4991 nextType == TokenType.PERIOD) {
4992 // "prefixOperator unaryExpression"
4993 // --> "prefixOperator postfixExpression"
4994 // --> "prefixOperator primary selector*"
4995 // --> "prefixOperator 'super' assignableSelector selector*"
4996 return new PrefixExpression(operator, parseUnaryExpression());
4997 }
4998 return new PrefixExpression(
4999 operator, new SuperExpression(getAndAdvance()));
5000 }
5001 return new PrefixExpression(operator, parseUnaryExpression());
5002 } else if (_currentToken.type.isIncrementOperator) {
5003 Token operator = getAndAdvance();
5004 if (_matchesKeyword(Keyword.SUPER)) {
5005 TokenType nextType = _peek().type;
5006 if (nextType == TokenType.OPEN_SQUARE_BRACKET ||
5007 nextType == TokenType.PERIOD) {
5008 // --> "prefixOperator 'super' assignableSelector selector*"
5009 return new PrefixExpression(operator, parseUnaryExpression());
5010 }
5011 //
5012 // Even though it is not valid to use an incrementing operator
5013 // ('++' or '--') before 'super', we can (and therefore must) interpret
5014 // "--super" as semantically equivalent to "-(-super)". Unfortunately,
5015 // we cannot do the same for "++super" because "+super" is also not
5016 // valid.
5017 //
5018 if (type == TokenType.MINUS_MINUS) {
5019 Token firstOperator = _createToken(operator, TokenType.MINUS);
5020 Token secondOperator =
5021 new Token(TokenType.MINUS, operator.offset + 1);
5022 secondOperator.setNext(_currentToken);
5023 firstOperator.setNext(secondOperator);
5024 operator.previous.setNext(firstOperator);
5025 return new PrefixExpression(
5026 firstOperator,
5027 new PrefixExpression(
5028 secondOperator, new SuperExpression(getAndAdvance())));
5029 }
5030 // Invalid operator before 'super'
5031 _reportErrorForCurrentToken(
5032 ParserErrorCode.INVALID_OPERATOR_FOR_SUPER, [operator.lexeme]);
5033 return new PrefixExpression(
5034 operator, new SuperExpression(getAndAdvance()));
5035 }
5036 return new PrefixExpression(
5037 operator, _parseAssignableExpressionNotStartingWithSuper(false));
5038 } else if (type == TokenType.PLUS) {
5039 _reportErrorForCurrentToken(ParserErrorCode.MISSING_IDENTIFIER);
5040 return createSyntheticIdentifier();
5041 } else if (_inAsync && _matchesString(_AWAIT)) {
5042 return parseAwaitExpression();
5043 }
5044 return parsePostfixExpression();
5045 }
5046
5047 /**
5048 * Parse a variable declaration. Return the variable declaration that was
5049 * parsed.
5050 *
5051 * variableDeclaration ::=
5052 * identifier ('=' expression)?
5053 */
5054 VariableDeclaration parseVariableDeclaration() {
5055 // TODO(paulberry): prior to the fix for bug 23204, we permitted
5056 // annotations before variable declarations (e.g. "String @deprecated s;").
5057 // Although such constructions are prohibited by the spec, we may want to
5058 // consider handling them anyway to allow for better parser recovery in the
5059 // event that the user erroneously tries to use them. However, as a
5060 // counterargument, this would likely degrade parser recovery in the event
5061 // of a construct like "class C { int @deprecated foo() {} }" (i.e. the
5062 // user is in the middle of inserting "int bar;" prior to
5063 // "@deprecated foo() {}").
5064 SimpleIdentifier name = parseSimpleIdentifier(isDeclaration: true);
5065 Token equals = null;
5066 Expression initializer = null;
5067 if (_matches(TokenType.EQ)) {
5068 equals = getAndAdvance();
5069 initializer = parseExpression2();
5070 }
5071 return new VariableDeclaration(name, equals, initializer);
5072 }
5073
5074 /**
5075 * Parse a variable declaration list. The [commentAndMetadata] is the metadata
5076 * to be associated with the variable declaration list. Return the variable
5077 * declaration list that was parsed.
5078 *
5079 * variableDeclarationList ::=
5080 * finalConstVarOrType variableDeclaration (',' variableDeclaration)*
5081 */
5082 VariableDeclarationList parseVariableDeclarationListAfterMetadata(
5083 CommentAndMetadata commentAndMetadata) {
5084 FinalConstVarOrType holder = parseFinalConstVarOrType(false);
5085 return parseVariableDeclarationListAfterType(
5086 commentAndMetadata, holder.keyword, holder.type);
5087 }
5088
5089 /**
5090 * Parse a variable declaration list. The [commentAndMetadata] is the metadata
5091 * to be associated with the variable declaration list, or `null` if there is
5092 * no attempt at parsing the comment and metadata. The [keyword] is the token
5093 * representing the 'final', 'const' or 'var' keyword, or `null` if there is
5094 * no keyword. The [type] is the type of the variables in the list. Return the
5095 * variable declaration list that was parsed.
5096 *
5097 * variableDeclarationList ::=
5098 * finalConstVarOrType variableDeclaration (',' variableDeclaration)*
5099 */
5100 VariableDeclarationList parseVariableDeclarationListAfterType(
5101 CommentAndMetadata commentAndMetadata, Token keyword, TypeName type) {
5102 if (type != null &&
5103 keyword != null &&
5104 _tokenMatchesKeyword(keyword, Keyword.VAR)) {
5105 _reportErrorForToken(ParserErrorCode.VAR_AND_TYPE, keyword);
5106 }
5107 List<VariableDeclaration> variables = <VariableDeclaration>[
5108 parseVariableDeclaration()
5109 ];
5110 while (_optional(TokenType.COMMA)) {
5111 variables.add(parseVariableDeclaration());
5112 }
5113 return new VariableDeclarationList(commentAndMetadata?.comment,
5114 commentAndMetadata?.metadata, keyword, type, variables);
5115 }
5116
5117 /**
5118 * Parse a variable declaration statement. The [commentAndMetadata] is the
5119 * metadata to be associated with the variable declaration statement, or
5120 * `null` if there is no attempt at parsing the comment and metadata. Return
5121 * the variable declaration statement that was parsed.
5122 *
5123 * variableDeclarationStatement ::=
5124 * variableDeclarationList ';'
5125 */
5126 VariableDeclarationStatement parseVariableDeclarationStatementAfterMetadata(
5127 CommentAndMetadata commentAndMetadata) {
5128 // Token startToken = currentToken;
5129 VariableDeclarationList variableList =
5130 parseVariableDeclarationListAfterMetadata(commentAndMetadata);
5131 // if (!matches(TokenType.SEMICOLON)) {
5132 // if (matches(startToken, Keyword.VAR) && isTypedIdentifier(startToken .getNext())) {
5133 // // TODO(brianwilkerson) This appears to be of the form "var type v ariable". We should do
5134 // // a better job of recovering in this case.
5135 // }
5136 // }
5137 Token semicolon = _expect(TokenType.SEMICOLON);
5138 return new VariableDeclarationStatement(variableList, semicolon);
5139 }
5140
5141 /**
5142 * Parse a while statement. Return the while statement that was parsed.
5143 *
5144 * This method assumes that the current token matches [Keyword.WHILE].
5145 *
5146 * whileStatement ::=
5147 * 'while' '(' expression ')' statement
5148 */
5149 Statement parseWhileStatement() {
5150 bool wasInLoop = _inLoop;
5151 _inLoop = true;
5152 try {
5153 Token keyword = getAndAdvance();
5154 Token leftParenthesis = _expect(TokenType.OPEN_PAREN);
5155 Expression condition = parseExpression2();
5156 Token rightParenthesis = _expect(TokenType.CLOSE_PAREN);
5157 Statement body = parseStatement2();
5158 return new WhileStatement(
5159 keyword, leftParenthesis, condition, rightParenthesis, body);
5160 } finally {
5161 _inLoop = wasInLoop;
5162 }
5163 }
5164
5165 /**
5166 * Parse a with clause. Return the with clause that was parsed.
5167 *
5168 * This method assumes that the current token matches `Keyword.WITH`.
5169 *
5170 * withClause ::=
5171 * 'with' typeName (',' typeName)*
5172 */
5173 WithClause parseWithClause() {
5174 Token withKeyword = getAndAdvance();
5175 List<TypeName> types = <TypeName>[parseTypeName(false)];
5176 while (_optional(TokenType.COMMA)) {
5177 types.add(parseTypeName(false));
5178 }
5179 return new WithClause(withKeyword, types);
5180 }
5181
5182 /**
5183 * Parse a yield statement. Return the yield statement that was parsed.
5184 *
5185 * This method assumes that the current token matches [Keyword.YIELD].
5186 *
5187 * yieldStatement ::=
5188 * 'yield' '*'? expression ';'
5189 */
5190 YieldStatement parseYieldStatement() {
5191 Token yieldToken = getAndAdvance();
5192 Token star = null;
5193 if (_matches(TokenType.STAR)) {
5194 star = getAndAdvance();
5195 }
5196 Expression expression = parseExpression2();
5197 Token semicolon = _expect(TokenType.SEMICOLON);
5198 return new YieldStatement(yieldToken, star, expression, semicolon);
5199 }
5200
5201 /**
5202 * Parse a prefixed identifier, starting at the [startToken], without actually
5203 * creating a prefixed identifier or changing the current token. Return the
5204 * token following the prefixed identifier that was parsed, or `null` if the
5205 * given token is not the first token in a valid prefixed identifier.
5206 *
5207 * This method must be kept in sync with [parsePrefixedIdentifier].
5208 *
5209 * prefixedIdentifier ::=
5210 * identifier ('.' identifier)?
5211 */
5212 Token skipPrefixedIdentifier(Token startToken) {
5213 Token token = skipSimpleIdentifier(startToken);
5214 if (token == null) {
5215 return null;
5216 } else if (!_tokenMatches(token, TokenType.PERIOD)) {
5217 return token;
5218 }
5219 token = token.next;
5220 Token nextToken = skipSimpleIdentifier(token);
5221 if (nextToken != null) {
5222 return nextToken;
5223 } else if (_tokenMatches(token, TokenType.CLOSE_PAREN) ||
5224 _tokenMatches(token, TokenType.COMMA)) {
5225 // If the `id.` is followed by something that cannot produce a valid
5226 // structure then assume this is a prefixed identifier but missing the
5227 // trailing identifier
5228 return token;
5229 }
5230 return null;
5231 }
5232
5233 /**
5234 * Parse a return type, starting at the [startToken], without actually
5235 * creating a return type or changing the current token. Return the token
5236 * following the return type that was parsed, or `null` if the given token is
5237 * not the first token in a valid return type.
5238 *
5239 * This method must be kept in sync with [parseReturnType].
5240 *
5241 * returnType ::=
5242 * 'void'
5243 * | type
5244 */
5245 Token skipReturnType(Token startToken) {
5246 if (_tokenMatchesKeyword(startToken, Keyword.VOID)) {
5247 return startToken.next;
5248 } else {
5249 return skipTypeName(startToken);
5250 }
5251 }
5252
5253 /**
5254 * Parse a simple identifier, starting at the [startToken], without actually
5255 * creating a simple identifier or changing the current token. Return the
5256 * token following the simple identifier that was parsed, or `null` if the
5257 * given token is not the first token in a valid simple identifier.
5258 *
5259 * This method must be kept in sync with [parseSimpleIdentifier].
5260 *
5261 * identifier ::=
5262 * IDENTIFIER
5263 */
5264 Token skipSimpleIdentifier(Token startToken) {
5265 if (_tokenMatches(startToken, TokenType.IDENTIFIER) ||
5266 _tokenMatchesPseudoKeyword(startToken)) {
5267 return startToken.next;
5268 }
5269 return null;
5270 }
5271
5272 /**
5273 * Parse a string literal, starting at the [startToken], without actually
5274 * creating a string literal or changing the current token. Return the token
5275 * following the string literal that was parsed, or `null` if the given token
5276 * is not the first token in a valid string literal.
5277 *
5278 * This method must be kept in sync with [parseStringLiteral].
5279 *
5280 * stringLiteral ::=
5281 * MULTI_LINE_STRING+
5282 * | SINGLE_LINE_STRING+
5283 */
5284 Token skipStringLiteral(Token startToken) {
5285 Token token = startToken;
5286 while (token != null && _tokenMatches(token, TokenType.STRING)) {
5287 token = token.next;
5288 TokenType type = token.type;
5289 if (type == TokenType.STRING_INTERPOLATION_EXPRESSION ||
5290 type == TokenType.STRING_INTERPOLATION_IDENTIFIER) {
5291 token = _skipStringInterpolation(token);
5292 }
5293 }
5294 if (identical(token, startToken)) {
5295 return null;
5296 }
5297 return token;
5298 }
5299
5300 /**
5301 * Parse a list of type arguments, starting at the [startToken], without
5302 * actually creating a type argument list or changing the current token.
5303 * Return the token following the type argument list that was parsed, or
5304 * `null` if the given token is not the first token in a valid type argument
5305 * list.
5306 *
5307 * This method must be kept in sync with [parseTypeArgumentList].
5308 *
5309 * typeArguments ::=
5310 * '<' typeList '>'
5311 *
5312 * typeList ::=
5313 * type (',' type)*
5314 */
5315 Token skipTypeArgumentList(Token startToken) {
5316 Token token = startToken;
5317 if (!_tokenMatches(token, TokenType.LT) &&
5318 !_injectGenericCommentTypeList()) {
5319 return null;
5320 }
5321 token = skipTypeName(token.next);
5322 if (token == null) {
5323 // If the start token '<' is followed by '>'
5324 // then assume this should be type argument list but is missing a type
5325 token = startToken.next;
5326 if (_tokenMatches(token, TokenType.GT)) {
5327 return token.next;
5328 }
5329 return null;
5330 }
5331 while (_tokenMatches(token, TokenType.COMMA)) {
5332 token = skipTypeName(token.next);
5333 if (token == null) {
5334 return null;
5335 }
5336 }
5337 if (token.type == TokenType.GT) {
5338 return token.next;
5339 } else if (token.type == TokenType.GT_GT) {
5340 Token second = new Token(TokenType.GT, token.offset + 1);
5341 second.setNextWithoutSettingPrevious(token.next);
5342 return second;
5343 }
5344 return null;
5345 }
5346
5347 /**
5348 * Parse a type name, starting at the [startToken], without actually creating
5349 * a type name or changing the current token. Return the token following the
5350 * type name that was parsed, or `null` if the given token is not the first
5351 * token in a valid type name.
5352 *
5353 * This method must be kept in sync with [parseTypeName].
5354 *
5355 * type ::=
5356 * qualified typeArguments?
5357 */
5358 Token skipTypeName(Token startToken) {
5359 Token token = skipPrefixedIdentifier(startToken);
5360 if (token == null) {
5361 return null;
5362 }
5363 if (_tokenMatches(token, TokenType.LT)) {
5364 token = skipTypeArgumentList(token);
5365 }
5366 return token;
5367 }
5368
5369 /**
5370 * Advance to the next token in the token stream.
5371 */
5372 void _advance() {
5373 _currentToken = _currentToken.next;
5374 }
5375
5376 /**
5377 * Append the character equivalent of the given [scalarValue] to the given
5378 * [builder]. Use the [startIndex] and [endIndex] to report an error, and
5379 * don't append anything to the builder, if the scalar value is invalid. The
5380 * [escapeSequence] is the escape sequence that was parsed to produce the
5381 * scalar value (used for error reporting).
5382 */
5383 void _appendScalarValue(StringBuffer buffer, String escapeSequence,
5384 int scalarValue, int startIndex, int endIndex) {
5385 if (scalarValue < 0 ||
5386 scalarValue > Character.MAX_CODE_POINT ||
5387 (scalarValue >= 0xD800 && scalarValue <= 0xDFFF)) {
5388 _reportErrorForCurrentToken(
5389 ParserErrorCode.INVALID_CODE_POINT, [escapeSequence]);
5390 return;
5391 }
5392 if (scalarValue < Character.MAX_VALUE) {
5393 buffer.writeCharCode(scalarValue);
5394 } else {
5395 buffer.write(Character.toChars(scalarValue));
5396 }
5397 }
5398
5399 /**
5400 * Clone all token starting from the given [token] up to the end of the token
5401 * stream, and return the first token in the new token stream.
5402 */
5403 Token _cloneTokens(Token token) {
5404 if (token == null) {
5405 return null;
5406 }
5407 token = token is CommentToken ? token.parent : token;
5408 Token head = new Token(TokenType.EOF, -1);
5409 head.setNext(head);
5410 Token current = head;
5411 while (token.type != TokenType.EOF) {
5412 Token clone = token.copy();
5413 current.setNext(clone);
5414 current = clone;
5415 token = token.next;
5416 }
5417 Token tail = new Token(TokenType.EOF, 0);
5418 tail.setNext(tail);
5419 current.setNext(tail);
5420 return head.next;
5421 }
5422
5423 /**
5424 * Convert the given [method] declaration into the nearest valid top-level
5425 * function declaration (that is, the function declaration that most closely
5426 * captures the components of the given method declaration).
5427 */
5428 FunctionDeclaration _convertToFunctionDeclaration(MethodDeclaration method) =>
5429 new FunctionDeclaration(
5430 method.documentationComment,
5431 method.metadata,
5432 method.externalKeyword,
5433 method.returnType,
5434 method.propertyKeyword,
5435 method.name,
5436 new FunctionExpression(
5437 method.typeParameters, method.parameters, method.body));
5438
5439 /**
5440 * Return `true` if the current token could be the start of a compilation unit
5441 * member. This method is used for recovery purposes to decide when to stop
5442 * skipping tokens after finding an error while parsing a compilation unit
5443 * member.
5444 */
5445 bool _couldBeStartOfCompilationUnitMember() {
5446 Keyword keyword = _currentToken.keyword;
5447 Token next = _currentToken.next;
5448 TokenType nextType = next.type;
5449 if ((keyword == Keyword.IMPORT ||
5450 keyword == Keyword.EXPORT ||
5451 keyword == Keyword.LIBRARY ||
5452 keyword == Keyword.PART) &&
5453 nextType != TokenType.PERIOD &&
5454 nextType != TokenType.LT) {
5455 // This looks like the start of a directive
5456 return true;
5457 } else if (keyword == Keyword.CLASS) {
5458 // This looks like the start of a class definition
5459 return true;
5460 } else if (keyword == Keyword.TYPEDEF &&
5461 nextType != TokenType.PERIOD &&
5462 nextType != TokenType.LT) {
5463 // This looks like the start of a typedef
5464 return true;
5465 } else if (keyword == Keyword.VOID ||
5466 ((keyword == Keyword.GET || keyword == Keyword.SET) &&
5467 _tokenMatchesIdentifier(next)) ||
5468 (keyword == Keyword.OPERATOR && _isOperator(next))) {
5469 // This looks like the start of a function
5470 return true;
5471 } else if (_matchesIdentifier()) {
5472 if (nextType == TokenType.OPEN_PAREN) {
5473 // This looks like the start of a function
5474 return true;
5475 }
5476 Token token = skipReturnType(_currentToken);
5477 if (token == null) {
5478 return false;
5479 }
5480 // TODO(brianwilkerson) This looks wrong; should we be checking 'token'?
5481 if (keyword == Keyword.GET ||
5482 keyword == Keyword.SET ||
5483 (keyword == Keyword.OPERATOR && _isOperator(next)) ||
5484 _matchesIdentifier()) {
5485 return true;
5486 }
5487 }
5488 return false;
5489 }
5490
5491 /**
5492 * Return a synthetic token representing the given [keyword].
5493 */
5494 Token _createSyntheticKeyword(Keyword keyword) => _injectToken(
5495 new Parser_SyntheticKeywordToken(keyword, _currentToken.offset));
5496
5497 /**
5498 * Return a synthetic token with the given [type].
5499 */
5500 Token _createSyntheticToken(TokenType type) =>
5501 _injectToken(new StringToken(type, "", _currentToken.offset));
5502
5503 /**
5504 * Create and return a new token with the given [type]. The token will replace
5505 * the first portion of the given [token], so it will have the same offset and
5506 * will have any comments that might have preceeded the token.
5507 */
5508 Token _createToken(Token token, TokenType type, {bool isBegin: false}) {
5509 CommentToken comments = token.precedingComments;
5510 if (comments == null) {
5511 if (isBegin) {
5512 return new BeginToken(type, token.offset);
5513 }
5514 return new Token(type, token.offset);
5515 } else if (isBegin) {
5516 return new BeginTokenWithComment(type, token.offset, comments);
5517 }
5518 return new TokenWithComment(type, token.offset, comments);
5519 }
5520
5521 /**
5522 * Check that the given [expression] is assignable and report an error if it
5523 * isn't.
5524 *
5525 * assignableExpression ::=
5526 * primary (arguments* assignableSelector)+
5527 * | 'super' unconditionalAssignableSelector
5528 * | identifier
5529 *
5530 * unconditionalAssignableSelector ::=
5531 * '[' expression ']'
5532 * | '.' identifier
5533 *
5534 * assignableSelector ::=
5535 * unconditionalAssignableSelector
5536 * | '?.' identifier
5537 */
5538 void _ensureAssignable(Expression expression) {
5539 if (expression != null && !expression.isAssignable) {
5540 _reportErrorForCurrentToken(
5541 ParserErrorCode.ILLEGAL_ASSIGNMENT_TO_NON_ASSIGNABLE);
5542 }
5543 }
5544
5545 /**
5546 * If the current token has the expected type, return it after advancing to
5547 * the next token. Otherwise report an error and return the current token
5548 * without advancing.
5549 *
5550 * Note that the method [_expectGt] should be used if the argument to this
5551 * method would be [TokenType.GT].
5552 *
5553 * The [type] is the type of token that is expected.
5554 */
5555 Token _expect(TokenType type) {
5556 if (_matches(type)) {
5557 return getAndAdvance();
5558 }
5559 // Remove uses of this method in favor of matches?
5560 // Pass in the error code to use to report the error?
5561 if (type == TokenType.SEMICOLON) {
5562 if (_tokenMatches(_currentToken.next, TokenType.SEMICOLON)) {
5563 _reportErrorForCurrentToken(
5564 ParserErrorCode.UNEXPECTED_TOKEN, [_currentToken.lexeme]);
5565 _advance();
5566 return getAndAdvance();
5567 }
5568 _reportErrorForToken(ParserErrorCode.EXPECTED_TOKEN,
5569 _currentToken.previous, [type.lexeme]);
5570 return _createSyntheticToken(TokenType.SEMICOLON);
5571 }
5572 _reportErrorForCurrentToken(ParserErrorCode.EXPECTED_TOKEN, [type.lexeme]);
5573 return _createSyntheticToken(type);
5574 }
5575
5576 /**
5577 * If the current token has the type [TokenType.GT], return it after advancing
5578 * to the next token. Otherwise report an error and create a synthetic token.
5579 */
5580 Token _expectGt() {
5581 if (_matchesGt()) {
5582 return getAndAdvance();
5583 }
5584 _reportErrorForCurrentToken(
5585 ParserErrorCode.EXPECTED_TOKEN, [TokenType.GT.lexeme]);
5586 return _createSyntheticToken(TokenType.GT);
5587 }
5588
5589 /**
5590 * If the current token is a keyword matching the given [keyword], return it
5591 * after advancing to the next token. Otherwise report an error and return the
5592 * current token without advancing.
5593 */
5594 Token _expectKeyword(Keyword keyword) {
5595 if (_matchesKeyword(keyword)) {
5596 return getAndAdvance();
5597 }
5598 // Remove uses of this method in favor of matches?
5599 // Pass in the error code to use to report the error?
5600 _reportErrorForCurrentToken(
5601 ParserErrorCode.EXPECTED_TOKEN, [keyword.syntax]);
5602 return _currentToken;
5603 }
5604
5605 /**
5606 * Search the given list of [ranges] for a range that contains the given
5607 * [index]. Return the range that was found, or `null` if none of the ranges
5608 * contain the index.
5609 */
5610 List<int> _findRange(List<List<int>> ranges, int index) {
5611 int rangeCount = ranges.length;
5612 for (int i = 0; i < rangeCount; i++) {
5613 List<int> range = ranges[i];
5614 if (range[0] <= index && index <= range[1]) {
5615 return range;
5616 } else if (index < range[0]) {
5617 return null;
5618 }
5619 }
5620 return null;
5621 }
5622
5623 /**
5624 * Return a list of the ranges of characters in the given [comment] that
5625 * should be treated as code blocks.
5626 */
5627 List<List<int>> _getCodeBlockRanges(String comment) {
5628 List<List<int>> ranges = <List<int>>[];
5629 int length = comment.length;
5630 if (length < 3) {
5631 return ranges;
5632 }
5633 int index = 0;
5634 int firstChar = comment.codeUnitAt(0);
5635 if (firstChar == 0x2F) {
5636 int secondChar = comment.codeUnitAt(1);
5637 int thirdChar = comment.codeUnitAt(2);
5638 if ((secondChar == 0x2A && thirdChar == 0x2A) ||
5639 (secondChar == 0x2F && thirdChar == 0x2F)) {
5640 index = 3;
5641 }
5642 }
5643 if (StringUtilities.startsWith4(comment, index, 0x20, 0x20, 0x20, 0x20)) {
5644 int end = index + 4;
5645 while (end < length &&
5646 comment.codeUnitAt(end) != 0xD &&
5647 comment.codeUnitAt(end) != 0xA) {
5648 end = end + 1;
5649 }
5650 ranges.add(<int>[index, end]);
5651 index = end;
5652 }
5653 while (index < length) {
5654 int currentChar = comment.codeUnitAt(index);
5655 if (currentChar == 0xD || currentChar == 0xA) {
5656 index = index + 1;
5657 while (index < length &&
5658 Character.isWhitespace(comment.codeUnitAt(index))) {
5659 index = index + 1;
5660 }
5661 if (StringUtilities.startsWith6(
5662 comment, index, 0x2A, 0x20, 0x20, 0x20, 0x20, 0x20)) {
5663 int end = index + 6;
5664 while (end < length &&
5665 comment.codeUnitAt(end) != 0xD &&
5666 comment.codeUnitAt(end) != 0xA) {
5667 end = end + 1;
5668 }
5669 ranges.add(<int>[index, end]);
5670 index = end;
5671 }
5672 } else if (index + 1 < length &&
5673 currentChar == 0x5B &&
5674 comment.codeUnitAt(index + 1) == 0x3A) {
5675 int end = StringUtilities.indexOf2(comment, index + 2, 0x3A, 0x5D);
5676 if (end < 0) {
5677 end = length;
5678 }
5679 ranges.add(<int>[index, end]);
5680 index = end + 1;
5681 } else {
5682 index = index + 1;
5683 }
5684 }
5685 return ranges;
5686 }
5687
5688 /**
5689 * Return the end token associated with the given [beginToken], or `null` if
5690 * either the given token is not a begin token or it does not have an end
5691 * token associated with it.
5692 */
5693 Token _getEndToken(Token beginToken) {
5694 if (beginToken is BeginToken) {
5695 return beginToken.endToken;
5696 }
5697 return null;
5698 }
5699
5700 bool _injectGenericComment(TokenType type, int prefixLen) {
5701 if (parseGenericMethodComments) {
5702 CommentToken t = _currentToken.precedingComments;
5703 for (; t != null; t = t.next) {
5704 if (t.type == type) {
5705 String comment = t.lexeme.substring(prefixLen, t.lexeme.length - 2);
5706 Token list = _scanGenericMethodComment(comment, t.offset + prefixLen);
5707 if (list != null) {
5708 // Remove the token from the comment stream.
5709 t.remove();
5710 // Insert the tokens into the stream.
5711 _injectTokenList(list);
5712 return true;
5713 }
5714 }
5715 }
5716 }
5717 return false;
5718 }
5719
5720 /**
5721 * Matches a generic comment type substitution and injects it into the token
5722 * stream. Returns true if a match was injected, otherwise false.
5723 *
5724 * These comments are of the form `/*=T*/`, in other words, a [TypeName]
5725 * inside a slash-star comment, preceded by equals sign.
5726 */
5727 bool _injectGenericCommentTypeAssign() {
5728 return _injectGenericComment(TokenType.GENERIC_METHOD_TYPE_ASSIGN, 3);
5729 }
5730
5731 /**
5732 * Matches a generic comment type parameters and injects them into the token
5733 * stream. Returns true if a match was injected, otherwise false.
5734 *
5735 * These comments are of the form `/*<K, V>*/`, in other words, a
5736 * [TypeParameterList] or [TypeArgumentList] inside a slash-star comment.
5737 */
5738 bool _injectGenericCommentTypeList() {
5739 return _injectGenericComment(TokenType.GENERIC_METHOD_TYPE_LIST, 2);
5740 }
5741
5742 /**
5743 * Inject the given [token] into the token stream immediately before the
5744 * current token.
5745 */
5746 Token _injectToken(Token token) {
5747 Token previous = _currentToken.previous;
5748 token.setNext(_currentToken);
5749 previous.setNext(token);
5750 return token;
5751 }
5752
5753 void _injectTokenList(Token firstToken) {
5754 // Scanner creates a cyclic EOF token.
5755 Token lastToken = firstToken;
5756 while (lastToken.next.type != TokenType.EOF) {
5757 lastToken = lastToken.next;
5758 }
5759 // Inject these new tokens into the stream.
5760 Token previous = _currentToken.previous;
5761 lastToken.setNext(_currentToken);
5762 previous.setNext(firstToken);
5763 _currentToken = firstToken;
5764 }
5765
5766 /**
5767 * Return `true` if the current token could be the question mark in a
5768 * condition expression. The current token is assumed to be a question mark.
5769 */
5770 bool _isConditionalOperator() {
5771 void parseOperation(Parser parser) {
5772 parser.parseExpressionWithoutCascade();
5773 }
5774
5775 Token token = _skip(_currentToken.next, parseOperation);
5776 if (token == null || !_tokenMatches(token, TokenType.COLON)) {
5777 return false;
5778 }
5779 token = _skip(token.next, parseOperation);
5780 return token != null;
5781 }
5782
5783 /**
5784 * Return `true` if the given [character] is a valid hexadecimal digit.
5785 */
5786 bool _isHexDigit(int character) =>
5787 (0x30 <= character && character <= 0x39) ||
5788 (0x41 <= character && character <= 0x46) ||
5789 (0x61 <= character && character <= 0x66);
5790
5791 bool _isLikelyArgumentList() {
5792 // Try to reduce the amount of lookahead required here before enabling
5793 // generic methods.
5794 if (_matches(TokenType.OPEN_PAREN)) {
5795 return true;
5796 }
5797 if (!parseGenericMethods) {
5798 return false;
5799 }
5800 Token token = skipTypeArgumentList(_currentToken);
5801 return token != null && _tokenMatches(token, TokenType.OPEN_PAREN);
5802 }
5803
5804 /**
5805 * Given that we have just found bracketed text within the given [comment],
5806 * look to see whether that text is (a) followed by a parenthesized link
5807 * address, (b) followed by a colon, or (c) followed by optional whitespace
5808 * and another square bracket. The [rightIndex] is the index of the right
5809 * bracket. Return `true` if the bracketed text is followed by a link address.
5810 *
5811 * This method uses the syntax described by the
5812 * <a href="http://daringfireball.net/projects/markdown/syntax">markdown</a>
5813 * project.
5814 */
5815 bool _isLinkText(String comment, int rightIndex) {
5816 int length = comment.length;
5817 int index = rightIndex + 1;
5818 if (index >= length) {
5819 return false;
5820 }
5821 int nextChar = comment.codeUnitAt(index);
5822 if (nextChar == 0x28 || nextChar == 0x3A) {
5823 return true;
5824 }
5825 while (Character.isWhitespace(nextChar)) {
5826 index = index + 1;
5827 if (index >= length) {
5828 return false;
5829 }
5830 nextChar = comment.codeUnitAt(index);
5831 }
5832 return nextChar == 0x5B;
5833 }
5834
5835 /**
5836 * Return `true` if the given [startToken] appears to be the beginning of an
5837 * operator declaration.
5838 */
5839 bool _isOperator(Token startToken) {
5840 // Accept any operator here, even if it is not user definable.
5841 if (!startToken.isOperator) {
5842 return false;
5843 }
5844 // Token "=" means that it is actually a field initializer.
5845 if (startToken.type == TokenType.EQ) {
5846 return false;
5847 }
5848 // Consume all operator tokens.
5849 Token token = startToken.next;
5850 while (token.isOperator) {
5851 token = token.next;
5852 }
5853 // Formal parameter list is expect now.
5854 return _tokenMatches(token, TokenType.OPEN_PAREN);
5855 }
5856
5857 bool _isPeekGenericTypeParametersAndOpenParen() {
5858 if (!parseGenericMethods) {
5859 return false;
5860 }
5861 Token token = _skipTypeParameterList(_peek());
5862 return token != null && _tokenMatches(token, TokenType.OPEN_PAREN);
5863 }
5864
5865 /**
5866 * Return `true` if the [startToken] appears to be the first token of a type
5867 * name that is followed by a variable or field formal parameter.
5868 */
5869 bool _isTypedIdentifier(Token startToken) {
5870 Token token = skipReturnType(startToken);
5871 if (token == null) {
5872 return false;
5873 } else if (_tokenMatchesIdentifier(token)) {
5874 return true;
5875 } else if (_tokenMatchesKeyword(token, Keyword.THIS) &&
5876 _tokenMatches(token.next, TokenType.PERIOD) &&
5877 _tokenMatchesIdentifier(token.next.next)) {
5878 return true;
5879 } else if (_tokenMatchesKeyword(startToken, Keyword.VOID)) {
5880 // The keyword 'void' isn't a valid identifier, so it should be assumed to
5881 // be a type name.
5882 return true;
5883 } else if (startToken.next != token &&
5884 !_tokenMatches(token, TokenType.OPEN_PAREN)) {
5885 // The type is more than a simple identifier, so it should be assumed to
5886 // be a type name.
5887 return true;
5888 }
5889 return false;
5890 }
5891
5892 /**
5893 * Increments the error reporting lock level. If level is more than `0`, then
5894 * [reportError] wont report any error.
5895 */
5896 void _lockErrorListener() {
5897 _errorListenerLock++;
5898 }
5899
5900 /**
5901 * Return `true` if the current token has the given [type]. Note that the
5902 * method [_matchesGt] should be used if the argument to this method would be
5903 * [TokenType.GT].
5904 */
5905 bool _matches(TokenType type) => _currentToken.type == type;
5906
5907 /**
5908 * Return `true` if the current token has a type of [TokenType.GT]. Note that
5909 * this method, unlike other variants, will modify the token stream if
5910 * possible to match desired type. In particular, if the next token is either
5911 * a '>>' or '>>>', the token stream will be re-written and `true` will be
5912 * returned.
5913 */
5914 bool _matchesGt() {
5915 TokenType currentType = _currentToken.type;
5916 if (currentType == TokenType.GT) {
5917 return true;
5918 } else if (currentType == TokenType.GT_GT) {
5919 Token first = _createToken(_currentToken, TokenType.GT);
5920 Token second = new Token(TokenType.GT, _currentToken.offset + 1);
5921 second.setNext(_currentToken.next);
5922 first.setNext(second);
5923 _currentToken.previous.setNext(first);
5924 _currentToken = first;
5925 return true;
5926 } else if (currentType == TokenType.GT_EQ) {
5927 Token first = _createToken(_currentToken, TokenType.GT);
5928 Token second = new Token(TokenType.EQ, _currentToken.offset + 1);
5929 second.setNext(_currentToken.next);
5930 first.setNext(second);
5931 _currentToken.previous.setNext(first);
5932 _currentToken = first;
5933 return true;
5934 } else if (currentType == TokenType.GT_GT_EQ) {
5935 int offset = _currentToken.offset;
5936 Token first = _createToken(_currentToken, TokenType.GT);
5937 Token second = new Token(TokenType.GT, offset + 1);
5938 Token third = new Token(TokenType.EQ, offset + 2);
5939 third.setNext(_currentToken.next);
5940 second.setNext(third);
5941 first.setNext(second);
5942 _currentToken.previous.setNext(first);
5943 _currentToken = first;
5944 return true;
5945 }
5946 return false;
5947 }
5948
5949 /**
5950 * Return `true` if the current token is a valid identifier. Valid identifiers
5951 * include built-in identifiers (pseudo-keywords).
5952 */
5953 bool _matchesIdentifier() => _tokenMatchesIdentifier(_currentToken);
5954
5955 /**
5956 * Return `true` if the current token matches the given [keyword].
5957 */
5958 bool _matchesKeyword(Keyword keyword) =>
5959 _tokenMatchesKeyword(_currentToken, keyword);
5960
5961 /**
5962 * Return `true` if the current token matches the given [identifier].
5963 */
5964 bool _matchesString(String identifier) =>
5965 _currentToken.type == TokenType.IDENTIFIER &&
5966 _currentToken.lexeme == identifier;
5967
5968 /**
5969 * If the current token has the given [type], then advance to the next token
5970 * and return `true`. Otherwise, return `false` without advancing. This method
5971 * should not be invoked with an argument value of [TokenType.GT].
5972 */
5973 bool _optional(TokenType type) {
5974 if (_currentToken.type == type) {
5975 _advance();
5976 return true;
5977 }
5978 return false;
5979 }
5980
5981 /**
5982 * Parse an argument list when we need to check for an open paren and recover
5983 * when there isn't one. Return the argument list that was parsed.
5984 */
5985 ArgumentList _parseArgumentListChecked() {
5986 if (_matches(TokenType.OPEN_PAREN)) {
5987 return parseArgumentList();
5988 }
5989 _reportErrorForCurrentToken(
5990 ParserErrorCode.EXPECTED_TOKEN, [TokenType.OPEN_PAREN.lexeme]);
5991 // Recovery: Look to see whether there is a close paren that isn't matched
5992 // to an open paren and if so parse the list of arguments as normal.
5993 return new ArgumentList(_createSyntheticToken(TokenType.OPEN_PAREN), null,
5994 _createSyntheticToken(TokenType.CLOSE_PAREN));
5995 }
5996
5997 /**
5998 * Parse an assert within a constructor's initializer list. Return the assert.
5999 *
6000 * This method assumes that the current token matches `Keyword.ASSERT`.
6001 *
6002 * assertInitializer ::=
6003 * 'assert' '(' expression [',' expression] ')'
6004 */
6005 void _parseAssertInitializer() {
6006 // TODO(brianwilkerson) Capture the syntax in the AST using a new class,
6007 // such as AssertInitializer
6008 Token keyword = getAndAdvance();
6009 Token leftParen = _expect(TokenType.OPEN_PAREN);
6010 Expression expression = parseExpression2();
6011 Token comma;
6012 Expression message;
6013 if (_matches(TokenType.COMMA)) {
6014 comma = getAndAdvance();
6015 message = parseExpression2();
6016 }
6017 Token rightParen = _expect(TokenType.CLOSE_PAREN);
6018 // return new AssertInitializer(
6019 // keyword, leftParen, expression, comma, message, rightParen);
6020 }
6021
6022 /**
6023 * Parse an assignable expression given that the current token is not 'super'.
6024 * The [primaryAllowed] is `true` if the expression is allowed to be a primary
6025 * without any assignable selector. Return the assignable expression that was
6026 * parsed.
6027 */
6028 Expression _parseAssignableExpressionNotStartingWithSuper(
6029 bool primaryAllowed) {
6030 //
6031 // A primary expression can start with an identifier. We resolve the
6032 // ambiguity by determining whether the primary consists of anything other
6033 // than an identifier and/or is followed by an assignableSelector.
6034 //
6035 Expression expression = parsePrimaryExpression();
6036 bool isOptional = primaryAllowed || expression is SimpleIdentifier;
6037 while (true) {
6038 while (_isLikelyArgumentList()) {
6039 TypeArgumentList typeArguments = _parseOptionalTypeArguments();
6040 ArgumentList argumentList = parseArgumentList();
6041 Expression currentExpression = expression;
6042 if (currentExpression is SimpleIdentifier) {
6043 expression = new MethodInvocation(
6044 null, null, currentExpression, typeArguments, argumentList);
6045 } else if (currentExpression is PrefixedIdentifier) {
6046 expression = new MethodInvocation(
6047 currentExpression.prefix,
6048 currentExpression.period,
6049 currentExpression.identifier,
6050 typeArguments,
6051 argumentList);
6052 } else if (currentExpression is PropertyAccess) {
6053 expression = new MethodInvocation(
6054 currentExpression.target,
6055 currentExpression.operator,
6056 currentExpression.propertyName,
6057 typeArguments,
6058 argumentList);
6059 } else {
6060 expression = new FunctionExpressionInvocation(
6061 expression, typeArguments, argumentList);
6062 }
6063 if (!primaryAllowed) {
6064 isOptional = false;
6065 }
6066 }
6067 Expression selectorExpression = parseAssignableSelector(
6068 expression, isOptional || (expression is PrefixedIdentifier));
6069 if (identical(selectorExpression, expression)) {
6070 if (!isOptional && (expression is PrefixedIdentifier)) {
6071 PrefixedIdentifier identifier = expression as PrefixedIdentifier;
6072 expression = new PropertyAccess(
6073 identifier.prefix, identifier.period, identifier.identifier);
6074 }
6075 return expression;
6076 }
6077 expression = selectorExpression;
6078 isOptional = true;
6079 }
6080 }
6081
6082 /**
6083 * Parse a block when we need to check for an open curly brace and recover
6084 * when there isn't one. Return the block that was parsed.
6085 *
6086 * block ::=
6087 * '{' statements '}'
6088 */
6089 Block _parseBlockChecked() {
6090 if (_matches(TokenType.OPEN_CURLY_BRACKET)) {
6091 return parseBlock();
6092 }
6093 // TODO(brianwilkerson) Improve the error message.
6094 _reportErrorForCurrentToken(
6095 ParserErrorCode.EXPECTED_TOKEN, [TokenType.OPEN_CURLY_BRACKET.lexeme]);
6096 // Recovery: Check for an unmatched closing curly bracket and parse
6097 // statements until it is reached.
6098 return new Block(_createSyntheticToken(TokenType.OPEN_CURLY_BRACKET), null,
6099 _createSyntheticToken(TokenType.CLOSE_CURLY_BRACKET));
6100 }
6101
6102 /**
6103 * Parse a list of class members. The [className] is the name of the class
6104 * whose members are being parsed. The [closingBracket] is the closing bracket
6105 * for the class, or `null` if the closing bracket is missing. Return the list
6106 * of class members that were parsed.
6107 *
6108 * classMembers ::=
6109 * (metadata memberDefinition)*
6110 */
6111 List<ClassMember> _parseClassMembers(String className, Token closingBracket) {
6112 List<ClassMember> members = <ClassMember>[];
6113 Token memberStart = _currentToken;
6114 TokenType type = _currentToken.type;
6115 Keyword keyword = _currentToken.keyword;
6116 while (type != TokenType.EOF &&
6117 type != TokenType.CLOSE_CURLY_BRACKET &&
6118 (closingBracket != null ||
6119 (keyword != Keyword.CLASS && keyword != Keyword.TYPEDEF))) {
6120 if (type == TokenType.SEMICOLON) {
6121 _reportErrorForToken(ParserErrorCode.UNEXPECTED_TOKEN, _currentToken,
6122 [_currentToken.lexeme]);
6123 _advance();
6124 } else {
6125 ClassMember member = parseClassMember(className);
6126 if (member != null) {
6127 members.add(member);
6128 }
6129 }
6130 if (identical(_currentToken, memberStart)) {
6131 _reportErrorForToken(ParserErrorCode.UNEXPECTED_TOKEN, _currentToken,
6132 [_currentToken.lexeme]);
6133 _advance();
6134 }
6135 memberStart = _currentToken;
6136 type = _currentToken.type;
6137 keyword = _currentToken.keyword;
6138 }
6139 return members;
6140 }
6141
6142 /**
6143 * Parse a class type alias. The [commentAndMetadata] is the metadata to be
6144 * associated with the member. The [abstractKeyword] is the token representing
6145 * the 'abstract' keyword. The [classKeyword] is the token representing the
6146 * 'class' keyword. The [className] is the name of the alias, and the
6147 * [typeParameters] are the type parameters following the name. Return the
6148 * class type alias that was parsed.
6149 *
6150 * classTypeAlias ::=
6151 * identifier typeParameters? '=' 'abstract'? mixinApplication
6152 *
6153 * mixinApplication ::=
6154 * type withClause implementsClause? ';'
6155 */
6156 ClassTypeAlias _parseClassTypeAliasAfterName(
6157 CommentAndMetadata commentAndMetadata,
6158 Token abstractKeyword,
6159 Token classKeyword,
6160 SimpleIdentifier className,
6161 TypeParameterList typeParameters) {
6162 Token equals = _expect(TokenType.EQ);
6163 TypeName superclass = parseTypeName(false);
6164 WithClause withClause = null;
6165 if (_matchesKeyword(Keyword.WITH)) {
6166 withClause = parseWithClause();
6167 } else {
6168 _reportErrorForCurrentToken(
6169 ParserErrorCode.EXPECTED_TOKEN, [Keyword.WITH.syntax]);
6170 }
6171 ImplementsClause implementsClause = null;
6172 if (_matchesKeyword(Keyword.IMPLEMENTS)) {
6173 implementsClause = parseImplementsClause();
6174 }
6175 Token semicolon;
6176 if (_matches(TokenType.SEMICOLON)) {
6177 semicolon = getAndAdvance();
6178 } else {
6179 if (_matches(TokenType.OPEN_CURLY_BRACKET)) {
6180 _reportErrorForCurrentToken(
6181 ParserErrorCode.EXPECTED_TOKEN, [TokenType.SEMICOLON.lexeme]);
6182 Token leftBracket = getAndAdvance();
6183 _parseClassMembers(className.name, _getEndToken(leftBracket));
6184 _expect(TokenType.CLOSE_CURLY_BRACKET);
6185 } else {
6186 _reportErrorForToken(ParserErrorCode.EXPECTED_TOKEN,
6187 _currentToken.previous, [TokenType.SEMICOLON.lexeme]);
6188 }
6189 semicolon = _createSyntheticToken(TokenType.SEMICOLON);
6190 }
6191 return new ClassTypeAlias(
6192 commentAndMetadata.comment,
6193 commentAndMetadata.metadata,
6194 classKeyword,
6195 className,
6196 typeParameters,
6197 equals,
6198 abstractKeyword,
6199 superclass,
6200 withClause,
6201 implementsClause,
6202 semicolon);
6203 }
6204
6205 /**
6206 * Parse a list of configurations. Return the configurations that were parsed,
6207 * or `null` if there are no configurations.
6208 */
6209 List<Configuration> _parseConfigurations() {
6210 List<Configuration> configurations = null;
6211 while (_matchesKeyword(Keyword.IF)) {
6212 configurations ??= <Configuration>[];
6213 configurations.add(parseConfiguration());
6214 }
6215 return configurations;
6216 }
6217
6218 ConstructorDeclaration _parseConstructor(
6219 CommentAndMetadata commentAndMetadata,
6220 Token externalKeyword,
6221 Token constKeyword,
6222 Token factoryKeyword,
6223 SimpleIdentifier returnType,
6224 Token period,
6225 SimpleIdentifier name,
6226 FormalParameterList parameters) {
6227 bool bodyAllowed = externalKeyword == null;
6228 Token separator = null;
6229 List<ConstructorInitializer> initializers = null;
6230 if (_matches(TokenType.COLON)) {
6231 separator = getAndAdvance();
6232 initializers = <ConstructorInitializer>[];
6233 do {
6234 Keyword keyword = _currentToken.keyword;
6235 if (keyword == Keyword.THIS) {
6236 TokenType nextType = _peek().type;
6237 if (nextType == TokenType.OPEN_PAREN) {
6238 bodyAllowed = false;
6239 initializers.add(parseRedirectingConstructorInvocation(false));
6240 } else if (nextType == TokenType.PERIOD &&
6241 _tokenMatches(_peekAt(3), TokenType.OPEN_PAREN)) {
6242 bodyAllowed = false;
6243 initializers.add(parseRedirectingConstructorInvocation(true));
6244 } else {
6245 initializers.add(parseConstructorFieldInitializer(true));
6246 }
6247 } else if (keyword == Keyword.SUPER) {
6248 initializers.add(parseSuperConstructorInvocation());
6249 } else if (_matches(TokenType.OPEN_CURLY_BRACKET) ||
6250 _matches(TokenType.FUNCTION)) {
6251 _reportErrorForCurrentToken(ParserErrorCode.MISSING_INITIALIZER);
6252 } else if (_enableAssertInitializer &&
6253 _matchesKeyword(Keyword.ASSERT)) {
6254 _parseAssertInitializer();
6255 } else {
6256 initializers.add(parseConstructorFieldInitializer(false));
6257 }
6258 } while (_optional(TokenType.COMMA));
6259 if (factoryKeyword != null) {
6260 _reportErrorForToken(
6261 ParserErrorCode.FACTORY_WITH_INITIALIZERS, factoryKeyword);
6262 }
6263 }
6264 ConstructorName redirectedConstructor = null;
6265 FunctionBody body;
6266 if (_matches(TokenType.EQ)) {
6267 separator = getAndAdvance();
6268 redirectedConstructor = parseConstructorName();
6269 body = new EmptyFunctionBody(_expect(TokenType.SEMICOLON));
6270 if (factoryKeyword == null) {
6271 _reportErrorForNode(
6272 ParserErrorCode.REDIRECTION_IN_NON_FACTORY_CONSTRUCTOR,
6273 redirectedConstructor);
6274 }
6275 } else {
6276 body =
6277 parseFunctionBody(true, ParserErrorCode.MISSING_FUNCTION_BODY, false);
6278 if (constKeyword != null &&
6279 factoryKeyword != null &&
6280 externalKeyword == null) {
6281 _reportErrorForToken(ParserErrorCode.CONST_FACTORY, factoryKeyword);
6282 } else if (body is EmptyFunctionBody) {
6283 if (factoryKeyword != null &&
6284 externalKeyword == null &&
6285 _parseFunctionBodies) {
6286 _reportErrorForToken(
6287 ParserErrorCode.FACTORY_WITHOUT_BODY, factoryKeyword);
6288 }
6289 } else {
6290 if (constKeyword != null) {
6291 _reportErrorForNode(
6292 ParserErrorCode.CONST_CONSTRUCTOR_WITH_BODY, body);
6293 } else if (externalKeyword != null) {
6294 _reportErrorForNode(
6295 ParserErrorCode.EXTERNAL_CONSTRUCTOR_WITH_BODY, body);
6296 } else if (!bodyAllowed) {
6297 _reportErrorForNode(
6298 ParserErrorCode.REDIRECTING_CONSTRUCTOR_WITH_BODY, body);
6299 }
6300 }
6301 }
6302 return new ConstructorDeclaration(
6303 commentAndMetadata.comment,
6304 commentAndMetadata.metadata,
6305 externalKeyword,
6306 constKeyword,
6307 factoryKeyword,
6308 returnType,
6309 period,
6310 name,
6311 parameters,
6312 separator,
6313 initializers,
6314 redirectedConstructor,
6315 body);
6316 }
6317
6318 /**
6319 * Parse an enum constant declaration. Return the enum constant declaration
6320 * that was parsed.
6321 *
6322 * Specified:
6323 *
6324 * enumConstant ::=
6325 * id
6326 *
6327 * Actual:
6328 *
6329 * enumConstant ::=
6330 * metadata id
6331 */
6332 EnumConstantDeclaration _parseEnumConstantDeclaration() {
6333 CommentAndMetadata commentAndMetadata = parseCommentAndMetadata();
6334 SimpleIdentifier name;
6335 if (_matchesIdentifier()) {
6336 name = _parseSimpleIdentifierUnchecked(isDeclaration: true);
6337 } else {
6338 name = createSyntheticIdentifier();
6339 }
6340 if (commentAndMetadata.hasMetadata) {
6341 _reportErrorForNode(ParserErrorCode.ANNOTATION_ON_ENUM_CONSTANT,
6342 commentAndMetadata.metadata[0]);
6343 }
6344 return new EnumConstantDeclaration(
6345 commentAndMetadata.comment, commentAndMetadata.metadata, name);
6346 }
6347
6348 /**
6349 * Parse a list of formal parameters given that the list starts with the given
6350 * [leftParenthesis]. Return the formal parameters that were parsed.
6351 */
6352 FormalParameterList _parseFormalParameterListAfterParen(
6353 Token leftParenthesis) {
6354 if (_matches(TokenType.CLOSE_PAREN)) {
6355 return new FormalParameterList(
6356 leftParenthesis, null, null, null, getAndAdvance());
6357 }
6358 //
6359 // Even though it is invalid to have default parameters outside of brackets,
6360 // required parameters inside of brackets, or multiple groups of default and
6361 // named parameters, we allow all of these cases so that we can recover
6362 // better.
6363 //
6364 List<FormalParameter> parameters = <FormalParameter>[];
6365 Token leftSquareBracket = null;
6366 Token rightSquareBracket = null;
6367 Token leftCurlyBracket = null;
6368 Token rightCurlyBracket = null;
6369 ParameterKind kind = ParameterKind.REQUIRED;
6370 bool firstParameter = true;
6371 bool reportedMultiplePositionalGroups = false;
6372 bool reportedMultipleNamedGroups = false;
6373 bool reportedMixedGroups = false;
6374 bool wasOptionalParameter = false;
6375 Token initialToken = null;
6376 do {
6377 if (firstParameter) {
6378 firstParameter = false;
6379 } else if (!_optional(TokenType.COMMA)) {
6380 // TODO(brianwilkerson) The token is wrong, we need to recover from this
6381 // case.
6382 if (_getEndToken(leftParenthesis) != null) {
6383 _reportErrorForCurrentToken(
6384 ParserErrorCode.EXPECTED_TOKEN, [TokenType.COMMA.lexeme]);
6385 } else {
6386 _reportErrorForToken(ParserErrorCode.MISSING_CLOSING_PARENTHESIS,
6387 _currentToken.previous);
6388 break;
6389 }
6390 }
6391 initialToken = _currentToken;
6392 //
6393 // Handle the beginning of parameter groups.
6394 //
6395 TokenType type = _currentToken.type;
6396 if (type == TokenType.OPEN_SQUARE_BRACKET) {
6397 wasOptionalParameter = true;
6398 if (leftSquareBracket != null && !reportedMultiplePositionalGroups) {
6399 _reportErrorForCurrentToken(
6400 ParserErrorCode.MULTIPLE_POSITIONAL_PARAMETER_GROUPS);
6401 reportedMultiplePositionalGroups = true;
6402 }
6403 if (leftCurlyBracket != null && !reportedMixedGroups) {
6404 _reportErrorForCurrentToken(ParserErrorCode.MIXED_PARAMETER_GROUPS);
6405 reportedMixedGroups = true;
6406 }
6407 leftSquareBracket = getAndAdvance();
6408 kind = ParameterKind.POSITIONAL;
6409 } else if (type == TokenType.OPEN_CURLY_BRACKET) {
6410 wasOptionalParameter = true;
6411 if (leftCurlyBracket != null && !reportedMultipleNamedGroups) {
6412 _reportErrorForCurrentToken(
6413 ParserErrorCode.MULTIPLE_NAMED_PARAMETER_GROUPS);
6414 reportedMultipleNamedGroups = true;
6415 }
6416 if (leftSquareBracket != null && !reportedMixedGroups) {
6417 _reportErrorForCurrentToken(ParserErrorCode.MIXED_PARAMETER_GROUPS);
6418 reportedMixedGroups = true;
6419 }
6420 leftCurlyBracket = getAndAdvance();
6421 kind = ParameterKind.NAMED;
6422 }
6423 //
6424 // Parse and record the parameter.
6425 //
6426 FormalParameter parameter = parseFormalParameter(kind);
6427 parameters.add(parameter);
6428 if (kind == ParameterKind.REQUIRED && wasOptionalParameter) {
6429 _reportErrorForNode(
6430 ParserErrorCode.NORMAL_BEFORE_OPTIONAL_PARAMETERS, parameter);
6431 }
6432 //
6433 // Handle the end of parameter groups.
6434 //
6435 // TODO(brianwilkerson) Improve the detection and reporting of missing and
6436 // mismatched delimiters.
6437 type = _currentToken.type;
6438
6439 // Advance past trailing commas as appropriate.
6440 if (type == TokenType.COMMA) {
6441 // Only parse commas trailing normal (non-positional/named) params.
6442 if (rightSquareBracket == null && rightCurlyBracket == null) {
6443 Token next = _peek();
6444 if (next.type == TokenType.CLOSE_PAREN ||
6445 next.type == TokenType.CLOSE_CURLY_BRACKET ||
6446 next.type == TokenType.CLOSE_SQUARE_BRACKET) {
6447 _advance();
6448 type = _currentToken.type;
6449 }
6450 }
6451 }
6452
6453 if (type == TokenType.CLOSE_SQUARE_BRACKET) {
6454 rightSquareBracket = getAndAdvance();
6455 if (leftSquareBracket == null) {
6456 if (leftCurlyBracket != null) {
6457 _reportErrorForCurrentToken(
6458 ParserErrorCode.WRONG_TERMINATOR_FOR_PARAMETER_GROUP, ["}"]);
6459 rightCurlyBracket = rightSquareBracket;
6460 rightSquareBracket = null;
6461 } else {
6462 _reportErrorForCurrentToken(
6463 ParserErrorCode.UNEXPECTED_TERMINATOR_FOR_PARAMETER_GROUP,
6464 ["["]);
6465 }
6466 }
6467 kind = ParameterKind.REQUIRED;
6468 } else if (type == TokenType.CLOSE_CURLY_BRACKET) {
6469 rightCurlyBracket = getAndAdvance();
6470 if (leftCurlyBracket == null) {
6471 if (leftSquareBracket != null) {
6472 _reportErrorForCurrentToken(
6473 ParserErrorCode.WRONG_TERMINATOR_FOR_PARAMETER_GROUP, ["]"]);
6474 rightSquareBracket = rightCurlyBracket;
6475 rightCurlyBracket = null;
6476 } else {
6477 _reportErrorForCurrentToken(
6478 ParserErrorCode.UNEXPECTED_TERMINATOR_FOR_PARAMETER_GROUP,
6479 ["{"]);
6480 }
6481 }
6482 kind = ParameterKind.REQUIRED;
6483 }
6484 } while (!_matches(TokenType.CLOSE_PAREN) &&
6485 !identical(initialToken, _currentToken));
6486 Token rightParenthesis = _expect(TokenType.CLOSE_PAREN);
6487 //
6488 // Check that the groups were closed correctly.
6489 //
6490 if (leftSquareBracket != null && rightSquareBracket == null) {
6491 _reportErrorForCurrentToken(
6492 ParserErrorCode.MISSING_TERMINATOR_FOR_PARAMETER_GROUP, ["]"]);
6493 }
6494 if (leftCurlyBracket != null && rightCurlyBracket == null) {
6495 _reportErrorForCurrentToken(
6496 ParserErrorCode.MISSING_TERMINATOR_FOR_PARAMETER_GROUP, ["}"]);
6497 }
6498 //
6499 // Build the parameter list.
6500 //
6501 leftSquareBracket ??= leftCurlyBracket;
6502 rightSquareBracket ??= rightCurlyBracket;
6503 return new FormalParameterList(leftParenthesis, parameters,
6504 leftSquareBracket, rightSquareBracket, rightParenthesis);
6505 }
6506
6507 /**
6508 * Parse a list of formal parameters. Return the formal parameters that were
6509 * parsed.
6510 *
6511 * This method assumes that the current token matches `TokenType.OPEN_PAREN`.
6512 */
6513 FormalParameterList _parseFormalParameterListUnchecked() {
6514 return _parseFormalParameterListAfterParen(getAndAdvance());
6515 }
6516
6517 /**
6518 * Parse a function declaration statement. The [commentAndMetadata] is the
6519 * documentation comment and metadata to be associated with the declaration.
6520 * The [returnType] is the return type, or `null` if there is no return type.
6521 * Return the function declaration statement that was parsed.
6522 *
6523 * functionDeclarationStatement ::=
6524 * functionSignature functionBody
6525 */
6526 Statement _parseFunctionDeclarationStatementAfterReturnType(
6527 CommentAndMetadata commentAndMetadata, TypeName returnType) {
6528 FunctionDeclaration declaration =
6529 parseFunctionDeclaration(commentAndMetadata, null, returnType);
6530 Token propertyKeyword = declaration.propertyKeyword;
6531 if (propertyKeyword != null) {
6532 if (propertyKeyword.keyword == Keyword.GET) {
6533 _reportErrorForToken(
6534 ParserErrorCode.GETTER_IN_FUNCTION, propertyKeyword);
6535 } else {
6536 _reportErrorForToken(
6537 ParserErrorCode.SETTER_IN_FUNCTION, propertyKeyword);
6538 }
6539 }
6540 return new FunctionDeclarationStatement(declaration);
6541 }
6542
6543 /**
6544 * Parse a function type alias. The [commentAndMetadata] is the metadata to be
6545 * associated with the member. The [keyword] is the token representing the
6546 * 'typedef' keyword. Return the function type alias that was parsed.
6547 *
6548 * functionTypeAlias ::=
6549 * functionPrefix typeParameterList? formalParameterList ';'
6550 *
6551 * functionPrefix ::=
6552 * returnType? name
6553 */
6554 FunctionTypeAlias _parseFunctionTypeAlias(
6555 CommentAndMetadata commentAndMetadata, Token keyword) {
6556 TypeName returnType = null;
6557 if (hasReturnTypeInTypeAlias) {
6558 returnType = parseReturnType();
6559 }
6560 SimpleIdentifier name = parseSimpleIdentifier(isDeclaration: true);
6561 TypeParameterList typeParameters = null;
6562 if (_matches(TokenType.LT)) {
6563 typeParameters = parseTypeParameterList();
6564 }
6565 TokenType type = _currentToken.type;
6566 if (type == TokenType.SEMICOLON || type == TokenType.EOF) {
6567 _reportErrorForCurrentToken(ParserErrorCode.MISSING_TYPEDEF_PARAMETERS);
6568 FormalParameterList parameters = new FormalParameterList(
6569 _createSyntheticToken(TokenType.OPEN_PAREN),
6570 null,
6571 null,
6572 null,
6573 _createSyntheticToken(TokenType.CLOSE_PAREN));
6574 Token semicolon = _expect(TokenType.SEMICOLON);
6575 return new FunctionTypeAlias(
6576 commentAndMetadata.comment,
6577 commentAndMetadata.metadata,
6578 keyword,
6579 returnType,
6580 name,
6581 typeParameters,
6582 parameters,
6583 semicolon);
6584 } else if (type == TokenType.OPEN_PAREN) {
6585 FormalParameterList parameters = _parseFormalParameterListUnchecked();
6586 _validateFormalParameterList(parameters);
6587 Token semicolon = _expect(TokenType.SEMICOLON);
6588 return new FunctionTypeAlias(
6589 commentAndMetadata.comment,
6590 commentAndMetadata.metadata,
6591 keyword,
6592 returnType,
6593 name,
6594 typeParameters,
6595 parameters,
6596 semicolon);
6597 } else {
6598 _reportErrorForCurrentToken(ParserErrorCode.MISSING_TYPEDEF_PARAMETERS);
6599 // Recovery: At the very least we should skip to the start of the next
6600 // valid compilation unit member, allowing for the possibility of finding
6601 // the typedef parameters before that point.
6602 return new FunctionTypeAlias(
6603 commentAndMetadata.comment,
6604 commentAndMetadata.metadata,
6605 keyword,
6606 returnType,
6607 name,
6608 typeParameters,
6609 new FormalParameterList(_createSyntheticToken(TokenType.OPEN_PAREN),
6610 null, null, null, _createSyntheticToken(TokenType.CLOSE_PAREN)),
6611 _createSyntheticToken(TokenType.SEMICOLON));
6612 }
6613 }
6614
6615 /**
6616 * Parses generic type parameters from a comment.
6617 *
6618 * Normally this is handled by [_parseGenericMethodTypeParameters], but if the
6619 * code already handles the normal generic type parameters, the comment
6620 * matcher can be called directly. For example, we may have already tried
6621 * matching `<` (less than sign) in a method declaration, and be currently
6622 * on the `(` (open paren) because we didn't find it. In that case, this
6623 * function will parse the preceding comment such as `/*<T, R>*/`.
6624 */
6625 TypeParameterList _parseGenericCommentTypeParameters() {
6626 if (_injectGenericCommentTypeList()) {
6627 return parseTypeParameterList();
6628 }
6629 return null;
6630 }
6631
6632 /**
6633 * Parse the generic method or function's type parameters.
6634 *
6635 * For backwards compatibility this can optionally use comments.
6636 * See [parseGenericMethodComments].
6637 */
6638 TypeParameterList _parseGenericMethodTypeParameters() {
6639 if (parseGenericMethods && _matches(TokenType.LT) ||
6640 _injectGenericCommentTypeList()) {
6641 return parseTypeParameterList();
6642 }
6643 return null;
6644 }
6645
6646 /**
6647 * Parse a library name. The [missingNameError] is the error code to be used
6648 * if the library name is missing. The [missingNameToken] is the token
6649 * associated with the error produced if the library name is missing. Return
6650 * the library name that was parsed.
6651 *
6652 * libraryName ::=
6653 * libraryIdentifier
6654 */
6655 LibraryIdentifier _parseLibraryName(
6656 ParserErrorCode missingNameError, Token missingNameToken) {
6657 if (_matchesIdentifier()) {
6658 return parseLibraryIdentifier();
6659 } else if (_matches(TokenType.STRING)) {
6660 // Recovery: This should be extended to handle arbitrary tokens until we
6661 // can find a token that can start a compilation unit member.
6662 StringLiteral string = parseStringLiteral();
6663 _reportErrorForNode(ParserErrorCode.NON_IDENTIFIER_LIBRARY_NAME, string);
6664 } else {
6665 _reportErrorForToken(missingNameError, missingNameToken);
6666 }
6667 return new LibraryIdentifier(
6668 <SimpleIdentifier>[createSyntheticIdentifier()]);
6669 }
6670
6671 /**
6672 * Parse a method declaration. The [commentAndMetadata] is the documentation
6673 * comment and metadata to be associated with the declaration. The
6674 * [externalKeyword] is the 'external' token. The [staticKeyword] is the
6675 * static keyword, or `null` if the getter is not static. The [returnType] is
6676 * the return type of the method. The [name] is the name of the method. The
6677 * [parameters] is the parameters to the method. Return the method declaration
6678 * that was parsed.
6679 *
6680 * functionDeclaration ::=
6681 * ('external' 'static'?)? functionSignature functionBody
6682 * | 'external'? functionSignature ';'
6683 */
6684 MethodDeclaration _parseMethodDeclarationAfterParameters(
6685 CommentAndMetadata commentAndMetadata,
6686 Token externalKeyword,
6687 Token staticKeyword,
6688 TypeName returnType,
6689 SimpleIdentifier name,
6690 TypeParameterList typeParameters,
6691 FormalParameterList parameters) {
6692 FunctionBody body = parseFunctionBody(
6693 externalKeyword != null || staticKeyword == null,
6694 ParserErrorCode.MISSING_FUNCTION_BODY,
6695 false);
6696 if (externalKeyword != null) {
6697 if (body is! EmptyFunctionBody) {
6698 _reportErrorForNode(ParserErrorCode.EXTERNAL_METHOD_WITH_BODY, body);
6699 }
6700 } else if (staticKeyword != null) {
6701 if (body is EmptyFunctionBody && _parseFunctionBodies) {
6702 _reportErrorForNode(ParserErrorCode.ABSTRACT_STATIC_METHOD, body);
6703 }
6704 }
6705 return new MethodDeclaration(
6706 commentAndMetadata.comment,
6707 commentAndMetadata.metadata,
6708 externalKeyword,
6709 staticKeyword,
6710 returnType,
6711 null,
6712 null,
6713 name,
6714 typeParameters,
6715 parameters,
6716 body);
6717 }
6718
6719 /**
6720 * Parse a method declaration. The [commentAndMetadata] is the documentation
6721 * comment and metadata to be associated with the declaration. The
6722 * [externalKeyword] is the 'external' token. The [staticKeyword] is the
6723 * static keyword, or `null` if the getter is not static. The [returnType] is
6724 * the return type of the method. Return the method declaration that was
6725 * parsed.
6726 *
6727 * functionDeclaration ::=
6728 * 'external'? 'static'? functionSignature functionBody
6729 * | 'external'? functionSignature ';'
6730 */
6731 MethodDeclaration _parseMethodDeclarationAfterReturnType(
6732 CommentAndMetadata commentAndMetadata,
6733 Token externalKeyword,
6734 Token staticKeyword,
6735 TypeName returnType) {
6736 SimpleIdentifier methodName = parseSimpleIdentifier(isDeclaration: true);
6737 TypeParameterList typeParameters = _parseGenericMethodTypeParameters();
6738 FormalParameterList parameters;
6739 TokenType type = _currentToken.type;
6740 // TODO(brianwilkerson) Figure out why we care what the current token is if
6741 // it isn't a paren.
6742 if (type != TokenType.OPEN_PAREN &&
6743 (type == TokenType.OPEN_CURLY_BRACKET || type == TokenType.FUNCTION)) {
6744 _reportErrorForToken(
6745 ParserErrorCode.MISSING_METHOD_PARAMETERS, _currentToken.previous);
6746 parameters = new FormalParameterList(
6747 _createSyntheticToken(TokenType.OPEN_PAREN),
6748 null,
6749 null,
6750 null,
6751 _createSyntheticToken(TokenType.CLOSE_PAREN));
6752 } else {
6753 parameters = parseFormalParameterList();
6754 }
6755 _validateFormalParameterList(parameters);
6756 return _parseMethodDeclarationAfterParameters(
6757 commentAndMetadata,
6758 externalKeyword,
6759 staticKeyword,
6760 returnType,
6761 methodName,
6762 typeParameters,
6763 parameters);
6764 }
6765
6766 /**
6767 * Parse a class native clause. Return the native clause that was parsed.
6768 *
6769 * This method assumes that the current token matches `_NATIVE`.
6770 *
6771 * classNativeClause ::=
6772 * 'native' name
6773 */
6774 NativeClause _parseNativeClause() {
6775 Token keyword = getAndAdvance();
6776 StringLiteral name = parseStringLiteral();
6777 return new NativeClause(keyword, name);
6778 }
6779
6780 /**
7039 * Parse an operator declaration starting after the 'operator' keyword. The 6781 * Parse an operator declaration starting after the 'operator' keyword. The
7040 * [commentAndMetadata] is the documentation comment and metadata to be 6782 * [commentAndMetadata] is the documentation comment and metadata to be
7041 * associated with the declaration. The [externalKeyword] is the 'external' 6783 * associated with the declaration. The [externalKeyword] is the 'external'
7042 * token. The [returnType] is the return type that has already been parsed, or 6784 * token. The [returnType] is the return type that has already been parsed, or
7043 * `null` if there was no return type. The [operatorKeyword] is the 'operator' 6785 * `null` if there was no return type. The [operatorKeyword] is the 'operator'
7044 * keyword. Return the operator declaration that was parsed. 6786 * keyword. Return the operator declaration that was parsed.
7045 * 6787 *
7046 * operatorDeclaration ::= 6788 * operatorDeclaration ::=
7047 * operatorSignature (';' | functionBody) 6789 * operatorSignature (';' | functionBody)
7048 * 6790 *
(...skipping 131 matching lines...) Expand 10 before | Expand all | Expand 10 after
7180 return new PartOfDirective( 6922 return new PartOfDirective(
7181 commentAndMetadata.comment, 6923 commentAndMetadata.comment,
7182 commentAndMetadata.metadata, 6924 commentAndMetadata.metadata,
7183 partKeyword, 6925 partKeyword,
7184 ofKeyword, 6926 ofKeyword,
7185 libraryName, 6927 libraryName,
7186 semicolon); 6928 semicolon);
7187 } 6929 }
7188 6930
7189 /** 6931 /**
7190 * Parse a part or part-of directive. The [commentAndMetadata] is the metadata
7191 * to be associated with the directive. Return the part or part-of directive
7192 * that was parsed.
7193 *
7194 * This method assumes that the current token matches `Keyword.PART`.
7195 *
7196 * partDirective ::=
7197 * metadata 'part' stringLiteral ';'
7198 *
7199 * partOfDirective ::=
7200 * metadata 'part' 'of' identifier ';'
7201 */
7202 Directive _parsePartOrPartOfDirective(CommentAndMetadata commentAndMetadata) {
7203 if (_tokenMatchesString(_peek(), _OF)) {
7204 return _parsePartOfDirective(commentAndMetadata);
7205 }
7206 return _parsePartDirective(commentAndMetadata);
7207 }
7208
7209 /**
7210 * Parse a postfix expression. Return the postfix expression that was parsed.
7211 *
7212 * postfixExpression ::=
7213 * assignableExpression postfixOperator
7214 * | primary selector*
7215 *
7216 * selector ::=
7217 * assignableSelector
7218 * | argumentList
7219 */
7220 Expression _parsePostfixExpression() {
7221 Expression operand = parseAssignableExpression(true);
7222 TokenType type = _currentToken.type;
7223 if (type == TokenType.OPEN_SQUARE_BRACKET ||
7224 type == TokenType.PERIOD ||
7225 type == TokenType.QUESTION_PERIOD ||
7226 type == TokenType.OPEN_PAREN ||
7227 (parseGenericMethods && type == TokenType.LT)) {
7228 do {
7229 if (_isLikelyArgumentList()) {
7230 TypeArgumentList typeArguments = _parseOptionalTypeArguments();
7231 ArgumentList argumentList = parseArgumentList();
7232 Expression currentOperand = operand;
7233 if (currentOperand is PropertyAccess) {
7234 operand = new MethodInvocation(
7235 currentOperand.target,
7236 currentOperand.operator,
7237 currentOperand.propertyName,
7238 typeArguments,
7239 argumentList);
7240 } else {
7241 operand = new FunctionExpressionInvocation(
7242 operand, typeArguments, argumentList);
7243 }
7244 } else {
7245 operand = _parseAssignableSelector(operand, true);
7246 }
7247 type = _currentToken.type;
7248 } while (type == TokenType.OPEN_SQUARE_BRACKET ||
7249 type == TokenType.PERIOD ||
7250 type == TokenType.QUESTION_PERIOD ||
7251 type == TokenType.OPEN_PAREN);
7252 return operand;
7253 }
7254 if (!_currentToken.type.isIncrementOperator) {
7255 return operand;
7256 }
7257 _ensureAssignable(operand);
7258 Token operator = getAndAdvance();
7259 return new PostfixExpression(operand, operator);
7260 }
7261
7262 /**
7263 * Parse a prefixed identifier given that the given [qualifier] was already 6932 * Parse a prefixed identifier given that the given [qualifier] was already
7264 * parsed. Return the prefixed identifier that was parsed. 6933 * parsed. Return the prefixed identifier that was parsed.
7265 * 6934 *
7266 * prefixedIdentifier ::= 6935 * prefixedIdentifier ::=
7267 * identifier ('.' identifier)? 6936 * identifier ('.' identifier)?
7268 */ 6937 */
7269 Identifier _parsePrefixedIdentifierAfterIdentifier( 6938 Identifier _parsePrefixedIdentifierAfterIdentifier(
7270 SimpleIdentifier qualifier) { 6939 SimpleIdentifier qualifier) {
7271 if (!_matches(TokenType.PERIOD) || _injectGenericCommentTypeList()) { 6940 if (!_matches(TokenType.PERIOD) || _injectGenericCommentTypeList()) {
7272 return qualifier; 6941 return qualifier;
(...skipping 11 matching lines...) Expand all
7284 * 6953 *
7285 * prefixedIdentifier ::= 6954 * prefixedIdentifier ::=
7286 * identifier ('.' identifier)? 6955 * identifier ('.' identifier)?
7287 */ 6956 */
7288 Identifier _parsePrefixedIdentifierUnchecked() { 6957 Identifier _parsePrefixedIdentifierUnchecked() {
7289 return _parsePrefixedIdentifierAfterIdentifier( 6958 return _parsePrefixedIdentifierAfterIdentifier(
7290 _parseSimpleIdentifierUnchecked()); 6959 _parseSimpleIdentifierUnchecked());
7291 } 6960 }
7292 6961
7293 /** 6962 /**
7294 * Parse a redirecting constructor invocation. The flag [hasPeriod] should be
7295 * `true` if the `this` is followed by a period. Return the redirecting
7296 * constructor invocation that was parsed.
7297 *
7298 * This method assumes that the current token matches `Keyword.THIS`.
7299 *
7300 * redirectingConstructorInvocation ::=
7301 * 'this' ('.' identifier)? arguments
7302 */
7303 RedirectingConstructorInvocation _parseRedirectingConstructorInvocation(
7304 bool hasPeriod) {
7305 Token keyword = getAndAdvance();
7306 Token period = null;
7307 SimpleIdentifier constructorName = null;
7308 if (hasPeriod) {
7309 period = getAndAdvance();
7310 if (_matchesIdentifier()) {
7311 constructorName = _parseSimpleIdentifierUnchecked(isDeclaration: false);
7312 } else {
7313 _reportErrorForCurrentToken(ParserErrorCode.MISSING_IDENTIFIER);
7314 constructorName = createSyntheticIdentifier(isDeclaration: false);
7315 _advance();
7316 }
7317 }
7318 ArgumentList argumentList = _parseArgumentListChecked();
7319 return new RedirectingConstructorInvocation(
7320 keyword, period, constructorName, argumentList);
7321 }
7322
7323 /**
7324 * Parse a setter. The [commentAndMetadata] is the documentation comment and
7325 * metadata to be associated with the declaration. The [externalKeyword] is
7326 * the 'external' token. The [staticKeyword] is the static keyword, or `null`
7327 * if the setter is not static. The [returnType] is the return type that has
7328 * already been parsed, or `null` if there was no return type. Return the
7329 * setter that was parsed.
7330 *
7331 * This method assumes that the current token matches `Keyword.SET`.
7332 *
7333 * setter ::=
7334 * setterSignature functionBody?
7335 *
7336 * setterSignature ::=
7337 * 'external'? 'static'? returnType? 'set' identifier formalParameterL ist
7338 */
7339 MethodDeclaration _parseSetter(CommentAndMetadata commentAndMetadata,
7340 Token externalKeyword, Token staticKeyword, TypeName returnType) {
7341 Token propertyKeyword = getAndAdvance();
7342 SimpleIdentifier name = parseSimpleIdentifier(isDeclaration: true);
7343 FormalParameterList parameters = parseFormalParameterList();
7344 _validateFormalParameterList(parameters);
7345 FunctionBody body = parseFunctionBody(
7346 externalKeyword != null || staticKeyword == null,
7347 ParserErrorCode.STATIC_SETTER_WITHOUT_BODY,
7348 false);
7349 if (externalKeyword != null && body is! EmptyFunctionBody) {
7350 _reportErrorForCurrentToken(ParserErrorCode.EXTERNAL_SETTER_WITH_BODY);
7351 }
7352 return new MethodDeclaration(
7353 commentAndMetadata.comment,
7354 commentAndMetadata.metadata,
7355 externalKeyword,
7356 staticKeyword,
7357 returnType,
7358 propertyKeyword,
7359 null,
7360 name,
7361 null,
7362 parameters,
7363 body);
7364 }
7365
7366 /**
7367 * Parse a simple identifier. Return the simple identifier that was parsed. 6963 * Parse a simple identifier. Return the simple identifier that was parsed.
7368 * 6964 *
7369 * This method assumes that the current token matches an identifier. 6965 * This method assumes that the current token matches an identifier.
7370 * 6966 *
7371 * identifier ::= 6967 * identifier ::=
7372 * IDENTIFIER 6968 * IDENTIFIER
7373 */ 6969 */
7374 SimpleIdentifier _parseSimpleIdentifierUnchecked( 6970 SimpleIdentifier _parseSimpleIdentifierUnchecked(
7375 {bool isDeclaration: false}) { 6971 {bool isDeclaration: false}) {
7376 String lexeme = _currentToken.lexeme; 6972 String lexeme = _currentToken.lexeme;
(...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after
7477 _matches(TokenType.STRING_INTERPOLATION_IDENTIFIER)) { 7073 _matches(TokenType.STRING_INTERPOLATION_IDENTIFIER)) {
7478 strings.add(_parseStringInterpolation(string)); 7074 strings.add(_parseStringInterpolation(string));
7479 } else { 7075 } else {
7480 strings.add(new SimpleStringLiteral( 7076 strings.add(new SimpleStringLiteral(
7481 string, computeStringValue(string.lexeme, true, true))); 7077 string, computeStringValue(string.lexeme, true, true)));
7482 } 7078 }
7483 } while (_matches(TokenType.STRING)); 7079 } while (_matches(TokenType.STRING));
7484 return strings.length == 1 ? strings[0] : new AdjacentStrings(strings); 7080 return strings.length == 1 ? strings[0] : new AdjacentStrings(strings);
7485 } 7081 }
7486 7082
7487 /**
7488 * Parse a type alias. The [commentAndMetadata] is the metadata to be
7489 * associated with the member. Return the type alias that was parsed.
7490 *
7491 * This method assumes that the current token matches [Keyword.TYPEDEF].
7492 *
7493 * typeAlias ::=
7494 * 'typedef' typeAliasBody
7495 *
7496 * typeAliasBody ::=
7497 * classTypeAlias
7498 * | functionTypeAlias
7499 *
7500 * classTypeAlias ::=
7501 * identifier typeParameters? '=' 'abstract'? mixinApplication
7502 *
7503 * mixinApplication ::=
7504 * qualified withClause implementsClause? ';'
7505 *
7506 * functionTypeAlias ::=
7507 * functionPrefix typeParameterList? formalParameterList ';'
7508 *
7509 * functionPrefix ::=
7510 * returnType? name
7511 */
7512 TypeAlias _parseTypeAlias(CommentAndMetadata commentAndMetadata) {
7513 Token keyword = getAndAdvance();
7514 if (_matchesIdentifier()) {
7515 Token next = _peek();
7516 if (_tokenMatches(next, TokenType.LT)) {
7517 next = _skipTypeParameterList(next);
7518 if (next != null && _tokenMatches(next, TokenType.EQ)) {
7519 TypeAlias typeAlias =
7520 parseClassTypeAlias(commentAndMetadata, null, keyword);
7521 _reportErrorForToken(
7522 ParserErrorCode.DEPRECATED_CLASS_TYPE_ALIAS, keyword);
7523 return typeAlias;
7524 }
7525 } else if (_tokenMatches(next, TokenType.EQ)) {
7526 TypeAlias typeAlias =
7527 parseClassTypeAlias(commentAndMetadata, null, keyword);
7528 _reportErrorForToken(
7529 ParserErrorCode.DEPRECATED_CLASS_TYPE_ALIAS, keyword);
7530 return typeAlias;
7531 }
7532 }
7533 return _parseFunctionTypeAlias(commentAndMetadata, keyword);
7534 }
7535
7536 TypeName _parseTypeName(bool inExpression) { 7083 TypeName _parseTypeName(bool inExpression) {
7537 Identifier typeName; 7084 Identifier typeName;
7538 if (_matchesIdentifier()) { 7085 if (_matchesIdentifier()) {
7539 typeName = _parsePrefixedIdentifierUnchecked(); 7086 typeName = _parsePrefixedIdentifierUnchecked();
7540 } else if (_matchesKeyword(Keyword.VAR)) { 7087 } else if (_matchesKeyword(Keyword.VAR)) {
7541 _reportErrorForCurrentToken(ParserErrorCode.VAR_AS_TYPE_NAME); 7088 _reportErrorForCurrentToken(ParserErrorCode.VAR_AS_TYPE_NAME);
7542 typeName = new SimpleIdentifier(getAndAdvance()); 7089 typeName = new SimpleIdentifier(getAndAdvance());
7543 } else { 7090 } else {
7544 typeName = createSyntheticIdentifier(); 7091 typeName = createSyntheticIdentifier();
7545 _reportErrorForCurrentToken(ParserErrorCode.EXPECTED_TYPE_NAME); 7092 _reportErrorForCurrentToken(ParserErrorCode.EXPECTED_TYPE_NAME);
(...skipping 1638 matching lines...) Expand 10 before | Expand all | Expand 10 after
9184 */ 8731 */
9185 const ParserErrorCode(String name, String message, [String correction]) 8732 const ParserErrorCode(String name, String message, [String correction])
9186 : super(name, message, correction); 8733 : super(name, message, correction);
9187 8734
9188 @override 8735 @override
9189 ErrorSeverity get errorSeverity => ErrorSeverity.ERROR; 8736 ErrorSeverity get errorSeverity => ErrorSeverity.ERROR;
9190 8737
9191 @override 8738 @override
9192 ErrorType get type => ErrorType.SYNTACTIC_ERROR; 8739 ErrorType get type => ErrorType.SYNTACTIC_ERROR;
9193 } 8740 }
OLDNEW
« no previous file with comments | « no previous file | pkg/analyzer/test/generated/parser_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698