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

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

Issue 2348353002: First steps toward 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';
(...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after
95 new MethodTrampoline(0, (Parser target) => target.parseTypeParameter()), 95 new MethodTrampoline(0, (Parser target) => target.parseTypeParameter()),
96 'parseTypeParameterList_0': new MethodTrampoline( 96 'parseTypeParameterList_0': new MethodTrampoline(
97 0, (Parser target) => target.parseTypeParameterList()), 97 0, (Parser target) => target.parseTypeParameterList()),
98 'parseWithClause_0': 98 'parseWithClause_0':
99 new MethodTrampoline(0, (Parser target) => target.parseWithClause()), 99 new MethodTrampoline(0, (Parser target) => target.parseWithClause()),
100 'advance_0': new MethodTrampoline(0, (Parser target) => target._advance()), 100 'advance_0': new MethodTrampoline(0, (Parser target) => target._advance()),
101 'appendScalarValue_5': new MethodTrampoline( 101 'appendScalarValue_5': new MethodTrampoline(
102 5, 102 5,
103 (Parser target, arg0, arg1, arg2, arg3, arg4) => 103 (Parser target, arg0, arg1, arg2, arg3, arg4) =>
104 target._appendScalarValue(arg0, arg1, arg2, arg3, arg4)), 104 target._appendScalarValue(arg0, arg1, arg2, arg3, arg4)),
105 'computeStringValue_3': new MethodTrampoline(
106 3,
107 (Parser target, arg0, arg1, arg2) =>
108 target._computeStringValue(arg0, arg1, arg2)),
109 'convertToFunctionDeclaration_1': new MethodTrampoline( 105 'convertToFunctionDeclaration_1': new MethodTrampoline(
110 1, (Parser target, arg0) => target._convertToFunctionDeclaration(arg0)), 106 1, (Parser target, arg0) => target._convertToFunctionDeclaration(arg0)),
111 'couldBeStartOfCompilationUnitMember_0': new MethodTrampoline( 107 'couldBeStartOfCompilationUnitMember_0': new MethodTrampoline(
112 0, (Parser target) => target._couldBeStartOfCompilationUnitMember()), 108 0, (Parser target) => target._couldBeStartOfCompilationUnitMember()),
113 'createSyntheticIdentifier_0': new MethodTrampoline( 109 'createSyntheticIdentifier_0': new MethodTrampoline(
114 0, (Parser target) => target._createSyntheticIdentifier()), 110 0, (Parser target) => target.createSyntheticIdentifier()),
115 'createSyntheticKeyword_1': new MethodTrampoline( 111 'createSyntheticKeyword_1': new MethodTrampoline(
116 1, (Parser target, arg0) => target._createSyntheticKeyword(arg0)), 112 1, (Parser target, arg0) => target._createSyntheticKeyword(arg0)),
117 'createSyntheticStringLiteral_0': new MethodTrampoline( 113 'createSyntheticStringLiteral_0': new MethodTrampoline(
118 0, (Parser target) => target._createSyntheticStringLiteral()), 114 0, (Parser target) => target.createSyntheticStringLiteral()),
119 'createSyntheticToken_1': new MethodTrampoline( 115 'createSyntheticToken_1': new MethodTrampoline(
120 1, (Parser target, arg0) => target._createSyntheticToken(arg0)), 116 1, (Parser target, arg0) => target._createSyntheticToken(arg0)),
121 'ensureAssignable_1': new MethodTrampoline( 117 'ensureAssignable_1': new MethodTrampoline(
122 1, (Parser target, arg0) => target._ensureAssignable(arg0)), 118 1, (Parser target, arg0) => target._ensureAssignable(arg0)),
123 'expect_1': 119 'expect_1':
124 new MethodTrampoline(1, (Parser target, arg0) => target._expect(arg0)), 120 new MethodTrampoline(1, (Parser target, arg0) => target._expect(arg0)),
125 'expectGt_0': new MethodTrampoline(0, (Parser target) => target._expectGt()), 121 'expectGt_0': new MethodTrampoline(0, (Parser target) => target._expectGt()),
126 'expectKeyword_1': new MethodTrampoline( 122 'expectKeyword_1': new MethodTrampoline(
127 1, (Parser target, arg0) => target._expectKeyword(arg0)), 123 1, (Parser target, arg0) => target._expectKeyword(arg0)),
128 'findRange_2': new MethodTrampoline( 124 'findRange_2': new MethodTrampoline(
129 2, 125 2,
130 (Parser target, List<List<int>> arg0, int arg1) => 126 (Parser target, List<List<int>> arg0, int arg1) =>
131 target._findRange(arg0, arg1)), 127 target._findRange(arg0, arg1)),
132 'getCodeBlockRanges_1': new MethodTrampoline( 128 'getCodeBlockRanges_1': new MethodTrampoline(
133 1, (Parser target, arg0) => target._getCodeBlockRanges(arg0)), 129 1, (Parser target, arg0) => target._getCodeBlockRanges(arg0)),
134 'getEndToken_1': new MethodTrampoline( 130 'getEndToken_1': new MethodTrampoline(
135 1, (Parser target, arg0) => target._getEndToken(arg0)), 131 1, (Parser target, arg0) => target._getEndToken(arg0)),
136 'injectToken_1': new MethodTrampoline( 132 'injectToken_1': new MethodTrampoline(
137 1, (Parser target, arg0) => target._injectToken(arg0)), 133 1, (Parser target, arg0) => target._injectToken(arg0)),
138 'isFunctionDeclaration_0': new MethodTrampoline( 134 'isFunctionDeclaration_0': new MethodTrampoline(
139 0, (Parser target) => target._isFunctionDeclaration()), 135 0, (Parser target) => target.isFunctionDeclaration()),
140 'isFunctionExpression_1': new MethodTrampoline( 136 'isFunctionExpression_1': new MethodTrampoline(
141 1, (Parser target, arg0) => target._isFunctionExpression(arg0)), 137 1, (Parser target, arg0) => target.isFunctionExpression(arg0)),
142 'isHexDigit_1': new MethodTrampoline( 138 'isHexDigit_1': new MethodTrampoline(
143 1, (Parser target, arg0) => target._isHexDigit(arg0)), 139 1, (Parser target, arg0) => target._isHexDigit(arg0)),
144 'isInitializedVariableDeclaration_0': new MethodTrampoline( 140 'isInitializedVariableDeclaration_0': new MethodTrampoline(
145 0, (Parser target) => target._isInitializedVariableDeclaration()), 141 0, (Parser target) => target.isInitializedVariableDeclaration()),
146 'isLinkText_2': new MethodTrampoline( 142 'isLinkText_2': new MethodTrampoline(
147 2, (Parser target, arg0, arg1) => target._isLinkText(arg0, arg1)), 143 2, (Parser target, arg0, arg1) => target._isLinkText(arg0, arg1)),
148 'isOperator_1': new MethodTrampoline( 144 'isOperator_1': new MethodTrampoline(
149 1, (Parser target, arg0) => target._isOperator(arg0)), 145 1, (Parser target, arg0) => target._isOperator(arg0)),
150 'isSwitchMember_0': 146 'isSwitchMember_0':
151 new MethodTrampoline(0, (Parser target) => target._isSwitchMember()), 147 new MethodTrampoline(0, (Parser target) => target.isSwitchMember()),
152 'isTypedIdentifier_1': new MethodTrampoline( 148 'isTypedIdentifier_1': new MethodTrampoline(
153 1, (Parser target, arg0) => target._isTypedIdentifier(arg0)), 149 1, (Parser target, arg0) => target._isTypedIdentifier(arg0)),
154 'lockErrorListener_0': 150 'lockErrorListener_0':
155 new MethodTrampoline(0, (Parser target) => target._lockErrorListener()), 151 new MethodTrampoline(0, (Parser target) => target._lockErrorListener()),
156 'matches_1': 152 'matches_1':
157 new MethodTrampoline(1, (Parser target, arg0) => target._matches(arg0)), 153 new MethodTrampoline(1, (Parser target, arg0) => target._matches(arg0)),
158 'matchesGt_0': 154 'matchesGt_0':
159 new MethodTrampoline(0, (Parser target) => target._matchesGt()), 155 new MethodTrampoline(0, (Parser target) => target._matchesGt()),
160 'matchesIdentifier_0': 156 'matchesIdentifier_0':
161 new MethodTrampoline(0, (Parser target) => target._matchesIdentifier()), 157 new MethodTrampoline(0, (Parser target) => target._matchesIdentifier()),
162 'matchesKeyword_1': new MethodTrampoline( 158 'matchesKeyword_1': new MethodTrampoline(
163 1, (Parser target, arg0) => target._matchesKeyword(arg0)), 159 1, (Parser target, arg0) => target._matchesKeyword(arg0)),
164 'matchesString_1': new MethodTrampoline( 160 'matchesString_1': new MethodTrampoline(
165 1, (Parser target, arg0) => target._matchesString(arg0)), 161 1, (Parser target, arg0) => target._matchesString(arg0)),
166 'optional_1': 162 'optional_1':
167 new MethodTrampoline(1, (Parser target, arg0) => target._optional(arg0)), 163 new MethodTrampoline(1, (Parser target, arg0) => target._optional(arg0)),
168 'parseAdditiveExpression_0': new MethodTrampoline( 164 'parseAdditiveExpression_0': new MethodTrampoline(
169 0, (Parser target) => target._parseAdditiveExpression()), 165 0, (Parser target) => target.parseAdditiveExpression()),
170 'parseAssertStatement_0': new MethodTrampoline( 166 'parseAssertStatement_0':
171 0, (Parser target) => target._parseAssertStatement()), 167 new MethodTrampoline(0, (Parser target) => target.parseAssertStatement()),
172 'parseAssignableExpression_1': new MethodTrampoline( 168 'parseAssignableExpression_1': new MethodTrampoline(
173 1, (Parser target, arg0) => target._parseAssignableExpression(arg0)), 169 1, (Parser target, arg0) => target.parseAssignableExpression(arg0)),
174 'parseAssignableSelector_2': new MethodTrampoline( 170 'parseAssignableSelector_2': new MethodTrampoline(
175 2, 171 2,
176 (Parser target, arg0, arg1) => 172 (Parser target, arg0, arg1) =>
177 target._parseAssignableSelector(arg0, arg1)), 173 target._parseAssignableSelector(arg0, arg1)),
178 'parseAwaitExpression_0': new MethodTrampoline( 174 'parseAwaitExpression_0':
179 0, (Parser target) => target._parseAwaitExpression()), 175 new MethodTrampoline(0, (Parser target) => target.parseAwaitExpression()),
180 'parseBitwiseAndExpression_0': new MethodTrampoline( 176 'parseBitwiseAndExpression_0': new MethodTrampoline(
181 0, (Parser target) => target._parseBitwiseAndExpression()), 177 0, (Parser target) => target.parseBitwiseAndExpression()),
182 'parseBitwiseXorExpression_0': new MethodTrampoline( 178 'parseBitwiseXorExpression_0': new MethodTrampoline(
183 0, (Parser target) => target._parseBitwiseXorExpression()), 179 0, (Parser target) => target.parseBitwiseXorExpression()),
184 'parseBreakStatement_0': 180 'parseBreakStatement_0':
185 new MethodTrampoline(0, (Parser target) => target._parseBreakStatement()), 181 new MethodTrampoline(0, (Parser target) => target.parseBreakStatement()),
186 'parseCascadeSection_0': 182 'parseCascadeSection_0':
187 new MethodTrampoline(0, (Parser target) => target._parseCascadeSection()), 183 new MethodTrampoline(0, (Parser target) => target.parseCascadeSection()),
188 'parseClassDeclaration_2': new MethodTrampoline(2, 184 'parseClassDeclaration_2': new MethodTrampoline(2,
189 (Parser target, arg0, arg1) => target._parseClassDeclaration(arg0, arg1)), 185 (Parser target, arg0, arg1) => target.parseClassDeclaration(arg0, arg1)),
190 'parseClassMembers_2': new MethodTrampoline( 186 'parseClassMembers_2': new MethodTrampoline(
191 2, (Parser target, arg0, arg1) => target._parseClassMembers(arg0, arg1)), 187 2, (Parser target, arg0, arg1) => target._parseClassMembers(arg0, arg1)),
192 'parseClassTypeAlias_3': new MethodTrampoline( 188 'parseClassTypeAlias_3': new MethodTrampoline(
193 3, 189 3,
194 (Parser target, arg0, arg1, arg2) => 190 (Parser target, arg0, arg1, arg2) =>
195 target._parseClassTypeAlias(arg0, arg1, arg2)), 191 target.parseClassTypeAlias(arg0, arg1, arg2)),
196 'parseCombinator_0': 192 'parseCombinator_0':
197 new MethodTrampoline(0, (Parser target) => target.parseCombinator()), 193 new MethodTrampoline(0, (Parser target) => target.parseCombinator()),
198 'parseCombinators_0': 194 'parseCombinators_0':
199 new MethodTrampoline(0, (Parser target) => target._parseCombinators()), 195 new MethodTrampoline(0, (Parser target) => target.parseCombinators()),
200 'parseCommentAndMetadata_0': new MethodTrampoline( 196 'parseCommentAndMetadata_0': new MethodTrampoline(
201 0, (Parser target) => target._parseCommentAndMetadata()), 197 0, (Parser target) => target.parseCommentAndMetadata()),
202 'parseCommentReference_2': new MethodTrampoline(2, 198 'parseCommentReference_2': new MethodTrampoline(2,
203 (Parser target, arg0, arg1) => target._parseCommentReference(arg0, arg1)), 199 (Parser target, arg0, arg1) => target.parseCommentReference(arg0, arg1)),
204 'parseCommentReferences_1': new MethodTrampoline( 200 'parseCommentReferences_1': new MethodTrampoline(
205 1, 201 1,
206 (Parser target, List<DocumentationCommentToken> arg0) => 202 (Parser target, List<DocumentationCommentToken> arg0) =>
207 target._parseCommentReferences(arg0)), 203 target._parseCommentReferences(arg0)),
208 'parseCompilationUnitMember_1': new MethodTrampoline( 204 'parseCompilationUnitMember_1': new MethodTrampoline(
209 1, (Parser target, arg0) => target._parseCompilationUnitMember(arg0)), 205 1, (Parser target, arg0) => target.parseCompilationUnitMember(arg0)),
210 'parseConfiguration_0': 206 'parseConfiguration_0':
211 new MethodTrampoline(0, (Parser target) => target._parseConfiguration()), 207 new MethodTrampoline(0, (Parser target) => target.parseConfiguration()),
212 'parseConstExpression_0': new MethodTrampoline( 208 'parseConstExpression_0':
213 0, (Parser target) => target._parseConstExpression()), 209 new MethodTrampoline(0, (Parser target) => target.parseConstExpression()),
214 'parseConstructor_8': new MethodTrampoline( 210 'parseConstructor_8': new MethodTrampoline(
215 8, 211 8,
216 (Parser target, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7) => target 212 (Parser target, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7) => target
217 ._parseConstructor(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7)), 213 ._parseConstructor(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7)),
218 'parseConstructorFieldInitializer_1': new MethodTrampoline(1, 214 'parseConstructorFieldInitializer_1': new MethodTrampoline(1,
219 (Parser target, arg0) => target._parseConstructorFieldInitializer(arg0)), 215 (Parser target, arg0) => target._parseConstructorFieldInitializer(arg0)),
220 'parseContinueStatement_0': new MethodTrampoline( 216 'parseContinueStatement_0': new MethodTrampoline(
221 0, (Parser target) => target._parseContinueStatement()), 217 0, (Parser target) => target.parseContinueStatement()),
222 'parseDirective_1': new MethodTrampoline( 218 'parseDirective_1': new MethodTrampoline(
223 1, (Parser target, arg0) => target._parseDirective(arg0)), 219 1, (Parser target, arg0) => target._parseDirective(arg0)),
224 'parseDirectives_0': 220 'parseDirectives_0':
225 new MethodTrampoline(0, (Parser target) => target._parseDirectives()), 221 new MethodTrampoline(0, (Parser target) => target.parseDirectives2()),
226 'parseDocumentationComment_0': new MethodTrampoline(0, (Parser target) { 222 'parseDocumentationComment_0': new MethodTrampoline(0, (Parser target) {
227 List<DocumentationCommentToken> tokens = 223 List<DocumentationCommentToken> tokens =
228 target._parseDocumentationCommentTokens(); 224 target.parseDocumentationCommentTokens();
229 return target._parseDocumentationComment(tokens); 225 return target.parseDocumentationComment(tokens);
230 }), 226 }),
231 'parseDoStatement_0': 227 'parseDoStatement_0':
232 new MethodTrampoline(0, (Parser target) => target._parseDoStatement()), 228 new MethodTrampoline(0, (Parser target) => target.parseDoStatement()),
233 'parseDottedName_0': 229 'parseDottedName_0':
234 new MethodTrampoline(0, (Parser target) => target._parseDottedName()), 230 new MethodTrampoline(0, (Parser target) => target.parseDottedName()),
235 'parseEmptyStatement_0': 231 'parseEmptyStatement_0':
236 new MethodTrampoline(0, (Parser target) => target._parseEmptyStatement()), 232 new MethodTrampoline(0, (Parser target) => target.parseEmptyStatement()),
237 'parseEnumConstantDeclaration_0': new MethodTrampoline( 233 'parseEnumConstantDeclaration_0': new MethodTrampoline(
238 0, (Parser target) => target._parseEnumConstantDeclaration()), 234 0, (Parser target) => target._parseEnumConstantDeclaration()),
239 'parseEnumDeclaration_1': new MethodTrampoline( 235 'parseEnumDeclaration_1': new MethodTrampoline(
240 1, (Parser target, arg0) => target._parseEnumDeclaration(arg0)), 236 1, (Parser target, arg0) => target.parseEnumDeclaration(arg0)),
241 'parseEqualityExpression_0': new MethodTrampoline( 237 'parseEqualityExpression_0': new MethodTrampoline(
242 0, (Parser target) => target._parseEqualityExpression()), 238 0, (Parser target) => target._parseEqualityExpression()),
243 'parseExportDirective_1': new MethodTrampoline( 239 'parseExportDirective_1': new MethodTrampoline(
244 1, (Parser target, arg0) => target._parseExportDirective(arg0)), 240 1, (Parser target, arg0) => target._parseExportDirective(arg0)),
245 'parseExpressionList_0': 241 'parseExpressionList_0':
246 new MethodTrampoline(0, (Parser target) => target._parseExpressionList()), 242 new MethodTrampoline(0, (Parser target) => target.parseExpressionList()),
247 'parseFinalConstVarOrType_1': new MethodTrampoline( 243 'parseFinalConstVarOrType_1': new MethodTrampoline(
248 1, (Parser target, arg0) => target._parseFinalConstVarOrType(arg0)), 244 1, (Parser target, arg0) => target.parseFinalConstVarOrType(arg0)),
249 'parseFormalParameter_1': new MethodTrampoline( 245 'parseFormalParameter_1': new MethodTrampoline(
250 1, (Parser target, arg0) => target._parseFormalParameter(arg0)), 246 1, (Parser target, arg0) => target._parseFormalParameter(arg0)),
251 'parseForStatement_0': 247 'parseForStatement_0':
252 new MethodTrampoline(0, (Parser target) => target._parseForStatement()), 248 new MethodTrampoline(0, (Parser target) => target.parseForStatement()),
253 'parseFunctionBody_3': new MethodTrampoline( 249 'parseFunctionBody_3': new MethodTrampoline(
254 3, 250 3,
255 (Parser target, arg0, arg1, arg2) => 251 (Parser target, arg0, arg1, arg2) =>
256 target._parseFunctionBody(arg0, arg1, arg2)), 252 target.parseFunctionBody(arg0, arg1, arg2)),
257 'parseFunctionDeclaration_3': new MethodTrampoline( 253 'parseFunctionDeclaration_3': new MethodTrampoline(
258 3, 254 3,
259 (Parser target, arg0, arg1, arg2) => 255 (Parser target, arg0, arg1, arg2) =>
260 target._parseFunctionDeclaration(arg0, arg1, arg2)), 256 target._parseFunctionDeclaration(arg0, arg1, arg2)),
261 'parseFunctionDeclarationStatement_0': new MethodTrampoline( 257 'parseFunctionDeclarationStatement_0': new MethodTrampoline(
262 0, (Parser target) => target._parseFunctionDeclarationStatement()), 258 0, (Parser target) => target.parseFunctionDeclarationStatement()),
263 'parseFunctionDeclarationStatementAfterReturnType_2': new MethodTrampoline( 259 'parseFunctionDeclarationStatementAfterReturnType_2': new MethodTrampoline(
264 2, 260 2,
265 (Parser target, arg0, arg1) => 261 (Parser target, arg0, arg1) =>
266 target._parseFunctionDeclarationStatementAfterReturnType(arg0, arg1)), 262 target._parseFunctionDeclarationStatementAfterReturnType(arg0, arg1)),
267 'parseFunctionTypeAlias_2': new MethodTrampoline( 263 'parseFunctionTypeAlias_2': new MethodTrampoline(
268 2, 264 2,
269 (Parser target, arg0, arg1) => 265 (Parser target, arg0, arg1) =>
270 target._parseFunctionTypeAlias(arg0, arg1)), 266 target._parseFunctionTypeAlias(arg0, arg1)),
271 'parseGetter_4': new MethodTrampoline( 267 'parseGetter_4': new MethodTrampoline(
272 4, 268 4,
273 (Parser target, arg0, arg1, arg2, arg3) => 269 (Parser target, arg0, arg1, arg2, arg3) =>
274 target._parseGetter(arg0, arg1, arg2, arg3)), 270 target._parseGetter(arg0, arg1, arg2, arg3)),
275 'parseIdentifierList_0': 271 'parseIdentifierList_0':
276 new MethodTrampoline(0, (Parser target) => target._parseIdentifierList()), 272 new MethodTrampoline(0, (Parser target) => target._parseIdentifierList()),
277 'parseIfStatement_0': 273 'parseIfStatement_0':
278 new MethodTrampoline(0, (Parser target) => target._parseIfStatement()), 274 new MethodTrampoline(0, (Parser target) => target.parseIfStatement()),
279 'parseImportDirective_1': new MethodTrampoline( 275 'parseImportDirective_1': new MethodTrampoline(
280 1, (Parser target, arg0) => target._parseImportDirective(arg0)), 276 1, (Parser target, arg0) => target._parseImportDirective(arg0)),
281 'parseInitializedIdentifierList_4': new MethodTrampoline( 277 'parseInitializedIdentifierList_4': new MethodTrampoline(
282 4, 278 4,
283 (Parser target, arg0, arg1, arg2, arg3) => 279 (Parser target, arg0, arg1, arg2, arg3) =>
284 target._parseInitializedIdentifierList(arg0, arg1, arg2, arg3)), 280 target._parseInitializedIdentifierList(arg0, arg1, arg2, arg3)),
285 'parseInstanceCreationExpression_1': new MethodTrampoline(1, 281 'parseInstanceCreationExpression_1': new MethodTrampoline(1,
286 (Parser target, arg0) => target._parseInstanceCreationExpression(arg0)), 282 (Parser target, arg0) => target._parseInstanceCreationExpression(arg0)),
287 'parseLibraryDirective_1': new MethodTrampoline( 283 'parseLibraryDirective_1': new MethodTrampoline(
288 1, (Parser target, arg0) => target._parseLibraryDirective(arg0)), 284 1, (Parser target, arg0) => target._parseLibraryDirective(arg0)),
289 'parseLibraryName_2': new MethodTrampoline( 285 'parseLibraryName_2': new MethodTrampoline(
290 2, (Parser target, arg0, arg1) => target._parseLibraryName(arg0, arg1)), 286 2, (Parser target, arg0, arg1) => target._parseLibraryName(arg0, arg1)),
291 'parseListLiteral_2': new MethodTrampoline( 287 'parseListLiteral_2': new MethodTrampoline(
292 2, (Parser target, arg0, arg1) => target._parseListLiteral(arg0, arg1)), 288 2, (Parser target, arg0, arg1) => target._parseListLiteral(arg0, arg1)),
293 'parseListOrMapLiteral_1': new MethodTrampoline( 289 'parseListOrMapLiteral_1': new MethodTrampoline(
294 1, (Parser target, arg0) => target._parseListOrMapLiteral(arg0)), 290 1, (Parser target, arg0) => target.parseListOrMapLiteral(arg0)),
295 'parseLogicalAndExpression_0': new MethodTrampoline( 291 'parseLogicalAndExpression_0': new MethodTrampoline(
296 0, (Parser target) => target._parseLogicalAndExpression()), 292 0, (Parser target) => target._parseLogicalAndExpression()),
297 'parseMapLiteral_2': new MethodTrampoline( 293 'parseMapLiteral_2': new MethodTrampoline(
298 2, (Parser target, arg0, arg1) => target._parseMapLiteral(arg0, arg1)), 294 2, (Parser target, arg0, arg1) => target._parseMapLiteral(arg0, arg1)),
299 'parseMethodDeclarationAfterParameters_7': new MethodTrampoline( 295 'parseMethodDeclarationAfterParameters_7': new MethodTrampoline(
300 7, 296 7,
301 (Parser target, arg0, arg1, arg2, arg3, arg4, arg5, arg6) => 297 (Parser target, arg0, arg1, arg2, arg3, arg4, arg5, arg6) =>
302 target._parseMethodDeclarationAfterParameters( 298 target._parseMethodDeclarationAfterParameters(
303 arg0, arg1, arg2, arg3, arg4, arg5, arg6)), 299 arg0, arg1, arg2, arg3, arg4, arg5, arg6)),
304 'parseMethodDeclarationAfterReturnType_4': new MethodTrampoline( 300 'parseMethodDeclarationAfterReturnType_4': new MethodTrampoline(
305 4, 301 4,
306 (Parser target, arg0, arg1, arg2, arg3) => target 302 (Parser target, arg0, arg1, arg2, arg3) => target
307 ._parseMethodDeclarationAfterReturnType(arg0, arg1, arg2, arg3)), 303 ._parseMethodDeclarationAfterReturnType(arg0, arg1, arg2, arg3)),
308 'parseModifiers_0': 304 'parseModifiers_0':
309 new MethodTrampoline(0, (Parser target) => target._parseModifiers()), 305 new MethodTrampoline(0, (Parser target) => target._parseModifiers()),
310 'parseMultiplicativeExpression_0': new MethodTrampoline( 306 'parseMultiplicativeExpression_0': new MethodTrampoline(
311 0, (Parser target) => target._parseMultiplicativeExpression()), 307 0, (Parser target) => target.parseMultiplicativeExpression()),
312 'parseNativeClause_0': 308 'parseNativeClause_0':
313 new MethodTrampoline(0, (Parser target) => target._parseNativeClause()), 309 new MethodTrampoline(0, (Parser target) => target._parseNativeClause()),
314 'parseNewExpression_0': 310 'parseNewExpression_0':
315 new MethodTrampoline(0, (Parser target) => target._parseNewExpression()), 311 new MethodTrampoline(0, (Parser target) => target._parseNewExpression()),
316 'parseNonLabeledStatement_0': new MethodTrampoline( 312 'parseNonLabeledStatement_0': new MethodTrampoline(
317 0, (Parser target) => target._parseNonLabeledStatement()), 313 0, (Parser target) => target._parseNonLabeledStatement()),
318 'parseOperator_3': new MethodTrampoline( 314 'parseOperator_3': new MethodTrampoline(
319 3, 315 3,
320 (Parser target, arg0, arg1, arg2) => 316 (Parser target, arg0, arg1, arg2) =>
321 target._parseOperator(arg0, arg1, arg2)), 317 target.parseOperator(arg0, arg1, arg2)),
322 'parseOptionalReturnType_0': new MethodTrampoline( 318 'parseOptionalReturnType_0': new MethodTrampoline(
323 0, (Parser target) => target._parseOptionalReturnType()), 319 0, (Parser target) => target._parseOptionalReturnType()),
324 'parsePartDirective_1': new MethodTrampoline( 320 'parsePartDirective_1': new MethodTrampoline(
325 1, (Parser target, arg0) => target._parsePartOrPartOfDirective(arg0)), 321 1, (Parser target, arg0) => target._parsePartOrPartOfDirective(arg0)),
326 'parsePostfixExpression_0': new MethodTrampoline( 322 'parsePostfixExpression_0': new MethodTrampoline(
327 0, (Parser target) => target._parsePostfixExpression()), 323 0, (Parser target) => target._parsePostfixExpression()),
328 'parsePrimaryExpression_0': new MethodTrampoline( 324 'parsePrimaryExpression_0': new MethodTrampoline(
329 0, (Parser target) => target._parsePrimaryExpression()), 325 0, (Parser target) => target.parsePrimaryExpression()),
330 'parseRedirectingConstructorInvocation_1': new MethodTrampoline( 326 'parseRedirectingConstructorInvocation_1': new MethodTrampoline(
331 1, 327 1,
332 (Parser target, arg0) => 328 (Parser target, arg0) =>
333 target._parseRedirectingConstructorInvocation(arg0)), 329 target._parseRedirectingConstructorInvocation(arg0)),
334 'parseRelationalExpression_0': new MethodTrampoline( 330 'parseRelationalExpression_0': new MethodTrampoline(
335 0, (Parser target) => target._parseRelationalExpression()), 331 0, (Parser target) => target.parseRelationalExpression()),
336 'parseRethrowExpression_0': new MethodTrampoline( 332 'parseRethrowExpression_0': new MethodTrampoline(
337 0, (Parser target) => target._parseRethrowExpression()), 333 0, (Parser target) => target.parseRethrowExpression()),
338 'parseReturnStatement_0': new MethodTrampoline( 334 'parseReturnStatement_0':
339 0, (Parser target) => target._parseReturnStatement()), 335 new MethodTrampoline(0, (Parser target) => target.parseReturnStatement()),
340 'parseSetter_4': new MethodTrampoline( 336 'parseSetter_4': new MethodTrampoline(
341 4, 337 4,
342 (Parser target, arg0, arg1, arg2, arg3) => 338 (Parser target, arg0, arg1, arg2, arg3) =>
343 target._parseSetter(arg0, arg1, arg2, arg3)), 339 target._parseSetter(arg0, arg1, arg2, arg3)),
344 'parseShiftExpression_0': new MethodTrampoline( 340 'parseShiftExpression_0':
345 0, (Parser target) => target._parseShiftExpression()), 341 new MethodTrampoline(0, (Parser target) => target.parseShiftExpression()),
346 'parseStatementList_0': 342 'parseStatementList_0':
347 new MethodTrampoline(0, (Parser target) => target._parseStatementList()), 343 new MethodTrampoline(0, (Parser target) => target._parseStatementList()),
348 'parseStringInterpolation_1': new MethodTrampoline( 344 'parseStringInterpolation_1': new MethodTrampoline(
349 1, (Parser target, arg0) => target._parseStringInterpolation(arg0)), 345 1, (Parser target, arg0) => target._parseStringInterpolation(arg0)),
350 'parseSuperConstructorInvocation_0': new MethodTrampoline( 346 'parseSuperConstructorInvocation_0': new MethodTrampoline(
351 0, (Parser target) => target._parseSuperConstructorInvocation()), 347 0, (Parser target) => target.parseSuperConstructorInvocation()),
352 'parseSwitchStatement_0': new MethodTrampoline( 348 'parseSwitchStatement_0':
353 0, (Parser target) => target._parseSwitchStatement()), 349 new MethodTrampoline(0, (Parser target) => target.parseSwitchStatement()),
354 'parseSymbolLiteral_0': 350 'parseSymbolLiteral_0':
355 new MethodTrampoline(0, (Parser target) => target._parseSymbolLiteral()), 351 new MethodTrampoline(0, (Parser target) => target.parseSymbolLiteral()),
356 'parseThrowExpression_0': new MethodTrampoline( 352 'parseThrowExpression_0':
357 0, (Parser target) => target._parseThrowExpression()), 353 new MethodTrampoline(0, (Parser target) => target.parseThrowExpression()),
358 'parseThrowExpressionWithoutCascade_0': new MethodTrampoline( 354 'parseThrowExpressionWithoutCascade_0': new MethodTrampoline(
359 0, (Parser target) => target._parseThrowExpressionWithoutCascade()), 355 0, (Parser target) => target.parseThrowExpressionWithoutCascade()),
360 'parseTryStatement_0': 356 'parseTryStatement_0':
361 new MethodTrampoline(0, (Parser target) => target._parseTryStatement()), 357 new MethodTrampoline(0, (Parser target) => target.parseTryStatement()),
362 'parseTypeAlias_1': new MethodTrampoline( 358 'parseTypeAlias_1': new MethodTrampoline(
363 1, (Parser target, arg0) => target._parseTypeAlias(arg0)), 359 1, (Parser target, arg0) => target._parseTypeAlias(arg0)),
364 'parseUnaryExpression_0': new MethodTrampoline( 360 'parseUnaryExpression_0':
365 0, (Parser target) => target._parseUnaryExpression()), 361 new MethodTrampoline(0, (Parser target) => target.parseUnaryExpression()),
366 'parseVariableDeclaration_0': new MethodTrampoline( 362 'parseVariableDeclaration_0': new MethodTrampoline(
367 0, (Parser target) => target._parseVariableDeclaration()), 363 0, (Parser target) => target.parseVariableDeclaration()),
368 'parseVariableDeclarationListAfterMetadata_1': new MethodTrampoline( 364 'parseVariableDeclarationListAfterMetadata_1': new MethodTrampoline(
369 1, 365 1,
370 (Parser target, arg0) => 366 (Parser target, arg0) =>
371 target._parseVariableDeclarationListAfterMetadata(arg0)), 367 target.parseVariableDeclarationListAfterMetadata(arg0)),
372 'parseVariableDeclarationListAfterType_3': new MethodTrampoline( 368 'parseVariableDeclarationListAfterType_3': new MethodTrampoline(
373 3, 369 3,
374 (Parser target, arg0, arg1, arg2) => 370 (Parser target, arg0, arg1, arg2) =>
375 target._parseVariableDeclarationListAfterType(arg0, arg1, arg2)), 371 target.parseVariableDeclarationListAfterType(arg0, arg1, arg2)),
376 'parseVariableDeclarationStatementAfterMetadata_1': new MethodTrampoline( 372 'parseVariableDeclarationStatementAfterMetadata_1': new MethodTrampoline(
377 1, 373 1,
378 (Parser target, arg0) => 374 (Parser target, arg0) =>
379 target._parseVariableDeclarationStatementAfterMetadata(arg0)), 375 target.parseVariableDeclarationStatementAfterMetadata(arg0)),
380 'parseVariableDeclarationStatementAfterType_3': new MethodTrampoline( 376 'parseVariableDeclarationStatementAfterType_3': new MethodTrampoline(
381 3, 377 3,
382 (Parser target, arg0, arg1, arg2) => 378 (Parser target, arg0, arg1, arg2) =>
383 target._parseVariableDeclarationStatementAfterType(arg0, arg1, arg2)), 379 target._parseVariableDeclarationStatementAfterType(arg0, arg1, arg2)),
384 'parseWhileStatement_0': 380 'parseWhileStatement_0':
385 new MethodTrampoline(0, (Parser target) => target._parseWhileStatement()), 381 new MethodTrampoline(0, (Parser target) => target.parseWhileStatement()),
386 'parseYieldStatement_0': 382 'parseYieldStatement_0':
387 new MethodTrampoline(0, (Parser target) => target._parseYieldStatement()), 383 new MethodTrampoline(0, (Parser target) => target.parseYieldStatement()),
388 'peek_0': new MethodTrampoline(0, (Parser target) => target._peek()), 384 'peek_0': new MethodTrampoline(0, (Parser target) => target._peek()),
389 'peekAt_1': 385 'peekAt_1':
390 new MethodTrampoline(1, (Parser target, arg0) => target._peekAt(arg0)), 386 new MethodTrampoline(1, (Parser target, arg0) => target._peekAt(arg0)),
391 'reportError_1': new MethodTrampoline( 387 'reportError_1': new MethodTrampoline(
392 1, (Parser target, arg0) => target._reportError(arg0)), 388 1, (Parser target, arg0) => target._reportError(arg0)),
393 'reportErrorForCurrentToken_2': new MethodTrampoline( 389 'reportErrorForCurrentToken_2': new MethodTrampoline(
394 2, 390 2,
395 (Parser target, arg0, arg1) => 391 (Parser target, arg0, arg1) =>
396 target._reportErrorForCurrentToken(arg0, arg1)), 392 target._reportErrorForCurrentToken(arg0, arg1)),
397 'reportErrorForNode_3': new MethodTrampoline( 393 'reportErrorForNode_3': new MethodTrampoline(
398 3, 394 3,
399 (Parser target, arg0, arg1, arg2) => 395 (Parser target, arg0, arg1, arg2) =>
400 target._reportErrorForNode(arg0, arg1, arg2)), 396 target._reportErrorForNode(arg0, arg1, arg2)),
401 'reportErrorForToken_3': new MethodTrampoline( 397 'reportErrorForToken_3': new MethodTrampoline(
402 3, 398 3,
403 (Parser target, arg0, arg1, arg2) => 399 (Parser target, arg0, arg1, arg2) =>
404 target._reportErrorForToken(arg0, arg1, arg2)), 400 target._reportErrorForToken(arg0, arg1, arg2)),
405 'skipBlock_0': 401 'skipBlock_0':
406 new MethodTrampoline(0, (Parser target) => target._skipBlock()), 402 new MethodTrampoline(0, (Parser target) => target._skipBlock()),
407 'skipFinalConstVarOrType_1': new MethodTrampoline( 403 'skipFinalConstVarOrType_1': new MethodTrampoline(
408 1, (Parser target, arg0) => target._skipFinalConstVarOrType(arg0)), 404 1, (Parser target, arg0) => target._skipFinalConstVarOrType(arg0)),
409 'skipFormalParameterList_1': new MethodTrampoline( 405 'skipFormalParameterList_1': new MethodTrampoline(
410 1, (Parser target, arg0) => target._skipFormalParameterList(arg0)), 406 1, (Parser target, arg0) => target._skipFormalParameterList(arg0)),
411 'skipPastMatchingToken_1': new MethodTrampoline( 407 'skipPastMatchingToken_1': new MethodTrampoline(
412 1, (Parser target, arg0) => target._skipPastMatchingToken(arg0)), 408 1, (Parser target, arg0) => target._skipPastMatchingToken(arg0)),
413 'skipPrefixedIdentifier_1': new MethodTrampoline( 409 'skipPrefixedIdentifier_1': new MethodTrampoline(
414 1, (Parser target, arg0) => target._skipPrefixedIdentifier(arg0)), 410 1, (Parser target, arg0) => target.skipPrefixedIdentifier(arg0)),
415 'skipReturnType_1': new MethodTrampoline( 411 'skipReturnType_1': new MethodTrampoline(
416 1, (Parser target, arg0) => target._skipReturnType(arg0)), 412 1, (Parser target, arg0) => target.skipReturnType(arg0)),
417 'skipSimpleIdentifier_1': new MethodTrampoline( 413 'skipSimpleIdentifier_1': new MethodTrampoline(
418 1, (Parser target, arg0) => target._skipSimpleIdentifier(arg0)), 414 1, (Parser target, arg0) => target.skipSimpleIdentifier(arg0)),
419 'skipStringInterpolation_1': new MethodTrampoline( 415 'skipStringInterpolation_1': new MethodTrampoline(
420 1, (Parser target, arg0) => target._skipStringInterpolation(arg0)), 416 1, (Parser target, arg0) => target._skipStringInterpolation(arg0)),
421 'skipStringLiteral_1': new MethodTrampoline( 417 'skipStringLiteral_1': new MethodTrampoline(
422 1, (Parser target, arg0) => target._skipStringLiteral(arg0)), 418 1, (Parser target, arg0) => target.skipStringLiteral(arg0)),
423 'skipTypeArgumentList_1': new MethodTrampoline( 419 'skipTypeArgumentList_1': new MethodTrampoline(
424 1, (Parser target, arg0) => target._skipTypeArgumentList(arg0)), 420 1, (Parser target, arg0) => target.skipTypeArgumentList(arg0)),
425 'skipTypeName_1': new MethodTrampoline( 421 'skipTypeName_1': new MethodTrampoline(
426 1, (Parser target, arg0) => target._skipTypeName(arg0)), 422 1, (Parser target, arg0) => target.skipTypeName(arg0)),
427 'skipTypeParameterList_1': new MethodTrampoline( 423 'skipTypeParameterList_1': new MethodTrampoline(
428 1, (Parser target, arg0) => target._skipTypeParameterList(arg0)), 424 1, (Parser target, arg0) => target._skipTypeParameterList(arg0)),
429 'tokenMatches_2': new MethodTrampoline( 425 'tokenMatches_2': new MethodTrampoline(
430 2, (Parser target, arg0, arg1) => target._tokenMatches(arg0, arg1)), 426 2, (Parser target, arg0, arg1) => target._tokenMatches(arg0, arg1)),
431 'tokenMatchesIdentifier_1': new MethodTrampoline( 427 'tokenMatchesIdentifier_1': new MethodTrampoline(
432 1, (Parser target, arg0) => target._tokenMatchesIdentifier(arg0)), 428 1, (Parser target, arg0) => target._tokenMatchesIdentifier(arg0)),
433 'tokenMatchesKeyword_2': new MethodTrampoline(2, 429 'tokenMatchesKeyword_2': new MethodTrampoline(2,
434 (Parser target, arg0, arg1) => target._tokenMatchesKeyword(arg0, arg1)), 430 (Parser target, arg0, arg1) => target._tokenMatchesKeyword(arg0, arg1)),
435 'tokenMatchesString_2': new MethodTrampoline( 431 'tokenMatchesString_2': new MethodTrampoline(
436 2, (Parser target, arg0, arg1) => target._tokenMatchesString(arg0, arg1)), 432 2, (Parser target, arg0, arg1) => target._tokenMatchesString(arg0, arg1)),
437 'translateCharacter_3': new MethodTrampoline(
438 3,
439 (Parser target, arg0, arg1, arg2) =>
440 target._translateCharacter(arg0, arg1, arg2)),
441 'unlockErrorListener_0': 433 'unlockErrorListener_0':
442 new MethodTrampoline(0, (Parser target) => target._unlockErrorListener()), 434 new MethodTrampoline(0, (Parser target) => target._unlockErrorListener()),
443 'validateFormalParameterList_1': new MethodTrampoline( 435 'validateFormalParameterList_1': new MethodTrampoline(
444 1, (Parser target, arg0) => target._validateFormalParameterList(arg0)), 436 1, (Parser target, arg0) => target._validateFormalParameterList(arg0)),
445 'validateModifiersForClass_1': new MethodTrampoline( 437 'validateModifiersForClass_1': new MethodTrampoline(
446 1, (Parser target, arg0) => target._validateModifiersForClass(arg0)), 438 1, (Parser target, arg0) => target._validateModifiersForClass(arg0)),
447 'validateModifiersForConstructor_1': new MethodTrampoline(1, 439 'validateModifiersForConstructor_1': new MethodTrampoline(1,
448 (Parser target, arg0) => target._validateModifiersForConstructor(arg0)), 440 (Parser target, arg0) => target._validateModifiersForConstructor(arg0)),
449 'validateModifiersForEnum_1': new MethodTrampoline( 441 'validateModifiersForEnum_1': new MethodTrampoline(
450 1, (Parser target, arg0) => target._validateModifiersForEnum(arg0)), 442 1, (Parser target, arg0) => target._validateModifiersForEnum(arg0)),
(...skipping 19 matching lines...) Expand all
470 target._validateModifiersForTopLevelFunction(arg0)), 462 target._validateModifiersForTopLevelFunction(arg0)),
471 'validateModifiersForTopLevelVariable_1': new MethodTrampoline( 463 'validateModifiersForTopLevelVariable_1': new MethodTrampoline(
472 1, 464 1,
473 (Parser target, arg0) => 465 (Parser target, arg0) =>
474 target._validateModifiersForTopLevelVariable(arg0)), 466 target._validateModifiersForTopLevelVariable(arg0)),
475 'validateModifiersForTypedef_1': new MethodTrampoline( 467 'validateModifiersForTypedef_1': new MethodTrampoline(
476 1, (Parser target, arg0) => target._validateModifiersForTypedef(arg0)), 468 1, (Parser target, arg0) => target._validateModifiersForTypedef(arg0)),
477 }; 469 };
478 470
479 Object invokeParserMethodImpl( 471 Object invokeParserMethodImpl(
480 Parser parser, String methodName, List<Object> objects, Token tokenStream) { 472 Parser parser, String methodName, List<Object> objects) {
481 parser.currentToken = tokenStream;
482 MethodTrampoline method = 473 MethodTrampoline method =
483 methodTable_Parser['${methodName}_${objects.length}']; 474 methodTable_Parser['${methodName}_${objects.length}'];
484 if (method == null) { 475 if (method == null) {
485 throw new ArgumentError('There is no method named $methodName'); 476 throw new ArgumentError('There is no method named $methodName');
486 } 477 }
487 return method.invoke(parser, objects); 478 return method.invoke(parser, objects);
488 } 479 }
489 480
490 /** 481 /**
491 * A simple data-holder for a method that needs to return multiple values. 482 * A simple data-holder for a method that needs to return multiple values.
(...skipping 250 matching lines...) Expand 10 before | Expand all | Expand 10 after
742 */ 733 */
743 bool parseGenericMethodComments = false; 734 bool parseGenericMethodComments = false;
744 735
745 /** 736 /**
746 * Initialize a newly created parser to parse tokens in the given [_source] 737 * Initialize a newly created parser to parse tokens in the given [_source]
747 * and to report any errors that are found to the given [_errorListener]. 738 * and to report any errors that are found to the given [_errorListener].
748 */ 739 */
749 Parser(this._source, this._errorListener); 740 Parser(this._source, this._errorListener);
750 741
751 /** 742 /**
743 * Return the current token.
744 */
745 Token get currentToken => _currentToken;
746
747 /**
752 * Set the token with which the parse is to begin to the given [token]. 748 * Set the token with which the parse is to begin to the given [token].
753 */ 749 */
754 void set currentToken(Token token) { 750 void set currentToken(Token token) {
755 this._currentToken = token; 751 this._currentToken = token;
756 } 752 }
757 753
758 /** 754 /**
759 * Return `true` if the parser is to parse asserts in the initializer list of 755 * Return `true` if the parser is to parse asserts in the initializer list of
760 * a constructor. 756 * a constructor.
761 */ 757 */
(...skipping 22 matching lines...) Expand all
784 } 780 }
785 781
786 /** 782 /**
787 * Return `true` if the current token is the first token of a return type that 783 * Return `true` if the current token is the first token of a return type that
788 * is followed by an identifier, possibly followed by a list of type 784 * is followed by an identifier, possibly followed by a list of type
789 * parameters, followed by a left-parenthesis. This is used by 785 * parameters, followed by a left-parenthesis. This is used by
790 * [_parseTypeAlias] to determine whether or not to parse a return type. 786 * [_parseTypeAlias] to determine whether or not to parse a return type.
791 */ 787 */
792 @deprecated 788 @deprecated
793 bool get hasReturnTypeInTypeAlias { 789 bool get hasReturnTypeInTypeAlias {
794 Token next = _skipReturnType(_currentToken); 790 Token next = skipReturnType(_currentToken);
795 if (next == null) { 791 if (next == null) {
796 return false; 792 return false;
797 } 793 }
798 return _tokenMatchesIdentifier(next); 794 return _tokenMatchesIdentifier(next);
799 } 795 }
800 796
801 /** 797 /**
802 * Set whether the parser is to parse the async support. 798 * Set whether the parser is to parse the async support.
803 */ 799 */
804 void set parseAsync(bool parseAsync) { 800 void set parseAsync(bool parseAsync) {
805 this._parseAsync = parseAsync; 801 this._parseAsync = parseAsync;
806 } 802 }
807 803
808 @deprecated 804 @deprecated
809 bool get parseConditionalDirectives => true; 805 bool get parseConditionalDirectives => true;
810 806
811 @deprecated 807 @deprecated
812 void set parseConditionalDirectives(bool value) {} 808 void set parseConditionalDirectives(bool value) {}
813 809
814 /** 810 /**
815 * Set whether parser is to parse function bodies. 811 * Set whether parser is to parse function bodies.
816 */ 812 */
817 void set parseFunctionBodies(bool parseFunctionBodies) { 813 void set parseFunctionBodies(bool parseFunctionBodies) {
818 this._parseFunctionBodies = parseFunctionBodies; 814 this._parseFunctionBodies = parseFunctionBodies;
819 } 815 }
820 816
821 /** 817 /**
818 * Return the content of a string with the given literal representation. The
819 * [lexeme] is the literal representation of the string. The flag [isFirst] is
820 * `true` if this is the first token in a string literal. The flag [isLast] is
821 * `true` if this is the last token in a string literal.
822 */
823 String computeStringValue(String lexeme, bool isFirst, bool isLast) {
824 StringLexemeHelper helper = new StringLexemeHelper(lexeme, isFirst, isLast);
825 int start = helper.start;
826 int end = helper.end;
827 bool stringEndsAfterStart = end >= start;
828 assert(stringEndsAfterStart);
829 if (!stringEndsAfterStart) {
830 AnalysisEngine.instance.logger.logError(
831 "Internal error: computeStringValue($lexeme, $isFirst, $isLast)");
832 return "";
833 }
834 if (helper.isRaw) {
835 return lexeme.substring(start, end);
836 }
837 StringBuffer buffer = new StringBuffer();
838 int index = start;
839 while (index < end) {
840 index = _translateCharacter(buffer, lexeme, index);
841 }
842 return buffer.toString();
843 }
844
845 /**
846 * Return a synthetic identifier.
847 */
848 SimpleIdentifier createSyntheticIdentifier({bool isDeclaration: false}) {
849 Token syntheticToken;
850 if (_currentToken.type == TokenType.KEYWORD) {
851 // Consider current keyword token as an identifier.
852 // It is not always true, e.g. "^is T" where "^" is place the place for
853 // synthetic identifier. By creating SyntheticStringToken we can
854 // distinguish a real identifier from synthetic. In the code completion
855 // behavior will depend on a cursor position - before or on "is".
856 syntheticToken = _injectToken(new SyntheticStringToken(
857 TokenType.IDENTIFIER, _currentToken.lexeme, _currentToken.offset));
858 } else {
859 syntheticToken = _createSyntheticToken(TokenType.IDENTIFIER);
860 }
861 return new SimpleIdentifier(syntheticToken, isDeclaration: isDeclaration);
862 }
863
864 /**
865 * Return a synthetic string literal.
866 */
867 SimpleStringLiteral createSyntheticStringLiteral() =>
868 new SimpleStringLiteral(_createSyntheticToken(TokenType.STRING), "");
869
870 /**
822 * Advance to the next token in the token stream, making it the new current 871 * Advance to the next token in the token stream, making it the new current
823 * token and return the token that was current before this method was invoked. 872 * token and return the token that was current before this method was invoked.
824 */ 873 */
825 Token getAndAdvance() { 874 Token getAndAdvance() {
826 Token token = _currentToken; 875 Token token = _currentToken;
827 _currentToken = _currentToken.next; 876 _currentToken = _currentToken.next;
828 return token; 877 return token;
829 } 878 }
830 879
831 /** 880 /**
881 * Return `true` if the current token appears to be the beginning of a
882 * function declaration.
883 */
884 bool isFunctionDeclaration() {
885 Keyword keyword = _currentToken.keyword;
886 if (keyword == Keyword.VOID) {
887 return true;
888 }
889 Token afterReturnType = skipTypeName(_currentToken);
890 if (afterReturnType == null) {
891 // There was no return type, but it is optional, so go back to where we
892 // started.
893 afterReturnType = _currentToken;
894 }
895 Token afterIdentifier = skipSimpleIdentifier(afterReturnType);
896 if (afterIdentifier == null) {
897 // It's possible that we parsed the function name as if it were a type
898 // name, so see whether it makes sense if we assume that there is no type.
899 afterIdentifier = skipSimpleIdentifier(_currentToken);
900 }
901 if (afterIdentifier == null) {
902 return false;
903 }
904 if (isFunctionExpression(afterIdentifier)) {
905 return true;
906 }
907 // It's possible that we have found a getter. While this isn't valid at this
908 // point we test for it in order to recover better.
909 if (keyword == Keyword.GET) {
910 Token afterName = skipSimpleIdentifier(_currentToken.next);
911 if (afterName == null) {
912 return false;
913 }
914 TokenType type = afterName.type;
915 return type == TokenType.FUNCTION || type == TokenType.OPEN_CURLY_BRACKET;
916 } else if (_tokenMatchesKeyword(afterReturnType, Keyword.GET)) {
917 Token afterName = skipSimpleIdentifier(afterReturnType.next);
918 if (afterName == null) {
919 return false;
920 }
921 TokenType type = afterName.type;
922 return type == TokenType.FUNCTION || type == TokenType.OPEN_CURLY_BRACKET;
923 }
924 return false;
925 }
926
927 /**
928 * Return `true` if the given [token] appears to be the beginning of a
929 * function expression.
930 */
931 bool isFunctionExpression(Token token) {
932 // Function expressions aren't allowed in initializer lists.
933 if (_inInitializer) {
934 return false;
935 }
936 Token afterTypeParameters = _skipTypeParameterList(token);
937 if (afterTypeParameters == null) {
938 afterTypeParameters = token;
939 }
940 Token afterParameters = _skipFormalParameterList(afterTypeParameters);
941 if (afterParameters == null) {
942 return false;
943 }
944 if (afterParameters.matchesAny(
945 const <TokenType>[TokenType.OPEN_CURLY_BRACKET, TokenType.FUNCTION])) {
946 return true;
947 }
948 String lexeme = afterParameters.lexeme;
949 return lexeme == ASYNC || lexeme == SYNC;
950 }
951
952 /**
953 * Return `true` if the current token is the first token in an initialized
954 * variable declaration rather than an expression. This method assumes that we
955 * have already skipped past any metadata that might be associated with the
956 * declaration.
957 *
958 * initializedVariableDeclaration ::=
959 * declaredIdentifier ('=' expression)? (',' initializedIdentifier)*
960 *
961 * declaredIdentifier ::=
962 * metadata finalConstVarOrType identifier
963 *
964 * finalConstVarOrType ::=
965 * 'final' type?
966 * | 'const' type?
967 * | 'var'
968 * | type
969 *
970 * type ::=
971 * qualified typeArguments?
972 *
973 * initializedIdentifier ::=
974 * identifier ('=' expression)?
975 */
976 bool isInitializedVariableDeclaration() {
977 Keyword keyword = _currentToken.keyword;
978 if (keyword == Keyword.FINAL || keyword == Keyword.VAR) {
979 // An expression cannot start with a keyword other than 'const',
980 // 'rethrow', or 'throw'.
981 return true;
982 }
983 if (keyword == Keyword.CONST) {
984 // Look to see whether we might be at the start of a list or map literal,
985 // otherwise this should be the start of a variable declaration.
986 return !_peek().matchesAny(const <TokenType>[
987 TokenType.LT,
988 TokenType.OPEN_CURLY_BRACKET,
989 TokenType.OPEN_SQUARE_BRACKET,
990 TokenType.INDEX
991 ]);
992 }
993 bool allowAdditionalTokens = true;
994 // We know that we have an identifier, and need to see whether it might be
995 // a type name.
996 if (_currentToken.type != TokenType.IDENTIFIER) {
997 allowAdditionalTokens = false;
998 }
999 Token token = skipTypeName(_currentToken);
1000 if (token == null) {
1001 // There was no type name, so this can't be a declaration.
1002 return false;
1003 }
1004 if (token.type != TokenType.IDENTIFIER) {
1005 allowAdditionalTokens = false;
1006 }
1007 token = skipSimpleIdentifier(token);
1008 if (token == null) {
1009 return false;
1010 }
1011 TokenType type = token.type;
1012 // Usual cases in valid code:
1013 // String v = '';
1014 // String v, v2;
1015 // String v;
1016 // for (String item in items) {}
1017 if (type == TokenType.EQ ||
1018 type == TokenType.COMMA ||
1019 type == TokenType.SEMICOLON ||
1020 token.keyword == Keyword.IN) {
1021 return true;
1022 }
1023 // It is OK to parse as a variable declaration in these cases:
1024 // String v }
1025 // String v if (true) print('OK');
1026 // String v { print(42); }
1027 // ...but not in these cases:
1028 // get getterName {
1029 // String get getterName
1030 if (allowAdditionalTokens) {
1031 if (type == TokenType.CLOSE_CURLY_BRACKET ||
1032 type == TokenType.KEYWORD ||
1033 type == TokenType.IDENTIFIER ||
1034 type == TokenType.OPEN_CURLY_BRACKET) {
1035 return true;
1036 }
1037 }
1038 return false;
1039 }
1040
1041 /**
1042 * Return `true` if the current token appears to be the beginning of a switch
1043 * member.
1044 */
1045 bool isSwitchMember() {
1046 Token token = _currentToken;
1047 while (_tokenMatches(token, TokenType.IDENTIFIER) &&
1048 _tokenMatches(token.next, TokenType.COLON)) {
1049 token = token.next.next;
1050 }
1051 Keyword keyword = token.keyword;
1052 return keyword == Keyword.CASE || keyword == Keyword.DEFAULT;
1053 }
1054
1055 /**
1056 * Parse an additive expression. Return the additive expression that was
1057 * parsed.
1058 *
1059 * additiveExpression ::=
1060 * multiplicativeExpression (additiveOperator multiplicativeExpression )*
1061 * | 'super' (additiveOperator multiplicativeExpression)+
1062 */
1063 Expression parseAdditiveExpression() {
1064 Expression expression;
1065 if (_currentToken.keyword == Keyword.SUPER &&
1066 _currentToken.next.type.isAdditiveOperator) {
1067 expression = new SuperExpression(getAndAdvance());
1068 } else {
1069 expression = parseMultiplicativeExpression();
1070 }
1071 while (_currentToken.type.isAdditiveOperator) {
1072 expression = new BinaryExpression(
1073 expression, getAndAdvance(), parseMultiplicativeExpression());
1074 }
1075 return expression;
1076 }
1077
1078 /**
832 * Parse an annotation. Return the annotation that was parsed. 1079 * Parse an annotation. Return the annotation that was parsed.
833 * 1080 *
834 * This method assumes that the current token matches [TokenType.AT]. 1081 * This method assumes that the current token matches [TokenType.AT].
835 * 1082 *
836 * annotation ::= 1083 * annotation ::=
837 * '@' qualified ('.' identifier)? arguments? 1084 * '@' qualified ('.' identifier)? arguments?
838 */ 1085 */
839 Annotation parseAnnotation() { 1086 Annotation parseAnnotation() {
840 Token atSign = getAndAdvance(); 1087 Token atSign = getAndAdvance();
841 Identifier name = parsePrefixedIdentifier(); 1088 Identifier name = parsePrefixedIdentifier();
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after
930 // If there is, then we're more likely missing a comma and should go back 1177 // If there is, then we're more likely missing a comma and should go back
931 // to parsing arguments. 1178 // to parsing arguments.
932 Token rightParenthesis = _expect(TokenType.CLOSE_PAREN); 1179 Token rightParenthesis = _expect(TokenType.CLOSE_PAREN);
933 return new ArgumentList(leftParenthesis, arguments, rightParenthesis); 1180 return new ArgumentList(leftParenthesis, arguments, rightParenthesis);
934 } finally { 1181 } finally {
935 _inInitializer = wasInInitializer; 1182 _inInitializer = wasInInitializer;
936 } 1183 }
937 } 1184 }
938 1185
939 /** 1186 /**
1187 * Parse an assert statement. Return the assert statement.
1188 *
1189 * This method assumes that the current token matches `Keyword.ASSERT`.
1190 *
1191 * assertStatement ::=
1192 * 'assert' '(' expression [',' expression] ')' ';'
1193 */
1194 AssertStatement parseAssertStatement() {
1195 Token keyword = getAndAdvance();
1196 Token leftParen = _expect(TokenType.OPEN_PAREN);
1197 Expression expression = parseExpression2();
1198 Token comma;
1199 Expression message;
1200 if (_matches(TokenType.COMMA)) {
1201 comma = getAndAdvance();
1202 message = parseExpression2();
1203 }
1204 Token rightParen = _expect(TokenType.CLOSE_PAREN);
1205 Token semicolon = _expect(TokenType.SEMICOLON);
1206 return new AssertStatement(
1207 keyword, leftParen, expression, comma, message, rightParen, semicolon);
1208 }
1209
1210 /**
1211 * Parse an assignable expression. The [primaryAllowed] is `true` if the
1212 * expression is allowed to be a primary without any assignable selector.
1213 * Return the assignable expression that was parsed.
1214 *
1215 * assignableExpression ::=
1216 * primary (arguments* assignableSelector)+
1217 * | 'super' unconditionalAssignableSelector
1218 * | identifier
1219 */
1220 Expression parseAssignableExpression(bool primaryAllowed) {
1221 if (_matchesKeyword(Keyword.SUPER)) {
1222 return _parseAssignableSelector(
1223 new SuperExpression(getAndAdvance()), false,
1224 allowConditional: false);
1225 }
1226 return _parseAssignableExpressionNotStartingWithSuper(primaryAllowed);
1227 }
1228
1229 /**
1230 * Parse a await expression. Return the await expression that was parsed.
1231 *
1232 * This method assumes that the current token matches `_AWAIT`.
1233 *
1234 * awaitExpression ::=
1235 * 'await' unaryExpression
1236 */
1237 AwaitExpression parseAwaitExpression() {
1238 Token awaitToken = getAndAdvance();
1239 Expression expression = parseUnaryExpression();
1240 return new AwaitExpression(awaitToken, expression);
1241 }
1242
1243 /**
1244 * Parse a bitwise and expression. Return the bitwise and expression that was
1245 * parsed.
1246 *
1247 * bitwiseAndExpression ::=
1248 * shiftExpression ('&' shiftExpression)*
1249 * | 'super' ('&' shiftExpression)+
1250 */
1251 Expression parseBitwiseAndExpression() {
1252 Expression expression;
1253 if (_currentToken.keyword == Keyword.SUPER &&
1254 _currentToken.next.type == TokenType.AMPERSAND) {
1255 expression = new SuperExpression(getAndAdvance());
1256 } else {
1257 expression = parseShiftExpression();
1258 }
1259 while (_currentToken.type == TokenType.AMPERSAND) {
1260 expression = new BinaryExpression(
1261 expression, getAndAdvance(), parseShiftExpression());
1262 }
1263 return expression;
1264 }
1265
1266 /**
940 * Parse a bitwise or expression. Return the bitwise or expression that was 1267 * Parse a bitwise or expression. Return the bitwise or expression that was
941 * parsed. 1268 * parsed.
942 * 1269 *
943 * bitwiseOrExpression ::= 1270 * bitwiseOrExpression ::=
944 * bitwiseXorExpression ('|' bitwiseXorExpression)* 1271 * bitwiseXorExpression ('|' bitwiseXorExpression)*
945 * | 'super' ('|' bitwiseXorExpression)+ 1272 * | 'super' ('|' bitwiseXorExpression)+
946 */ 1273 */
947 Expression parseBitwiseOrExpression() { 1274 Expression parseBitwiseOrExpression() {
948 Expression expression; 1275 Expression expression;
949 if (_currentToken.keyword == Keyword.SUPER && 1276 if (_currentToken.keyword == Keyword.SUPER &&
950 _currentToken.next.type == TokenType.BAR) { 1277 _currentToken.next.type == TokenType.BAR) {
951 expression = new SuperExpression(getAndAdvance()); 1278 expression = new SuperExpression(getAndAdvance());
952 } else { 1279 } else {
953 expression = _parseBitwiseXorExpression(); 1280 expression = parseBitwiseXorExpression();
954 } 1281 }
955 while (_currentToken.type == TokenType.BAR) { 1282 while (_currentToken.type == TokenType.BAR) {
956 expression = new BinaryExpression( 1283 expression = new BinaryExpression(
957 expression, getAndAdvance(), _parseBitwiseXorExpression()); 1284 expression, getAndAdvance(), parseBitwiseXorExpression());
958 } 1285 }
959 return expression; 1286 return expression;
960 } 1287 }
1288
1289 /**
1290 * Parse a bitwise exclusive-or expression. Return the bitwise exclusive-or
1291 * expression that was parsed.
1292 *
1293 * bitwiseXorExpression ::=
1294 * bitwiseAndExpression ('^' bitwiseAndExpression)*
1295 * | 'super' ('^' bitwiseAndExpression)+
1296 */
1297 Expression parseBitwiseXorExpression() {
1298 Expression expression;
1299 if (_currentToken.keyword == Keyword.SUPER &&
1300 _currentToken.next.type == TokenType.CARET) {
1301 expression = new SuperExpression(getAndAdvance());
1302 } else {
1303 expression = parseBitwiseAndExpression();
1304 }
1305 while (_currentToken.type == TokenType.CARET) {
1306 expression = new BinaryExpression(
1307 expression, getAndAdvance(), parseBitwiseAndExpression());
1308 }
1309 return expression;
1310 }
961 1311
962 /** 1312 /**
963 * Parse a block. Return the block that was parsed. 1313 * Parse a block. Return the block that was parsed.
964 * 1314 *
965 * This method assumes that the current token matches 1315 * This method assumes that the current token matches
966 * [TokenType.OPEN_CURLY_BRACKET]. 1316 * [TokenType.OPEN_CURLY_BRACKET].
967 * 1317 *
968 * block ::= 1318 * block ::=
969 * '{' statements '}' 1319 * '{' statements '}'
970 */ 1320 */
(...skipping 20 matching lines...) Expand all
991 } 1341 }
992 // Recovery: If the next token is not a right curly bracket, look at the 1342 // Recovery: If the next token is not a right curly bracket, look at the
993 // left curly bracket to see whether there is a matching right bracket. If 1343 // left curly bracket to see whether there is a matching right bracket. If
994 // there is, then we're more likely missing a semi-colon and should go back 1344 // there is, then we're more likely missing a semi-colon and should go back
995 // to parsing statements. 1345 // to parsing statements.
996 Token rightBracket = _expect(TokenType.CLOSE_CURLY_BRACKET); 1346 Token rightBracket = _expect(TokenType.CLOSE_CURLY_BRACKET);
997 return new Block(leftBracket, statements, rightBracket); 1347 return new Block(leftBracket, statements, rightBracket);
998 } 1348 }
999 1349
1000 /** 1350 /**
1351 * Parse a break statement. Return the break statement that was parsed.
1352 *
1353 * This method assumes that the current token matches `Keyword.BREAK`.
1354 *
1355 * breakStatement ::=
1356 * 'break' identifier? ';'
1357 */
1358 Statement parseBreakStatement() {
1359 Token breakKeyword = getAndAdvance();
1360 SimpleIdentifier label = null;
1361 if (_matchesIdentifier()) {
1362 label = _parseSimpleIdentifierUnchecked();
1363 }
1364 if (!_inLoop && !_inSwitch && label == null) {
1365 _reportErrorForToken(ParserErrorCode.BREAK_OUTSIDE_OF_LOOP, breakKeyword);
1366 }
1367 Token semicolon = _expect(TokenType.SEMICOLON);
1368 return new BreakStatement(breakKeyword, label, semicolon);
1369 }
1370
1371 /**
1372 * Parse a cascade section. Return the expression representing the cascaded
1373 * method invocation.
1374 *
1375 * This method assumes that the current token matches
1376 * `TokenType.PERIOD_PERIOD`.
1377 *
1378 * cascadeSection ::=
1379 * '..' (cascadeSelector typeArguments? arguments*)
1380 * (assignableSelector typeArguments? arguments*)* cascadeAssignment?
1381 *
1382 * cascadeSelector ::=
1383 * '[' expression ']'
1384 * | identifier
1385 *
1386 * cascadeAssignment ::=
1387 * assignmentOperator expressionWithoutCascade
1388 */
1389 Expression parseCascadeSection() {
1390 Token period = getAndAdvance();
1391 Expression expression = null;
1392 SimpleIdentifier functionName = null;
1393 if (_matchesIdentifier()) {
1394 functionName = _parseSimpleIdentifierUnchecked();
1395 } else if (_currentToken.type == TokenType.OPEN_SQUARE_BRACKET) {
1396 Token leftBracket = getAndAdvance();
1397 bool wasInInitializer = _inInitializer;
1398 _inInitializer = false;
1399 try {
1400 Expression index = parseExpression2();
1401 Token rightBracket = _expect(TokenType.CLOSE_SQUARE_BRACKET);
1402 expression = new IndexExpression.forCascade(
1403 period, leftBracket, index, rightBracket);
1404 period = null;
1405 } finally {
1406 _inInitializer = wasInInitializer;
1407 }
1408 } else {
1409 _reportErrorForToken(ParserErrorCode.MISSING_IDENTIFIER, _currentToken,
1410 [_currentToken.lexeme]);
1411 functionName = createSyntheticIdentifier();
1412 }
1413 assert((expression == null && functionName != null) ||
1414 (expression != null && functionName == null));
1415 if (_isLikelyArgumentList()) {
1416 do {
1417 TypeArgumentList typeArguments = _parseOptionalTypeArguments();
1418 if (functionName != null) {
1419 expression = new MethodInvocation(expression, period, functionName,
1420 typeArguments, parseArgumentList());
1421 period = null;
1422 functionName = null;
1423 } else if (expression == null) {
1424 // It should not be possible to get here.
1425 expression = new MethodInvocation(expression, period,
1426 createSyntheticIdentifier(), typeArguments, parseArgumentList());
1427 } else {
1428 expression = new FunctionExpressionInvocation(
1429 expression, typeArguments, parseArgumentList());
1430 }
1431 } while (_isLikelyArgumentList());
1432 } else if (functionName != null) {
1433 expression = new PropertyAccess(expression, period, functionName);
1434 period = null;
1435 }
1436 assert(expression != null);
1437 bool progress = true;
1438 while (progress) {
1439 progress = false;
1440 Expression selector = _parseAssignableSelector(expression, true);
1441 if (!identical(selector, expression)) {
1442 expression = selector;
1443 progress = true;
1444 while (_isLikelyArgumentList()) {
1445 TypeArgumentList typeArguments = _parseOptionalTypeArguments();
1446 Expression currentExpression = expression;
1447 if (currentExpression is PropertyAccess) {
1448 expression = new MethodInvocation(
1449 currentExpression.target,
1450 currentExpression.operator,
1451 currentExpression.propertyName,
1452 typeArguments,
1453 parseArgumentList());
1454 } else {
1455 expression = new FunctionExpressionInvocation(
1456 expression, typeArguments, parseArgumentList());
1457 }
1458 }
1459 }
1460 }
1461 if (_currentToken.type.isAssignmentOperator) {
1462 Token operator = getAndAdvance();
1463 _ensureAssignable(expression);
1464 expression = new AssignmentExpression(
1465 expression, operator, parseExpressionWithoutCascade());
1466 }
1467 return expression;
1468 }
1469
1470 /**
1471 * Parse a class declaration. The [commentAndMetadata] is the metadata to be
1472 * associated with the member. The [abstractKeyword] is the token for the
1473 * keyword 'abstract', or `null` if the keyword was not given. Return the
1474 * class declaration that was parsed.
1475 *
1476 * This method assumes that the current token matches `Keyword.CLASS`.
1477 *
1478 * classDeclaration ::=
1479 * metadata 'abstract'? 'class' name typeParameterList? (extendsClause withClause?)? implementsClause? '{' classMembers '}' |
1480 * metadata 'abstract'? 'class' mixinApplicationClass
1481 */
1482 CompilationUnitMember parseClassDeclaration(
1483 CommentAndMetadata commentAndMetadata, Token abstractKeyword) {
1484 //
1485 // Parse the name and type parameters.
1486 //
1487 Token keyword = getAndAdvance();
1488 SimpleIdentifier name = parseSimpleIdentifier(isDeclaration: true);
1489 String className = name.name;
1490 TypeParameterList typeParameters = null;
1491 TokenType type = _currentToken.type;
1492 if (type == TokenType.LT) {
1493 typeParameters = parseTypeParameterList();
1494 type = _currentToken.type;
1495 }
1496 //
1497 // Check to see whether this might be a class type alias rather than a class
1498 // declaration.
1499 //
1500 if (type == TokenType.EQ) {
1501 return _parseClassTypeAliasAfterName(
1502 commentAndMetadata, abstractKeyword, keyword, name, typeParameters);
1503 }
1504 //
1505 // Parse the clauses. The parser accepts clauses in any order, but will
1506 // generate errors if they are not in the order required by the
1507 // specification.
1508 //
1509 ExtendsClause extendsClause = null;
1510 WithClause withClause = null;
1511 ImplementsClause implementsClause = null;
1512 bool foundClause = true;
1513 while (foundClause) {
1514 Keyword keyword = _currentToken.keyword;
1515 if (keyword == Keyword.EXTENDS) {
1516 if (extendsClause == null) {
1517 extendsClause = parseExtendsClause();
1518 if (withClause != null) {
1519 _reportErrorForToken(
1520 ParserErrorCode.WITH_BEFORE_EXTENDS, withClause.withKeyword);
1521 } else if (implementsClause != null) {
1522 _reportErrorForToken(ParserErrorCode.IMPLEMENTS_BEFORE_EXTENDS,
1523 implementsClause.implementsKeyword);
1524 }
1525 } else {
1526 _reportErrorForToken(ParserErrorCode.MULTIPLE_EXTENDS_CLAUSES,
1527 extendsClause.extendsKeyword);
1528 parseExtendsClause();
1529 }
1530 } else if (keyword == Keyword.WITH) {
1531 if (withClause == null) {
1532 withClause = parseWithClause();
1533 if (implementsClause != null) {
1534 _reportErrorForToken(ParserErrorCode.IMPLEMENTS_BEFORE_WITH,
1535 implementsClause.implementsKeyword);
1536 }
1537 } else {
1538 _reportErrorForToken(
1539 ParserErrorCode.MULTIPLE_WITH_CLAUSES, withClause.withKeyword);
1540 parseWithClause();
1541 // TODO(brianwilkerson) Should we merge the list of applied mixins
1542 // into a single list?
1543 }
1544 } else if (keyword == Keyword.IMPLEMENTS) {
1545 if (implementsClause == null) {
1546 implementsClause = parseImplementsClause();
1547 } else {
1548 _reportErrorForToken(ParserErrorCode.MULTIPLE_IMPLEMENTS_CLAUSES,
1549 implementsClause.implementsKeyword);
1550 parseImplementsClause();
1551 // TODO(brianwilkerson) Should we merge the list of implemented
1552 // classes into a single list?
1553 }
1554 } else {
1555 foundClause = false;
1556 }
1557 }
1558 if (withClause != null && extendsClause == null) {
1559 _reportErrorForToken(
1560 ParserErrorCode.WITH_WITHOUT_EXTENDS, withClause.withKeyword);
1561 }
1562 //
1563 // Look for and skip over the extra-lingual 'native' specification.
1564 //
1565 NativeClause nativeClause = null;
1566 if (_matchesString(_NATIVE) && _tokenMatches(_peek(), TokenType.STRING)) {
1567 nativeClause = _parseNativeClause();
1568 }
1569 //
1570 // Parse the body of the class.
1571 //
1572 Token leftBracket = null;
1573 List<ClassMember> members = null;
1574 Token rightBracket = null;
1575 if (_matches(TokenType.OPEN_CURLY_BRACKET)) {
1576 leftBracket = getAndAdvance();
1577 members = _parseClassMembers(className, _getEndToken(leftBracket));
1578 rightBracket = _expect(TokenType.CLOSE_CURLY_BRACKET);
1579 } else {
1580 // Recovery: Check for an unmatched closing curly bracket and parse
1581 // members until it is reached.
1582 leftBracket = _createSyntheticToken(TokenType.OPEN_CURLY_BRACKET);
1583 rightBracket = _createSyntheticToken(TokenType.CLOSE_CURLY_BRACKET);
1584 _reportErrorForCurrentToken(ParserErrorCode.MISSING_CLASS_BODY);
1585 }
1586 ClassDeclaration classDeclaration = new ClassDeclaration(
1587 commentAndMetadata.comment,
1588 commentAndMetadata.metadata,
1589 abstractKeyword,
1590 keyword,
1591 name,
1592 typeParameters,
1593 extendsClause,
1594 withClause,
1595 implementsClause,
1596 leftBracket,
1597 members,
1598 rightBracket);
1599 classDeclaration.nativeClause = nativeClause;
1600 return classDeclaration;
1601 }
1602
1603 /**
1001 * Parse a class member. The [className] is the name of the class containing 1604 * Parse a class member. The [className] is the name of the class containing
1002 * the member being parsed. Return the class member that was parsed, or `null` 1605 * the member being parsed. Return the class member that was parsed, or `null`
1003 * if what was found was not a valid class member. 1606 * if what was found was not a valid class member.
1004 * 1607 *
1005 * classMemberDefinition ::= 1608 * classMemberDefinition ::=
1006 * declaration ';' 1609 * declaration ';'
1007 * | methodSignature functionBody 1610 * | methodSignature functionBody
1008 */ 1611 */
1009 ClassMember parseClassMember(String className) { 1612 ClassMember parseClassMember(String className) {
1010 CommentAndMetadata commentAndMetadata = _parseCommentAndMetadata(); 1613 CommentAndMetadata commentAndMetadata = parseCommentAndMetadata();
1011 Modifiers modifiers = _parseModifiers(); 1614 Modifiers modifiers = _parseModifiers();
1012 Keyword keyword = _currentToken.keyword; 1615 Keyword keyword = _currentToken.keyword;
1013 if (keyword == Keyword.VOID) { 1616 if (keyword == Keyword.VOID) {
1014 TypeName returnType = 1617 TypeName returnType =
1015 new TypeName(new SimpleIdentifier(getAndAdvance()), null); 1618 new TypeName(new SimpleIdentifier(getAndAdvance()), null);
1016 keyword = _currentToken.keyword; 1619 keyword = _currentToken.keyword;
1017 Token next = _peek(); 1620 Token next = _peek();
1018 bool isFollowedByIdentifier = _tokenMatchesIdentifier(next); 1621 bool isFollowedByIdentifier = _tokenMatchesIdentifier(next);
1019 if (keyword == Keyword.GET && isFollowedByIdentifier) { 1622 if (keyword == Keyword.GET && isFollowedByIdentifier) {
1020 _validateModifiersForGetterOrSetterOrMethod(modifiers); 1623 _validateModifiersForGetterOrSetterOrMethod(modifiers);
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
1058 _validateModifiersForField(modifiers), 1661 _validateModifiersForField(modifiers),
1059 returnType); 1662 returnType);
1060 } 1663 }
1061 } 1664 }
1062 if (_isOperator(_currentToken)) { 1665 if (_isOperator(_currentToken)) {
1063 // 1666 //
1064 // We appear to have found an operator declaration without the 1667 // We appear to have found an operator declaration without the
1065 // 'operator' keyword. 1668 // 'operator' keyword.
1066 // 1669 //
1067 _validateModifiersForOperator(modifiers); 1670 _validateModifiersForOperator(modifiers);
1068 return _parseOperator( 1671 return parseOperator(
1069 commentAndMetadata, modifiers.externalKeyword, returnType); 1672 commentAndMetadata, modifiers.externalKeyword, returnType);
1070 } 1673 }
1071 _reportErrorForToken( 1674 _reportErrorForToken(
1072 ParserErrorCode.EXPECTED_EXECUTABLE, _currentToken); 1675 ParserErrorCode.EXPECTED_EXECUTABLE, _currentToken);
1073 return null; 1676 return null;
1074 } 1677 }
1075 } 1678 }
1076 Token next = _peek(); 1679 Token next = _peek();
1077 bool isFollowedByIdentifier = _tokenMatchesIdentifier(next); 1680 bool isFollowedByIdentifier = _tokenMatchesIdentifier(next);
1078 if (keyword == Keyword.GET && isFollowedByIdentifier) { 1681 if (keyword == Keyword.GET && isFollowedByIdentifier) {
1079 _validateModifiersForGetterOrSetterOrMethod(modifiers); 1682 _validateModifiersForGetterOrSetterOrMethod(modifiers);
1080 return _parseGetter(commentAndMetadata, modifiers.externalKeyword, 1683 return _parseGetter(commentAndMetadata, modifiers.externalKeyword,
1081 modifiers.staticKeyword, null); 1684 modifiers.staticKeyword, null);
1082 } else if (keyword == Keyword.SET && isFollowedByIdentifier) { 1685 } else if (keyword == Keyword.SET && isFollowedByIdentifier) {
1083 _validateModifiersForGetterOrSetterOrMethod(modifiers); 1686 _validateModifiersForGetterOrSetterOrMethod(modifiers);
1084 return _parseSetter(commentAndMetadata, modifiers.externalKeyword, 1687 return _parseSetter(commentAndMetadata, modifiers.externalKeyword,
1085 modifiers.staticKeyword, null); 1688 modifiers.staticKeyword, null);
1086 } else if (keyword == Keyword.OPERATOR && _isOperator(next)) { 1689 } else if (keyword == Keyword.OPERATOR && _isOperator(next)) {
1087 _validateModifiersForOperator(modifiers); 1690 _validateModifiersForOperator(modifiers);
1088 return _parseOperatorAfterKeyword( 1691 return _parseOperatorAfterKeyword(
1089 commentAndMetadata, modifiers.externalKeyword, null, getAndAdvance()); 1692 commentAndMetadata, modifiers.externalKeyword, null, getAndAdvance());
1090 } else if (!_matchesIdentifier()) { 1693 } else if (!_matchesIdentifier()) {
1091 // 1694 //
1092 // Recover from an error. 1695 // Recover from an error.
1093 // 1696 //
1094 if (_matchesKeyword(Keyword.CLASS)) { 1697 if (_matchesKeyword(Keyword.CLASS)) {
1095 _reportErrorForCurrentToken(ParserErrorCode.CLASS_IN_CLASS); 1698 _reportErrorForCurrentToken(ParserErrorCode.CLASS_IN_CLASS);
1096 // TODO(brianwilkerson) We don't currently have any way to capture the 1699 // TODO(brianwilkerson) We don't currently have any way to capture the
1097 // class that was parsed. 1700 // class that was parsed.
1098 _parseClassDeclaration(commentAndMetadata, null); 1701 parseClassDeclaration(commentAndMetadata, null);
1099 return null; 1702 return null;
1100 } else if (_matchesKeyword(Keyword.ABSTRACT) && 1703 } else if (_matchesKeyword(Keyword.ABSTRACT) &&
1101 _tokenMatchesKeyword(_peek(), Keyword.CLASS)) { 1704 _tokenMatchesKeyword(_peek(), Keyword.CLASS)) {
1102 _reportErrorForToken(ParserErrorCode.CLASS_IN_CLASS, _peek()); 1705 _reportErrorForToken(ParserErrorCode.CLASS_IN_CLASS, _peek());
1103 // TODO(brianwilkerson) We don't currently have any way to capture the 1706 // TODO(brianwilkerson) We don't currently have any way to capture the
1104 // class that was parsed. 1707 // class that was parsed.
1105 _parseClassDeclaration(commentAndMetadata, getAndAdvance()); 1708 parseClassDeclaration(commentAndMetadata, getAndAdvance());
1106 return null; 1709 return null;
1107 } else if (_matchesKeyword(Keyword.ENUM)) { 1710 } else if (_matchesKeyword(Keyword.ENUM)) {
1108 _reportErrorForToken(ParserErrorCode.ENUM_IN_CLASS, _peek()); 1711 _reportErrorForToken(ParserErrorCode.ENUM_IN_CLASS, _peek());
1109 // TODO(brianwilkerson) We don't currently have any way to capture the 1712 // TODO(brianwilkerson) We don't currently have any way to capture the
1110 // enum that was parsed. 1713 // enum that was parsed.
1111 _parseEnumDeclaration(commentAndMetadata); 1714 parseEnumDeclaration(commentAndMetadata);
1112 return null; 1715 return null;
1113 } else if (_isOperator(_currentToken)) { 1716 } else if (_isOperator(_currentToken)) {
1114 // 1717 //
1115 // We appear to have found an operator declaration without the 1718 // We appear to have found an operator declaration without the
1116 // 'operator' keyword. 1719 // 'operator' keyword.
1117 // 1720 //
1118 _validateModifiersForOperator(modifiers); 1721 _validateModifiersForOperator(modifiers);
1119 return _parseOperator( 1722 return parseOperator(
1120 commentAndMetadata, modifiers.externalKeyword, null); 1723 commentAndMetadata, modifiers.externalKeyword, null);
1121 } 1724 }
1122 Token keyword = modifiers.varKeyword; 1725 Token keyword = modifiers.varKeyword;
1123 if (keyword == null) { 1726 if (keyword == null) {
1124 keyword = modifiers.finalKeyword; 1727 keyword = modifiers.finalKeyword;
1125 } 1728 }
1126 if (keyword == null) { 1729 if (keyword == null) {
1127 keyword = modifiers.constKeyword; 1730 keyword = modifiers.constKeyword;
1128 } 1731 }
1129 if (keyword != null) { 1732 if (keyword != null) {
1130 // 1733 //
1131 // We appear to have found an incomplete field declaration. 1734 // We appear to have found an incomplete field declaration.
1132 // 1735 //
1133 _reportErrorForCurrentToken(ParserErrorCode.MISSING_IDENTIFIER); 1736 _reportErrorForCurrentToken(ParserErrorCode.MISSING_IDENTIFIER);
1134 VariableDeclaration variable = 1737 VariableDeclaration variable =
1135 new VariableDeclaration(_createSyntheticIdentifier(), null, null); 1738 new VariableDeclaration(createSyntheticIdentifier(), null, null);
1136 List<VariableDeclaration> variables = <VariableDeclaration>[variable]; 1739 List<VariableDeclaration> variables = <VariableDeclaration>[variable];
1137 return new FieldDeclaration( 1740 return new FieldDeclaration(
1138 commentAndMetadata.comment, 1741 commentAndMetadata.comment,
1139 commentAndMetadata.metadata, 1742 commentAndMetadata.metadata,
1140 null, 1743 null,
1141 new VariableDeclarationList(null, null, keyword, null, variables), 1744 new VariableDeclarationList(null, null, keyword, null, variables),
1142 _expect(TokenType.SEMICOLON)); 1745 _expect(TokenType.SEMICOLON));
1143 } 1746 }
1144 _reportErrorForToken( 1747 _reportErrorForToken(
1145 ParserErrorCode.EXPECTED_CLASS_MEMBER, _currentToken); 1748 ParserErrorCode.EXPECTED_CLASS_MEMBER, _currentToken);
1146 if (commentAndMetadata.comment != null || 1749 if (commentAndMetadata.comment != null ||
1147 commentAndMetadata.hasMetadata) { 1750 commentAndMetadata.hasMetadata) {
1148 // 1751 //
1149 // We appear to have found an incomplete declaration at the end of the 1752 // We appear to have found an incomplete declaration at the end of the
1150 // class. At this point it consists of a metadata, which we don't want 1753 // class. At this point it consists of a metadata, which we don't want
1151 // to loose, so we'll treat it as a method declaration with a missing 1754 // to loose, so we'll treat it as a method declaration with a missing
1152 // name, parameters and empty body. 1755 // name, parameters and empty body.
1153 // 1756 //
1154 return new MethodDeclaration( 1757 return new MethodDeclaration(
1155 commentAndMetadata.comment, 1758 commentAndMetadata.comment,
1156 commentAndMetadata.metadata, 1759 commentAndMetadata.metadata,
1157 null, 1760 null,
1158 null, 1761 null,
1159 null, 1762 null,
1160 null, 1763 null,
1161 null, 1764 null,
1162 _createSyntheticIdentifier(isDeclaration: true), 1765 createSyntheticIdentifier(isDeclaration: true),
1163 null, 1766 null,
1164 new FormalParameterList( 1767 new FormalParameterList(
1165 null, <FormalParameter>[], null, null, null), 1768 null, <FormalParameter>[], null, null, null),
1166 new EmptyFunctionBody(_createSyntheticToken(TokenType.SEMICOLON))); 1769 new EmptyFunctionBody(_createSyntheticToken(TokenType.SEMICOLON)));
1167 } 1770 }
1168 return null; 1771 return null;
1169 } else if (_tokenMatches(next, TokenType.PERIOD) && 1772 } else if (_tokenMatches(next, TokenType.PERIOD) &&
1170 _tokenMatchesIdentifier(_peekAt(2)) && 1773 _tokenMatchesIdentifier(_peekAt(2)) &&
1171 _tokenMatches(_peekAt(3), TokenType.OPEN_PAREN)) { 1774 _tokenMatches(_peekAt(3), TokenType.OPEN_PAREN)) {
1172 return _parseConstructor( 1775 return _parseConstructor(
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after
1260 modifiers.staticKeyword, 1863 modifiers.staticKeyword,
1261 _validateModifiersForField(modifiers), 1864 _validateModifiersForField(modifiers),
1262 type); 1865 type);
1263 } 1866 }
1264 if (_isOperator(_currentToken)) { 1867 if (_isOperator(_currentToken)) {
1265 // 1868 //
1266 // We appear to have found an operator declaration without the 1869 // We appear to have found an operator declaration without the
1267 // 'operator' keyword. 1870 // 'operator' keyword.
1268 // 1871 //
1269 _validateModifiersForOperator(modifiers); 1872 _validateModifiersForOperator(modifiers);
1270 return _parseOperator( 1873 return parseOperator(
1271 commentAndMetadata, modifiers.externalKeyword, type); 1874 commentAndMetadata, modifiers.externalKeyword, type);
1272 } 1875 }
1273 // 1876 //
1274 // We appear to have found an incomplete declaration before another 1877 // We appear to have found an incomplete declaration before another
1275 // declaration. At this point it consists of a type name, so we'll treat 1878 // declaration. At this point it consists of a type name, so we'll treat
1276 // it as a field declaration with a missing field name and semicolon. 1879 // it as a field declaration with a missing field name and semicolon.
1277 // 1880 //
1278 _reportErrorForToken( 1881 _reportErrorForToken(
1279 ParserErrorCode.EXPECTED_CLASS_MEMBER, _currentToken); 1882 ParserErrorCode.EXPECTED_CLASS_MEMBER, _currentToken);
1280 try { 1883 try {
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after
1325 _currentToken = _injectToken( 1928 _currentToken = _injectToken(
1326 new Parser_SyntheticKeywordToken(Keyword.GET, _currentToken.offset)); 1929 new Parser_SyntheticKeywordToken(Keyword.GET, _currentToken.offset));
1327 return _parseGetter(commentAndMetadata, modifiers.externalKeyword, 1930 return _parseGetter(commentAndMetadata, modifiers.externalKeyword,
1328 modifiers.staticKeyword, type); 1931 modifiers.staticKeyword, type);
1329 } 1932 }
1330 return _parseInitializedIdentifierList(commentAndMetadata, 1933 return _parseInitializedIdentifierList(commentAndMetadata,
1331 modifiers.staticKeyword, _validateModifiersForField(modifiers), type); 1934 modifiers.staticKeyword, _validateModifiersForField(modifiers), type);
1332 } 1935 }
1333 1936
1334 /** 1937 /**
1938 * Parse a class type alias. The [commentAndMetadata] is the metadata to be
1939 * associated with the member. The [abstractKeyword] is the token representing
1940 * the 'abstract' keyword. The [classKeyword] is the token representing the
1941 * 'class' keyword. Return the class type alias that was parsed.
1942 *
1943 * This method assumes that the current token matches an identifier.
1944 *
1945 * classTypeAlias ::=
1946 * identifier typeParameters? '=' 'abstract'? mixinApplication
1947 *
1948 * mixinApplication ::=
1949 * type withClause implementsClause? ';'
1950 */
1951 ClassTypeAlias parseClassTypeAlias(CommentAndMetadata commentAndMetadata,
1952 Token abstractKeyword, Token classKeyword) {
1953 SimpleIdentifier className =
1954 _parseSimpleIdentifierUnchecked(isDeclaration: true);
1955 TypeParameterList typeParameters = null;
1956 if (_matches(TokenType.LT)) {
1957 typeParameters = parseTypeParameterList();
1958 }
1959 return _parseClassTypeAliasAfterName(commentAndMetadata, abstractKeyword,
1960 classKeyword, className, typeParameters);
1961 }
1962
1963 /**
1335 * Parse a single combinator. Return the combinator that was parsed, or `null` 1964 * Parse a single combinator. Return the combinator that was parsed, or `null`
1336 * if no combinator is found. 1965 * if no combinator is found.
1337 * 1966 *
1338 * combinator ::= 1967 * combinator ::=
1339 * 'show' identifier (',' identifier)* 1968 * 'show' identifier (',' identifier)*
1340 * | 'hide' identifier (',' identifier)* 1969 * | 'hide' identifier (',' identifier)*
1341 */ 1970 */
1342 Combinator parseCombinator() { 1971 Combinator parseCombinator() {
1343 if (_matchesString(_SHOW)) { 1972 if (_matchesString(_SHOW)) {
1344 return new ShowCombinator(getAndAdvance(), _parseIdentifierList()); 1973 return new ShowCombinator(getAndAdvance(), _parseIdentifierList());
1345 } else if (_matchesString(_HIDE)) { 1974 } else if (_matchesString(_HIDE)) {
1346 return new HideCombinator(getAndAdvance(), _parseIdentifierList()); 1975 return new HideCombinator(getAndAdvance(), _parseIdentifierList());
1347 } 1976 }
1348 return null; 1977 return null;
1349 } 1978 }
1350 1979
1351 /** 1980 /**
1981 * Parse a list of combinators in a directive. Return the combinators that
1982 * were parsed, or `null` if there are no combinators.
1983 *
1984 * combinator ::=
1985 * 'show' identifier (',' identifier)*
1986 * | 'hide' identifier (',' identifier)*
1987 */
1988 List<Combinator> parseCombinators() {
1989 List<Combinator> combinators = null;
1990 while (true) {
1991 Combinator combinator = parseCombinator();
1992 if (combinator == null) {
1993 break;
1994 }
1995 combinators ??= <Combinator>[];
1996 combinators.add(combinator);
1997 }
1998 return combinators;
1999 }
2000
2001 /**
2002 * Parse the documentation comment and metadata preceding a declaration. This
2003 * method allows any number of documentation comments to occur before, after
2004 * or between the metadata, but only returns the last (right-most)
2005 * documentation comment that is found. Return the documentation comment and
2006 * metadata that were parsed.
2007 *
2008 * metadata ::=
2009 * annotation*
2010 */
2011 CommentAndMetadata parseCommentAndMetadata() {
2012 // TODO(brianwilkerson) Consider making the creation of documentation
2013 // comments be lazy.
2014 List<DocumentationCommentToken> tokens = parseDocumentationCommentTokens();
2015 List<Annotation> metadata = null;
2016 while (_matches(TokenType.AT)) {
2017 metadata ??= <Annotation>[];
2018 metadata.add(parseAnnotation());
2019 List<DocumentationCommentToken> optionalTokens =
2020 parseDocumentationCommentTokens();
2021 if (optionalTokens != null) {
2022 tokens = optionalTokens;
2023 }
2024 }
2025 return new CommentAndMetadata(parseDocumentationComment(tokens), metadata);
2026 }
2027
2028 /**
2029 * Parse a comment reference from the source between square brackets. The
2030 * [referenceSource] is the source occurring between the square brackets
2031 * within a documentation comment. The [sourceOffset] is the offset of the
2032 * first character of the reference source. Return the comment reference that
2033 * was parsed, or `null` if no reference could be found.
2034 *
2035 * commentReference ::=
2036 * 'new'? prefixedIdentifier
2037 */
2038 CommentReference parseCommentReference(
2039 String referenceSource, int sourceOffset) {
2040 // TODO(brianwilkerson) The errors are not getting the right offset/length
2041 // and are being duplicated.
2042 try {
2043 BooleanErrorListener listener = new BooleanErrorListener();
2044 Scanner scanner = new Scanner(
2045 null, new SubSequenceReader(referenceSource, sourceOffset), listener);
2046 scanner.setSourceStart(1, 1);
2047 Token firstToken = scanner.tokenize();
2048 if (listener.errorReported) {
2049 return null;
2050 }
2051 if (firstToken.type == TokenType.EOF) {
2052 Token syntheticToken =
2053 new SyntheticStringToken(TokenType.IDENTIFIER, "", sourceOffset);
2054 syntheticToken.setNext(firstToken);
2055 return new CommentReference(null, new SimpleIdentifier(syntheticToken));
2056 }
2057 Token newKeyword = null;
2058 if (_tokenMatchesKeyword(firstToken, Keyword.NEW)) {
2059 newKeyword = firstToken;
2060 firstToken = firstToken.next;
2061 }
2062 if (firstToken.isUserDefinableOperator) {
2063 if (firstToken.next.type != TokenType.EOF) {
2064 return null;
2065 }
2066 Identifier identifier = new SimpleIdentifier(firstToken);
2067 return new CommentReference(null, identifier);
2068 } else if (_tokenMatchesKeyword(firstToken, Keyword.OPERATOR)) {
2069 Token secondToken = firstToken.next;
2070 if (secondToken.isUserDefinableOperator) {
2071 if (secondToken.next.type != TokenType.EOF) {
2072 return null;
2073 }
2074 Identifier identifier = new SimpleIdentifier(secondToken);
2075 return new CommentReference(null, identifier);
2076 }
2077 return null;
2078 } else if (_tokenMatchesIdentifier(firstToken)) {
2079 Token secondToken = firstToken.next;
2080 Token thirdToken = secondToken.next;
2081 Token nextToken;
2082 Identifier identifier;
2083 if (_tokenMatches(secondToken, TokenType.PERIOD)) {
2084 if (thirdToken.isUserDefinableOperator) {
2085 identifier = new PrefixedIdentifier(
2086 new SimpleIdentifier(firstToken),
2087 secondToken,
2088 new SimpleIdentifier(thirdToken));
2089 nextToken = thirdToken.next;
2090 } else if (_tokenMatchesKeyword(thirdToken, Keyword.OPERATOR)) {
2091 Token fourthToken = thirdToken.next;
2092 if (fourthToken.isUserDefinableOperator) {
2093 identifier = new PrefixedIdentifier(
2094 new SimpleIdentifier(firstToken),
2095 secondToken,
2096 new SimpleIdentifier(fourthToken));
2097 nextToken = fourthToken.next;
2098 } else {
2099 return null;
2100 }
2101 } else if (_tokenMatchesIdentifier(thirdToken)) {
2102 identifier = new PrefixedIdentifier(
2103 new SimpleIdentifier(firstToken),
2104 secondToken,
2105 new SimpleIdentifier(thirdToken));
2106 nextToken = thirdToken.next;
2107 }
2108 } else {
2109 identifier = new SimpleIdentifier(firstToken);
2110 nextToken = firstToken.next;
2111 }
2112 if (nextToken.type != TokenType.EOF) {
2113 return null;
2114 }
2115 return new CommentReference(newKeyword, identifier);
2116 } else {
2117 Keyword keyword = firstToken.keyword;
2118 if (keyword == Keyword.THIS ||
2119 keyword == Keyword.NULL ||
2120 keyword == Keyword.TRUE ||
2121 keyword == Keyword.FALSE) {
2122 // TODO(brianwilkerson) If we want to support this we will need to
2123 // extend the definition of CommentReference to take an expression
2124 // rather than an identifier. For now we just ignore it to reduce the
2125 // number of errors produced, but that's probably not a valid long ter m
2126 // approach.
2127 return null;
2128 }
2129 }
2130 } catch (exception) {
2131 // Ignored because we assume that it wasn't a real comment reference.
2132 }
2133 return null;
2134 }
2135
2136 /**
1352 * Parse a compilation unit, starting with the given [token]. Return the 2137 * Parse a compilation unit, starting with the given [token]. Return the
1353 * compilation unit that was parsed. 2138 * compilation unit that was parsed.
1354 */ 2139 */
1355 CompilationUnit parseCompilationUnit(Token token) { 2140 CompilationUnit parseCompilationUnit(Token token) {
1356 _currentToken = token; 2141 _currentToken = token;
1357 return parseCompilationUnit2(); 2142 return parseCompilationUnit2();
1358 } 2143 }
1359 2144
1360 /** 2145 /**
1361 * Parse a compilation unit. Return the compilation unit that was parsed. 2146 * Parse a compilation unit. Return the compilation unit that was parsed.
(...skipping 25 matching lines...) Expand all
1387 // 2172 //
1388 bool libraryDirectiveFound = false; 2173 bool libraryDirectiveFound = false;
1389 bool partOfDirectiveFound = false; 2174 bool partOfDirectiveFound = false;
1390 bool partDirectiveFound = false; 2175 bool partDirectiveFound = false;
1391 bool directiveFoundAfterDeclaration = false; 2176 bool directiveFoundAfterDeclaration = false;
1392 List<Directive> directives = <Directive>[]; 2177 List<Directive> directives = <Directive>[];
1393 List<CompilationUnitMember> declarations = <CompilationUnitMember>[]; 2178 List<CompilationUnitMember> declarations = <CompilationUnitMember>[];
1394 Token memberStart = _currentToken; 2179 Token memberStart = _currentToken;
1395 TokenType type = _currentToken.type; 2180 TokenType type = _currentToken.type;
1396 while (type != TokenType.EOF) { 2181 while (type != TokenType.EOF) {
1397 CommentAndMetadata commentAndMetadata = _parseCommentAndMetadata(); 2182 CommentAndMetadata commentAndMetadata = parseCommentAndMetadata();
1398 Keyword keyword = _currentToken.keyword; 2183 Keyword keyword = _currentToken.keyword;
1399 TokenType nextType = _currentToken.next.type; 2184 TokenType nextType = _currentToken.next.type;
1400 if ((keyword == Keyword.IMPORT || 2185 if ((keyword == Keyword.IMPORT ||
1401 keyword == Keyword.EXPORT || 2186 keyword == Keyword.EXPORT ||
1402 keyword == Keyword.LIBRARY || 2187 keyword == Keyword.LIBRARY ||
1403 keyword == Keyword.PART) && 2188 keyword == Keyword.PART) &&
1404 nextType != TokenType.PERIOD && 2189 nextType != TokenType.PERIOD &&
1405 nextType != TokenType.LT && 2190 nextType != TokenType.LT &&
1406 nextType != TokenType.OPEN_PAREN) { 2191 nextType != TokenType.OPEN_PAREN) {
1407 Directive parseDirective() { 2192 Directive parseDirective() {
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after
1454 directives.add(directive); 2239 directives.add(directive);
1455 } else if (type == TokenType.SEMICOLON) { 2240 } else if (type == TokenType.SEMICOLON) {
1456 // TODO(brianwilkerson) Consider moving this error detection into 2241 // TODO(brianwilkerson) Consider moving this error detection into
1457 // _parseCompilationUnitMember (in the places where EXPECTED_EXECUTABLE 2242 // _parseCompilationUnitMember (in the places where EXPECTED_EXECUTABLE
1458 // is being generated). 2243 // is being generated).
1459 _reportErrorForToken(ParserErrorCode.UNEXPECTED_TOKEN, _currentToken, 2244 _reportErrorForToken(ParserErrorCode.UNEXPECTED_TOKEN, _currentToken,
1460 [_currentToken.lexeme]); 2245 [_currentToken.lexeme]);
1461 _advance(); 2246 _advance();
1462 } else { 2247 } else {
1463 CompilationUnitMember member = 2248 CompilationUnitMember member =
1464 _parseCompilationUnitMember(commentAndMetadata); 2249 parseCompilationUnitMember(commentAndMetadata);
1465 if (member != null) { 2250 if (member != null) {
1466 declarations.add(member); 2251 declarations.add(member);
1467 } 2252 }
1468 } 2253 }
1469 if (identical(_currentToken, memberStart)) { 2254 if (identical(_currentToken, memberStart)) {
1470 _reportErrorForToken(ParserErrorCode.UNEXPECTED_TOKEN, _currentToken, 2255 _reportErrorForToken(ParserErrorCode.UNEXPECTED_TOKEN, _currentToken,
1471 [_currentToken.lexeme]); 2256 [_currentToken.lexeme]);
1472 _advance(); 2257 _advance();
1473 while (!_matches(TokenType.EOF) && 2258 while (!_matches(TokenType.EOF) &&
1474 !_couldBeStartOfCompilationUnitMember()) { 2259 !_couldBeStartOfCompilationUnitMember()) {
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
1507 directives[i].keyword); 2292 directives[i].keyword);
1508 } 2293 }
1509 // } 2294 // }
1510 } 2295 }
1511 } 2296 }
1512 return new CompilationUnit( 2297 return new CompilationUnit(
1513 firstToken, scriptTag, directives, declarations, _currentToken); 2298 firstToken, scriptTag, directives, declarations, _currentToken);
1514 } 2299 }
1515 2300
1516 /** 2301 /**
2302 * Parse a compilation unit member. The [commentAndMetadata] is the metadata
2303 * to be associated with the member. Return the compilation unit member that
2304 * was parsed, or `null` if what was parsed could not be represented as a
2305 * compilation unit member.
2306 *
2307 * compilationUnitMember ::=
2308 * classDefinition
2309 * | functionTypeAlias
2310 * | external functionSignature
2311 * | external getterSignature
2312 * | external setterSignature
2313 * | functionSignature functionBody
2314 * | returnType? getOrSet identifier formalParameterList functionBody
2315 * | (final | const) type? staticFinalDeclarationList ';'
2316 * | variableDeclaration ';'
2317 */
2318 CompilationUnitMember parseCompilationUnitMember(
2319 CommentAndMetadata commentAndMetadata) {
2320 Modifiers modifiers = _parseModifiers();
2321 Keyword keyword = _currentToken.keyword;
2322 if (keyword == Keyword.CLASS) {
2323 return parseClassDeclaration(
2324 commentAndMetadata, _validateModifiersForClass(modifiers));
2325 }
2326 Token next = _peek();
2327 TokenType nextType = next.type;
2328 if (keyword == Keyword.TYPEDEF &&
2329 nextType != TokenType.PERIOD &&
2330 nextType != TokenType.LT &&
2331 nextType != TokenType.OPEN_PAREN) {
2332 _validateModifiersForTypedef(modifiers);
2333 return _parseTypeAlias(commentAndMetadata);
2334 } else if (keyword == Keyword.ENUM) {
2335 _validateModifiersForEnum(modifiers);
2336 return parseEnumDeclaration(commentAndMetadata);
2337 } else if (keyword == Keyword.VOID) {
2338 TypeName returnType =
2339 new TypeName(new SimpleIdentifier(getAndAdvance()), null);
2340 keyword = _currentToken.keyword;
2341 next = _peek();
2342 if ((keyword == Keyword.GET || keyword == Keyword.SET) &&
2343 _tokenMatchesIdentifier(next)) {
2344 _validateModifiersForTopLevelFunction(modifiers);
2345 return _parseFunctionDeclaration(
2346 commentAndMetadata, modifiers.externalKeyword, returnType);
2347 } else if (keyword == Keyword.OPERATOR && _isOperator(next)) {
2348 _reportErrorForToken(ParserErrorCode.TOP_LEVEL_OPERATOR, _currentToken);
2349 return _convertToFunctionDeclaration(_parseOperatorAfterKeyword(
2350 commentAndMetadata,
2351 modifiers.externalKeyword,
2352 returnType,
2353 getAndAdvance()));
2354 } else if (_matchesIdentifier() &&
2355 next.matchesAny(const <TokenType>[
2356 TokenType.OPEN_PAREN,
2357 TokenType.OPEN_CURLY_BRACKET,
2358 TokenType.FUNCTION,
2359 TokenType.LT
2360 ])) {
2361 _validateModifiersForTopLevelFunction(modifiers);
2362 return _parseFunctionDeclaration(
2363 commentAndMetadata, modifiers.externalKeyword, returnType);
2364 } else {
2365 //
2366 // We have found an error of some kind. Try to recover.
2367 //
2368 if (_matchesIdentifier()) {
2369 if (next.matchesAny(const <TokenType>[
2370 TokenType.EQ,
2371 TokenType.COMMA,
2372 TokenType.SEMICOLON
2373 ])) {
2374 //
2375 // We appear to have a variable declaration with a type of "void".
2376 //
2377 _reportErrorForNode(ParserErrorCode.VOID_VARIABLE, returnType);
2378 return new TopLevelVariableDeclaration(
2379 commentAndMetadata.comment,
2380 commentAndMetadata.metadata,
2381 parseVariableDeclarationListAfterType(null,
2382 _validateModifiersForTopLevelVariable(modifiers), null),
2383 _expect(TokenType.SEMICOLON));
2384 }
2385 }
2386 _reportErrorForToken(
2387 ParserErrorCode.EXPECTED_EXECUTABLE, _currentToken);
2388 return null;
2389 }
2390 } else if ((keyword == Keyword.GET || keyword == Keyword.SET) &&
2391 _tokenMatchesIdentifier(next)) {
2392 _validateModifiersForTopLevelFunction(modifiers);
2393 return _parseFunctionDeclaration(
2394 commentAndMetadata, modifiers.externalKeyword, null);
2395 } else if (keyword == Keyword.OPERATOR && _isOperator(next)) {
2396 _reportErrorForToken(ParserErrorCode.TOP_LEVEL_OPERATOR, _currentToken);
2397 return _convertToFunctionDeclaration(_parseOperatorAfterKeyword(
2398 commentAndMetadata,
2399 modifiers.externalKeyword,
2400 null,
2401 getAndAdvance()));
2402 } else if (!_matchesIdentifier()) {
2403 Token keyword = modifiers.varKeyword;
2404 if (keyword == null) {
2405 keyword = modifiers.finalKeyword;
2406 }
2407 if (keyword == null) {
2408 keyword = modifiers.constKeyword;
2409 }
2410 if (keyword != null) {
2411 //
2412 // We appear to have found an incomplete top-level variable declaration.
2413 //
2414 _reportErrorForCurrentToken(ParserErrorCode.MISSING_IDENTIFIER);
2415 VariableDeclaration variable =
2416 new VariableDeclaration(createSyntheticIdentifier(), null, null);
2417 List<VariableDeclaration> variables = <VariableDeclaration>[variable];
2418 return new TopLevelVariableDeclaration(
2419 commentAndMetadata.comment,
2420 commentAndMetadata.metadata,
2421 new VariableDeclarationList(null, null, keyword, null, variables),
2422 _expect(TokenType.SEMICOLON));
2423 }
2424 _reportErrorForToken(ParserErrorCode.EXPECTED_EXECUTABLE, _currentToken);
2425 return null;
2426 } else if (_isPeekGenericTypeParametersAndOpenParen()) {
2427 return _parseFunctionDeclaration(
2428 commentAndMetadata, modifiers.externalKeyword, null);
2429 } else if (_tokenMatches(next, TokenType.OPEN_PAREN)) {
2430 TypeName returnType = _parseOptionalTypeNameComment();
2431 _validateModifiersForTopLevelFunction(modifiers);
2432 return _parseFunctionDeclaration(
2433 commentAndMetadata, modifiers.externalKeyword, returnType);
2434 } else if (next.matchesAny(const <TokenType>[
2435 TokenType.EQ,
2436 TokenType.COMMA,
2437 TokenType.SEMICOLON
2438 ])) {
2439 if (modifiers.constKeyword == null &&
2440 modifiers.finalKeyword == null &&
2441 modifiers.varKeyword == null) {
2442 _reportErrorForCurrentToken(
2443 ParserErrorCode.MISSING_CONST_FINAL_VAR_OR_TYPE);
2444 }
2445 return new TopLevelVariableDeclaration(
2446 commentAndMetadata.comment,
2447 commentAndMetadata.metadata,
2448 parseVariableDeclarationListAfterType(
2449 null, _validateModifiersForTopLevelVariable(modifiers), null),
2450 _expect(TokenType.SEMICOLON));
2451 }
2452 TypeName returnType = parseReturnType();
2453 keyword = _currentToken.keyword;
2454 next = _peek();
2455 if ((keyword == Keyword.GET || keyword == Keyword.SET) &&
2456 _tokenMatchesIdentifier(next)) {
2457 _validateModifiersForTopLevelFunction(modifiers);
2458 return _parseFunctionDeclaration(
2459 commentAndMetadata, modifiers.externalKeyword, returnType);
2460 } else if (keyword == Keyword.OPERATOR && _isOperator(next)) {
2461 _reportErrorForToken(ParserErrorCode.TOP_LEVEL_OPERATOR, _currentToken);
2462 return _convertToFunctionDeclaration(_parseOperatorAfterKeyword(
2463 commentAndMetadata,
2464 modifiers.externalKeyword,
2465 returnType,
2466 getAndAdvance()));
2467 } else if (_matches(TokenType.AT)) {
2468 return new TopLevelVariableDeclaration(
2469 commentAndMetadata.comment,
2470 commentAndMetadata.metadata,
2471 parseVariableDeclarationListAfterType(null,
2472 _validateModifiersForTopLevelVariable(modifiers), returnType),
2473 _expect(TokenType.SEMICOLON));
2474 } else if (!_matchesIdentifier()) {
2475 // TODO(brianwilkerson) Generalize this error. We could also be parsing a
2476 // top-level variable at this point.
2477 _reportErrorForToken(ParserErrorCode.EXPECTED_EXECUTABLE, _currentToken);
2478 Token semicolon;
2479 if (_matches(TokenType.SEMICOLON)) {
2480 semicolon = getAndAdvance();
2481 } else {
2482 semicolon = _createSyntheticToken(TokenType.SEMICOLON);
2483 }
2484 VariableDeclaration variable =
2485 new VariableDeclaration(createSyntheticIdentifier(), null, null);
2486 List<VariableDeclaration> variables = <VariableDeclaration>[variable];
2487 return new TopLevelVariableDeclaration(
2488 commentAndMetadata.comment,
2489 commentAndMetadata.metadata,
2490 new VariableDeclarationList(null, null, null, returnType, variables),
2491 semicolon);
2492 } else if (next.matchesAny(const <TokenType>[
2493 TokenType.OPEN_PAREN,
2494 TokenType.FUNCTION,
2495 TokenType.OPEN_CURLY_BRACKET,
2496 TokenType.LT
2497 ])) {
2498 _validateModifiersForTopLevelFunction(modifiers);
2499 return _parseFunctionDeclaration(
2500 commentAndMetadata, modifiers.externalKeyword, returnType);
2501 }
2502 return new TopLevelVariableDeclaration(
2503 commentAndMetadata.comment,
2504 commentAndMetadata.metadata,
2505 parseVariableDeclarationListAfterType(
2506 null, _validateModifiersForTopLevelVariable(modifiers), returnType),
2507 _expect(TokenType.SEMICOLON));
2508 }
2509
2510 /**
1517 * Parse a conditional expression. Return the conditional expression that was 2511 * Parse a conditional expression. Return the conditional expression that was
1518 * parsed. 2512 * parsed.
1519 * 2513 *
1520 * conditionalExpression ::= 2514 * conditionalExpression ::=
1521 * ifNullExpression ('?' expressionWithoutCascade ':' expressionWithou tCascade)? 2515 * ifNullExpression ('?' expressionWithoutCascade ':' expressionWithou tCascade)?
1522 */ 2516 */
1523 Expression parseConditionalExpression() { 2517 Expression parseConditionalExpression() {
1524 Expression condition = parseIfNullExpression(); 2518 Expression condition = parseIfNullExpression();
1525 if (_currentToken.type != TokenType.QUESTION) { 2519 if (_currentToken.type != TokenType.QUESTION) {
1526 return condition; 2520 return condition;
1527 } 2521 }
1528 Token question = getAndAdvance(); 2522 Token question = getAndAdvance();
1529 Expression thenExpression = parseExpressionWithoutCascade(); 2523 Expression thenExpression = parseExpressionWithoutCascade();
1530 Token colon = _expect(TokenType.COLON); 2524 Token colon = _expect(TokenType.COLON);
1531 Expression elseExpression = parseExpressionWithoutCascade(); 2525 Expression elseExpression = parseExpressionWithoutCascade();
1532 return new ConditionalExpression( 2526 return new ConditionalExpression(
1533 condition, question, thenExpression, colon, elseExpression); 2527 condition, question, thenExpression, colon, elseExpression);
1534 } 2528 }
1535 2529
1536 /** 2530 /**
2531 * Parse a configuration in either an import or export directive.
2532 *
2533 * This method assumes that the current token matches `Keyword.IF`.
2534 *
2535 * configuration ::=
2536 * 'if' '(' test ')' uri
2537 *
2538 * test ::=
2539 * dottedName ('==' stringLiteral)?
2540 *
2541 * dottedName ::=
2542 * identifier ('.' identifier)*
2543 */
2544 Configuration parseConfiguration() {
2545 Token ifKeyword = getAndAdvance();
2546 Token leftParenthesis = _expect(TokenType.OPEN_PAREN);
2547 DottedName name = parseDottedName();
2548 Token equalToken = null;
2549 StringLiteral value = null;
2550 if (_matches(TokenType.EQ_EQ)) {
2551 equalToken = getAndAdvance();
2552 value = parseStringLiteral();
2553 if (value is StringInterpolation) {
2554 _reportErrorForNode(
2555 ParserErrorCode.INVALID_LITERAL_IN_CONFIGURATION, value);
2556 }
2557 }
2558 Token rightParenthesis = _expect(TokenType.CLOSE_PAREN);
2559 StringLiteral libraryUri = _parseUri();
2560 return new Configuration(ifKeyword, leftParenthesis, name, equalToken,
2561 value, rightParenthesis, libraryUri);
2562 }
2563
2564 /**
2565 * Parse a const expression. Return the const expression that was parsed.
2566 *
2567 * This method assumes that the current token matches `Keyword.CONST`.
2568 *
2569 * constExpression ::=
2570 * instanceCreationExpression
2571 * | listLiteral
2572 * | mapLiteral
2573 */
2574 Expression parseConstExpression() {
2575 Token keyword = getAndAdvance();
2576 TokenType type = _currentToken.type;
2577 if (type == TokenType.LT || _injectGenericCommentTypeList()) {
2578 return parseListOrMapLiteral(keyword);
2579 } else if (type == TokenType.OPEN_SQUARE_BRACKET ||
2580 type == TokenType.INDEX) {
2581 return _parseListLiteral(keyword, null);
2582 } else if (type == TokenType.OPEN_CURLY_BRACKET) {
2583 return _parseMapLiteral(keyword, null);
2584 }
2585 return _parseInstanceCreationExpression(keyword);
2586 }
2587
2588 /**
1537 * Parse the name of a constructor. Return the constructor name that was 2589 * Parse the name of a constructor. Return the constructor name that was
1538 * parsed. 2590 * parsed.
1539 * 2591 *
1540 * constructorName: 2592 * constructorName:
1541 * type ('.' identifier)? 2593 * type ('.' identifier)?
1542 */ 2594 */
1543 ConstructorName parseConstructorName() { 2595 ConstructorName parseConstructorName() {
1544 TypeName type = parseTypeName(false); 2596 TypeName type = parseTypeName(false);
1545 Token period = null; 2597 Token period = null;
1546 SimpleIdentifier name = null; 2598 SimpleIdentifier name = null;
1547 if (_matches(TokenType.PERIOD)) { 2599 if (_matches(TokenType.PERIOD)) {
1548 period = getAndAdvance(); 2600 period = getAndAdvance();
1549 name = parseSimpleIdentifier(); 2601 name = parseSimpleIdentifier();
1550 } 2602 }
1551 return new ConstructorName(type, period, name); 2603 return new ConstructorName(type, period, name);
1552 } 2604 }
1553 2605
1554 /** 2606 /**
2607 * Parse a continue statement. Return the continue statement that was parsed.
2608 *
2609 * This method assumes that the current token matches `Keyword.CONTINUE`.
2610 *
2611 * continueStatement ::=
2612 * 'continue' identifier? ';'
2613 */
2614 Statement parseContinueStatement() {
2615 Token continueKeyword = getAndAdvance();
2616 if (!_inLoop && !_inSwitch) {
2617 _reportErrorForToken(
2618 ParserErrorCode.CONTINUE_OUTSIDE_OF_LOOP, continueKeyword);
2619 }
2620 SimpleIdentifier label = null;
2621 if (_matchesIdentifier()) {
2622 label = _parseSimpleIdentifierUnchecked();
2623 }
2624 if (_inSwitch && !_inLoop && label == null) {
2625 _reportErrorForToken(
2626 ParserErrorCode.CONTINUE_WITHOUT_LABEL_IN_CASE, continueKeyword);
2627 }
2628 Token semicolon = _expect(TokenType.SEMICOLON);
2629 return new ContinueStatement(continueKeyword, label, semicolon);
2630 }
2631
2632 /**
1555 * Parse the script tag and directives in a compilation unit, starting with 2633 * Parse the script tag and directives in a compilation unit, starting with
1556 * the given [token], until the first non-directive is encountered. The 2634 * the given [token], until the first non-directive is encountered. The
1557 * remainder of the compilation unit will not be parsed. Specifically, if 2635 * remainder of the compilation unit will not be parsed. Specifically, if
1558 * there are directives later in the file, they will not be parsed. Return the 2636 * there are directives later in the file, they will not be parsed. Return the
1559 * compilation unit that was parsed. 2637 * compilation unit that was parsed.
1560 */ 2638 */
1561 CompilationUnit parseDirectives(Token token) { 2639 CompilationUnit parseDirectives(Token token) {
1562 _currentToken = token; 2640 _currentToken = token;
1563 return _parseDirectives(); 2641 return parseDirectives2();
1564 }
1565
1566 /**
1567 * Parse an expression, starting with the given [token]. Return the expression
1568 * that was parsed, or `null` if the tokens do not represent a recognizable
1569 * expression.
1570 */
1571 Expression parseExpression(Token token) {
1572 _currentToken = token;
1573 return parseExpression2();
1574 }
1575
1576 /**
1577 * Parse an expression that might contain a cascade. Return the expression
1578 * that was parsed.
1579 *
1580 * expression ::=
1581 * assignableExpression assignmentOperator expression
1582 * | conditionalExpression cascadeSection*
1583 * | throwExpression
1584 */
1585 Expression parseExpression2() {
1586 Keyword keyword = _currentToken.keyword;
1587 if (keyword == Keyword.THROW) {
1588 return _parseThrowExpression();
1589 } else if (keyword == Keyword.RETHROW) {
1590 // TODO(brianwilkerson) Rethrow is a statement again.
1591 return _parseRethrowExpression();
1592 }
1593 //
1594 // assignableExpression is a subset of conditionalExpression, so we can
1595 // parse a conditional expression and then determine whether it is followed
1596 // by an assignmentOperator, checking for conformance to the restricted
1597 // grammar after making that determination.
1598 //
1599 Expression expression = parseConditionalExpression();
1600 TokenType type = _currentToken.type;
1601 if (type == TokenType.PERIOD_PERIOD) {
1602 List<Expression> cascadeSections = <Expression>[];
1603 do {
1604 Expression section = _parseCascadeSection();
1605 if (section != null) {
1606 cascadeSections.add(section);
1607 }
1608 } while (_currentToken.type == TokenType.PERIOD_PERIOD);
1609 return new CascadeExpression(expression, cascadeSections);
1610 } else if (type.isAssignmentOperator) {
1611 Token operator = getAndAdvance();
1612 _ensureAssignable(expression);
1613 return new AssignmentExpression(expression, operator, parseExpression2());
1614 }
1615 return expression;
1616 }
1617
1618 /**
1619 * Parse an expression that does not contain any cascades. Return the
1620 * expression that was parsed.
1621 *
1622 * expressionWithoutCascade ::=
1623 * assignableExpression assignmentOperator expressionWithoutCascade
1624 * | conditionalExpression
1625 * | throwExpressionWithoutCascade
1626 */
1627 Expression parseExpressionWithoutCascade() {
1628 if (_matchesKeyword(Keyword.THROW)) {
1629 return _parseThrowExpressionWithoutCascade();
1630 } else if (_matchesKeyword(Keyword.RETHROW)) {
1631 return _parseRethrowExpression();
1632 }
1633 //
1634 // assignableExpression is a subset of conditionalExpression, so we can
1635 // parse a conditional expression and then determine whether it is followed
1636 // by an assignmentOperator, checking for conformance to the restricted
1637 // grammar after making that determination.
1638 //
1639 Expression expression = parseConditionalExpression();
1640 if (_currentToken.type.isAssignmentOperator) {
1641 Token operator = getAndAdvance();
1642 _ensureAssignable(expression);
1643 expression = new AssignmentExpression(
1644 expression, operator, parseExpressionWithoutCascade());
1645 }
1646 return expression;
1647 }
1648
1649 /**
1650 * Parse a class extends clause. Return the class extends clause that was
1651 * parsed.
1652 *
1653 * This method assumes that the current token matches `Keyword.EXTENDS`.
1654 *
1655 * classExtendsClause ::=
1656 * 'extends' type
1657 */
1658 ExtendsClause parseExtendsClause() {
1659 Token keyword = getAndAdvance();
1660 TypeName superclass = parseTypeName(false);
1661 return new ExtendsClause(keyword, superclass);
1662 }
1663
1664 /**
1665 * Parse a list of formal parameters. Return the formal parameters that were
1666 * parsed.
1667 *
1668 * formalParameterList ::=
1669 * '(' ')'
1670 * | '(' normalFormalParameters (',' optionalFormalParameters)? ')'
1671 * | '(' optionalFormalParameters ')'
1672 *
1673 * normalFormalParameters ::=
1674 * normalFormalParameter (',' normalFormalParameter)*
1675 *
1676 * optionalFormalParameters ::=
1677 * optionalPositionalFormalParameters
1678 * | namedFormalParameters
1679 *
1680 * optionalPositionalFormalParameters ::=
1681 * '[' defaultFormalParameter (',' defaultFormalParameter)* ']'
1682 *
1683 * namedFormalParameters ::=
1684 * '{' defaultNamedParameter (',' defaultNamedParameter)* '}'
1685 */
1686 FormalParameterList parseFormalParameterList() {
1687 if (_matches(TokenType.OPEN_PAREN)) {
1688 return _parseFormalParameterListUnchecked();
1689 }
1690 // TODO(brianwilkerson) Improve the error message.
1691 _reportErrorForCurrentToken(
1692 ParserErrorCode.EXPECTED_TOKEN, [TokenType.OPEN_PAREN.lexeme]);
1693 // Recovery: Check for an unmatched closing paren and parse parameters until
1694 // it is reached.
1695 return _parseFormalParameterListAfterParen(
1696 _createSyntheticToken(TokenType.OPEN_PAREN));
1697 }
1698
1699 /**
1700 * Parse a function expression. Return the function expression that was
1701 * parsed.
1702 *
1703 * functionExpression ::=
1704 * typeParameters? formalParameterList functionExpressionBody
1705 */
1706 FunctionExpression parseFunctionExpression() {
1707 TypeParameterList typeParameters = _parseGenericMethodTypeParameters();
1708 FormalParameterList parameters = parseFormalParameterList();
1709 _validateFormalParameterList(parameters);
1710 FunctionBody body =
1711 _parseFunctionBody(false, ParserErrorCode.MISSING_FUNCTION_BODY, true);
1712 return new FunctionExpression(typeParameters, parameters, body);
1713 }
1714
1715 /**
1716 * Parse an if-null expression. Return the if-null expression that was
1717 * parsed.
1718 *
1719 * ifNullExpression ::= logicalOrExpression ('??' logicalOrExpression)*
1720 */
1721 Expression parseIfNullExpression() {
1722 Expression expression = parseLogicalOrExpression();
1723 while (_currentToken.type == TokenType.QUESTION_QUESTION) {
1724 expression = new BinaryExpression(
1725 expression, getAndAdvance(), parseLogicalOrExpression());
1726 }
1727 return expression;
1728 }
1729
1730 /**
1731 * Parse an implements clause. Return the implements clause that was parsed.
1732 *
1733 * This method assumes that the current token matches `Keyword.IMPLEMENTS`.
1734 *
1735 * implementsClause ::=
1736 * 'implements' type (',' type)*
1737 */
1738 ImplementsClause parseImplementsClause() {
1739 Token keyword = getAndAdvance();
1740 List<TypeName> interfaces = <TypeName>[];
1741 interfaces.add(parseTypeName(false));
1742 while (_optional(TokenType.COMMA)) {
1743 interfaces.add(parseTypeName(false));
1744 }
1745 return new ImplementsClause(keyword, interfaces);
1746 }
1747
1748 /**
1749 * Parse a label. Return the label that was parsed.
1750 *
1751 * This method assumes that the current token matches an identifier and that
1752 * the following token matches `TokenType.COLON`.
1753 *
1754 * label ::=
1755 * identifier ':'
1756 */
1757 Label parseLabel({bool isDeclaration: false}) {
1758 SimpleIdentifier label =
1759 _parseSimpleIdentifierUnchecked(isDeclaration: isDeclaration);
1760 Token colon = getAndAdvance();
1761 return new Label(label, colon);
1762 }
1763
1764 /**
1765 * Parse a library identifier. Return the library identifier that was parsed.
1766 *
1767 * libraryIdentifier ::=
1768 * identifier ('.' identifier)*
1769 */
1770 LibraryIdentifier parseLibraryIdentifier() {
1771 List<SimpleIdentifier> components = <SimpleIdentifier>[];
1772 components.add(parseSimpleIdentifier());
1773 while (_optional(TokenType.PERIOD)) {
1774 components.add(parseSimpleIdentifier());
1775 }
1776 return new LibraryIdentifier(components);
1777 }
1778
1779 /**
1780 * Parse a logical or expression. Return the logical or expression that was
1781 * parsed.
1782 *
1783 * logicalOrExpression ::=
1784 * logicalAndExpression ('||' logicalAndExpression)*
1785 */
1786 Expression parseLogicalOrExpression() {
1787 Expression expression = _parseLogicalAndExpression();
1788 while (_currentToken.type == TokenType.BAR_BAR) {
1789 expression = new BinaryExpression(
1790 expression, getAndAdvance(), _parseLogicalAndExpression());
1791 }
1792 return expression;
1793 }
1794
1795 /**
1796 * Parse a map literal entry. Return the map literal entry that was parsed.
1797 *
1798 * mapLiteralEntry ::=
1799 * expression ':' expression
1800 */
1801 MapLiteralEntry parseMapLiteralEntry() {
1802 Expression key = parseExpression2();
1803 Token separator = _expect(TokenType.COLON);
1804 Expression value = parseExpression2();
1805 return new MapLiteralEntry(key, separator, value);
1806 }
1807
1808 /**
1809 * Parse a normal formal parameter. Return the normal formal parameter that
1810 * was parsed.
1811 *
1812 * normalFormalParameter ::=
1813 * functionSignature
1814 * | fieldFormalParameter
1815 * | simpleFormalParameter
1816 *
1817 * functionSignature:
1818 * metadata returnType? identifier typeParameters? formalParameterList
1819 *
1820 * fieldFormalParameter ::=
1821 * metadata finalConstVarOrType? 'this' '.' identifier
1822 *
1823 * simpleFormalParameter ::=
1824 * declaredIdentifier
1825 * | metadata identifier
1826 */
1827 NormalFormalParameter parseNormalFormalParameter() {
1828 CommentAndMetadata commentAndMetadata = _parseCommentAndMetadata();
1829 FinalConstVarOrType holder = _parseFinalConstVarOrType(true);
1830 Token thisKeyword = null;
1831 Token period = null;
1832 if (_matchesKeyword(Keyword.THIS)) {
1833 thisKeyword = getAndAdvance();
1834 period = _expect(TokenType.PERIOD);
1835 }
1836 SimpleIdentifier identifier = parseSimpleIdentifier();
1837 TypeParameterList typeParameters = _parseGenericMethodTypeParameters();
1838 if (_matches(TokenType.OPEN_PAREN)) {
1839 FormalParameterList parameters = _parseFormalParameterListUnchecked();
1840 if (thisKeyword == null) {
1841 if (holder.keyword != null) {
1842 _reportErrorForToken(
1843 ParserErrorCode.FUNCTION_TYPED_PARAMETER_VAR, holder.keyword);
1844 }
1845 Token question = null;
1846 if (enableNnbd && _matches(TokenType.QUESTION)) {
1847 question = getAndAdvance();
1848 }
1849 return new FunctionTypedFormalParameter(
1850 commentAndMetadata.comment,
1851 commentAndMetadata.metadata,
1852 holder.type,
1853 new SimpleIdentifier(identifier.token, isDeclaration: true),
1854 typeParameters,
1855 parameters,
1856 question: question);
1857 } else {
1858 return new FieldFormalParameter(
1859 commentAndMetadata.comment,
1860 commentAndMetadata.metadata,
1861 holder.keyword,
1862 holder.type,
1863 thisKeyword,
1864 period,
1865 identifier,
1866 typeParameters,
1867 parameters);
1868 }
1869 } else if (typeParameters != null) {
1870 // TODO(brianwilkerson) Report an error. It looks like a function-typed
1871 // parameter with no parameter list.
1872 //_reportErrorForToken(ParserErrorCode.MISSING_PARAMETERS, typeParameters. endToken);
1873 }
1874 TypeName type = holder.type;
1875 if (type != null) {
1876 if (_tokenMatchesKeyword(type.name.beginToken, Keyword.VOID)) {
1877 _reportErrorForToken(
1878 ParserErrorCode.VOID_PARAMETER, type.name.beginToken);
1879 } else if (holder.keyword != null &&
1880 _tokenMatchesKeyword(holder.keyword, Keyword.VAR)) {
1881 _reportErrorForToken(ParserErrorCode.VAR_AND_TYPE, holder.keyword);
1882 }
1883 }
1884 if (thisKeyword != null) {
1885 // TODO(brianwilkerson) If there are type parameters but no parameters,
1886 // should we create a synthetic empty parameter list here so we can
1887 // capture the type parameters?
1888 return new FieldFormalParameter(
1889 commentAndMetadata.comment,
1890 commentAndMetadata.metadata,
1891 holder.keyword,
1892 holder.type,
1893 thisKeyword,
1894 period,
1895 identifier,
1896 null,
1897 null);
1898 }
1899 return new SimpleFormalParameter(
1900 commentAndMetadata.comment,
1901 commentAndMetadata.metadata,
1902 holder.keyword,
1903 holder.type,
1904 new SimpleIdentifier(identifier.token, isDeclaration: true));
1905 }
1906
1907 /**
1908 * Parse a prefixed identifier. Return the prefixed identifier that was
1909 * parsed.
1910 *
1911 * prefixedIdentifier ::=
1912 * identifier ('.' identifier)?
1913 */
1914 Identifier parsePrefixedIdentifier() {
1915 return _parsePrefixedIdentifierAfterIdentifier(parseSimpleIdentifier());
1916 }
1917
1918 /**
1919 * Parse a return type. Return the return type that was parsed.
1920 *
1921 * returnType ::=
1922 * 'void'
1923 * | type
1924 */
1925 TypeName parseReturnType() {
1926 if (_currentToken.keyword == Keyword.VOID) {
1927 return new TypeName(new SimpleIdentifier(getAndAdvance()), null);
1928 } else {
1929 return parseTypeName(false);
1930 }
1931 }
1932
1933 /**
1934 * Parse a simple identifier. Return the simple identifier that was parsed.
1935 *
1936 * identifier ::=
1937 * IDENTIFIER
1938 */
1939 SimpleIdentifier parseSimpleIdentifier({bool isDeclaration: false}) {
1940 if (_matchesIdentifier()) {
1941 return _parseSimpleIdentifierUnchecked(isDeclaration: isDeclaration);
1942 }
1943 _reportErrorForCurrentToken(ParserErrorCode.MISSING_IDENTIFIER);
1944 return _createSyntheticIdentifier(isDeclaration: isDeclaration);
1945 }
1946
1947 /**
1948 * Parse a statement, starting with the given [token]. Return the statement
1949 * that was parsed, or `null` if the tokens do not represent a recognizable
1950 * statement.
1951 */
1952 Statement parseStatement(Token token) {
1953 _currentToken = token;
1954 return parseStatement2();
1955 }
1956
1957 /**
1958 * Parse a statement. Return the statement that was parsed.
1959 *
1960 * statement ::=
1961 * label* nonLabeledStatement
1962 */
1963 Statement parseStatement2() {
1964 List<Label> labels = null;
1965 while (_matchesIdentifier() && _currentToken.next.type == TokenType.COLON) {
1966 Label label = parseLabel(isDeclaration: true);
1967 if (labels == null) {
1968 labels = <Label>[label];
1969 } else {
1970 labels.add(label);
1971 }
1972 }
1973 Statement statement = _parseNonLabeledStatement();
1974 if (labels == null) {
1975 return statement;
1976 }
1977 return new LabeledStatement(labels, statement);
1978 }
1979
1980 /**
1981 * Parse a sequence of statements, starting with the given [token]. Return the
1982 * statements that were parsed, or `null` if the tokens do not represent a
1983 * recognizable sequence of statements.
1984 */
1985 List<Statement> parseStatements(Token token) {
1986 _currentToken = token;
1987 return _parseStatementList();
1988 }
1989
1990 /**
1991 * Parse a string literal. Return the string literal that was parsed.
1992 *
1993 * stringLiteral ::=
1994 * MULTI_LINE_STRING+
1995 * | SINGLE_LINE_STRING+
1996 */
1997 StringLiteral parseStringLiteral() {
1998 if (_matches(TokenType.STRING)) {
1999 return _parseStringLiteralUnchecked();
2000 }
2001 _reportErrorForCurrentToken(ParserErrorCode.EXPECTED_STRING_LITERAL);
2002 return _createSyntheticStringLiteral();
2003 }
2004
2005 /**
2006 * Parse a list of type arguments. Return the type argument list that was
2007 * parsed.
2008 *
2009 * This method assumes that the current token matches `TokenType.LT`.
2010 *
2011 * typeArguments ::=
2012 * '<' typeList '>'
2013 *
2014 * typeList ::=
2015 * type (',' type)*
2016 */
2017 TypeArgumentList parseTypeArgumentList() {
2018 Token leftBracket = getAndAdvance();
2019 List<TypeName> arguments = <TypeName>[parseTypeName(false)];
2020 while (_optional(TokenType.COMMA)) {
2021 arguments.add(parseTypeName(false));
2022 }
2023 Token rightBracket = _expectGt();
2024 return new TypeArgumentList(leftBracket, arguments, rightBracket);
2025 }
2026
2027 /**
2028 * Parse a type name. Return the type name that was parsed.
2029 *
2030 * type ::=
2031 * qualified typeArguments?
2032 */
2033 TypeName parseTypeName(bool inExpression) {
2034 TypeName realType = _parseTypeName(inExpression);
2035 // If this is followed by a generic method type comment, allow the comment
2036 // type to replace the real type name.
2037 // TODO(jmesserly): this feels like a big hammer. Can we restrict it to
2038 // only work inside generic methods?
2039 TypeName typeFromComment = _parseOptionalTypeNameComment();
2040 return typeFromComment ?? realType;
2041 }
2042
2043 /**
2044 * Parse a type parameter. Return the type parameter that was parsed.
2045 *
2046 * typeParameter ::=
2047 * metadata name ('extends' bound)?
2048 */
2049 TypeParameter parseTypeParameter() {
2050 CommentAndMetadata commentAndMetadata = _parseCommentAndMetadata();
2051 SimpleIdentifier name = parseSimpleIdentifier(isDeclaration: true);
2052 if (_matchesKeyword(Keyword.EXTENDS)) {
2053 Token keyword = getAndAdvance();
2054 TypeName bound = parseTypeName(false);
2055 return new TypeParameter(commentAndMetadata.comment,
2056 commentAndMetadata.metadata, name, keyword, bound);
2057 }
2058 return new TypeParameter(commentAndMetadata.comment,
2059 commentAndMetadata.metadata, name, null, null);
2060 }
2061
2062 /**
2063 * Parse a list of type parameters. Return the list of type parameters that
2064 * were parsed.
2065 *
2066 * This method assumes that the current token matches `TokenType.LT`.
2067 *
2068 * typeParameterList ::=
2069 * '<' typeParameter (',' typeParameter)* '>'
2070 */
2071 TypeParameterList parseTypeParameterList() {
2072 Token leftBracket = getAndAdvance();
2073 List<TypeParameter> typeParameters = <TypeParameter>[parseTypeParameter()];
2074 while (_optional(TokenType.COMMA)) {
2075 typeParameters.add(parseTypeParameter());
2076 }
2077 Token rightBracket = _expectGt();
2078 return new TypeParameterList(leftBracket, typeParameters, rightBracket);
2079 }
2080
2081 /**
2082 * Parse a with clause. Return the with clause that was parsed.
2083 *
2084 * This method assumes that the current token matches `Keyword.WITH`.
2085 *
2086 * withClause ::=
2087 * 'with' typeName (',' typeName)*
2088 */
2089 WithClause parseWithClause() {
2090 Token withKeyword = getAndAdvance();
2091 List<TypeName> types = <TypeName>[parseTypeName(false)];
2092 while (_optional(TokenType.COMMA)) {
2093 types.add(parseTypeName(false));
2094 }
2095 return new WithClause(withKeyword, types);
2096 }
2097
2098 /**
2099 * Advance to the next token in the token stream.
2100 */
2101 void _advance() {
2102 _currentToken = _currentToken.next;
2103 }
2104
2105 /**
2106 * Append the character equivalent of the given [scalarValue] to the given
2107 * [builder]. Use the [startIndex] and [endIndex] to report an error, and
2108 * don't append anything to the builder, if the scalar value is invalid. The
2109 * [escapeSequence] is the escape sequence that was parsed to produce the
2110 * scalar value (used for error reporting).
2111 */
2112 void _appendScalarValue(StringBuffer buffer, String escapeSequence,
2113 int scalarValue, int startIndex, int endIndex) {
2114 if (scalarValue < 0 ||
2115 scalarValue > Character.MAX_CODE_POINT ||
2116 (scalarValue >= 0xD800 && scalarValue <= 0xDFFF)) {
2117 _reportErrorForCurrentToken(
2118 ParserErrorCode.INVALID_CODE_POINT, [escapeSequence]);
2119 return;
2120 }
2121 if (scalarValue < Character.MAX_VALUE) {
2122 buffer.writeCharCode(scalarValue);
2123 } else {
2124 buffer.write(Character.toChars(scalarValue));
2125 }
2126 }
2127
2128 /**
2129 * Clone all token starting from the given [token] up to the end of the token
2130 * stream, and return the first token in the new token stream.
2131 */
2132 Token _cloneTokens(Token token) {
2133 if (token == null) {
2134 return null;
2135 }
2136 token = token is CommentToken ? token.parent : token;
2137 Token head = new Token(TokenType.EOF, -1);
2138 head.setNext(head);
2139 Token current = head;
2140 while (token.type != TokenType.EOF) {
2141 Token clone = token.copy();
2142 current.setNext(clone);
2143 current = clone;
2144 token = token.next;
2145 }
2146 Token tail = new Token(TokenType.EOF, 0);
2147 tail.setNext(tail);
2148 current.setNext(tail);
2149 return head.next;
2150 }
2151
2152 /**
2153 * Return the content of a string with the given literal representation. The
2154 * [lexeme] is the literal representation of the string. The flag [isFirst] is
2155 * `true` if this is the first token in a string literal. The flag [isLast] is
2156 * `true` if this is the last token in a string literal.
2157 */
2158 String _computeStringValue(String lexeme, bool isFirst, bool isLast) {
2159 StringLexemeHelper helper = new StringLexemeHelper(lexeme, isFirst, isLast);
2160 int start = helper.start;
2161 int end = helper.end;
2162 bool stringEndsAfterStart = end >= start;
2163 assert(stringEndsAfterStart);
2164 if (!stringEndsAfterStart) {
2165 AnalysisEngine.instance.logger.logError(
2166 "Internal error: computeStringValue($lexeme, $isFirst, $isLast)");
2167 return "";
2168 }
2169 if (helper.isRaw) {
2170 return lexeme.substring(start, end);
2171 }
2172 StringBuffer buffer = new StringBuffer();
2173 int index = start;
2174 while (index < end) {
2175 index = _translateCharacter(buffer, lexeme, index);
2176 }
2177 return buffer.toString();
2178 }
2179
2180 /**
2181 * Convert the given [method] declaration into the nearest valid top-level
2182 * function declaration (that is, the function declaration that most closely
2183 * captures the components of the given method declaration).
2184 */
2185 FunctionDeclaration _convertToFunctionDeclaration(MethodDeclaration method) =>
2186 new FunctionDeclaration(
2187 method.documentationComment,
2188 method.metadata,
2189 method.externalKeyword,
2190 method.returnType,
2191 method.propertyKeyword,
2192 method.name,
2193 new FunctionExpression(
2194 method.typeParameters, method.parameters, method.body));
2195
2196 /**
2197 * Return `true` if the current token could be the start of a compilation unit
2198 * member. This method is used for recovery purposes to decide when to stop
2199 * skipping tokens after finding an error while parsing a compilation unit
2200 * member.
2201 */
2202 bool _couldBeStartOfCompilationUnitMember() {
2203 Keyword keyword = _currentToken.keyword;
2204 Token next = _currentToken.next;
2205 TokenType nextType = next.type;
2206 if ((keyword == Keyword.IMPORT ||
2207 keyword == Keyword.EXPORT ||
2208 keyword == Keyword.LIBRARY ||
2209 keyword == Keyword.PART) &&
2210 nextType != TokenType.PERIOD &&
2211 nextType != TokenType.LT) {
2212 // This looks like the start of a directive
2213 return true;
2214 } else if (keyword == Keyword.CLASS) {
2215 // This looks like the start of a class definition
2216 return true;
2217 } else if (keyword == Keyword.TYPEDEF &&
2218 nextType != TokenType.PERIOD &&
2219 nextType != TokenType.LT) {
2220 // This looks like the start of a typedef
2221 return true;
2222 } else if (keyword == Keyword.VOID ||
2223 ((keyword == Keyword.GET || keyword == Keyword.SET) &&
2224 _tokenMatchesIdentifier(next)) ||
2225 (keyword == Keyword.OPERATOR && _isOperator(next))) {
2226 // This looks like the start of a function
2227 return true;
2228 } else if (_matchesIdentifier()) {
2229 if (nextType == TokenType.OPEN_PAREN) {
2230 // This looks like the start of a function
2231 return true;
2232 }
2233 Token token = _skipReturnType(_currentToken);
2234 if (token == null) {
2235 return false;
2236 }
2237 // TODO(brianwilkerson) This looks wrong; should we be checking 'token'?
2238 if (keyword == Keyword.GET ||
2239 keyword == Keyword.SET ||
2240 (keyword == Keyword.OPERATOR && _isOperator(next)) ||
2241 _matchesIdentifier()) {
2242 return true;
2243 }
2244 }
2245 return false;
2246 }
2247
2248 /**
2249 * Return a synthetic identifier.
2250 */
2251 SimpleIdentifier _createSyntheticIdentifier({bool isDeclaration: false}) {
2252 Token syntheticToken;
2253 if (_currentToken.type == TokenType.KEYWORD) {
2254 // Consider current keyword token as an identifier.
2255 // It is not always true, e.g. "^is T" where "^" is place the place for
2256 // synthetic identifier. By creating SyntheticStringToken we can
2257 // distinguish a real identifier from synthetic. In the code completion
2258 // behavior will depend on a cursor position - before or on "is".
2259 syntheticToken = _injectToken(new SyntheticStringToken(
2260 TokenType.IDENTIFIER, _currentToken.lexeme, _currentToken.offset));
2261 } else {
2262 syntheticToken = _createSyntheticToken(TokenType.IDENTIFIER);
2263 }
2264 return new SimpleIdentifier(syntheticToken, isDeclaration: isDeclaration);
2265 }
2266
2267 /**
2268 * Return a synthetic token representing the given [keyword].
2269 */
2270 Token _createSyntheticKeyword(Keyword keyword) => _injectToken(
2271 new Parser_SyntheticKeywordToken(keyword, _currentToken.offset));
2272
2273 /**
2274 * Return a synthetic string literal.
2275 */
2276 SimpleStringLiteral _createSyntheticStringLiteral() =>
2277 new SimpleStringLiteral(_createSyntheticToken(TokenType.STRING), "");
2278
2279 /**
2280 * Return a synthetic token with the given [type].
2281 */
2282 Token _createSyntheticToken(TokenType type) =>
2283 _injectToken(new StringToken(type, "", _currentToken.offset));
2284
2285 /**
2286 * Create and return a new token with the given [type]. The token will replace
2287 * the first portion of the given [token], so it will have the same offset and
2288 * will have any comments that might have preceeded the token.
2289 */
2290 Token _createToken(Token token, TokenType type, {bool isBegin: false}) {
2291 CommentToken comments = token.precedingComments;
2292 if (comments == null) {
2293 if (isBegin) {
2294 return new BeginToken(type, token.offset);
2295 }
2296 return new Token(type, token.offset);
2297 } else if (isBegin) {
2298 return new BeginTokenWithComment(type, token.offset, comments);
2299 }
2300 return new TokenWithComment(type, token.offset, comments);
2301 }
2302
2303 /**
2304 * Check that the given [expression] is assignable and report an error if it
2305 * isn't.
2306 *
2307 * assignableExpression ::=
2308 * primary (arguments* assignableSelector)+
2309 * | 'super' unconditionalAssignableSelector
2310 * | identifier
2311 *
2312 * unconditionalAssignableSelector ::=
2313 * '[' expression ']'
2314 * | '.' identifier
2315 *
2316 * assignableSelector ::=
2317 * unconditionalAssignableSelector
2318 * | '?.' identifier
2319 */
2320 void _ensureAssignable(Expression expression) {
2321 if (expression != null && !expression.isAssignable) {
2322 _reportErrorForCurrentToken(
2323 ParserErrorCode.ILLEGAL_ASSIGNMENT_TO_NON_ASSIGNABLE);
2324 }
2325 }
2326
2327 /**
2328 * If the current token has the expected type, return it after advancing to
2329 * the next token. Otherwise report an error and return the current token
2330 * without advancing.
2331 *
2332 * Note that the method [_expectGt] should be used if the argument to this
2333 * method would be [TokenType.GT].
2334 *
2335 * The [type] is the type of token that is expected.
2336 */
2337 Token _expect(TokenType type) {
2338 if (_matches(type)) {
2339 return getAndAdvance();
2340 }
2341 // Remove uses of this method in favor of matches?
2342 // Pass in the error code to use to report the error?
2343 if (type == TokenType.SEMICOLON) {
2344 if (_tokenMatches(_currentToken.next, TokenType.SEMICOLON)) {
2345 _reportErrorForCurrentToken(
2346 ParserErrorCode.UNEXPECTED_TOKEN, [_currentToken.lexeme]);
2347 _advance();
2348 return getAndAdvance();
2349 }
2350 _reportErrorForToken(ParserErrorCode.EXPECTED_TOKEN,
2351 _currentToken.previous, [type.lexeme]);
2352 return _createSyntheticToken(TokenType.SEMICOLON);
2353 }
2354 _reportErrorForCurrentToken(ParserErrorCode.EXPECTED_TOKEN, [type.lexeme]);
2355 return _createSyntheticToken(type);
2356 }
2357
2358 /**
2359 * If the current token has the type [TokenType.GT], return it after advancing
2360 * to the next token. Otherwise report an error and create a synthetic token.
2361 */
2362 Token _expectGt() {
2363 if (_matchesGt()) {
2364 return getAndAdvance();
2365 }
2366 _reportErrorForCurrentToken(
2367 ParserErrorCode.EXPECTED_TOKEN, [TokenType.GT.lexeme]);
2368 return _createSyntheticToken(TokenType.GT);
2369 }
2370
2371 /**
2372 * If the current token is a keyword matching the given [keyword], return it
2373 * after advancing to the next token. Otherwise report an error and return the
2374 * current token without advancing.
2375 */
2376 Token _expectKeyword(Keyword keyword) {
2377 if (_matchesKeyword(keyword)) {
2378 return getAndAdvance();
2379 }
2380 // Remove uses of this method in favor of matches?
2381 // Pass in the error code to use to report the error?
2382 _reportErrorForCurrentToken(
2383 ParserErrorCode.EXPECTED_TOKEN, [keyword.syntax]);
2384 return _currentToken;
2385 }
2386
2387 /**
2388 * Search the given list of [ranges] for a range that contains the given
2389 * [index]. Return the range that was found, or `null` if none of the ranges
2390 * contain the index.
2391 */
2392 List<int> _findRange(List<List<int>> ranges, int index) {
2393 int rangeCount = ranges.length;
2394 for (int i = 0; i < rangeCount; i++) {
2395 List<int> range = ranges[i];
2396 if (range[0] <= index && index <= range[1]) {
2397 return range;
2398 } else if (index < range[0]) {
2399 return null;
2400 }
2401 }
2402 return null;
2403 }
2404
2405 /**
2406 * Return a list of the ranges of characters in the given [comment] that
2407 * should be treated as code blocks.
2408 */
2409 List<List<int>> _getCodeBlockRanges(String comment) {
2410 List<List<int>> ranges = <List<int>>[];
2411 int length = comment.length;
2412 if (length < 3) {
2413 return ranges;
2414 }
2415 int index = 0;
2416 int firstChar = comment.codeUnitAt(0);
2417 if (firstChar == 0x2F) {
2418 int secondChar = comment.codeUnitAt(1);
2419 int thirdChar = comment.codeUnitAt(2);
2420 if ((secondChar == 0x2A && thirdChar == 0x2A) ||
2421 (secondChar == 0x2F && thirdChar == 0x2F)) {
2422 index = 3;
2423 }
2424 }
2425 if (StringUtilities.startsWith4(comment, index, 0x20, 0x20, 0x20, 0x20)) {
2426 int end = index + 4;
2427 while (end < length &&
2428 comment.codeUnitAt(end) != 0xD &&
2429 comment.codeUnitAt(end) != 0xA) {
2430 end = end + 1;
2431 }
2432 ranges.add(<int>[index, end]);
2433 index = end;
2434 }
2435 while (index < length) {
2436 int currentChar = comment.codeUnitAt(index);
2437 if (currentChar == 0xD || currentChar == 0xA) {
2438 index = index + 1;
2439 while (index < length &&
2440 Character.isWhitespace(comment.codeUnitAt(index))) {
2441 index = index + 1;
2442 }
2443 if (StringUtilities.startsWith6(
2444 comment, index, 0x2A, 0x20, 0x20, 0x20, 0x20, 0x20)) {
2445 int end = index + 6;
2446 while (end < length &&
2447 comment.codeUnitAt(end) != 0xD &&
2448 comment.codeUnitAt(end) != 0xA) {
2449 end = end + 1;
2450 }
2451 ranges.add(<int>[index, end]);
2452 index = end;
2453 }
2454 } else if (index + 1 < length &&
2455 currentChar == 0x5B &&
2456 comment.codeUnitAt(index + 1) == 0x3A) {
2457 int end = StringUtilities.indexOf2(comment, index + 2, 0x3A, 0x5D);
2458 if (end < 0) {
2459 end = length;
2460 }
2461 ranges.add(<int>[index, end]);
2462 index = end + 1;
2463 } else {
2464 index = index + 1;
2465 }
2466 }
2467 return ranges;
2468 }
2469
2470 /**
2471 * Return the end token associated with the given [beginToken], or `null` if
2472 * either the given token is not a begin token or it does not have an end
2473 * token associated with it.
2474 */
2475 Token _getEndToken(Token beginToken) {
2476 if (beginToken is BeginToken) {
2477 return beginToken.endToken;
2478 }
2479 return null;
2480 }
2481
2482 bool _injectGenericComment(TokenType type, int prefixLen) {
2483 if (parseGenericMethodComments) {
2484 CommentToken t = _currentToken.precedingComments;
2485 for (; t != null; t = t.next) {
2486 if (t.type == type) {
2487 String comment = t.lexeme.substring(prefixLen, t.lexeme.length - 2);
2488 Token list = _scanGenericMethodComment(comment, t.offset + prefixLen);
2489 if (list != null) {
2490 // Remove the token from the comment stream.
2491 t.remove();
2492 // Insert the tokens into the stream.
2493 _injectTokenList(list);
2494 return true;
2495 }
2496 }
2497 }
2498 }
2499 return false;
2500 }
2501
2502 /**
2503 * Matches a generic comment type substitution and injects it into the token
2504 * stream. Returns true if a match was injected, otherwise false.
2505 *
2506 * These comments are of the form `/*=T*/`, in other words, a [TypeName]
2507 * inside a slash-star comment, preceded by equals sign.
2508 */
2509 bool _injectGenericCommentTypeAssign() {
2510 return _injectGenericComment(TokenType.GENERIC_METHOD_TYPE_ASSIGN, 3);
2511 }
2512
2513 /**
2514 * Matches a generic comment type parameters and injects them into the token
2515 * stream. Returns true if a match was injected, otherwise false.
2516 *
2517 * These comments are of the form `/*<K, V>*/`, in other words, a
2518 * [TypeParameterList] or [TypeArgumentList] inside a slash-star comment.
2519 */
2520 bool _injectGenericCommentTypeList() {
2521 return _injectGenericComment(TokenType.GENERIC_METHOD_TYPE_LIST, 2);
2522 }
2523
2524 /**
2525 * Inject the given [token] into the token stream immediately before the
2526 * current token.
2527 */
2528 Token _injectToken(Token token) {
2529 Token previous = _currentToken.previous;
2530 token.setNext(_currentToken);
2531 previous.setNext(token);
2532 return token;
2533 }
2534
2535 void _injectTokenList(Token firstToken) {
2536 // Scanner creates a cyclic EOF token.
2537 Token lastToken = firstToken;
2538 while (lastToken.next.type != TokenType.EOF) {
2539 lastToken = lastToken.next;
2540 }
2541 // Inject these new tokens into the stream.
2542 Token previous = _currentToken.previous;
2543 lastToken.setNext(_currentToken);
2544 previous.setNext(firstToken);
2545 _currentToken = firstToken;
2546 }
2547
2548 /**
2549 * Return `true` if the current token could be the question mark in a
2550 * condition expression. The current token is assumed to be a question mark.
2551 */
2552 bool _isConditionalOperator() {
2553 void parseOperation(Parser parser) {
2554 parser.parseExpressionWithoutCascade();
2555 }
2556
2557 Token token = _skip(_currentToken.next, parseOperation);
2558 if (token == null || !_tokenMatches(token, TokenType.COLON)) {
2559 return false;
2560 }
2561 token = _skip(token.next, parseOperation);
2562 return token != null;
2563 }
2564
2565 /**
2566 * Return `true` if the current token appears to be the beginning of a
2567 * function declaration.
2568 */
2569 bool _isFunctionDeclaration() {
2570 Keyword keyword = _currentToken.keyword;
2571 if (keyword == Keyword.VOID) {
2572 return true;
2573 }
2574 Token afterReturnType = _skipTypeName(_currentToken);
2575 if (afterReturnType == null) {
2576 // There was no return type, but it is optional, so go back to where we
2577 // started.
2578 afterReturnType = _currentToken;
2579 }
2580 Token afterIdentifier = _skipSimpleIdentifier(afterReturnType);
2581 if (afterIdentifier == null) {
2582 // It's possible that we parsed the function name as if it were a type
2583 // name, so see whether it makes sense if we assume that there is no type.
2584 afterIdentifier = _skipSimpleIdentifier(_currentToken);
2585 }
2586 if (afterIdentifier == null) {
2587 return false;
2588 }
2589 if (_isFunctionExpression(afterIdentifier)) {
2590 return true;
2591 }
2592 // It's possible that we have found a getter. While this isn't valid at this
2593 // point we test for it in order to recover better.
2594 if (keyword == Keyword.GET) {
2595 Token afterName = _skipSimpleIdentifier(_currentToken.next);
2596 if (afterName == null) {
2597 return false;
2598 }
2599 TokenType type = afterName.type;
2600 return type == TokenType.FUNCTION || type == TokenType.OPEN_CURLY_BRACKET;
2601 } else if (_tokenMatchesKeyword(afterReturnType, Keyword.GET)) {
2602 Token afterName = _skipSimpleIdentifier(afterReturnType.next);
2603 if (afterName == null) {
2604 return false;
2605 }
2606 TokenType type = afterName.type;
2607 return type == TokenType.FUNCTION || type == TokenType.OPEN_CURLY_BRACKET;
2608 }
2609 return false;
2610 }
2611
2612 /**
2613 * Return `true` if the given [token] appears to be the beginning of a
2614 * function expression.
2615 */
2616 bool _isFunctionExpression(Token token) {
2617 // Function expressions aren't allowed in initializer lists.
2618 if (_inInitializer) {
2619 return false;
2620 }
2621 Token afterTypeParameters = _skipTypeParameterList(token);
2622 if (afterTypeParameters == null) {
2623 afterTypeParameters = token;
2624 }
2625 Token afterParameters = _skipFormalParameterList(afterTypeParameters);
2626 if (afterParameters == null) {
2627 return false;
2628 }
2629 if (afterParameters.matchesAny(
2630 const <TokenType>[TokenType.OPEN_CURLY_BRACKET, TokenType.FUNCTION])) {
2631 return true;
2632 }
2633 String lexeme = afterParameters.lexeme;
2634 return lexeme == ASYNC || lexeme == SYNC;
2635 }
2636
2637 /**
2638 * Return `true` if the given [character] is a valid hexadecimal digit.
2639 */
2640 bool _isHexDigit(int character) =>
2641 (0x30 <= character && character <= 0x39) ||
2642 (0x41 <= character && character <= 0x46) ||
2643 (0x61 <= character && character <= 0x66);
2644
2645 /**
2646 * Return `true` if the current token is the first token in an initialized
2647 * variable declaration rather than an expression. This method assumes that we
2648 * have already skipped past any metadata that might be associated with the
2649 * declaration.
2650 *
2651 * initializedVariableDeclaration ::=
2652 * declaredIdentifier ('=' expression)? (',' initializedIdentifier)*
2653 *
2654 * declaredIdentifier ::=
2655 * metadata finalConstVarOrType identifier
2656 *
2657 * finalConstVarOrType ::=
2658 * 'final' type?
2659 * | 'const' type?
2660 * | 'var'
2661 * | type
2662 *
2663 * type ::=
2664 * qualified typeArguments?
2665 *
2666 * initializedIdentifier ::=
2667 * identifier ('=' expression)?
2668 */
2669 bool _isInitializedVariableDeclaration() {
2670 Keyword keyword = _currentToken.keyword;
2671 if (keyword == Keyword.FINAL || keyword == Keyword.VAR) {
2672 // An expression cannot start with a keyword other than 'const',
2673 // 'rethrow', or 'throw'.
2674 return true;
2675 }
2676 if (keyword == Keyword.CONST) {
2677 // Look to see whether we might be at the start of a list or map literal,
2678 // otherwise this should be the start of a variable declaration.
2679 return !_peek().matchesAny(const <TokenType>[
2680 TokenType.LT,
2681 TokenType.OPEN_CURLY_BRACKET,
2682 TokenType.OPEN_SQUARE_BRACKET,
2683 TokenType.INDEX
2684 ]);
2685 }
2686 bool allowAdditionalTokens = true;
2687 // We know that we have an identifier, and need to see whether it might be
2688 // a type name.
2689 if (_currentToken.type != TokenType.IDENTIFIER) {
2690 allowAdditionalTokens = false;
2691 }
2692 Token token = _skipTypeName(_currentToken);
2693 if (token == null) {
2694 // There was no type name, so this can't be a declaration.
2695 return false;
2696 }
2697 if (token.type != TokenType.IDENTIFIER) {
2698 allowAdditionalTokens = false;
2699 }
2700 token = _skipSimpleIdentifier(token);
2701 if (token == null) {
2702 return false;
2703 }
2704 TokenType type = token.type;
2705 // Usual cases in valid code:
2706 // String v = '';
2707 // String v, v2;
2708 // String v;
2709 // for (String item in items) {}
2710 if (type == TokenType.EQ ||
2711 type == TokenType.COMMA ||
2712 type == TokenType.SEMICOLON ||
2713 token.keyword == Keyword.IN) {
2714 return true;
2715 }
2716 // It is OK to parse as a variable declaration in these cases:
2717 // String v }
2718 // String v if (true) print('OK');
2719 // String v { print(42); }
2720 // ...but not in these cases:
2721 // get getterName {
2722 // String get getterName
2723 if (allowAdditionalTokens) {
2724 if (type == TokenType.CLOSE_CURLY_BRACKET ||
2725 type == TokenType.KEYWORD ||
2726 type == TokenType.IDENTIFIER ||
2727 type == TokenType.OPEN_CURLY_BRACKET) {
2728 return true;
2729 }
2730 }
2731 return false;
2732 }
2733
2734 bool _isLikelyArgumentList() {
2735 // Try to reduce the amount of lookahead required here before enabling
2736 // generic methods.
2737 if (_matches(TokenType.OPEN_PAREN)) {
2738 return true;
2739 }
2740 if (!parseGenericMethods) {
2741 return false;
2742 }
2743 Token token = _skipTypeArgumentList(_currentToken);
2744 return token != null && _tokenMatches(token, TokenType.OPEN_PAREN);
2745 }
2746
2747 /**
2748 * Given that we have just found bracketed text within the given [comment],
2749 * look to see whether that text is (a) followed by a parenthesized link
2750 * address, (b) followed by a colon, or (c) followed by optional whitespace
2751 * and another square bracket. The [rightIndex] is the index of the right
2752 * bracket. Return `true` if the bracketed text is followed by a link address.
2753 *
2754 * This method uses the syntax described by the
2755 * <a href="http://daringfireball.net/projects/markdown/syntax">markdown</a>
2756 * project.
2757 */
2758 bool _isLinkText(String comment, int rightIndex) {
2759 int length = comment.length;
2760 int index = rightIndex + 1;
2761 if (index >= length) {
2762 return false;
2763 }
2764 int nextChar = comment.codeUnitAt(index);
2765 if (nextChar == 0x28 || nextChar == 0x3A) {
2766 return true;
2767 }
2768 while (Character.isWhitespace(nextChar)) {
2769 index = index + 1;
2770 if (index >= length) {
2771 return false;
2772 }
2773 nextChar = comment.codeUnitAt(index);
2774 }
2775 return nextChar == 0x5B;
2776 }
2777
2778 /**
2779 * Return `true` if the given [startToken] appears to be the beginning of an
2780 * operator declaration.
2781 */
2782 bool _isOperator(Token startToken) {
2783 // Accept any operator here, even if it is not user definable.
2784 if (!startToken.isOperator) {
2785 return false;
2786 }
2787 // Token "=" means that it is actually a field initializer.
2788 if (startToken.type == TokenType.EQ) {
2789 return false;
2790 }
2791 // Consume all operator tokens.
2792 Token token = startToken.next;
2793 while (token.isOperator) {
2794 token = token.next;
2795 }
2796 // Formal parameter list is expect now.
2797 return _tokenMatches(token, TokenType.OPEN_PAREN);
2798 }
2799
2800 bool _isPeekGenericTypeParametersAndOpenParen() {
2801 if (!parseGenericMethods) {
2802 return false;
2803 }
2804 Token token = _skipTypeParameterList(_peek());
2805 return token != null && _tokenMatches(token, TokenType.OPEN_PAREN);
2806 }
2807
2808 /**
2809 * Return `true` if the current token appears to be the beginning of a switch
2810 * member.
2811 */
2812 bool _isSwitchMember() {
2813 Token token = _currentToken;
2814 while (_tokenMatches(token, TokenType.IDENTIFIER) &&
2815 _tokenMatches(token.next, TokenType.COLON)) {
2816 token = token.next.next;
2817 }
2818 Keyword keyword = token.keyword;
2819 return keyword == Keyword.CASE || keyword == Keyword.DEFAULT;
2820 }
2821
2822 /**
2823 * Return `true` if the [startToken] appears to be the first token of a type
2824 * name that is followed by a variable or field formal parameter.
2825 */
2826 bool _isTypedIdentifier(Token startToken) {
2827 Token token = _skipReturnType(startToken);
2828 if (token == null) {
2829 return false;
2830 } else if (_tokenMatchesIdentifier(token)) {
2831 return true;
2832 } else if (_tokenMatchesKeyword(token, Keyword.THIS) &&
2833 _tokenMatches(token.next, TokenType.PERIOD) &&
2834 _tokenMatchesIdentifier(token.next.next)) {
2835 return true;
2836 } else if (_tokenMatchesKeyword(startToken, Keyword.VOID)) {
2837 // The keyword 'void' isn't a valid identifier, so it should be assumed to
2838 // be a type name.
2839 return true;
2840 } else if (startToken.next != token &&
2841 !_tokenMatches(token, TokenType.OPEN_PAREN)) {
2842 // The type is more than a simple identifier, so it should be assumed to
2843 // be a type name.
2844 return true;
2845 }
2846 return false;
2847 }
2848
2849 /**
2850 * Increments the error reporting lock level. If level is more than `0`, then
2851 * [reportError] wont report any error.
2852 */
2853 void _lockErrorListener() {
2854 _errorListenerLock++;
2855 }
2856
2857 /**
2858 * Return `true` if the current token has the given [type]. Note that the
2859 * method [_matchesGt] should be used if the argument to this method would be
2860 * [TokenType.GT].
2861 */
2862 bool _matches(TokenType type) => _currentToken.type == type;
2863
2864 /**
2865 * Return `true` if the current token has a type of [TokenType.GT]. Note that
2866 * this method, unlike other variants, will modify the token stream if
2867 * possible to match desired type. In particular, if the next token is either
2868 * a '>>' or '>>>', the token stream will be re-written and `true` will be
2869 * returned.
2870 */
2871 bool _matchesGt() {
2872 TokenType currentType = _currentToken.type;
2873 if (currentType == TokenType.GT) {
2874 return true;
2875 } else if (currentType == TokenType.GT_GT) {
2876 Token first = _createToken(_currentToken, TokenType.GT);
2877 Token second = new Token(TokenType.GT, _currentToken.offset + 1);
2878 second.setNext(_currentToken.next);
2879 first.setNext(second);
2880 _currentToken.previous.setNext(first);
2881 _currentToken = first;
2882 return true;
2883 } else if (currentType == TokenType.GT_EQ) {
2884 Token first = _createToken(_currentToken, TokenType.GT);
2885 Token second = new Token(TokenType.EQ, _currentToken.offset + 1);
2886 second.setNext(_currentToken.next);
2887 first.setNext(second);
2888 _currentToken.previous.setNext(first);
2889 _currentToken = first;
2890 return true;
2891 } else if (currentType == TokenType.GT_GT_EQ) {
2892 int offset = _currentToken.offset;
2893 Token first = _createToken(_currentToken, TokenType.GT);
2894 Token second = new Token(TokenType.GT, offset + 1);
2895 Token third = new Token(TokenType.EQ, offset + 2);
2896 third.setNext(_currentToken.next);
2897 second.setNext(third);
2898 first.setNext(second);
2899 _currentToken.previous.setNext(first);
2900 _currentToken = first;
2901 return true;
2902 }
2903 return false;
2904 }
2905
2906 /**
2907 * Return `true` if the current token is a valid identifier. Valid identifiers
2908 * include built-in identifiers (pseudo-keywords).
2909 */
2910 bool _matchesIdentifier() => _tokenMatchesIdentifier(_currentToken);
2911
2912 /**
2913 * Return `true` if the current token matches the given [keyword].
2914 */
2915 bool _matchesKeyword(Keyword keyword) =>
2916 _tokenMatchesKeyword(_currentToken, keyword);
2917
2918 /**
2919 * Return `true` if the current token matches the given [identifier].
2920 */
2921 bool _matchesString(String identifier) =>
2922 _currentToken.type == TokenType.IDENTIFIER &&
2923 _currentToken.lexeme == identifier;
2924
2925 /**
2926 * If the current token has the given [type], then advance to the next token
2927 * and return `true`. Otherwise, return `false` without advancing. This method
2928 * should not be invoked with an argument value of [TokenType.GT].
2929 */
2930 bool _optional(TokenType type) {
2931 if (_currentToken.type == type) {
2932 _advance();
2933 return true;
2934 }
2935 return false;
2936 }
2937
2938 /**
2939 * Parse an additive expression. Return the additive expression that was
2940 * parsed.
2941 *
2942 * additiveExpression ::=
2943 * multiplicativeExpression (additiveOperator multiplicativeExpression )*
2944 * | 'super' (additiveOperator multiplicativeExpression)+
2945 */
2946 Expression _parseAdditiveExpression() {
2947 Expression expression;
2948 if (_currentToken.keyword == Keyword.SUPER &&
2949 _currentToken.next.type.isAdditiveOperator) {
2950 expression = new SuperExpression(getAndAdvance());
2951 } else {
2952 expression = _parseMultiplicativeExpression();
2953 }
2954 while (_currentToken.type.isAdditiveOperator) {
2955 expression = new BinaryExpression(
2956 expression, getAndAdvance(), _parseMultiplicativeExpression());
2957 }
2958 return expression;
2959 }
2960
2961 /**
2962 * Parse an argument list when we need to check for an open paren and recover
2963 * when there isn't one. Return the argument list that was parsed.
2964 */
2965 ArgumentList _parseArgumentListChecked() {
2966 if (_matches(TokenType.OPEN_PAREN)) {
2967 return parseArgumentList();
2968 }
2969 _reportErrorForCurrentToken(
2970 ParserErrorCode.EXPECTED_TOKEN, [TokenType.OPEN_PAREN.lexeme]);
2971 // Recovery: Look to see whether there is a close paren that isn't matched
2972 // to an open paren and if so parse the list of arguments as normal.
2973 return new ArgumentList(_createSyntheticToken(TokenType.OPEN_PAREN), null,
2974 _createSyntheticToken(TokenType.CLOSE_PAREN));
2975 }
2976
2977 /**
2978 * Parse an assert within a constructor's initializer list. Return the assert.
2979 *
2980 * This method assumes that the current token matches `Keyword.ASSERT`.
2981 *
2982 * assertInitializer ::=
2983 * 'assert' '(' expression [',' expression] ')'
2984 */
2985 void _parseAssertInitializer() {
2986 // TODO(brianwilkerson) Capture the syntax in the AST using a new class,
2987 // such as AssertInitializer
2988 Token keyword = getAndAdvance();
2989 Token leftParen = _expect(TokenType.OPEN_PAREN);
2990 Expression expression = parseExpression2();
2991 Token comma;
2992 Expression message;
2993 if (_matches(TokenType.COMMA)) {
2994 comma = getAndAdvance();
2995 message = parseExpression2();
2996 }
2997 Token rightParen = _expect(TokenType.CLOSE_PAREN);
2998 // return new AssertInitializer(
2999 // keyword, leftParen, expression, comma, message, rightParen);
3000 }
3001
3002 /**
3003 * Parse an assert statement. Return the assert statement.
3004 *
3005 * This method assumes that the current token matches `Keyword.ASSERT`.
3006 *
3007 * assertStatement ::=
3008 * 'assert' '(' expression [',' expression] ')' ';'
3009 */
3010 AssertStatement _parseAssertStatement() {
3011 Token keyword = getAndAdvance();
3012 Token leftParen = _expect(TokenType.OPEN_PAREN);
3013 Expression expression = parseExpression2();
3014 Token comma;
3015 Expression message;
3016 if (_matches(TokenType.COMMA)) {
3017 comma = getAndAdvance();
3018 message = parseExpression2();
3019 }
3020 Token rightParen = _expect(TokenType.CLOSE_PAREN);
3021 Token semicolon = _expect(TokenType.SEMICOLON);
3022 return new AssertStatement(
3023 keyword, leftParen, expression, comma, message, rightParen, semicolon);
3024 }
3025
3026 /**
3027 * Parse an assignable expression. The [primaryAllowed] is `true` if the
3028 * expression is allowed to be a primary without any assignable selector.
3029 * Return the assignable expression that was parsed.
3030 *
3031 * assignableExpression ::=
3032 * primary (arguments* assignableSelector)+
3033 * | 'super' unconditionalAssignableSelector
3034 * | identifier
3035 */
3036 Expression _parseAssignableExpression(bool primaryAllowed) {
3037 if (_matchesKeyword(Keyword.SUPER)) {
3038 return _parseAssignableSelector(
3039 new SuperExpression(getAndAdvance()), false,
3040 allowConditional: false);
3041 }
3042 return _parseAssignableExpressionNotStartingWithSuper(primaryAllowed);
3043 }
3044
3045 /**
3046 * Parse an assignable expression given that the current token is not 'super'.
3047 * The [primaryAllowed] is `true` if the expression is allowed to be a primary
3048 * without any assignable selector. Return the assignable expression that was
3049 * parsed.
3050 */
3051 Expression _parseAssignableExpressionNotStartingWithSuper(
3052 bool primaryAllowed) {
3053 //
3054 // A primary expression can start with an identifier. We resolve the
3055 // ambiguity by determining whether the primary consists of anything other
3056 // than an identifier and/or is followed by an assignableSelector.
3057 //
3058 Expression expression = _parsePrimaryExpression();
3059 bool isOptional = primaryAllowed || expression is SimpleIdentifier;
3060 while (true) {
3061 while (_isLikelyArgumentList()) {
3062 TypeArgumentList typeArguments = _parseOptionalTypeArguments();
3063 ArgumentList argumentList = parseArgumentList();
3064 Expression currentExpression = expression;
3065 if (currentExpression is SimpleIdentifier) {
3066 expression = new MethodInvocation(
3067 null, null, currentExpression, typeArguments, argumentList);
3068 } else if (currentExpression is PrefixedIdentifier) {
3069 expression = new MethodInvocation(
3070 currentExpression.prefix,
3071 currentExpression.period,
3072 currentExpression.identifier,
3073 typeArguments,
3074 argumentList);
3075 } else if (currentExpression is PropertyAccess) {
3076 expression = new MethodInvocation(
3077 currentExpression.target,
3078 currentExpression.operator,
3079 currentExpression.propertyName,
3080 typeArguments,
3081 argumentList);
3082 } else {
3083 expression = new FunctionExpressionInvocation(
3084 expression, typeArguments, argumentList);
3085 }
3086 if (!primaryAllowed) {
3087 isOptional = false;
3088 }
3089 }
3090 Expression selectorExpression = _parseAssignableSelector(
3091 expression, isOptional || (expression is PrefixedIdentifier));
3092 if (identical(selectorExpression, expression)) {
3093 if (!isOptional && (expression is PrefixedIdentifier)) {
3094 PrefixedIdentifier identifier = expression as PrefixedIdentifier;
3095 expression = new PropertyAccess(
3096 identifier.prefix, identifier.period, identifier.identifier);
3097 }
3098 return expression;
3099 }
3100 expression = selectorExpression;
3101 isOptional = true;
3102 }
3103 }
3104
3105 /**
3106 * Parse an assignable selector. The [prefix] is the expression preceding the
3107 * selector. The [optional] is `true` if the selector is optional. Return the
3108 * assignable selector that was parsed, or the original prefix if there was no
3109 * assignable selector. If [allowConditional] is false, then the '?.'
3110 * operator will still be parsed, but a parse error will be generated.
3111 *
3112 * unconditionalAssignableSelector ::=
3113 * '[' expression ']'
3114 * | '.' identifier
3115 *
3116 * assignableSelector ::=
3117 * unconditionalAssignableSelector
3118 * | '?.' identifier
3119 */
3120 Expression _parseAssignableSelector(Expression prefix, bool optional,
3121 {bool allowConditional: true}) {
3122 TokenType type = _currentToken.type;
3123 if (type == TokenType.OPEN_SQUARE_BRACKET) {
3124 Token leftBracket = getAndAdvance();
3125 bool wasInInitializer = _inInitializer;
3126 _inInitializer = false;
3127 try {
3128 Expression index = parseExpression2();
3129 Token rightBracket = _expect(TokenType.CLOSE_SQUARE_BRACKET);
3130 return new IndexExpression.forTarget(
3131 prefix, leftBracket, index, rightBracket);
3132 } finally {
3133 _inInitializer = wasInInitializer;
3134 }
3135 } else {
3136 bool isQuestionPeriod = type == TokenType.QUESTION_PERIOD;
3137 if (type == TokenType.PERIOD || isQuestionPeriod) {
3138 if (isQuestionPeriod && !allowConditional) {
3139 _reportErrorForCurrentToken(
3140 ParserErrorCode.INVALID_OPERATOR_FOR_SUPER,
3141 [_currentToken.lexeme]);
3142 }
3143 Token operator = getAndAdvance();
3144 return new PropertyAccess(prefix, operator, parseSimpleIdentifier());
3145 } else {
3146 if (!optional) {
3147 // Report the missing selector.
3148 _reportErrorForCurrentToken(
3149 ParserErrorCode.MISSING_ASSIGNABLE_SELECTOR);
3150 }
3151 return prefix;
3152 }
3153 }
3154 }
3155
3156 /**
3157 * Parse a await expression. Return the await expression that was parsed.
3158 *
3159 * This method assumes that the current token matches `_AWAIT`.
3160 *
3161 * awaitExpression ::=
3162 * 'await' unaryExpression
3163 */
3164 AwaitExpression _parseAwaitExpression() {
3165 Token awaitToken = getAndAdvance();
3166 Expression expression = _parseUnaryExpression();
3167 return new AwaitExpression(awaitToken, expression);
3168 }
3169
3170 /**
3171 * Parse a bitwise and expression. Return the bitwise and expression that was
3172 * parsed.
3173 *
3174 * bitwiseAndExpression ::=
3175 * shiftExpression ('&' shiftExpression)*
3176 * | 'super' ('&' shiftExpression)+
3177 */
3178 Expression _parseBitwiseAndExpression() {
3179 Expression expression;
3180 if (_currentToken.keyword == Keyword.SUPER &&
3181 _currentToken.next.type == TokenType.AMPERSAND) {
3182 expression = new SuperExpression(getAndAdvance());
3183 } else {
3184 expression = _parseShiftExpression();
3185 }
3186 while (_currentToken.type == TokenType.AMPERSAND) {
3187 expression = new BinaryExpression(
3188 expression, getAndAdvance(), _parseShiftExpression());
3189 }
3190 return expression;
3191 }
3192
3193 /**
3194 * Parse a bitwise exclusive-or expression. Return the bitwise exclusive-or
3195 * expression that was parsed.
3196 *
3197 * bitwiseXorExpression ::=
3198 * bitwiseAndExpression ('^' bitwiseAndExpression)*
3199 * | 'super' ('^' bitwiseAndExpression)+
3200 */
3201 Expression _parseBitwiseXorExpression() {
3202 Expression expression;
3203 if (_currentToken.keyword == Keyword.SUPER &&
3204 _currentToken.next.type == TokenType.CARET) {
3205 expression = new SuperExpression(getAndAdvance());
3206 } else {
3207 expression = _parseBitwiseAndExpression();
3208 }
3209 while (_currentToken.type == TokenType.CARET) {
3210 expression = new BinaryExpression(
3211 expression, getAndAdvance(), _parseBitwiseAndExpression());
3212 }
3213 return expression;
3214 }
3215
3216 /**
3217 * Parse a block when we need to check for an open curly brace and recover
3218 * when there isn't one. Return the block that was parsed.
3219 *
3220 * block ::=
3221 * '{' statements '}'
3222 */
3223 Block _parseBlockChecked() {
3224 if (_matches(TokenType.OPEN_CURLY_BRACKET)) {
3225 return parseBlock();
3226 }
3227 // TODO(brianwilkerson) Improve the error message.
3228 _reportErrorForCurrentToken(
3229 ParserErrorCode.EXPECTED_TOKEN, [TokenType.OPEN_CURLY_BRACKET.lexeme]);
3230 // Recovery: Check for an unmatched closing curly bracket and parse
3231 // statements until it is reached.
3232 return new Block(_createSyntheticToken(TokenType.OPEN_CURLY_BRACKET), null,
3233 _createSyntheticToken(TokenType.CLOSE_CURLY_BRACKET));
3234 }
3235
3236 /**
3237 * Parse a break statement. Return the break statement that was parsed.
3238 *
3239 * This method assumes that the current token matches `Keyword.BREAK`.
3240 *
3241 * breakStatement ::=
3242 * 'break' identifier? ';'
3243 */
3244 Statement _parseBreakStatement() {
3245 Token breakKeyword = getAndAdvance();
3246 SimpleIdentifier label = null;
3247 if (_matchesIdentifier()) {
3248 label = _parseSimpleIdentifierUnchecked();
3249 }
3250 if (!_inLoop && !_inSwitch && label == null) {
3251 _reportErrorForToken(ParserErrorCode.BREAK_OUTSIDE_OF_LOOP, breakKeyword);
3252 }
3253 Token semicolon = _expect(TokenType.SEMICOLON);
3254 return new BreakStatement(breakKeyword, label, semicolon);
3255 }
3256
3257 /**
3258 * Parse a cascade section. Return the expression representing the cascaded
3259 * method invocation.
3260 *
3261 * This method assumes that the current token matches
3262 * `TokenType.PERIOD_PERIOD`.
3263 *
3264 * cascadeSection ::=
3265 * '..' (cascadeSelector typeArguments? arguments*)
3266 * (assignableSelector typeArguments? arguments*)* cascadeAssignment?
3267 *
3268 * cascadeSelector ::=
3269 * '[' expression ']'
3270 * | identifier
3271 *
3272 * cascadeAssignment ::=
3273 * assignmentOperator expressionWithoutCascade
3274 */
3275 Expression _parseCascadeSection() {
3276 Token period = getAndAdvance();
3277 Expression expression = null;
3278 SimpleIdentifier functionName = null;
3279 if (_matchesIdentifier()) {
3280 functionName = _parseSimpleIdentifierUnchecked();
3281 } else if (_currentToken.type == TokenType.OPEN_SQUARE_BRACKET) {
3282 Token leftBracket = getAndAdvance();
3283 bool wasInInitializer = _inInitializer;
3284 _inInitializer = false;
3285 try {
3286 Expression index = parseExpression2();
3287 Token rightBracket = _expect(TokenType.CLOSE_SQUARE_BRACKET);
3288 expression = new IndexExpression.forCascade(
3289 period, leftBracket, index, rightBracket);
3290 period = null;
3291 } finally {
3292 _inInitializer = wasInInitializer;
3293 }
3294 } else {
3295 _reportErrorForToken(ParserErrorCode.MISSING_IDENTIFIER, _currentToken,
3296 [_currentToken.lexeme]);
3297 functionName = _createSyntheticIdentifier();
3298 }
3299 assert((expression == null && functionName != null) ||
3300 (expression != null && functionName == null));
3301 if (_isLikelyArgumentList()) {
3302 do {
3303 TypeArgumentList typeArguments = _parseOptionalTypeArguments();
3304 if (functionName != null) {
3305 expression = new MethodInvocation(expression, period, functionName,
3306 typeArguments, parseArgumentList());
3307 period = null;
3308 functionName = null;
3309 } else if (expression == null) {
3310 // It should not be possible to get here.
3311 expression = new MethodInvocation(expression, period,
3312 _createSyntheticIdentifier(), typeArguments, parseArgumentList());
3313 } else {
3314 expression = new FunctionExpressionInvocation(
3315 expression, typeArguments, parseArgumentList());
3316 }
3317 } while (_isLikelyArgumentList());
3318 } else if (functionName != null) {
3319 expression = new PropertyAccess(expression, period, functionName);
3320 period = null;
3321 }
3322 assert(expression != null);
3323 bool progress = true;
3324 while (progress) {
3325 progress = false;
3326 Expression selector = _parseAssignableSelector(expression, true);
3327 if (!identical(selector, expression)) {
3328 expression = selector;
3329 progress = true;
3330 while (_isLikelyArgumentList()) {
3331 TypeArgumentList typeArguments = _parseOptionalTypeArguments();
3332 Expression currentExpression = expression;
3333 if (currentExpression is PropertyAccess) {
3334 expression = new MethodInvocation(
3335 currentExpression.target,
3336 currentExpression.operator,
3337 currentExpression.propertyName,
3338 typeArguments,
3339 parseArgumentList());
3340 } else {
3341 expression = new FunctionExpressionInvocation(
3342 expression, typeArguments, parseArgumentList());
3343 }
3344 }
3345 }
3346 }
3347 if (_currentToken.type.isAssignmentOperator) {
3348 Token operator = getAndAdvance();
3349 _ensureAssignable(expression);
3350 expression = new AssignmentExpression(
3351 expression, operator, parseExpressionWithoutCascade());
3352 }
3353 return expression;
3354 }
3355
3356 /**
3357 * Parse a class declaration. The [commentAndMetadata] is the metadata to be
3358 * associated with the member. The [abstractKeyword] is the token for the
3359 * keyword 'abstract', or `null` if the keyword was not given. Return the
3360 * class declaration that was parsed.
3361 *
3362 * This method assumes that the current token matches `Keyword.CLASS`.
3363 *
3364 * classDeclaration ::=
3365 * metadata 'abstract'? 'class' name typeParameterList? (extendsClause withClause?)? implementsClause? '{' classMembers '}' |
3366 * metadata 'abstract'? 'class' mixinApplicationClass
3367 */
3368 CompilationUnitMember _parseClassDeclaration(
3369 CommentAndMetadata commentAndMetadata, Token abstractKeyword) {
3370 //
3371 // Parse the name and type parameters.
3372 //
3373 Token keyword = getAndAdvance();
3374 SimpleIdentifier name = parseSimpleIdentifier(isDeclaration: true);
3375 String className = name.name;
3376 TypeParameterList typeParameters = null;
3377 TokenType type = _currentToken.type;
3378 if (type == TokenType.LT) {
3379 typeParameters = parseTypeParameterList();
3380 type = _currentToken.type;
3381 }
3382 //
3383 // Check to see whether this might be a class type alias rather than a class
3384 // declaration.
3385 //
3386 if (type == TokenType.EQ) {
3387 return _parseClassTypeAliasAfterName(
3388 commentAndMetadata, abstractKeyword, keyword, name, typeParameters);
3389 }
3390 //
3391 // Parse the clauses. The parser accepts clauses in any order, but will
3392 // generate errors if they are not in the order required by the
3393 // specification.
3394 //
3395 ExtendsClause extendsClause = null;
3396 WithClause withClause = null;
3397 ImplementsClause implementsClause = null;
3398 bool foundClause = true;
3399 while (foundClause) {
3400 Keyword keyword = _currentToken.keyword;
3401 if (keyword == Keyword.EXTENDS) {
3402 if (extendsClause == null) {
3403 extendsClause = parseExtendsClause();
3404 if (withClause != null) {
3405 _reportErrorForToken(
3406 ParserErrorCode.WITH_BEFORE_EXTENDS, withClause.withKeyword);
3407 } else if (implementsClause != null) {
3408 _reportErrorForToken(ParserErrorCode.IMPLEMENTS_BEFORE_EXTENDS,
3409 implementsClause.implementsKeyword);
3410 }
3411 } else {
3412 _reportErrorForToken(ParserErrorCode.MULTIPLE_EXTENDS_CLAUSES,
3413 extendsClause.extendsKeyword);
3414 parseExtendsClause();
3415 }
3416 } else if (keyword == Keyword.WITH) {
3417 if (withClause == null) {
3418 withClause = parseWithClause();
3419 if (implementsClause != null) {
3420 _reportErrorForToken(ParserErrorCode.IMPLEMENTS_BEFORE_WITH,
3421 implementsClause.implementsKeyword);
3422 }
3423 } else {
3424 _reportErrorForToken(
3425 ParserErrorCode.MULTIPLE_WITH_CLAUSES, withClause.withKeyword);
3426 parseWithClause();
3427 // TODO(brianwilkerson) Should we merge the list of applied mixins
3428 // into a single list?
3429 }
3430 } else if (keyword == Keyword.IMPLEMENTS) {
3431 if (implementsClause == null) {
3432 implementsClause = parseImplementsClause();
3433 } else {
3434 _reportErrorForToken(ParserErrorCode.MULTIPLE_IMPLEMENTS_CLAUSES,
3435 implementsClause.implementsKeyword);
3436 parseImplementsClause();
3437 // TODO(brianwilkerson) Should we merge the list of implemented
3438 // classes into a single list?
3439 }
3440 } else {
3441 foundClause = false;
3442 }
3443 }
3444 if (withClause != null && extendsClause == null) {
3445 _reportErrorForToken(
3446 ParserErrorCode.WITH_WITHOUT_EXTENDS, withClause.withKeyword);
3447 }
3448 //
3449 // Look for and skip over the extra-lingual 'native' specification.
3450 //
3451 NativeClause nativeClause = null;
3452 if (_matchesString(_NATIVE) && _tokenMatches(_peek(), TokenType.STRING)) {
3453 nativeClause = _parseNativeClause();
3454 }
3455 //
3456 // Parse the body of the class.
3457 //
3458 Token leftBracket = null;
3459 List<ClassMember> members = null;
3460 Token rightBracket = null;
3461 if (_matches(TokenType.OPEN_CURLY_BRACKET)) {
3462 leftBracket = getAndAdvance();
3463 members = _parseClassMembers(className, _getEndToken(leftBracket));
3464 rightBracket = _expect(TokenType.CLOSE_CURLY_BRACKET);
3465 } else {
3466 // Recovery: Check for an unmatched closing curly bracket and parse
3467 // members until it is reached.
3468 leftBracket = _createSyntheticToken(TokenType.OPEN_CURLY_BRACKET);
3469 rightBracket = _createSyntheticToken(TokenType.CLOSE_CURLY_BRACKET);
3470 _reportErrorForCurrentToken(ParserErrorCode.MISSING_CLASS_BODY);
3471 }
3472 ClassDeclaration classDeclaration = new ClassDeclaration(
3473 commentAndMetadata.comment,
3474 commentAndMetadata.metadata,
3475 abstractKeyword,
3476 keyword,
3477 name,
3478 typeParameters,
3479 extendsClause,
3480 withClause,
3481 implementsClause,
3482 leftBracket,
3483 members,
3484 rightBracket);
3485 classDeclaration.nativeClause = nativeClause;
3486 return classDeclaration;
3487 }
3488
3489 /**
3490 * Parse a list of class members. The [className] is the name of the class
3491 * whose members are being parsed. The [closingBracket] is the closing bracket
3492 * for the class, or `null` if the closing bracket is missing. Return the list
3493 * of class members that were parsed.
3494 *
3495 * classMembers ::=
3496 * (metadata memberDefinition)*
3497 */
3498 List<ClassMember> _parseClassMembers(String className, Token closingBracket) {
3499 List<ClassMember> members = <ClassMember>[];
3500 Token memberStart = _currentToken;
3501 TokenType type = _currentToken.type;
3502 Keyword keyword = _currentToken.keyword;
3503 while (type != TokenType.EOF &&
3504 type != TokenType.CLOSE_CURLY_BRACKET &&
3505 (closingBracket != null ||
3506 (keyword != Keyword.CLASS && keyword != Keyword.TYPEDEF))) {
3507 if (type == TokenType.SEMICOLON) {
3508 _reportErrorForToken(ParserErrorCode.UNEXPECTED_TOKEN, _currentToken,
3509 [_currentToken.lexeme]);
3510 _advance();
3511 } else {
3512 ClassMember member = parseClassMember(className);
3513 if (member != null) {
3514 members.add(member);
3515 }
3516 }
3517 if (identical(_currentToken, memberStart)) {
3518 _reportErrorForToken(ParserErrorCode.UNEXPECTED_TOKEN, _currentToken,
3519 [_currentToken.lexeme]);
3520 _advance();
3521 }
3522 memberStart = _currentToken;
3523 type = _currentToken.type;
3524 keyword = _currentToken.keyword;
3525 }
3526 return members;
3527 }
3528
3529 /**
3530 * Parse a class type alias. The [commentAndMetadata] is the metadata to be
3531 * associated with the member. The [abstractKeyword] is the token representing
3532 * the 'abstract' keyword. The [classKeyword] is the token representing the
3533 * 'class' keyword. Return the class type alias that was parsed.
3534 *
3535 * This method assumes that the current token matches an identifier.
3536 *
3537 * classTypeAlias ::=
3538 * identifier typeParameters? '=' 'abstract'? mixinApplication
3539 *
3540 * mixinApplication ::=
3541 * type withClause implementsClause? ';'
3542 */
3543 ClassTypeAlias _parseClassTypeAlias(CommentAndMetadata commentAndMetadata,
3544 Token abstractKeyword, Token classKeyword) {
3545 SimpleIdentifier className =
3546 _parseSimpleIdentifierUnchecked(isDeclaration: true);
3547 TypeParameterList typeParameters = null;
3548 if (_matches(TokenType.LT)) {
3549 typeParameters = parseTypeParameterList();
3550 }
3551 return _parseClassTypeAliasAfterName(commentAndMetadata, abstractKeyword,
3552 classKeyword, className, typeParameters);
3553 }
3554
3555 /**
3556 * Parse a class type alias. The [commentAndMetadata] is the metadata to be
3557 * associated with the member. The [abstractKeyword] is the token representing
3558 * the 'abstract' keyword. The [classKeyword] is the token representing the
3559 * 'class' keyword. The [className] is the name of the alias, and the
3560 * [typeParameters] are the type parameters following the name. Return the
3561 * class type alias that was parsed.
3562 *
3563 * classTypeAlias ::=
3564 * identifier typeParameters? '=' 'abstract'? mixinApplication
3565 *
3566 * mixinApplication ::=
3567 * type withClause implementsClause? ';'
3568 */
3569 ClassTypeAlias _parseClassTypeAliasAfterName(
3570 CommentAndMetadata commentAndMetadata,
3571 Token abstractKeyword,
3572 Token classKeyword,
3573 SimpleIdentifier className,
3574 TypeParameterList typeParameters) {
3575 Token equals = _expect(TokenType.EQ);
3576 TypeName superclass = parseTypeName(false);
3577 WithClause withClause = null;
3578 if (_matchesKeyword(Keyword.WITH)) {
3579 withClause = parseWithClause();
3580 } else {
3581 _reportErrorForCurrentToken(
3582 ParserErrorCode.EXPECTED_TOKEN, [Keyword.WITH.syntax]);
3583 }
3584 ImplementsClause implementsClause = null;
3585 if (_matchesKeyword(Keyword.IMPLEMENTS)) {
3586 implementsClause = parseImplementsClause();
3587 }
3588 Token semicolon;
3589 if (_matches(TokenType.SEMICOLON)) {
3590 semicolon = getAndAdvance();
3591 } else {
3592 if (_matches(TokenType.OPEN_CURLY_BRACKET)) {
3593 _reportErrorForCurrentToken(
3594 ParserErrorCode.EXPECTED_TOKEN, [TokenType.SEMICOLON.lexeme]);
3595 Token leftBracket = getAndAdvance();
3596 _parseClassMembers(className.name, _getEndToken(leftBracket));
3597 _expect(TokenType.CLOSE_CURLY_BRACKET);
3598 } else {
3599 _reportErrorForToken(ParserErrorCode.EXPECTED_TOKEN,
3600 _currentToken.previous, [TokenType.SEMICOLON.lexeme]);
3601 }
3602 semicolon = _createSyntheticToken(TokenType.SEMICOLON);
3603 }
3604 return new ClassTypeAlias(
3605 commentAndMetadata.comment,
3606 commentAndMetadata.metadata,
3607 classKeyword,
3608 className,
3609 typeParameters,
3610 equals,
3611 abstractKeyword,
3612 superclass,
3613 withClause,
3614 implementsClause,
3615 semicolon);
3616 }
3617
3618 /**
3619 * Parse a list of combinators in a directive. Return the combinators that
3620 * were parsed, or `null` if there are no combinators.
3621 *
3622 * combinator ::=
3623 * 'show' identifier (',' identifier)*
3624 * | 'hide' identifier (',' identifier)*
3625 */
3626 List<Combinator> _parseCombinators() {
3627 List<Combinator> combinators = null;
3628 while (true) {
3629 Combinator combinator = parseCombinator();
3630 if (combinator == null) {
3631 break;
3632 }
3633 combinators ??= <Combinator>[];
3634 combinators.add(combinator);
3635 }
3636 return combinators;
3637 }
3638
3639 /**
3640 * Parse the documentation comment and metadata preceding a declaration. This
3641 * method allows any number of documentation comments to occur before, after
3642 * or between the metadata, but only returns the last (right-most)
3643 * documentation comment that is found. Return the documentation comment and
3644 * metadata that were parsed.
3645 *
3646 * metadata ::=
3647 * annotation*
3648 */
3649 CommentAndMetadata _parseCommentAndMetadata() {
3650 // TODO(brianwilkerson) Consider making the creation of documentation
3651 // comments be lazy.
3652 List<DocumentationCommentToken> tokens = _parseDocumentationCommentTokens();
3653 List<Annotation> metadata = null;
3654 while (_matches(TokenType.AT)) {
3655 metadata ??= <Annotation>[];
3656 metadata.add(parseAnnotation());
3657 List<DocumentationCommentToken> optionalTokens =
3658 _parseDocumentationCommentTokens();
3659 if (optionalTokens != null) {
3660 tokens = optionalTokens;
3661 }
3662 }
3663 return new CommentAndMetadata(_parseDocumentationComment(tokens), metadata);
3664 }
3665
3666 /**
3667 * Parse a comment reference from the source between square brackets. The
3668 * [referenceSource] is the source occurring between the square brackets
3669 * within a documentation comment. The [sourceOffset] is the offset of the
3670 * first character of the reference source. Return the comment reference that
3671 * was parsed, or `null` if no reference could be found.
3672 *
3673 * commentReference ::=
3674 * 'new'? prefixedIdentifier
3675 */
3676 CommentReference _parseCommentReference(
3677 String referenceSource, int sourceOffset) {
3678 // TODO(brianwilkerson) The errors are not getting the right offset/length
3679 // and are being duplicated.
3680 try {
3681 BooleanErrorListener listener = new BooleanErrorListener();
3682 Scanner scanner = new Scanner(
3683 null, new SubSequenceReader(referenceSource, sourceOffset), listener);
3684 scanner.setSourceStart(1, 1);
3685 Token firstToken = scanner.tokenize();
3686 if (listener.errorReported) {
3687 return null;
3688 }
3689 if (firstToken.type == TokenType.EOF) {
3690 Token syntheticToken =
3691 new SyntheticStringToken(TokenType.IDENTIFIER, "", sourceOffset);
3692 syntheticToken.setNext(firstToken);
3693 return new CommentReference(null, new SimpleIdentifier(syntheticToken));
3694 }
3695 Token newKeyword = null;
3696 if (_tokenMatchesKeyword(firstToken, Keyword.NEW)) {
3697 newKeyword = firstToken;
3698 firstToken = firstToken.next;
3699 }
3700 if (firstToken.isUserDefinableOperator) {
3701 if (firstToken.next.type != TokenType.EOF) {
3702 return null;
3703 }
3704 Identifier identifier = new SimpleIdentifier(firstToken);
3705 return new CommentReference(null, identifier);
3706 } else if (_tokenMatchesKeyword(firstToken, Keyword.OPERATOR)) {
3707 Token secondToken = firstToken.next;
3708 if (secondToken.isUserDefinableOperator) {
3709 if (secondToken.next.type != TokenType.EOF) {
3710 return null;
3711 }
3712 Identifier identifier = new SimpleIdentifier(secondToken);
3713 return new CommentReference(null, identifier);
3714 }
3715 return null;
3716 } else if (_tokenMatchesIdentifier(firstToken)) {
3717 Token secondToken = firstToken.next;
3718 Token thirdToken = secondToken.next;
3719 Token nextToken;
3720 Identifier identifier;
3721 if (_tokenMatches(secondToken, TokenType.PERIOD)) {
3722 if (thirdToken.isUserDefinableOperator) {
3723 identifier = new PrefixedIdentifier(
3724 new SimpleIdentifier(firstToken),
3725 secondToken,
3726 new SimpleIdentifier(thirdToken));
3727 nextToken = thirdToken.next;
3728 } else if (_tokenMatchesKeyword(thirdToken, Keyword.OPERATOR)) {
3729 Token fourthToken = thirdToken.next;
3730 if (fourthToken.isUserDefinableOperator) {
3731 identifier = new PrefixedIdentifier(
3732 new SimpleIdentifier(firstToken),
3733 secondToken,
3734 new SimpleIdentifier(fourthToken));
3735 nextToken = fourthToken.next;
3736 } else {
3737 return null;
3738 }
3739 } else if (_tokenMatchesIdentifier(thirdToken)) {
3740 identifier = new PrefixedIdentifier(
3741 new SimpleIdentifier(firstToken),
3742 secondToken,
3743 new SimpleIdentifier(thirdToken));
3744 nextToken = thirdToken.next;
3745 }
3746 } else {
3747 identifier = new SimpleIdentifier(firstToken);
3748 nextToken = firstToken.next;
3749 }
3750 if (nextToken.type != TokenType.EOF) {
3751 return null;
3752 }
3753 return new CommentReference(newKeyword, identifier);
3754 } else {
3755 Keyword keyword = firstToken.keyword;
3756 if (keyword == Keyword.THIS ||
3757 keyword == Keyword.NULL ||
3758 keyword == Keyword.TRUE ||
3759 keyword == Keyword.FALSE) {
3760 // TODO(brianwilkerson) If we want to support this we will need to
3761 // extend the definition of CommentReference to take an expression
3762 // rather than an identifier. For now we just ignore it to reduce the
3763 // number of errors produced, but that's probably not a valid long ter m
3764 // approach.
3765 return null;
3766 }
3767 }
3768 } catch (exception) {
3769 // Ignored because we assume that it wasn't a real comment reference.
3770 }
3771 return null;
3772 }
3773
3774 /**
3775 * Parse all of the comment references occurring in the given array of
3776 * documentation comments. The [tokens] are the comment tokens representing
3777 * the documentation comments to be parsed. Return the comment references that
3778 * were parsed.
3779 *
3780 * commentReference ::=
3781 * '[' 'new'? qualified ']' libraryReference?
3782 *
3783 * libraryReference ::=
3784 * '(' stringLiteral ')'
3785 */
3786 List<CommentReference> _parseCommentReferences(
3787 List<DocumentationCommentToken> tokens) {
3788 List<CommentReference> references = <CommentReference>[];
3789 bool isInGitHubCodeBlock = false;
3790 for (DocumentationCommentToken token in tokens) {
3791 String comment = token.lexeme;
3792 // Skip GitHub code blocks.
3793 // https://help.github.com/articles/creating-and-highlighting-code-blocks/
3794 if (tokens.length != 1) {
3795 if (comment.indexOf('```') != -1) {
3796 isInGitHubCodeBlock = !isInGitHubCodeBlock;
3797 }
3798 if (isInGitHubCodeBlock) {
3799 continue;
3800 }
3801 }
3802 // Remove GitHub include code.
3803 comment = _removeGitHubInlineCode(comment);
3804 // Find references.
3805 int length = comment.length;
3806 List<List<int>> codeBlockRanges = _getCodeBlockRanges(comment);
3807 int leftIndex = comment.indexOf('[');
3808 while (leftIndex >= 0 && leftIndex + 1 < length) {
3809 List<int> range = _findRange(codeBlockRanges, leftIndex);
3810 if (range == null) {
3811 int nameOffset = token.offset + leftIndex + 1;
3812 int rightIndex = comment.indexOf(']', leftIndex);
3813 if (rightIndex >= 0) {
3814 int firstChar = comment.codeUnitAt(leftIndex + 1);
3815 if (firstChar != 0x27 && firstChar != 0x22) {
3816 if (_isLinkText(comment, rightIndex)) {
3817 // TODO(brianwilkerson) Handle the case where there's a library
3818 // URI in the link text.
3819 } else {
3820 CommentReference reference = _parseCommentReference(
3821 comment.substring(leftIndex + 1, rightIndex), nameOffset);
3822 if (reference != null) {
3823 references.add(reference);
3824 token.references.add(reference.beginToken);
3825 }
3826 }
3827 }
3828 } else {
3829 // terminating ']' is not typed yet
3830 int charAfterLeft = comment.codeUnitAt(leftIndex + 1);
3831 Token nameToken;
3832 if (Character.isLetterOrDigit(charAfterLeft)) {
3833 int nameEnd = StringUtilities.indexOfFirstNotLetterDigit(
3834 comment, leftIndex + 1);
3835 String name = comment.substring(leftIndex + 1, nameEnd);
3836 nameToken =
3837 new StringToken(TokenType.IDENTIFIER, name, nameOffset);
3838 } else {
3839 nameToken = new SyntheticStringToken(
3840 TokenType.IDENTIFIER, '', nameOffset);
3841 }
3842 nameToken.setNext(new SimpleToken(TokenType.EOF, nameToken.end));
3843 references.add(
3844 new CommentReference(null, new SimpleIdentifier(nameToken)));
3845 token.references.add(nameToken);
3846 // next character
3847 rightIndex = leftIndex + 1;
3848 }
3849 leftIndex = comment.indexOf('[', rightIndex);
3850 } else {
3851 leftIndex = comment.indexOf('[', range[1]);
3852 }
3853 }
3854 }
3855 return references;
3856 }
3857
3858 /**
3859 * Parse a compilation unit member. The [commentAndMetadata] is the metadata
3860 * to be associated with the member. Return the compilation unit member that
3861 * was parsed, or `null` if what was parsed could not be represented as a
3862 * compilation unit member.
3863 *
3864 * compilationUnitMember ::=
3865 * classDefinition
3866 * | functionTypeAlias
3867 * | external functionSignature
3868 * | external getterSignature
3869 * | external setterSignature
3870 * | functionSignature functionBody
3871 * | returnType? getOrSet identifier formalParameterList functionBody
3872 * | (final | const) type? staticFinalDeclarationList ';'
3873 * | variableDeclaration ';'
3874 */
3875 CompilationUnitMember _parseCompilationUnitMember(
3876 CommentAndMetadata commentAndMetadata) {
3877 Modifiers modifiers = _parseModifiers();
3878 Keyword keyword = _currentToken.keyword;
3879 if (keyword == Keyword.CLASS) {
3880 return _parseClassDeclaration(
3881 commentAndMetadata, _validateModifiersForClass(modifiers));
3882 }
3883 Token next = _peek();
3884 TokenType nextType = next.type;
3885 if (keyword == Keyword.TYPEDEF &&
3886 nextType != TokenType.PERIOD &&
3887 nextType != TokenType.LT &&
3888 nextType != TokenType.OPEN_PAREN) {
3889 _validateModifiersForTypedef(modifiers);
3890 return _parseTypeAlias(commentAndMetadata);
3891 } else if (keyword == Keyword.ENUM) {
3892 _validateModifiersForEnum(modifiers);
3893 return _parseEnumDeclaration(commentAndMetadata);
3894 } else if (keyword == Keyword.VOID) {
3895 TypeName returnType =
3896 new TypeName(new SimpleIdentifier(getAndAdvance()), null);
3897 keyword = _currentToken.keyword;
3898 next = _peek();
3899 if ((keyword == Keyword.GET || keyword == Keyword.SET) &&
3900 _tokenMatchesIdentifier(next)) {
3901 _validateModifiersForTopLevelFunction(modifiers);
3902 return _parseFunctionDeclaration(
3903 commentAndMetadata, modifiers.externalKeyword, returnType);
3904 } else if (keyword == Keyword.OPERATOR && _isOperator(next)) {
3905 _reportErrorForToken(ParserErrorCode.TOP_LEVEL_OPERATOR, _currentToken);
3906 return _convertToFunctionDeclaration(_parseOperatorAfterKeyword(
3907 commentAndMetadata,
3908 modifiers.externalKeyword,
3909 returnType,
3910 getAndAdvance()));
3911 } else if (_matchesIdentifier() &&
3912 next.matchesAny(const <TokenType>[
3913 TokenType.OPEN_PAREN,
3914 TokenType.OPEN_CURLY_BRACKET,
3915 TokenType.FUNCTION,
3916 TokenType.LT
3917 ])) {
3918 _validateModifiersForTopLevelFunction(modifiers);
3919 return _parseFunctionDeclaration(
3920 commentAndMetadata, modifiers.externalKeyword, returnType);
3921 } else {
3922 //
3923 // We have found an error of some kind. Try to recover.
3924 //
3925 if (_matchesIdentifier()) {
3926 if (next.matchesAny(const <TokenType>[
3927 TokenType.EQ,
3928 TokenType.COMMA,
3929 TokenType.SEMICOLON
3930 ])) {
3931 //
3932 // We appear to have a variable declaration with a type of "void".
3933 //
3934 _reportErrorForNode(ParserErrorCode.VOID_VARIABLE, returnType);
3935 return new TopLevelVariableDeclaration(
3936 commentAndMetadata.comment,
3937 commentAndMetadata.metadata,
3938 _parseVariableDeclarationListAfterType(null,
3939 _validateModifiersForTopLevelVariable(modifiers), null),
3940 _expect(TokenType.SEMICOLON));
3941 }
3942 }
3943 _reportErrorForToken(
3944 ParserErrorCode.EXPECTED_EXECUTABLE, _currentToken);
3945 return null;
3946 }
3947 } else if ((keyword == Keyword.GET || keyword == Keyword.SET) &&
3948 _tokenMatchesIdentifier(next)) {
3949 _validateModifiersForTopLevelFunction(modifiers);
3950 return _parseFunctionDeclaration(
3951 commentAndMetadata, modifiers.externalKeyword, null);
3952 } else if (keyword == Keyword.OPERATOR && _isOperator(next)) {
3953 _reportErrorForToken(ParserErrorCode.TOP_LEVEL_OPERATOR, _currentToken);
3954 return _convertToFunctionDeclaration(_parseOperatorAfterKeyword(
3955 commentAndMetadata,
3956 modifiers.externalKeyword,
3957 null,
3958 getAndAdvance()));
3959 } else if (!_matchesIdentifier()) {
3960 Token keyword = modifiers.varKeyword;
3961 if (keyword == null) {
3962 keyword = modifiers.finalKeyword;
3963 }
3964 if (keyword == null) {
3965 keyword = modifiers.constKeyword;
3966 }
3967 if (keyword != null) {
3968 //
3969 // We appear to have found an incomplete top-level variable declaration.
3970 //
3971 _reportErrorForCurrentToken(ParserErrorCode.MISSING_IDENTIFIER);
3972 VariableDeclaration variable =
3973 new VariableDeclaration(_createSyntheticIdentifier(), null, null);
3974 List<VariableDeclaration> variables = <VariableDeclaration>[variable];
3975 return new TopLevelVariableDeclaration(
3976 commentAndMetadata.comment,
3977 commentAndMetadata.metadata,
3978 new VariableDeclarationList(null, null, keyword, null, variables),
3979 _expect(TokenType.SEMICOLON));
3980 }
3981 _reportErrorForToken(ParserErrorCode.EXPECTED_EXECUTABLE, _currentToken);
3982 return null;
3983 } else if (_isPeekGenericTypeParametersAndOpenParen()) {
3984 return _parseFunctionDeclaration(
3985 commentAndMetadata, modifiers.externalKeyword, null);
3986 } else if (_tokenMatches(next, TokenType.OPEN_PAREN)) {
3987 TypeName returnType = _parseOptionalTypeNameComment();
3988 _validateModifiersForTopLevelFunction(modifiers);
3989 return _parseFunctionDeclaration(
3990 commentAndMetadata, modifiers.externalKeyword, returnType);
3991 } else if (next.matchesAny(const <TokenType>[
3992 TokenType.EQ,
3993 TokenType.COMMA,
3994 TokenType.SEMICOLON
3995 ])) {
3996 if (modifiers.constKeyword == null &&
3997 modifiers.finalKeyword == null &&
3998 modifiers.varKeyword == null) {
3999 _reportErrorForCurrentToken(
4000 ParserErrorCode.MISSING_CONST_FINAL_VAR_OR_TYPE);
4001 }
4002 return new TopLevelVariableDeclaration(
4003 commentAndMetadata.comment,
4004 commentAndMetadata.metadata,
4005 _parseVariableDeclarationListAfterType(
4006 null, _validateModifiersForTopLevelVariable(modifiers), null),
4007 _expect(TokenType.SEMICOLON));
4008 }
4009 TypeName returnType = parseReturnType();
4010 keyword = _currentToken.keyword;
4011 next = _peek();
4012 if ((keyword == Keyword.GET || keyword == Keyword.SET) &&
4013 _tokenMatchesIdentifier(next)) {
4014 _validateModifiersForTopLevelFunction(modifiers);
4015 return _parseFunctionDeclaration(
4016 commentAndMetadata, modifiers.externalKeyword, returnType);
4017 } else if (keyword == Keyword.OPERATOR && _isOperator(next)) {
4018 _reportErrorForToken(ParserErrorCode.TOP_LEVEL_OPERATOR, _currentToken);
4019 return _convertToFunctionDeclaration(_parseOperatorAfterKeyword(
4020 commentAndMetadata,
4021 modifiers.externalKeyword,
4022 returnType,
4023 getAndAdvance()));
4024 } else if (_matches(TokenType.AT)) {
4025 return new TopLevelVariableDeclaration(
4026 commentAndMetadata.comment,
4027 commentAndMetadata.metadata,
4028 _parseVariableDeclarationListAfterType(null,
4029 _validateModifiersForTopLevelVariable(modifiers), returnType),
4030 _expect(TokenType.SEMICOLON));
4031 } else if (!_matchesIdentifier()) {
4032 // TODO(brianwilkerson) Generalize this error. We could also be parsing a
4033 // top-level variable at this point.
4034 _reportErrorForToken(ParserErrorCode.EXPECTED_EXECUTABLE, _currentToken);
4035 Token semicolon;
4036 if (_matches(TokenType.SEMICOLON)) {
4037 semicolon = getAndAdvance();
4038 } else {
4039 semicolon = _createSyntheticToken(TokenType.SEMICOLON);
4040 }
4041 VariableDeclaration variable =
4042 new VariableDeclaration(_createSyntheticIdentifier(), null, null);
4043 List<VariableDeclaration> variables = <VariableDeclaration>[variable];
4044 return new TopLevelVariableDeclaration(
4045 commentAndMetadata.comment,
4046 commentAndMetadata.metadata,
4047 new VariableDeclarationList(null, null, null, returnType, variables),
4048 semicolon);
4049 } else if (next.matchesAny(const <TokenType>[
4050 TokenType.OPEN_PAREN,
4051 TokenType.FUNCTION,
4052 TokenType.OPEN_CURLY_BRACKET,
4053 TokenType.LT
4054 ])) {
4055 _validateModifiersForTopLevelFunction(modifiers);
4056 return _parseFunctionDeclaration(
4057 commentAndMetadata, modifiers.externalKeyword, returnType);
4058 }
4059 return new TopLevelVariableDeclaration(
4060 commentAndMetadata.comment,
4061 commentAndMetadata.metadata,
4062 _parseVariableDeclarationListAfterType(
4063 null, _validateModifiersForTopLevelVariable(modifiers), returnType),
4064 _expect(TokenType.SEMICOLON));
4065 }
4066
4067 /**
4068 * Parse a configuration in either an import or export directive.
4069 *
4070 * This method assumes that the current token matches `Keyword.IF`.
4071 *
4072 * configuration ::=
4073 * 'if' '(' test ')' uri
4074 *
4075 * test ::=
4076 * dottedName ('==' stringLiteral)?
4077 *
4078 * dottedName ::=
4079 * identifier ('.' identifier)*
4080 */
4081 Configuration _parseConfiguration() {
4082 Token ifKeyword = getAndAdvance();
4083 Token leftParenthesis = _expect(TokenType.OPEN_PAREN);
4084 DottedName name = _parseDottedName();
4085 Token equalToken = null;
4086 StringLiteral value = null;
4087 if (_matches(TokenType.EQ_EQ)) {
4088 equalToken = getAndAdvance();
4089 value = parseStringLiteral();
4090 if (value is StringInterpolation) {
4091 _reportErrorForNode(
4092 ParserErrorCode.INVALID_LITERAL_IN_CONFIGURATION, value);
4093 }
4094 }
4095 Token rightParenthesis = _expect(TokenType.CLOSE_PAREN);
4096 StringLiteral libraryUri = _parseUri();
4097 return new Configuration(ifKeyword, leftParenthesis, name, equalToken,
4098 value, rightParenthesis, libraryUri);
4099 }
4100
4101 /**
4102 * Parse a list of configurations. Return the configurations that were parsed,
4103 * or `null` if there are no configurations.
4104 */
4105 List<Configuration> _parseConfigurations() {
4106 List<Configuration> configurations = null;
4107 while (_matchesKeyword(Keyword.IF)) {
4108 configurations ??= <Configuration>[];
4109 configurations.add(_parseConfiguration());
4110 }
4111 return configurations;
4112 }
4113
4114 /**
4115 * Parse a const expression. Return the const expression that was parsed.
4116 *
4117 * This method assumes that the current token matches `Keyword.CONST`.
4118 *
4119 * constExpression ::=
4120 * instanceCreationExpression
4121 * | listLiteral
4122 * | mapLiteral
4123 */
4124 Expression _parseConstExpression() {
4125 Token keyword = getAndAdvance();
4126 TokenType type = _currentToken.type;
4127 if (type == TokenType.LT || _injectGenericCommentTypeList()) {
4128 return _parseListOrMapLiteral(keyword);
4129 } else if (type == TokenType.OPEN_SQUARE_BRACKET ||
4130 type == TokenType.INDEX) {
4131 return _parseListLiteral(keyword, null);
4132 } else if (type == TokenType.OPEN_CURLY_BRACKET) {
4133 return _parseMapLiteral(keyword, null);
4134 }
4135 return _parseInstanceCreationExpression(keyword);
4136 }
4137
4138 ConstructorDeclaration _parseConstructor(
4139 CommentAndMetadata commentAndMetadata,
4140 Token externalKeyword,
4141 Token constKeyword,
4142 Token factoryKeyword,
4143 SimpleIdentifier returnType,
4144 Token period,
4145 SimpleIdentifier name,
4146 FormalParameterList parameters) {
4147 bool bodyAllowed = externalKeyword == null;
4148 Token separator = null;
4149 List<ConstructorInitializer> initializers = null;
4150 if (_matches(TokenType.COLON)) {
4151 separator = getAndAdvance();
4152 initializers = <ConstructorInitializer>[];
4153 do {
4154 Keyword keyword = _currentToken.keyword;
4155 if (keyword == Keyword.THIS) {
4156 TokenType nextType = _peek().type;
4157 if (nextType == TokenType.OPEN_PAREN) {
4158 bodyAllowed = false;
4159 initializers.add(_parseRedirectingConstructorInvocation(false));
4160 } else if (nextType == TokenType.PERIOD &&
4161 _tokenMatches(_peekAt(3), TokenType.OPEN_PAREN)) {
4162 bodyAllowed = false;
4163 initializers.add(_parseRedirectingConstructorInvocation(true));
4164 } else {
4165 initializers.add(_parseConstructorFieldInitializer(true));
4166 }
4167 } else if (keyword == Keyword.SUPER) {
4168 initializers.add(_parseSuperConstructorInvocation());
4169 } else if (_matches(TokenType.OPEN_CURLY_BRACKET) ||
4170 _matches(TokenType.FUNCTION)) {
4171 _reportErrorForCurrentToken(ParserErrorCode.MISSING_INITIALIZER);
4172 } else if (_enableAssertInitializer &&
4173 _matchesKeyword(Keyword.ASSERT)) {
4174 _parseAssertInitializer();
4175 } else {
4176 initializers.add(_parseConstructorFieldInitializer(false));
4177 }
4178 } while (_optional(TokenType.COMMA));
4179 if (factoryKeyword != null) {
4180 _reportErrorForToken(
4181 ParserErrorCode.FACTORY_WITH_INITIALIZERS, factoryKeyword);
4182 }
4183 }
4184 ConstructorName redirectedConstructor = null;
4185 FunctionBody body;
4186 if (_matches(TokenType.EQ)) {
4187 separator = getAndAdvance();
4188 redirectedConstructor = parseConstructorName();
4189 body = new EmptyFunctionBody(_expect(TokenType.SEMICOLON));
4190 if (factoryKeyword == null) {
4191 _reportErrorForNode(
4192 ParserErrorCode.REDIRECTION_IN_NON_FACTORY_CONSTRUCTOR,
4193 redirectedConstructor);
4194 }
4195 } else {
4196 body = _parseFunctionBody(
4197 true, ParserErrorCode.MISSING_FUNCTION_BODY, false);
4198 if (constKeyword != null &&
4199 factoryKeyword != null &&
4200 externalKeyword == null) {
4201 _reportErrorForToken(ParserErrorCode.CONST_FACTORY, factoryKeyword);
4202 } else if (body is EmptyFunctionBody) {
4203 if (factoryKeyword != null &&
4204 externalKeyword == null &&
4205 _parseFunctionBodies) {
4206 _reportErrorForToken(
4207 ParserErrorCode.FACTORY_WITHOUT_BODY, factoryKeyword);
4208 }
4209 } else {
4210 if (constKeyword != null) {
4211 _reportErrorForNode(
4212 ParserErrorCode.CONST_CONSTRUCTOR_WITH_BODY, body);
4213 } else if (externalKeyword != null) {
4214 _reportErrorForNode(
4215 ParserErrorCode.EXTERNAL_CONSTRUCTOR_WITH_BODY, body);
4216 } else if (!bodyAllowed) {
4217 _reportErrorForNode(
4218 ParserErrorCode.REDIRECTING_CONSTRUCTOR_WITH_BODY, body);
4219 }
4220 }
4221 }
4222 return new ConstructorDeclaration(
4223 commentAndMetadata.comment,
4224 commentAndMetadata.metadata,
4225 externalKeyword,
4226 constKeyword,
4227 factoryKeyword,
4228 returnType,
4229 period,
4230 name,
4231 parameters,
4232 separator,
4233 initializers,
4234 redirectedConstructor,
4235 body);
4236 }
4237
4238 /**
4239 * Parse a field initializer within a constructor. The flag [hasThis] should
4240 * be true if the current token is `this`. Return the field initializer that
4241 * was parsed.
4242 *
4243 * fieldInitializer:
4244 * ('this' '.')? identifier '=' conditionalExpression cascadeSection*
4245 */
4246 ConstructorFieldInitializer _parseConstructorFieldInitializer(bool hasThis) {
4247 Token keywordToken = null;
4248 Token period = null;
4249 if (hasThis) {
4250 keywordToken = getAndAdvance();
4251 period = _expect(TokenType.PERIOD);
4252 }
4253 SimpleIdentifier fieldName = parseSimpleIdentifier();
4254 Token equals = null;
4255 TokenType type = _currentToken.type;
4256 if (type == TokenType.EQ) {
4257 equals = getAndAdvance();
4258 } else {
4259 _reportErrorForCurrentToken(
4260 ParserErrorCode.MISSING_ASSIGNMENT_IN_INITIALIZER);
4261 Keyword keyword = _currentToken.keyword;
4262 if (keyword != Keyword.THIS &&
4263 keyword != Keyword.SUPER &&
4264 type != TokenType.OPEN_CURLY_BRACKET &&
4265 type != TokenType.FUNCTION) {
4266 equals = _createSyntheticToken(TokenType.EQ);
4267 } else {
4268 return new ConstructorFieldInitializer(keywordToken, period, fieldName,
4269 _createSyntheticToken(TokenType.EQ), _createSyntheticIdentifier());
4270 }
4271 }
4272 bool wasInInitializer = _inInitializer;
4273 _inInitializer = true;
4274 try {
4275 Expression expression = parseConditionalExpression();
4276 if (_matches(TokenType.PERIOD_PERIOD)) {
4277 List<Expression> cascadeSections = <Expression>[];
4278 do {
4279 Expression section = _parseCascadeSection();
4280 if (section != null) {
4281 cascadeSections.add(section);
4282 }
4283 } while (_matches(TokenType.PERIOD_PERIOD));
4284 expression = new CascadeExpression(expression, cascadeSections);
4285 }
4286 return new ConstructorFieldInitializer(
4287 keywordToken, period, fieldName, equals, expression);
4288 } finally {
4289 _inInitializer = wasInInitializer;
4290 }
4291 }
4292
4293 /**
4294 * Parse a continue statement. Return the continue statement that was parsed.
4295 *
4296 * This method assumes that the current token matches `Keyword.CONTINUE`.
4297 *
4298 * continueStatement ::=
4299 * 'continue' identifier? ';'
4300 */
4301 Statement _parseContinueStatement() {
4302 Token continueKeyword = getAndAdvance();
4303 if (!_inLoop && !_inSwitch) {
4304 _reportErrorForToken(
4305 ParserErrorCode.CONTINUE_OUTSIDE_OF_LOOP, continueKeyword);
4306 }
4307 SimpleIdentifier label = null;
4308 if (_matchesIdentifier()) {
4309 label = _parseSimpleIdentifierUnchecked();
4310 }
4311 if (_inSwitch && !_inLoop && label == null) {
4312 _reportErrorForToken(
4313 ParserErrorCode.CONTINUE_WITHOUT_LABEL_IN_CASE, continueKeyword);
4314 }
4315 Token semicolon = _expect(TokenType.SEMICOLON);
4316 return new ContinueStatement(continueKeyword, label, semicolon);
4317 }
4318
4319 /**
4320 * Parse a directive. The [commentAndMetadata] is the metadata to be
4321 * associated with the directive. Return the directive that was parsed.
4322 *
4323 * directive ::=
4324 * exportDirective
4325 * | libraryDirective
4326 * | importDirective
4327 * | partDirective
4328 */
4329 Directive _parseDirective(CommentAndMetadata commentAndMetadata) {
4330 if (_matchesKeyword(Keyword.IMPORT)) {
4331 return _parseImportDirective(commentAndMetadata);
4332 } else if (_matchesKeyword(Keyword.EXPORT)) {
4333 return _parseExportDirective(commentAndMetadata);
4334 } else if (_matchesKeyword(Keyword.LIBRARY)) {
4335 return _parseLibraryDirective(commentAndMetadata);
4336 } else if (_matchesKeyword(Keyword.PART)) {
4337 return _parsePartOrPartOfDirective(commentAndMetadata);
4338 } else {
4339 // Internal error: this method should not have been invoked if the current
4340 // token was something other than one of the above.
4341 throw new StateError(
4342 "parseDirective invoked in an invalid state; currentToken = $_currentT oken");
4343 }
4344 } 2642 }
4345 2643
4346 /** 2644 /**
4347 * Parse the script tag and directives in a compilation unit until the first 2645 * Parse the script tag and directives in a compilation unit until the first
4348 * non-directive is encountered. Return the compilation unit that was parsed. 2646 * non-directive is encountered. Return the compilation unit that was parsed.
4349 * 2647 *
4350 * compilationUnit ::= 2648 * compilationUnit ::=
4351 * scriptTag? directive* 2649 * scriptTag? directive*
4352 */ 2650 */
4353 CompilationUnit _parseDirectives() { 2651 CompilationUnit parseDirectives2() {
4354 Token firstToken = _currentToken; 2652 Token firstToken = _currentToken;
4355 ScriptTag scriptTag = null; 2653 ScriptTag scriptTag = null;
4356 if (_matches(TokenType.SCRIPT_TAG)) { 2654 if (_matches(TokenType.SCRIPT_TAG)) {
4357 scriptTag = new ScriptTag(getAndAdvance()); 2655 scriptTag = new ScriptTag(getAndAdvance());
4358 } 2656 }
4359 List<Directive> directives = <Directive>[]; 2657 List<Directive> directives = <Directive>[];
4360 while (!_matches(TokenType.EOF)) { 2658 while (!_matches(TokenType.EOF)) {
4361 CommentAndMetadata commentAndMetadata = _parseCommentAndMetadata(); 2659 CommentAndMetadata commentAndMetadata = parseCommentAndMetadata();
4362 Keyword keyword = _currentToken.keyword; 2660 Keyword keyword = _currentToken.keyword;
4363 TokenType type = _peek().type; 2661 TokenType type = _peek().type;
4364 if ((keyword == Keyword.IMPORT || 2662 if ((keyword == Keyword.IMPORT ||
4365 keyword == Keyword.EXPORT || 2663 keyword == Keyword.EXPORT ||
4366 keyword == Keyword.LIBRARY || 2664 keyword == Keyword.LIBRARY ||
4367 keyword == Keyword.PART) && 2665 keyword == Keyword.PART) &&
4368 type != TokenType.PERIOD && 2666 type != TokenType.PERIOD &&
4369 type != TokenType.LT && 2667 type != TokenType.LT &&
4370 type != TokenType.OPEN_PAREN) { 2668 type != TokenType.OPEN_PAREN) {
4371 directives.add(_parseDirective(commentAndMetadata)); 2669 directives.add(_parseDirective(commentAndMetadata));
(...skipping 13 matching lines...) Expand all
4385 2683
4386 /** 2684 /**
4387 * Parse a documentation comment based on the given list of documentation 2685 * Parse a documentation comment based on the given list of documentation
4388 * comment tokens. Return the documentation comment that was parsed, or `null` 2686 * comment tokens. Return the documentation comment that was parsed, or `null`
4389 * if there was no comment. 2687 * if there was no comment.
4390 * 2688 *
4391 * documentationComment ::= 2689 * documentationComment ::=
4392 * multiLineComment? 2690 * multiLineComment?
4393 * | singleLineComment* 2691 * | singleLineComment*
4394 */ 2692 */
4395 Comment _parseDocumentationComment(List<DocumentationCommentToken> tokens) { 2693 Comment parseDocumentationComment(List<DocumentationCommentToken> tokens) {
4396 if (tokens == null) { 2694 if (tokens == null) {
4397 return null; 2695 return null;
4398 } 2696 }
4399 List<CommentReference> references = _parseCommentReferences(tokens); 2697 List<CommentReference> references = _parseCommentReferences(tokens);
4400 return Comment.createDocumentationCommentWithReferences(tokens, references); 2698 return Comment.createDocumentationCommentWithReferences(tokens, references);
4401 } 2699 }
4402 2700
4403 /** 2701 /**
4404 * Parse a documentation comment. Return the documentation comment that was 2702 * Parse a documentation comment. Return the documentation comment that was
4405 * parsed, or `null` if there was no comment. 2703 * parsed, or `null` if there was no comment.
4406 * 2704 *
4407 * documentationComment ::= 2705 * documentationComment ::=
4408 * multiLineComment? 2706 * multiLineComment?
4409 * | singleLineComment* 2707 * | singleLineComment*
4410 */ 2708 */
4411 List<DocumentationCommentToken> _parseDocumentationCommentTokens() { 2709 List<DocumentationCommentToken> parseDocumentationCommentTokens() {
4412 List<DocumentationCommentToken> tokens = <DocumentationCommentToken>[]; 2710 List<DocumentationCommentToken> tokens = <DocumentationCommentToken>[];
4413 CommentToken commentToken = _currentToken.precedingComments; 2711 CommentToken commentToken = _currentToken.precedingComments;
4414 while (commentToken != null) { 2712 while (commentToken != null) {
4415 if (commentToken is DocumentationCommentToken) { 2713 if (commentToken is DocumentationCommentToken) {
4416 if (tokens.isNotEmpty) { 2714 if (tokens.isNotEmpty) {
4417 if (commentToken.type == TokenType.SINGLE_LINE_COMMENT) { 2715 if (commentToken.type == TokenType.SINGLE_LINE_COMMENT) {
4418 if (tokens[0].type != TokenType.SINGLE_LINE_COMMENT) { 2716 if (tokens[0].type != TokenType.SINGLE_LINE_COMMENT) {
4419 tokens.clear(); 2717 tokens.clear();
4420 } 2718 }
4421 } else { 2719 } else {
4422 tokens.clear(); 2720 tokens.clear();
4423 } 2721 }
4424 } 2722 }
4425 tokens.add(commentToken); 2723 tokens.add(commentToken);
4426 } 2724 }
4427 commentToken = commentToken.next; 2725 commentToken = commentToken.next;
4428 } 2726 }
4429 return tokens.isEmpty ? null : tokens; 2727 return tokens.isEmpty ? null : tokens;
4430 } 2728 }
4431 2729
4432 /** 2730 /**
4433 * Parse a do statement. Return the do statement that was parsed. 2731 * Parse a do statement. Return the do statement that was parsed.
4434 * 2732 *
4435 * This method assumes that the current token matches `Keyword.DO`. 2733 * This method assumes that the current token matches `Keyword.DO`.
4436 * 2734 *
4437 * doStatement ::= 2735 * doStatement ::=
4438 * 'do' statement 'while' '(' expression ')' ';' 2736 * 'do' statement 'while' '(' expression ')' ';'
4439 */ 2737 */
4440 Statement _parseDoStatement() { 2738 Statement parseDoStatement() {
4441 bool wasInLoop = _inLoop; 2739 bool wasInLoop = _inLoop;
4442 _inLoop = true; 2740 _inLoop = true;
4443 try { 2741 try {
4444 Token doKeyword = getAndAdvance(); 2742 Token doKeyword = getAndAdvance();
4445 Statement body = parseStatement2(); 2743 Statement body = parseStatement2();
4446 Token whileKeyword = _expectKeyword(Keyword.WHILE); 2744 Token whileKeyword = _expectKeyword(Keyword.WHILE);
4447 Token leftParenthesis = _expect(TokenType.OPEN_PAREN); 2745 Token leftParenthesis = _expect(TokenType.OPEN_PAREN);
4448 Expression condition = parseExpression2(); 2746 Expression condition = parseExpression2();
4449 Token rightParenthesis = _expect(TokenType.CLOSE_PAREN); 2747 Token rightParenthesis = _expect(TokenType.CLOSE_PAREN);
4450 Token semicolon = _expect(TokenType.SEMICOLON); 2748 Token semicolon = _expect(TokenType.SEMICOLON);
4451 return new DoStatement(doKeyword, body, whileKeyword, leftParenthesis, 2749 return new DoStatement(doKeyword, body, whileKeyword, leftParenthesis,
4452 condition, rightParenthesis, semicolon); 2750 condition, rightParenthesis, semicolon);
4453 } finally { 2751 } finally {
4454 _inLoop = wasInLoop; 2752 _inLoop = wasInLoop;
4455 } 2753 }
4456 } 2754 }
4457 2755
4458 /** 2756 /**
4459 * Parse a dotted name. Return the dotted name that was parsed. 2757 * Parse a dotted name. Return the dotted name that was parsed.
4460 * 2758 *
4461 * dottedName ::= 2759 * dottedName ::=
4462 * identifier ('.' identifier)* 2760 * identifier ('.' identifier)*
4463 */ 2761 */
4464 DottedName _parseDottedName() { 2762 DottedName parseDottedName() {
4465 List<SimpleIdentifier> components = <SimpleIdentifier>[ 2763 List<SimpleIdentifier> components = <SimpleIdentifier>[
4466 parseSimpleIdentifier() 2764 parseSimpleIdentifier()
4467 ]; 2765 ];
4468 while (_optional(TokenType.PERIOD)) { 2766 while (_optional(TokenType.PERIOD)) {
4469 components.add(parseSimpleIdentifier()); 2767 components.add(parseSimpleIdentifier());
4470 } 2768 }
4471 return new DottedName(components); 2769 return new DottedName(components);
4472 } 2770 }
4473 2771
4474 /** 2772 /**
4475 * Parse an empty statement. Return the empty statement that was parsed. 2773 * Parse an empty statement. Return the empty statement that was parsed.
4476 * 2774 *
4477 * This method assumes that the current token matches `TokenType.SEMICOLON`. 2775 * This method assumes that the current token matches `TokenType.SEMICOLON`.
4478 * 2776 *
4479 * emptyStatement ::= 2777 * emptyStatement ::=
4480 * ';' 2778 * ';'
4481 */ 2779 */
4482 Statement _parseEmptyStatement() => new EmptyStatement(getAndAdvance()); 2780 Statement parseEmptyStatement() => new EmptyStatement(getAndAdvance());
4483
4484 /**
4485 * Parse an enum constant declaration. Return the enum constant declaration
4486 * that was parsed.
4487 *
4488 * Specified:
4489 *
4490 * enumConstant ::=
4491 * id
4492 *
4493 * Actual:
4494 *
4495 * enumConstant ::=
4496 * metadata id
4497 */
4498 EnumConstantDeclaration _parseEnumConstantDeclaration() {
4499 CommentAndMetadata commentAndMetadata = _parseCommentAndMetadata();
4500 SimpleIdentifier name;
4501 if (_matchesIdentifier()) {
4502 name = _parseSimpleIdentifierUnchecked(isDeclaration: true);
4503 } else {
4504 name = _createSyntheticIdentifier();
4505 }
4506 if (commentAndMetadata.hasMetadata) {
4507 _reportErrorForNode(ParserErrorCode.ANNOTATION_ON_ENUM_CONSTANT,
4508 commentAndMetadata.metadata[0]);
4509 }
4510 return new EnumConstantDeclaration(
4511 commentAndMetadata.comment, commentAndMetadata.metadata, name);
4512 }
4513 2781
4514 /** 2782 /**
4515 * Parse an enum declaration. The [commentAndMetadata] is the metadata to be 2783 * Parse an enum declaration. The [commentAndMetadata] is the metadata to be
4516 * associated with the member. Return the enum declaration that was parsed. 2784 * associated with the member. Return the enum declaration that was parsed.
4517 * 2785 *
4518 * This method assumes that the current token matches `Keyword.ENUM`. 2786 * This method assumes that the current token matches `Keyword.ENUM`.
4519 * 2787 *
4520 * enumType ::= 2788 * enumType ::=
4521 * metadata 'enum' id '{' id (',' id)* (',')? '}' 2789 * metadata 'enum' id '{' id (',' id)* (',')? '}'
4522 */ 2790 */
4523 EnumDeclaration _parseEnumDeclaration(CommentAndMetadata commentAndMetadata) { 2791 EnumDeclaration parseEnumDeclaration(CommentAndMetadata commentAndMetadata) {
4524 Token keyword = getAndAdvance(); 2792 Token keyword = getAndAdvance();
4525 SimpleIdentifier name = parseSimpleIdentifier(isDeclaration: true); 2793 SimpleIdentifier name = parseSimpleIdentifier(isDeclaration: true);
4526 Token leftBracket = null; 2794 Token leftBracket = null;
4527 List<EnumConstantDeclaration> constants = <EnumConstantDeclaration>[]; 2795 List<EnumConstantDeclaration> constants = <EnumConstantDeclaration>[];
4528 Token rightBracket = null; 2796 Token rightBracket = null;
4529 if (_matches(TokenType.OPEN_CURLY_BRACKET)) { 2797 if (_matches(TokenType.OPEN_CURLY_BRACKET)) {
4530 leftBracket = getAndAdvance(); 2798 leftBracket = getAndAdvance();
4531 if (_matchesIdentifier() || _matches(TokenType.AT)) { 2799 if (_matchesIdentifier() || _matches(TokenType.AT)) {
4532 constants.add(_parseEnumConstantDeclaration()); 2800 constants.add(_parseEnumConstantDeclaration());
4533 } else if (_matches(TokenType.COMMA) && 2801 } else if (_matches(TokenType.COMMA) &&
(...skipping 20 matching lines...) Expand all
4554 commentAndMetadata.comment, 2822 commentAndMetadata.comment,
4555 commentAndMetadata.metadata, 2823 commentAndMetadata.metadata,
4556 keyword, 2824 keyword,
4557 name, 2825 name,
4558 leftBracket, 2826 leftBracket,
4559 constants, 2827 constants,
4560 rightBracket); 2828 rightBracket);
4561 } 2829 }
4562 2830
4563 /** 2831 /**
4564 * Parse an equality expression. Return the equality expression that was 2832 * Parse an expression, starting with the given [token]. Return the expression
4565 * parsed. 2833 * that was parsed, or `null` if the tokens do not represent a recognizable
4566 * 2834 * expression.
4567 * equalityExpression ::= 2835 */
4568 * relationalExpression (equalityOperator relationalExpression)? 2836 Expression parseExpression(Token token) {
4569 * | 'super' equalityOperator relationalExpression 2837 _currentToken = token;
4570 */ 2838 return parseExpression2();
4571 Expression _parseEqualityExpression() { 2839 }
4572 Expression expression; 2840
4573 if (_currentToken.keyword == Keyword.SUPER && 2841 /**
4574 _currentToken.next.type.isEqualityOperator) { 2842 * Parse an expression that might contain a cascade. Return the expression
4575 expression = new SuperExpression(getAndAdvance()); 2843 * that was parsed.
4576 } else { 2844 *
4577 expression = _parseRelationalExpression(); 2845 * expression ::=
4578 } 2846 * assignableExpression assignmentOperator expression
4579 bool leftEqualityExpression = false; 2847 * | conditionalExpression cascadeSection*
4580 while (_currentToken.type.isEqualityOperator) { 2848 * | throwExpression
4581 if (leftEqualityExpression) { 2849 */
4582 _reportErrorForNode( 2850 Expression parseExpression2() {
4583 ParserErrorCode.EQUALITY_CANNOT_BE_EQUALITY_OPERAND, expression); 2851 Keyword keyword = _currentToken.keyword;
4584 } 2852 if (keyword == Keyword.THROW) {
4585 expression = new BinaryExpression( 2853 return parseThrowExpression();
4586 expression, getAndAdvance(), _parseRelationalExpression()); 2854 } else if (keyword == Keyword.RETHROW) {
4587 leftEqualityExpression = true; 2855 // TODO(brianwilkerson) Rethrow is a statement again.
2856 return parseRethrowExpression();
2857 }
2858 //
2859 // assignableExpression is a subset of conditionalExpression, so we can
2860 // parse a conditional expression and then determine whether it is followed
2861 // by an assignmentOperator, checking for conformance to the restricted
2862 // grammar after making that determination.
2863 //
2864 Expression expression = parseConditionalExpression();
2865 TokenType type = _currentToken.type;
2866 if (type == TokenType.PERIOD_PERIOD) {
2867 List<Expression> cascadeSections = <Expression>[];
2868 do {
2869 Expression section = parseCascadeSection();
2870 if (section != null) {
2871 cascadeSections.add(section);
2872 }
2873 } while (_currentToken.type == TokenType.PERIOD_PERIOD);
2874 return new CascadeExpression(expression, cascadeSections);
2875 } else if (type.isAssignmentOperator) {
2876 Token operator = getAndAdvance();
2877 _ensureAssignable(expression);
2878 return new AssignmentExpression(expression, operator, parseExpression2());
4588 } 2879 }
4589 return expression; 2880 return expression;
4590 } 2881 }
4591 2882
4592 /** 2883 /**
4593 * Parse an export directive. The [commentAndMetadata] is the metadata to be
4594 * associated with the directive. Return the export directive that was parsed.
4595 *
4596 * This method assumes that the current token matches `Keyword.EXPORT`.
4597 *
4598 * exportDirective ::=
4599 * metadata 'export' stringLiteral configuration* combinator*';'
4600 */
4601 ExportDirective _parseExportDirective(CommentAndMetadata commentAndMetadata) {
4602 Token exportKeyword = getAndAdvance();
4603 StringLiteral libraryUri = _parseUri();
4604 List<Configuration> configurations = _parseConfigurations();
4605 List<Combinator> combinators = _parseCombinators();
4606 Token semicolon = _expect(TokenType.SEMICOLON);
4607 return new ExportDirective(
4608 commentAndMetadata.comment,
4609 commentAndMetadata.metadata,
4610 exportKeyword,
4611 libraryUri,
4612 configurations,
4613 combinators,
4614 semicolon);
4615 }
4616
4617 /**
4618 * Parse a list of expressions. Return the expression that was parsed. 2884 * Parse a list of expressions. Return the expression that was parsed.
4619 * 2885 *
4620 * expressionList ::= 2886 * expressionList ::=
4621 * expression (',' expression)* 2887 * expression (',' expression)*
4622 */ 2888 */
4623 List<Expression> _parseExpressionList() { 2889 List<Expression> parseExpressionList() {
4624 List<Expression> expressions = <Expression>[parseExpression2()]; 2890 List<Expression> expressions = <Expression>[parseExpression2()];
4625 while (_optional(TokenType.COMMA)) { 2891 while (_optional(TokenType.COMMA)) {
4626 expressions.add(parseExpression2()); 2892 expressions.add(parseExpression2());
4627 } 2893 }
4628 return expressions; 2894 return expressions;
4629 } 2895 }
4630 2896
4631 /** 2897 /**
2898 * Parse an expression that does not contain any cascades. Return the
2899 * expression that was parsed.
2900 *
2901 * expressionWithoutCascade ::=
2902 * assignableExpression assignmentOperator expressionWithoutCascade
2903 * | conditionalExpression
2904 * | throwExpressionWithoutCascade
2905 */
2906 Expression parseExpressionWithoutCascade() {
2907 if (_matchesKeyword(Keyword.THROW)) {
2908 return parseThrowExpressionWithoutCascade();
2909 } else if (_matchesKeyword(Keyword.RETHROW)) {
2910 return parseRethrowExpression();
2911 }
2912 //
2913 // assignableExpression is a subset of conditionalExpression, so we can
2914 // parse a conditional expression and then determine whether it is followed
2915 // by an assignmentOperator, checking for conformance to the restricted
2916 // grammar after making that determination.
2917 //
2918 Expression expression = parseConditionalExpression();
2919 if (_currentToken.type.isAssignmentOperator) {
2920 Token operator = getAndAdvance();
2921 _ensureAssignable(expression);
2922 expression = new AssignmentExpression(
2923 expression, operator, parseExpressionWithoutCascade());
2924 }
2925 return expression;
2926 }
2927
2928 /**
2929 * Parse a class extends clause. Return the class extends clause that was
2930 * parsed.
2931 *
2932 * This method assumes that the current token matches `Keyword.EXTENDS`.
2933 *
2934 * classExtendsClause ::=
2935 * 'extends' type
2936 */
2937 ExtendsClause parseExtendsClause() {
2938 Token keyword = getAndAdvance();
2939 TypeName superclass = parseTypeName(false);
2940 return new ExtendsClause(keyword, superclass);
2941 }
2942
2943 /**
4632 * Parse the 'final', 'const', 'var' or type preceding a variable declaration. 2944 * Parse the 'final', 'const', 'var' or type preceding a variable declaration.
4633 * The [optional] is `true` if the keyword and type are optional. Return the 2945 * The [optional] is `true` if the keyword and type are optional. Return the
4634 * 'final', 'const', 'var' or type that was parsed. 2946 * 'final', 'const', 'var' or type that was parsed.
4635 * 2947 *
4636 * finalConstVarOrType ::= 2948 * finalConstVarOrType ::=
4637 * 'final' type? 2949 * 'final' type?
4638 * | 'const' type? 2950 * | 'const' type?
4639 * | 'var' 2951 * | 'var'
4640 * | type 2952 * | type
4641 */ 2953 */
4642 FinalConstVarOrType _parseFinalConstVarOrType(bool optional) { 2954 FinalConstVarOrType parseFinalConstVarOrType(bool optional) {
4643 Token keywordToken = null; 2955 Token keywordToken = null;
4644 TypeName type = null; 2956 TypeName type = null;
4645 Keyword keyword = _currentToken.keyword; 2957 Keyword keyword = _currentToken.keyword;
4646 if (keyword == Keyword.FINAL || keyword == Keyword.CONST) { 2958 if (keyword == Keyword.FINAL || keyword == Keyword.CONST) {
4647 keywordToken = getAndAdvance(); 2959 keywordToken = getAndAdvance();
4648 if (_isTypedIdentifier(_currentToken)) { 2960 if (_isTypedIdentifier(_currentToken)) {
4649 type = parseTypeName(false); 2961 type = parseTypeName(false);
4650 } else { 2962 } else {
4651 // Support `final/*=T*/ x;` 2963 // Support `final/*=T*/ x;`
4652 type = _parseOptionalTypeNameComment(); 2964 type = _parseOptionalTypeNameComment();
(...skipping 13 matching lines...) Expand all
4666 ParserErrorCode.MISSING_CONST_FINAL_VAR_OR_TYPE); 2978 ParserErrorCode.MISSING_CONST_FINAL_VAR_OR_TYPE);
4667 } else { 2979 } else {
4668 // Support parameters such as `(/*=K*/ key, /*=V*/ value)` 2980 // Support parameters such as `(/*=K*/ key, /*=V*/ value)`
4669 // This is not supported if the type is required. 2981 // This is not supported if the type is required.
4670 type = _parseOptionalTypeNameComment(); 2982 type = _parseOptionalTypeNameComment();
4671 } 2983 }
4672 return new FinalConstVarOrType(keywordToken, type); 2984 return new FinalConstVarOrType(keywordToken, type);
4673 } 2985 }
4674 2986
4675 /** 2987 /**
4676 * Parse a formal parameter. At most one of `isOptional` and `isNamed` can be
4677 * `true`. The [kind] is the kind of parameter being expected based on the
4678 * presence or absence of group delimiters. Return the formal parameter that
4679 * was parsed.
4680 *
4681 * defaultFormalParameter ::=
4682 * normalFormalParameter ('=' expression)?
4683 *
4684 * defaultNamedParameter ::=
4685 * normalFormalParameter (':' expression)?
4686 */
4687 FormalParameter _parseFormalParameter(ParameterKind kind) {
4688 NormalFormalParameter parameter = parseNormalFormalParameter();
4689 TokenType type = _currentToken.type;
4690 if (type == TokenType.EQ) {
4691 Token separator = getAndAdvance();
4692 Expression defaultValue = parseExpression2();
4693 if (kind == ParameterKind.NAMED) {
4694 _reportErrorForToken(
4695 ParserErrorCode.WRONG_SEPARATOR_FOR_NAMED_PARAMETER, separator);
4696 } else if (kind == ParameterKind.REQUIRED) {
4697 _reportErrorForNode(
4698 ParserErrorCode.POSITIONAL_PARAMETER_OUTSIDE_GROUP, parameter);
4699 }
4700 return new DefaultFormalParameter(
4701 parameter, kind, separator, defaultValue);
4702 } else if (type == TokenType.COLON) {
4703 Token separator = getAndAdvance();
4704 Expression defaultValue = parseExpression2();
4705 if (kind == ParameterKind.POSITIONAL) {
4706 _reportErrorForToken(
4707 ParserErrorCode.WRONG_SEPARATOR_FOR_POSITIONAL_PARAMETER,
4708 separator);
4709 } else if (kind == ParameterKind.REQUIRED) {
4710 _reportErrorForNode(
4711 ParserErrorCode.NAMED_PARAMETER_OUTSIDE_GROUP, parameter);
4712 }
4713 return new DefaultFormalParameter(
4714 parameter, kind, separator, defaultValue);
4715 } else if (kind != ParameterKind.REQUIRED) {
4716 return new DefaultFormalParameter(parameter, kind, null, null);
4717 }
4718 return parameter;
4719 }
4720
4721 /**
4722 * Parse a list of formal parameters given that the list starts with the given
4723 * [leftParenthesis]. Return the formal parameters that were parsed.
4724 */
4725 FormalParameterList _parseFormalParameterListAfterParen(
4726 Token leftParenthesis) {
4727 if (_matches(TokenType.CLOSE_PAREN)) {
4728 return new FormalParameterList(
4729 leftParenthesis, null, null, null, getAndAdvance());
4730 }
4731 //
4732 // Even though it is invalid to have default parameters outside of brackets,
4733 // required parameters inside of brackets, or multiple groups of default and
4734 // named parameters, we allow all of these cases so that we can recover
4735 // better.
4736 //
4737 List<FormalParameter> parameters = <FormalParameter>[];
4738 Token leftSquareBracket = null;
4739 Token rightSquareBracket = null;
4740 Token leftCurlyBracket = null;
4741 Token rightCurlyBracket = null;
4742 ParameterKind kind = ParameterKind.REQUIRED;
4743 bool firstParameter = true;
4744 bool reportedMultiplePositionalGroups = false;
4745 bool reportedMultipleNamedGroups = false;
4746 bool reportedMixedGroups = false;
4747 bool wasOptionalParameter = false;
4748 Token initialToken = null;
4749 do {
4750 if (firstParameter) {
4751 firstParameter = false;
4752 } else if (!_optional(TokenType.COMMA)) {
4753 // TODO(brianwilkerson) The token is wrong, we need to recover from this
4754 // case.
4755 if (_getEndToken(leftParenthesis) != null) {
4756 _reportErrorForCurrentToken(
4757 ParserErrorCode.EXPECTED_TOKEN, [TokenType.COMMA.lexeme]);
4758 } else {
4759 _reportErrorForToken(ParserErrorCode.MISSING_CLOSING_PARENTHESIS,
4760 _currentToken.previous);
4761 break;
4762 }
4763 }
4764 initialToken = _currentToken;
4765 //
4766 // Handle the beginning of parameter groups.
4767 //
4768 TokenType type = _currentToken.type;
4769 if (type == TokenType.OPEN_SQUARE_BRACKET) {
4770 wasOptionalParameter = true;
4771 if (leftSquareBracket != null && !reportedMultiplePositionalGroups) {
4772 _reportErrorForCurrentToken(
4773 ParserErrorCode.MULTIPLE_POSITIONAL_PARAMETER_GROUPS);
4774 reportedMultiplePositionalGroups = true;
4775 }
4776 if (leftCurlyBracket != null && !reportedMixedGroups) {
4777 _reportErrorForCurrentToken(ParserErrorCode.MIXED_PARAMETER_GROUPS);
4778 reportedMixedGroups = true;
4779 }
4780 leftSquareBracket = getAndAdvance();
4781 kind = ParameterKind.POSITIONAL;
4782 } else if (type == TokenType.OPEN_CURLY_BRACKET) {
4783 wasOptionalParameter = true;
4784 if (leftCurlyBracket != null && !reportedMultipleNamedGroups) {
4785 _reportErrorForCurrentToken(
4786 ParserErrorCode.MULTIPLE_NAMED_PARAMETER_GROUPS);
4787 reportedMultipleNamedGroups = true;
4788 }
4789 if (leftSquareBracket != null && !reportedMixedGroups) {
4790 _reportErrorForCurrentToken(ParserErrorCode.MIXED_PARAMETER_GROUPS);
4791 reportedMixedGroups = true;
4792 }
4793 leftCurlyBracket = getAndAdvance();
4794 kind = ParameterKind.NAMED;
4795 }
4796 //
4797 // Parse and record the parameter.
4798 //
4799 FormalParameter parameter = _parseFormalParameter(kind);
4800 parameters.add(parameter);
4801 if (kind == ParameterKind.REQUIRED && wasOptionalParameter) {
4802 _reportErrorForNode(
4803 ParserErrorCode.NORMAL_BEFORE_OPTIONAL_PARAMETERS, parameter);
4804 }
4805 //
4806 // Handle the end of parameter groups.
4807 //
4808 // TODO(brianwilkerson) Improve the detection and reporting of missing and
4809 // mismatched delimiters.
4810 type = _currentToken.type;
4811
4812 // Advance past trailing commas as appropriate.
4813 if (type == TokenType.COMMA) {
4814 // Only parse commas trailing normal (non-positional/named) params.
4815 if (rightSquareBracket == null && rightCurlyBracket == null) {
4816 Token next = _peek();
4817 if (next.type == TokenType.CLOSE_PAREN ||
4818 next.type == TokenType.CLOSE_CURLY_BRACKET ||
4819 next.type == TokenType.CLOSE_SQUARE_BRACKET) {
4820 _advance();
4821 type = _currentToken.type;
4822 }
4823 }
4824 }
4825
4826 if (type == TokenType.CLOSE_SQUARE_BRACKET) {
4827 rightSquareBracket = getAndAdvance();
4828 if (leftSquareBracket == null) {
4829 if (leftCurlyBracket != null) {
4830 _reportErrorForCurrentToken(
4831 ParserErrorCode.WRONG_TERMINATOR_FOR_PARAMETER_GROUP, ["}"]);
4832 rightCurlyBracket = rightSquareBracket;
4833 rightSquareBracket = null;
4834 } else {
4835 _reportErrorForCurrentToken(
4836 ParserErrorCode.UNEXPECTED_TERMINATOR_FOR_PARAMETER_GROUP,
4837 ["["]);
4838 }
4839 }
4840 kind = ParameterKind.REQUIRED;
4841 } else if (type == TokenType.CLOSE_CURLY_BRACKET) {
4842 rightCurlyBracket = getAndAdvance();
4843 if (leftCurlyBracket == null) {
4844 if (leftSquareBracket != null) {
4845 _reportErrorForCurrentToken(
4846 ParserErrorCode.WRONG_TERMINATOR_FOR_PARAMETER_GROUP, ["]"]);
4847 rightSquareBracket = rightCurlyBracket;
4848 rightCurlyBracket = null;
4849 } else {
4850 _reportErrorForCurrentToken(
4851 ParserErrorCode.UNEXPECTED_TERMINATOR_FOR_PARAMETER_GROUP,
4852 ["{"]);
4853 }
4854 }
4855 kind = ParameterKind.REQUIRED;
4856 }
4857 } while (!_matches(TokenType.CLOSE_PAREN) &&
4858 !identical(initialToken, _currentToken));
4859 Token rightParenthesis = _expect(TokenType.CLOSE_PAREN);
4860 //
4861 // Check that the groups were closed correctly.
4862 //
4863 if (leftSquareBracket != null && rightSquareBracket == null) {
4864 _reportErrorForCurrentToken(
4865 ParserErrorCode.MISSING_TERMINATOR_FOR_PARAMETER_GROUP, ["]"]);
4866 }
4867 if (leftCurlyBracket != null && rightCurlyBracket == null) {
4868 _reportErrorForCurrentToken(
4869 ParserErrorCode.MISSING_TERMINATOR_FOR_PARAMETER_GROUP, ["}"]);
4870 }
4871 //
4872 // Build the parameter list.
4873 //
4874 leftSquareBracket ??= leftCurlyBracket;
4875 rightSquareBracket ??= rightCurlyBracket;
4876 return new FormalParameterList(leftParenthesis, parameters,
4877 leftSquareBracket, rightSquareBracket, rightParenthesis);
4878 }
4879
4880 /**
4881 * Parse a list of formal parameters. Return the formal parameters that were 2988 * Parse a list of formal parameters. Return the formal parameters that were
4882 * parsed. 2989 * parsed.
4883 * 2990 *
4884 * This method assumes that the current token matches `TokenType.OPEN_PAREN`. 2991 * formalParameterList ::=
4885 */ 2992 * '(' ')'
4886 FormalParameterList _parseFormalParameterListUnchecked() { 2993 * | '(' normalFormalParameters (',' optionalFormalParameters)? ')'
4887 return _parseFormalParameterListAfterParen(getAndAdvance()); 2994 * | '(' optionalFormalParameters ')'
2995 *
2996 * normalFormalParameters ::=
2997 * normalFormalParameter (',' normalFormalParameter)*
2998 *
2999 * optionalFormalParameters ::=
3000 * optionalPositionalFormalParameters
3001 * | namedFormalParameters
3002 *
3003 * optionalPositionalFormalParameters ::=
3004 * '[' defaultFormalParameter (',' defaultFormalParameter)* ']'
3005 *
3006 * namedFormalParameters ::=
3007 * '{' defaultNamedParameter (',' defaultNamedParameter)* '}'
3008 */
3009 FormalParameterList parseFormalParameterList() {
3010 if (_matches(TokenType.OPEN_PAREN)) {
3011 return _parseFormalParameterListUnchecked();
3012 }
3013 // TODO(brianwilkerson) Improve the error message.
3014 _reportErrorForCurrentToken(
3015 ParserErrorCode.EXPECTED_TOKEN, [TokenType.OPEN_PAREN.lexeme]);
3016 // Recovery: Check for an unmatched closing paren and parse parameters until
3017 // it is reached.
3018 return _parseFormalParameterListAfterParen(
3019 _createSyntheticToken(TokenType.OPEN_PAREN));
4888 } 3020 }
4889 3021
4890 /** 3022 /**
4891 * Parse a for statement. Return the for statement that was parsed. 3023 * Parse a for statement. Return the for statement that was parsed.
4892 * 3024 *
4893 * forStatement ::= 3025 * forStatement ::=
4894 * 'for' '(' forLoopParts ')' statement 3026 * 'for' '(' forLoopParts ')' statement
4895 * 3027 *
4896 * forLoopParts ::= 3028 * forLoopParts ::=
4897 * forInitializerStatement expression? ';' expressionList? 3029 * forInitializerStatement expression? ';' expressionList?
4898 * | declaredIdentifier 'in' expression 3030 * | declaredIdentifier 'in' expression
4899 * | identifier 'in' expression 3031 * | identifier 'in' expression
4900 * 3032 *
4901 * forInitializerStatement ::= 3033 * forInitializerStatement ::=
4902 * localVariableDeclaration ';' 3034 * localVariableDeclaration ';'
4903 * | expression? ';' 3035 * | expression? ';'
4904 */ 3036 */
4905 Statement _parseForStatement() { 3037 Statement parseForStatement() {
4906 bool wasInLoop = _inLoop; 3038 bool wasInLoop = _inLoop;
4907 _inLoop = true; 3039 _inLoop = true;
4908 try { 3040 try {
4909 Token awaitKeyword = null; 3041 Token awaitKeyword = null;
4910 if (_matchesString(_AWAIT)) { 3042 if (_matchesString(_AWAIT)) {
4911 awaitKeyword = getAndAdvance(); 3043 awaitKeyword = getAndAdvance();
4912 } 3044 }
4913 Token forKeyword = _expectKeyword(Keyword.FOR); 3045 Token forKeyword = _expectKeyword(Keyword.FOR);
4914 Token leftParenthesis = _expect(TokenType.OPEN_PAREN); 3046 Token leftParenthesis = _expect(TokenType.OPEN_PAREN);
4915 VariableDeclarationList variableList = null; 3047 VariableDeclarationList variableList = null;
4916 Expression initialization = null; 3048 Expression initialization = null;
4917 if (!_matches(TokenType.SEMICOLON)) { 3049 if (!_matches(TokenType.SEMICOLON)) {
4918 CommentAndMetadata commentAndMetadata = _parseCommentAndMetadata(); 3050 CommentAndMetadata commentAndMetadata = parseCommentAndMetadata();
4919 if (_matchesIdentifier() && 3051 if (_matchesIdentifier() &&
4920 (_tokenMatchesKeyword(_peek(), Keyword.IN) || 3052 (_tokenMatchesKeyword(_peek(), Keyword.IN) ||
4921 _tokenMatches(_peek(), TokenType.COLON))) { 3053 _tokenMatches(_peek(), TokenType.COLON))) {
4922 SimpleIdentifier variableName = _parseSimpleIdentifierUnchecked(); 3054 SimpleIdentifier variableName = _parseSimpleIdentifierUnchecked();
4923 variableList = new VariableDeclarationList(commentAndMetadata.comment, 3055 variableList = new VariableDeclarationList(commentAndMetadata.comment,
4924 commentAndMetadata.metadata, null, null, <VariableDeclaration>[ 3056 commentAndMetadata.metadata, null, null, <VariableDeclaration>[
4925 new VariableDeclaration(variableName, null, null) 3057 new VariableDeclaration(variableName, null, null)
4926 ]); 3058 ]);
4927 } else if (_isInitializedVariableDeclaration()) { 3059 } else if (isInitializedVariableDeclaration()) {
4928 variableList = 3060 variableList =
4929 _parseVariableDeclarationListAfterMetadata(commentAndMetadata); 3061 parseVariableDeclarationListAfterMetadata(commentAndMetadata);
4930 } else { 3062 } else {
4931 initialization = parseExpression2(); 3063 initialization = parseExpression2();
4932 } 3064 }
4933 TokenType type = _currentToken.type; 3065 TokenType type = _currentToken.type;
4934 if (_matchesKeyword(Keyword.IN) || type == TokenType.COLON) { 3066 if (_matchesKeyword(Keyword.IN) || type == TokenType.COLON) {
4935 if (type == TokenType.COLON) { 3067 if (type == TokenType.COLON) {
4936 _reportErrorForCurrentToken(ParserErrorCode.COLON_IN_PLACE_OF_IN); 3068 _reportErrorForCurrentToken(ParserErrorCode.COLON_IN_PLACE_OF_IN);
4937 } 3069 }
4938 DeclaredIdentifier loopVariable = null; 3070 DeclaredIdentifier loopVariable = null;
4939 SimpleIdentifier identifier = null; 3071 SimpleIdentifier identifier = null;
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after
5003 ParserErrorCode.INVALID_AWAIT_IN_FOR, awaitKeyword); 3135 ParserErrorCode.INVALID_AWAIT_IN_FOR, awaitKeyword);
5004 } 3136 }
5005 Token leftSeparator = _expect(TokenType.SEMICOLON); 3137 Token leftSeparator = _expect(TokenType.SEMICOLON);
5006 Expression condition = null; 3138 Expression condition = null;
5007 if (!_matches(TokenType.SEMICOLON)) { 3139 if (!_matches(TokenType.SEMICOLON)) {
5008 condition = parseExpression2(); 3140 condition = parseExpression2();
5009 } 3141 }
5010 Token rightSeparator = _expect(TokenType.SEMICOLON); 3142 Token rightSeparator = _expect(TokenType.SEMICOLON);
5011 List<Expression> updaters = null; 3143 List<Expression> updaters = null;
5012 if (!_matches(TokenType.CLOSE_PAREN)) { 3144 if (!_matches(TokenType.CLOSE_PAREN)) {
5013 updaters = _parseExpressionList(); 3145 updaters = parseExpressionList();
5014 } 3146 }
5015 Token rightParenthesis = _expect(TokenType.CLOSE_PAREN); 3147 Token rightParenthesis = _expect(TokenType.CLOSE_PAREN);
5016 Statement body = parseStatement2(); 3148 Statement body = parseStatement2();
5017 return new ForStatement( 3149 return new ForStatement(
5018 forKeyword, 3150 forKeyword,
5019 leftParenthesis, 3151 leftParenthesis,
5020 variableList, 3152 variableList,
5021 initialization, 3153 initialization,
5022 leftSeparator, 3154 leftSeparator,
5023 condition, 3155 condition,
(...skipping 14 matching lines...) Expand all
5038 * not have a terminating semicolon. Return the function body that was parsed. 3170 * not have a terminating semicolon. Return the function body that was parsed.
5039 * 3171 *
5040 * functionBody ::= 3172 * functionBody ::=
5041 * '=>' expression ';' 3173 * '=>' expression ';'
5042 * | block 3174 * | block
5043 * 3175 *
5044 * functionExpressionBody ::= 3176 * functionExpressionBody ::=
5045 * '=>' expression 3177 * '=>' expression
5046 * | block 3178 * | block
5047 */ 3179 */
5048 FunctionBody _parseFunctionBody( 3180 FunctionBody parseFunctionBody(
5049 bool mayBeEmpty, ParserErrorCode emptyErrorCode, bool inExpression) { 3181 bool mayBeEmpty, ParserErrorCode emptyErrorCode, bool inExpression) {
5050 bool wasInAsync = _inAsync; 3182 bool wasInAsync = _inAsync;
5051 bool wasInGenerator = _inGenerator; 3183 bool wasInGenerator = _inGenerator;
5052 bool wasInLoop = _inLoop; 3184 bool wasInLoop = _inLoop;
5053 bool wasInSwitch = _inSwitch; 3185 bool wasInSwitch = _inSwitch;
5054 _inAsync = false; 3186 _inAsync = false;
5055 _inGenerator = false; 3187 _inGenerator = false;
5056 _inLoop = false; 3188 _inLoop = false;
5057 _inSwitch = false; 3189 _inSwitch = false;
5058 try { 3190 try {
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after
5150 } 3282 }
5151 } finally { 3283 } finally {
5152 _inAsync = wasInAsync; 3284 _inAsync = wasInAsync;
5153 _inGenerator = wasInGenerator; 3285 _inGenerator = wasInGenerator;
5154 _inLoop = wasInLoop; 3286 _inLoop = wasInLoop;
5155 _inSwitch = wasInSwitch; 3287 _inSwitch = wasInSwitch;
5156 } 3288 }
5157 } 3289 }
5158 3290
5159 /** 3291 /**
3292 * Parse a function declaration statement. Return the function declaration
3293 * statement that was parsed.
3294 *
3295 * functionDeclarationStatement ::=
3296 * functionSignature functionBody
3297 */
3298 Statement parseFunctionDeclarationStatement() {
3299 Modifiers modifiers = _parseModifiers();
3300 _validateModifiersForFunctionDeclarationStatement(modifiers);
3301 return _parseFunctionDeclarationStatementAfterReturnType(
3302 parseCommentAndMetadata(), _parseOptionalReturnType());
3303 }
3304
3305 /**
3306 * Parse a function expression. Return the function expression that was
3307 * parsed.
3308 *
3309 * functionExpression ::=
3310 * typeParameters? formalParameterList functionExpressionBody
3311 */
3312 FunctionExpression parseFunctionExpression() {
3313 TypeParameterList typeParameters = _parseGenericMethodTypeParameters();
3314 FormalParameterList parameters = parseFormalParameterList();
3315 _validateFormalParameterList(parameters);
3316 FunctionBody body =
3317 parseFunctionBody(false, ParserErrorCode.MISSING_FUNCTION_BODY, true);
3318 return new FunctionExpression(typeParameters, parameters, body);
3319 }
3320
3321 /**
3322 * Parse an if-null expression. Return the if-null expression that was
3323 * parsed.
3324 *
3325 * ifNullExpression ::= logicalOrExpression ('??' logicalOrExpression)*
3326 */
3327 Expression parseIfNullExpression() {
3328 Expression expression = parseLogicalOrExpression();
3329 while (_currentToken.type == TokenType.QUESTION_QUESTION) {
3330 expression = new BinaryExpression(
3331 expression, getAndAdvance(), parseLogicalOrExpression());
3332 }
3333 return expression;
3334 }
3335
3336 /**
3337 * Parse an if statement. Return the if statement that was parsed.
3338 *
3339 * This method assumes that the current token matches `Keyword.IF`.
3340 *
3341 * ifStatement ::=
3342 * 'if' '(' expression ')' statement ('else' statement)?
3343 */
3344 Statement parseIfStatement() {
3345 Token ifKeyword = getAndAdvance();
3346 Token leftParenthesis = _expect(TokenType.OPEN_PAREN);
3347 Expression condition = parseExpression2();
3348 Token rightParenthesis = _expect(TokenType.CLOSE_PAREN);
3349 Statement thenStatement = parseStatement2();
3350 Token elseKeyword = null;
3351 Statement elseStatement = null;
3352 if (_matchesKeyword(Keyword.ELSE)) {
3353 elseKeyword = getAndAdvance();
3354 elseStatement = parseStatement2();
3355 }
3356 return new IfStatement(ifKeyword, leftParenthesis, condition,
3357 rightParenthesis, thenStatement, elseKeyword, elseStatement);
3358 }
3359
3360 /**
3361 * Parse an implements clause. Return the implements clause that was parsed.
3362 *
3363 * This method assumes that the current token matches `Keyword.IMPLEMENTS`.
3364 *
3365 * implementsClause ::=
3366 * 'implements' type (',' type)*
3367 */
3368 ImplementsClause parseImplementsClause() {
3369 Token keyword = getAndAdvance();
3370 List<TypeName> interfaces = <TypeName>[];
3371 interfaces.add(parseTypeName(false));
3372 while (_optional(TokenType.COMMA)) {
3373 interfaces.add(parseTypeName(false));
3374 }
3375 return new ImplementsClause(keyword, interfaces);
3376 }
3377
3378 /**
3379 * Parse a label. Return the label that was parsed.
3380 *
3381 * This method assumes that the current token matches an identifier and that
3382 * the following token matches `TokenType.COLON`.
3383 *
3384 * label ::=
3385 * identifier ':'
3386 */
3387 Label parseLabel({bool isDeclaration: false}) {
3388 SimpleIdentifier label =
3389 _parseSimpleIdentifierUnchecked(isDeclaration: isDeclaration);
3390 Token colon = getAndAdvance();
3391 return new Label(label, colon);
3392 }
3393
3394 /**
3395 * Parse a library identifier. Return the library identifier that was parsed.
3396 *
3397 * libraryIdentifier ::=
3398 * identifier ('.' identifier)*
3399 */
3400 LibraryIdentifier parseLibraryIdentifier() {
3401 List<SimpleIdentifier> components = <SimpleIdentifier>[];
3402 components.add(parseSimpleIdentifier());
3403 while (_optional(TokenType.PERIOD)) {
3404 components.add(parseSimpleIdentifier());
3405 }
3406 return new LibraryIdentifier(components);
3407 }
3408
3409 /**
3410 * 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
3412 * list or map literal that was parsed.
3413 *
3414 * listOrMapLiteral ::=
3415 * listLiteral
3416 * | mapLiteral
3417 */
3418 TypedLiteral parseListOrMapLiteral(Token modifier) {
3419 TypeArgumentList typeArguments = _parseOptionalTypeArguments();
3420 if (_matches(TokenType.OPEN_CURLY_BRACKET)) {
3421 return _parseMapLiteral(modifier, typeArguments);
3422 } else if (_matches(TokenType.OPEN_SQUARE_BRACKET) ||
3423 _matches(TokenType.INDEX)) {
3424 return _parseListLiteral(modifier, typeArguments);
3425 }
3426 _reportErrorForCurrentToken(ParserErrorCode.EXPECTED_LIST_OR_MAP_LITERAL);
3427 return new ListLiteral(
3428 modifier,
3429 typeArguments,
3430 _createSyntheticToken(TokenType.OPEN_SQUARE_BRACKET),
3431 null,
3432 _createSyntheticToken(TokenType.CLOSE_SQUARE_BRACKET));
3433 }
3434
3435 /**
3436 * Parse a logical or expression. Return the logical or expression that was
3437 * parsed.
3438 *
3439 * logicalOrExpression ::=
3440 * logicalAndExpression ('||' logicalAndExpression)*
3441 */
3442 Expression parseLogicalOrExpression() {
3443 Expression expression = _parseLogicalAndExpression();
3444 while (_currentToken.type == TokenType.BAR_BAR) {
3445 expression = new BinaryExpression(
3446 expression, getAndAdvance(), _parseLogicalAndExpression());
3447 }
3448 return expression;
3449 }
3450
3451 /**
3452 * Parse a map literal entry. Return the map literal entry that was parsed.
3453 *
3454 * mapLiteralEntry ::=
3455 * expression ':' expression
3456 */
3457 MapLiteralEntry parseMapLiteralEntry() {
3458 Expression key = parseExpression2();
3459 Token separator = _expect(TokenType.COLON);
3460 Expression value = parseExpression2();
3461 return new MapLiteralEntry(key, separator, value);
3462 }
3463
3464 /**
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 /**
5160 * Parse a function declaration. The [commentAndMetadata] is the documentation 6129 * Parse a function declaration. The [commentAndMetadata] is the documentation
5161 * comment and metadata to be associated with the declaration. The 6130 * comment and metadata to be associated with the declaration. The
5162 * [externalKeyword] is the 'external' keyword, or `null` if the function is 6131 * [externalKeyword] is the 'external' keyword, or `null` if the function is
5163 * not external. The [returnType] is the return type, or `null` if there is no 6132 * not external. The [returnType] is the return type, or `null` if there is no
5164 * return type. The [isStatement] is `true` if the function declaration is 6133 * return type. The [isStatement] is `true` if the function declaration is
5165 * being parsed as a statement. Return the function declaration that was 6134 * being parsed as a statement. Return the function declaration that was
5166 * parsed. 6135 * parsed.
5167 * 6136 *
5168 * functionDeclaration ::= 6137 * functionDeclaration ::=
5169 * functionSignature functionBody 6138 * functionSignature functionBody
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
5205 null, 6174 null,
5206 null, 6175 null,
5207 _createSyntheticToken(TokenType.CLOSE_PAREN)); 6176 _createSyntheticToken(TokenType.CLOSE_PAREN));
5208 } 6177 }
5209 } else if (_matches(TokenType.OPEN_PAREN)) { 6178 } else if (_matches(TokenType.OPEN_PAREN)) {
5210 _reportErrorForCurrentToken(ParserErrorCode.GETTER_WITH_PARAMETERS); 6179 _reportErrorForCurrentToken(ParserErrorCode.GETTER_WITH_PARAMETERS);
5211 _parseFormalParameterListUnchecked(); 6180 _parseFormalParameterListUnchecked();
5212 } 6181 }
5213 FunctionBody body; 6182 FunctionBody body;
5214 if (externalKeyword == null) { 6183 if (externalKeyword == null) {
5215 body = _parseFunctionBody( 6184 body = parseFunctionBody(
5216 false, ParserErrorCode.MISSING_FUNCTION_BODY, false); 6185 false, ParserErrorCode.MISSING_FUNCTION_BODY, false);
5217 } else { 6186 } else {
5218 body = new EmptyFunctionBody(_expect(TokenType.SEMICOLON)); 6187 body = new EmptyFunctionBody(_expect(TokenType.SEMICOLON));
5219 } 6188 }
5220 // if (!isStatement && matches(TokenType.SEMICOLON)) { 6189 // if (!isStatement && matches(TokenType.SEMICOLON)) {
5221 // // TODO(brianwilkerson) Improve this error message. 6190 // // TODO(brianwilkerson) Improve this error message.
5222 // reportError(ParserErrorCode.UNEXPECTED_TOKEN, currentToken.getLexeme ()); 6191 // reportError(ParserErrorCode.UNEXPECTED_TOKEN, currentToken.getLexeme ());
5223 // advance(); 6192 // advance();
5224 // } 6193 // }
5225 return new FunctionDeclaration( 6194 return new FunctionDeclaration(
5226 commentAndMetadata.comment, 6195 commentAndMetadata.comment,
5227 commentAndMetadata.metadata, 6196 commentAndMetadata.metadata,
5228 externalKeyword, 6197 externalKeyword,
5229 returnType, 6198 returnType,
5230 keywordToken, 6199 keywordToken,
5231 name, 6200 name,
5232 new FunctionExpression(typeParameters, parameters, body)); 6201 new FunctionExpression(typeParameters, parameters, body));
5233 } 6202 }
5234 6203
5235 /** 6204 /**
5236 * Parse a function declaration statement. Return the function declaration
5237 * statement that was parsed.
5238 *
5239 * functionDeclarationStatement ::=
5240 * functionSignature functionBody
5241 */
5242 Statement _parseFunctionDeclarationStatement() {
5243 Modifiers modifiers = _parseModifiers();
5244 _validateModifiersForFunctionDeclarationStatement(modifiers);
5245 return _parseFunctionDeclarationStatementAfterReturnType(
5246 _parseCommentAndMetadata(), _parseOptionalReturnType());
5247 }
5248
5249 /**
5250 * Parse a function declaration statement. The [commentAndMetadata] is the 6205 * Parse a function declaration statement. The [commentAndMetadata] is the
5251 * documentation comment and metadata to be associated with the declaration. 6206 * documentation comment and metadata to be associated with the declaration.
5252 * The [returnType] is the return type, or `null` if there is no return type. 6207 * The [returnType] is the return type, or `null` if there is no return type.
5253 * Return the function declaration statement that was parsed. 6208 * Return the function declaration statement that was parsed.
5254 * 6209 *
5255 * functionDeclarationStatement ::= 6210 * functionDeclarationStatement ::=
5256 * functionSignature functionBody 6211 * functionSignature functionBody
5257 */ 6212 */
5258 Statement _parseFunctionDeclarationStatementAfterReturnType( 6213 Statement _parseFunctionDeclarationStatementAfterReturnType(
5259 CommentAndMetadata commentAndMetadata, TypeName returnType) { 6214 CommentAndMetadata commentAndMetadata, TypeName returnType) {
(...skipping 134 matching lines...) Expand 10 before | Expand all | Expand 10 after
5394 MethodDeclaration _parseGetter(CommentAndMetadata commentAndMetadata, 6349 MethodDeclaration _parseGetter(CommentAndMetadata commentAndMetadata,
5395 Token externalKeyword, Token staticKeyword, TypeName returnType) { 6350 Token externalKeyword, Token staticKeyword, TypeName returnType) {
5396 Token propertyKeyword = getAndAdvance(); 6351 Token propertyKeyword = getAndAdvance();
5397 SimpleIdentifier name = parseSimpleIdentifier(isDeclaration: true); 6352 SimpleIdentifier name = parseSimpleIdentifier(isDeclaration: true);
5398 if (_matches(TokenType.OPEN_PAREN) && 6353 if (_matches(TokenType.OPEN_PAREN) &&
5399 _tokenMatches(_peek(), TokenType.CLOSE_PAREN)) { 6354 _tokenMatches(_peek(), TokenType.CLOSE_PAREN)) {
5400 _reportErrorForCurrentToken(ParserErrorCode.GETTER_WITH_PARAMETERS); 6355 _reportErrorForCurrentToken(ParserErrorCode.GETTER_WITH_PARAMETERS);
5401 _advance(); 6356 _advance();
5402 _advance(); 6357 _advance();
5403 } 6358 }
5404 FunctionBody body = _parseFunctionBody( 6359 FunctionBody body = parseFunctionBody(
5405 externalKeyword != null || staticKeyword == null, 6360 externalKeyword != null || staticKeyword == null,
5406 ParserErrorCode.STATIC_GETTER_WITHOUT_BODY, 6361 ParserErrorCode.STATIC_GETTER_WITHOUT_BODY,
5407 false); 6362 false);
5408 if (externalKeyword != null && body is! EmptyFunctionBody) { 6363 if (externalKeyword != null && body is! EmptyFunctionBody) {
5409 _reportErrorForCurrentToken(ParserErrorCode.EXTERNAL_GETTER_WITH_BODY); 6364 _reportErrorForCurrentToken(ParserErrorCode.EXTERNAL_GETTER_WITH_BODY);
5410 } 6365 }
5411 return new MethodDeclaration( 6366 return new MethodDeclaration(
5412 commentAndMetadata.comment, 6367 commentAndMetadata.comment,
5413 commentAndMetadata.metadata, 6368 commentAndMetadata.metadata,
5414 externalKeyword, 6369 externalKeyword,
(...skipping 18 matching lines...) Expand all
5433 List<SimpleIdentifier> identifiers = <SimpleIdentifier>[ 6388 List<SimpleIdentifier> identifiers = <SimpleIdentifier>[
5434 parseSimpleIdentifier() 6389 parseSimpleIdentifier()
5435 ]; 6390 ];
5436 while (_optional(TokenType.COMMA)) { 6391 while (_optional(TokenType.COMMA)) {
5437 identifiers.add(parseSimpleIdentifier()); 6392 identifiers.add(parseSimpleIdentifier());
5438 } 6393 }
5439 return identifiers; 6394 return identifiers;
5440 } 6395 }
5441 6396
5442 /** 6397 /**
5443 * Parse an if statement. Return the if statement that was parsed.
5444 *
5445 * This method assumes that the current token matches `Keyword.IF`.
5446 *
5447 * ifStatement ::=
5448 * 'if' '(' expression ')' statement ('else' statement)?
5449 */
5450 Statement _parseIfStatement() {
5451 Token ifKeyword = getAndAdvance();
5452 Token leftParenthesis = _expect(TokenType.OPEN_PAREN);
5453 Expression condition = parseExpression2();
5454 Token rightParenthesis = _expect(TokenType.CLOSE_PAREN);
5455 Statement thenStatement = parseStatement2();
5456 Token elseKeyword = null;
5457 Statement elseStatement = null;
5458 if (_matchesKeyword(Keyword.ELSE)) {
5459 elseKeyword = getAndAdvance();
5460 elseStatement = parseStatement2();
5461 }
5462 return new IfStatement(ifKeyword, leftParenthesis, condition,
5463 rightParenthesis, thenStatement, elseKeyword, elseStatement);
5464 }
5465
5466 /**
5467 * Parse an import directive. The [commentAndMetadata] is the metadata to be 6398 * Parse an import directive. The [commentAndMetadata] is the metadata to be
5468 * associated with the directive. Return the import directive that was parsed. 6399 * associated with the directive. Return the import directive that was parsed.
5469 * 6400 *
5470 * This method assumes that the current token matches `Keyword.IMPORT`. 6401 * This method assumes that the current token matches `Keyword.IMPORT`.
5471 * 6402 *
5472 * importDirective ::= 6403 * importDirective ::=
5473 * metadata 'import' stringLiteral configuration* (deferred)? ('as' id entifier)? combinator*';' 6404 * metadata 'import' stringLiteral configuration* (deferred)? ('as' id entifier)? combinator*';'
5474 */ 6405 */
5475 ImportDirective _parseImportDirective(CommentAndMetadata commentAndMetadata) { 6406 ImportDirective _parseImportDirective(CommentAndMetadata commentAndMetadata) {
5476 Token importKeyword = getAndAdvance(); 6407 Token importKeyword = getAndAdvance();
(...skipping 20 matching lines...) Expand all
5497 _tokenMatchesString(nextToken, _HIDE)) { 6428 _tokenMatchesString(nextToken, _HIDE)) {
5498 _reportErrorForCurrentToken( 6429 _reportErrorForCurrentToken(
5499 ParserErrorCode.UNEXPECTED_TOKEN, [_currentToken]); 6430 ParserErrorCode.UNEXPECTED_TOKEN, [_currentToken]);
5500 _advance(); 6431 _advance();
5501 if (_matchesKeyword(Keyword.AS)) { 6432 if (_matchesKeyword(Keyword.AS)) {
5502 asToken = getAndAdvance(); 6433 asToken = getAndAdvance();
5503 prefix = parseSimpleIdentifier(isDeclaration: true); 6434 prefix = parseSimpleIdentifier(isDeclaration: true);
5504 } 6435 }
5505 } 6436 }
5506 } 6437 }
5507 List<Combinator> combinators = _parseCombinators(); 6438 List<Combinator> combinators = parseCombinators();
5508 Token semicolon = _expect(TokenType.SEMICOLON); 6439 Token semicolon = _expect(TokenType.SEMICOLON);
5509 return new ImportDirective( 6440 return new ImportDirective(
5510 commentAndMetadata.comment, 6441 commentAndMetadata.comment,
5511 commentAndMetadata.metadata, 6442 commentAndMetadata.metadata,
5512 importKeyword, 6443 importKeyword,
5513 libraryUri, 6444 libraryUri,
5514 configurations, 6445 configurations,
5515 deferredToken, 6446 deferredToken,
5516 asToken, 6447 asToken,
5517 prefix, 6448 prefix,
(...skipping 19 matching lines...) Expand all
5537 * 6468 *
5538 * initializedIdentifier ::= 6469 * initializedIdentifier ::=
5539 * identifier ('=' expression)? 6470 * identifier ('=' expression)?
5540 */ 6471 */
5541 FieldDeclaration _parseInitializedIdentifierList( 6472 FieldDeclaration _parseInitializedIdentifierList(
5542 CommentAndMetadata commentAndMetadata, 6473 CommentAndMetadata commentAndMetadata,
5543 Token staticKeyword, 6474 Token staticKeyword,
5544 Token keyword, 6475 Token keyword,
5545 TypeName type) { 6476 TypeName type) {
5546 VariableDeclarationList fieldList = 6477 VariableDeclarationList fieldList =
5547 _parseVariableDeclarationListAfterType(null, keyword, type); 6478 parseVariableDeclarationListAfterType(null, keyword, type);
5548 return new FieldDeclaration( 6479 return new FieldDeclaration(
5549 commentAndMetadata.comment, 6480 commentAndMetadata.comment,
5550 commentAndMetadata.metadata, 6481 commentAndMetadata.metadata,
5551 staticKeyword, 6482 staticKeyword,
5552 fieldList, 6483 fieldList,
5553 _expect(TokenType.SEMICOLON)); 6484 _expect(TokenType.SEMICOLON));
5554 } 6485 }
5555 6486
5556 /** 6487 /**
5557 * Parse an instance creation expression. The [keyword] is the 'new' or 6488 * Parse an instance creation expression. The [keyword] is the 'new' or
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
5603 return parseLibraryIdentifier(); 6534 return parseLibraryIdentifier();
5604 } else if (_matches(TokenType.STRING)) { 6535 } else if (_matches(TokenType.STRING)) {
5605 // Recovery: This should be extended to handle arbitrary tokens until we 6536 // Recovery: This should be extended to handle arbitrary tokens until we
5606 // can find a token that can start a compilation unit member. 6537 // can find a token that can start a compilation unit member.
5607 StringLiteral string = parseStringLiteral(); 6538 StringLiteral string = parseStringLiteral();
5608 _reportErrorForNode(ParserErrorCode.NON_IDENTIFIER_LIBRARY_NAME, string); 6539 _reportErrorForNode(ParserErrorCode.NON_IDENTIFIER_LIBRARY_NAME, string);
5609 } else { 6540 } else {
5610 _reportErrorForToken(missingNameError, missingNameToken); 6541 _reportErrorForToken(missingNameError, missingNameToken);
5611 } 6542 }
5612 return new LibraryIdentifier( 6543 return new LibraryIdentifier(
5613 <SimpleIdentifier>[_createSyntheticIdentifier()]); 6544 <SimpleIdentifier>[createSyntheticIdentifier()]);
5614 } 6545 }
5615 6546
5616 /** 6547 /**
5617 * Parse a list literal. The [modifier] is the 'const' modifier appearing 6548 * Parse a list literal. The [modifier] is the 'const' modifier appearing
5618 * before the literal, or `null` if there is no modifier. The [typeArguments] 6549 * before the literal, or `null` if there is no modifier. The [typeArguments]
5619 * is the type arguments appearing before the literal, or `null` if there are 6550 * is the type arguments appearing before the literal, or `null` if there are
5620 * no type arguments. Return the list literal that was parsed. 6551 * no type arguments. Return the list literal that was parsed.
5621 * 6552 *
5622 * This method assumes that the current token matches either 6553 * This method assumes that the current token matches either
5623 * `TokenType.OPEN_SQUARE_BRACKET` or `TokenType.INDEX`. 6554 * `TokenType.OPEN_SQUARE_BRACKET` or `TokenType.INDEX`.
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
5660 } 6591 }
5661 Token rightBracket = _expect(TokenType.CLOSE_SQUARE_BRACKET); 6592 Token rightBracket = _expect(TokenType.CLOSE_SQUARE_BRACKET);
5662 return new ListLiteral( 6593 return new ListLiteral(
5663 modifier, typeArguments, leftBracket, elements, rightBracket); 6594 modifier, typeArguments, leftBracket, elements, rightBracket);
5664 } finally { 6595 } finally {
5665 _inInitializer = wasInInitializer; 6596 _inInitializer = wasInInitializer;
5666 } 6597 }
5667 } 6598 }
5668 6599
5669 /** 6600 /**
5670 * Parse a list or map literal. The [modifier] is the 'const' modifier
5671 * appearing before the literal, or `null` if there is no modifier. Return the
5672 * list or map literal that was parsed.
5673 *
5674 * listOrMapLiteral ::=
5675 * listLiteral
5676 * | mapLiteral
5677 */
5678 TypedLiteral _parseListOrMapLiteral(Token modifier) {
5679 TypeArgumentList typeArguments = _parseOptionalTypeArguments();
5680 if (_matches(TokenType.OPEN_CURLY_BRACKET)) {
5681 return _parseMapLiteral(modifier, typeArguments);
5682 } else if (_matches(TokenType.OPEN_SQUARE_BRACKET) ||
5683 _matches(TokenType.INDEX)) {
5684 return _parseListLiteral(modifier, typeArguments);
5685 }
5686 _reportErrorForCurrentToken(ParserErrorCode.EXPECTED_LIST_OR_MAP_LITERAL);
5687 return new ListLiteral(
5688 modifier,
5689 typeArguments,
5690 _createSyntheticToken(TokenType.OPEN_SQUARE_BRACKET),
5691 null,
5692 _createSyntheticToken(TokenType.CLOSE_SQUARE_BRACKET));
5693 }
5694
5695 /**
5696 * Parse a logical and expression. Return the logical and expression that was 6601 * Parse a logical and expression. Return the logical and expression that was
5697 * parsed. 6602 * parsed.
5698 * 6603 *
5699 * logicalAndExpression ::= 6604 * logicalAndExpression ::=
5700 * equalityExpression ('&&' equalityExpression)* 6605 * equalityExpression ('&&' equalityExpression)*
5701 */ 6606 */
5702 Expression _parseLogicalAndExpression() { 6607 Expression _parseLogicalAndExpression() {
5703 Expression expression = _parseEqualityExpression(); 6608 Expression expression = _parseEqualityExpression();
5704 while (_currentToken.type == TokenType.AMPERSAND_AMPERSAND) { 6609 while (_currentToken.type == TokenType.AMPERSAND_AMPERSAND) {
5705 expression = new BinaryExpression( 6610 expression = new BinaryExpression(
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
5759 * | 'external'? functionSignature ';' 6664 * | 'external'? functionSignature ';'
5760 */ 6665 */
5761 MethodDeclaration _parseMethodDeclarationAfterParameters( 6666 MethodDeclaration _parseMethodDeclarationAfterParameters(
5762 CommentAndMetadata commentAndMetadata, 6667 CommentAndMetadata commentAndMetadata,
5763 Token externalKeyword, 6668 Token externalKeyword,
5764 Token staticKeyword, 6669 Token staticKeyword,
5765 TypeName returnType, 6670 TypeName returnType,
5766 SimpleIdentifier name, 6671 SimpleIdentifier name,
5767 TypeParameterList typeParameters, 6672 TypeParameterList typeParameters,
5768 FormalParameterList parameters) { 6673 FormalParameterList parameters) {
5769 FunctionBody body = _parseFunctionBody( 6674 FunctionBody body = parseFunctionBody(
5770 externalKeyword != null || staticKeyword == null, 6675 externalKeyword != null || staticKeyword == null,
5771 ParserErrorCode.MISSING_FUNCTION_BODY, 6676 ParserErrorCode.MISSING_FUNCTION_BODY,
5772 false); 6677 false);
5773 if (externalKeyword != null) { 6678 if (externalKeyword != null) {
5774 if (body is! EmptyFunctionBody) { 6679 if (body is! EmptyFunctionBody) {
5775 _reportErrorForNode(ParserErrorCode.EXTERNAL_METHOD_WITH_BODY, body); 6680 _reportErrorForNode(ParserErrorCode.EXTERNAL_METHOD_WITH_BODY, body);
5776 } 6681 }
5777 } else if (staticKeyword != null) { 6682 } else if (staticKeyword != null) {
5778 if (body is EmptyFunctionBody && _parseFunctionBodies) { 6683 if (body is EmptyFunctionBody && _parseFunctionBodies) {
5779 _reportErrorForNode(ParserErrorCode.ABSTRACT_STATIC_METHOD, body); 6684 _reportErrorForNode(ParserErrorCode.ABSTRACT_STATIC_METHOD, body);
(...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after
5919 modifiers.varKeyword = getAndAdvance(); 6824 modifiers.varKeyword = getAndAdvance();
5920 } 6825 }
5921 } else { 6826 } else {
5922 progress = false; 6827 progress = false;
5923 } 6828 }
5924 } 6829 }
5925 return modifiers; 6830 return modifiers;
5926 } 6831 }
5927 6832
5928 /** 6833 /**
5929 * Parse a multiplicative expression. Return the multiplicative expression
5930 * that was parsed.
5931 *
5932 * multiplicativeExpression ::=
5933 * unaryExpression (multiplicativeOperator unaryExpression)*
5934 * | 'super' (multiplicativeOperator unaryExpression)+
5935 */
5936 Expression _parseMultiplicativeExpression() {
5937 Expression expression;
5938 if (_currentToken.keyword == Keyword.SUPER &&
5939 _currentToken.next.type.isMultiplicativeOperator) {
5940 expression = new SuperExpression(getAndAdvance());
5941 } else {
5942 expression = _parseUnaryExpression();
5943 }
5944 while (_currentToken.type.isMultiplicativeOperator) {
5945 expression = new BinaryExpression(
5946 expression, getAndAdvance(), _parseUnaryExpression());
5947 }
5948 return expression;
5949 }
5950
5951 /**
5952 * Parse a class native clause. Return the native clause that was parsed. 6834 * Parse a class native clause. Return the native clause that was parsed.
5953 * 6835 *
5954 * This method assumes that the current token matches `_NATIVE`. 6836 * This method assumes that the current token matches `_NATIVE`.
5955 * 6837 *
5956 * classNativeClause ::= 6838 * classNativeClause ::=
5957 * 'native' name 6839 * 'native' name
5958 */ 6840 */
5959 NativeClause _parseNativeClause() { 6841 NativeClause _parseNativeClause() {
5960 Token keyword = getAndAdvance(); 6842 Token keyword = getAndAdvance();
5961 StringLiteral name = parseStringLiteral(); 6843 StringLiteral name = parseStringLiteral();
(...skipping 26 matching lines...) Expand all
5988 * | returnStatement 6870 * | returnStatement
5989 * | switchStatement 6871 * | switchStatement
5990 * | tryStatement 6872 * | tryStatement
5991 * | whileStatement 6873 * | whileStatement
5992 * | variableDeclarationList ';' 6874 * | variableDeclarationList ';'
5993 * | expressionStatement 6875 * | expressionStatement
5994 * | functionSignature functionBody 6876 * | functionSignature functionBody
5995 */ 6877 */
5996 Statement _parseNonLabeledStatement() { 6878 Statement _parseNonLabeledStatement() {
5997 // TODO(brianwilkerson) Pass the comment and metadata on where appropriate. 6879 // TODO(brianwilkerson) Pass the comment and metadata on where appropriate.
5998 CommentAndMetadata commentAndMetadata = _parseCommentAndMetadata(); 6880 CommentAndMetadata commentAndMetadata = parseCommentAndMetadata();
5999 TokenType type = _currentToken.type; 6881 TokenType type = _currentToken.type;
6000 if (type == TokenType.OPEN_CURLY_BRACKET) { 6882 if (type == TokenType.OPEN_CURLY_BRACKET) {
6001 if (_tokenMatches(_peek(), TokenType.STRING)) { 6883 if (_tokenMatches(_peek(), TokenType.STRING)) {
6002 Token afterString = _skipStringLiteral(_currentToken.next); 6884 Token afterString = skipStringLiteral(_currentToken.next);
6003 if (afterString != null && afterString.type == TokenType.COLON) { 6885 if (afterString != null && afterString.type == TokenType.COLON) {
6004 return new ExpressionStatement( 6886 return new ExpressionStatement(
6005 parseExpression2(), _expect(TokenType.SEMICOLON)); 6887 parseExpression2(), _expect(TokenType.SEMICOLON));
6006 } 6888 }
6007 } 6889 }
6008 return parseBlock(); 6890 return parseBlock();
6009 } else if (type == TokenType.KEYWORD && 6891 } else if (type == TokenType.KEYWORD &&
6010 !_currentToken.keyword.isPseudoKeyword) { 6892 !_currentToken.keyword.isPseudoKeyword) {
6011 Keyword keyword = _currentToken.keyword; 6893 Keyword keyword = _currentToken.keyword;
6012 // TODO(jwren) compute some metrics to figure out a better order for this 6894 // TODO(jwren) compute some metrics to figure out a better order for this
6013 // if-then sequence to optimize performance 6895 // if-then sequence to optimize performance
6014 if (keyword == Keyword.ASSERT) { 6896 if (keyword == Keyword.ASSERT) {
6015 return _parseAssertStatement(); 6897 return parseAssertStatement();
6016 } else if (keyword == Keyword.BREAK) { 6898 } else if (keyword == Keyword.BREAK) {
6017 return _parseBreakStatement(); 6899 return parseBreakStatement();
6018 } else if (keyword == Keyword.CONTINUE) { 6900 } else if (keyword == Keyword.CONTINUE) {
6019 return _parseContinueStatement(); 6901 return parseContinueStatement();
6020 } else if (keyword == Keyword.DO) { 6902 } else if (keyword == Keyword.DO) {
6021 return _parseDoStatement(); 6903 return parseDoStatement();
6022 } else if (keyword == Keyword.FOR) { 6904 } else if (keyword == Keyword.FOR) {
6023 return _parseForStatement(); 6905 return parseForStatement();
6024 } else if (keyword == Keyword.IF) { 6906 } else if (keyword == Keyword.IF) {
6025 return _parseIfStatement(); 6907 return parseIfStatement();
6026 } else if (keyword == Keyword.RETHROW) { 6908 } else if (keyword == Keyword.RETHROW) {
6027 return new ExpressionStatement( 6909 return new ExpressionStatement(
6028 _parseRethrowExpression(), _expect(TokenType.SEMICOLON)); 6910 parseRethrowExpression(), _expect(TokenType.SEMICOLON));
6029 } else if (keyword == Keyword.RETURN) { 6911 } else if (keyword == Keyword.RETURN) {
6030 return _parseReturnStatement(); 6912 return parseReturnStatement();
6031 } else if (keyword == Keyword.SWITCH) { 6913 } else if (keyword == Keyword.SWITCH) {
6032 return _parseSwitchStatement(); 6914 return parseSwitchStatement();
6033 } else if (keyword == Keyword.THROW) { 6915 } else if (keyword == Keyword.THROW) {
6034 return new ExpressionStatement( 6916 return new ExpressionStatement(
6035 _parseThrowExpression(), _expect(TokenType.SEMICOLON)); 6917 parseThrowExpression(), _expect(TokenType.SEMICOLON));
6036 } else if (keyword == Keyword.TRY) { 6918 } else if (keyword == Keyword.TRY) {
6037 return _parseTryStatement(); 6919 return parseTryStatement();
6038 } else if (keyword == Keyword.WHILE) { 6920 } else if (keyword == Keyword.WHILE) {
6039 return _parseWhileStatement(); 6921 return parseWhileStatement();
6040 } else if (keyword == Keyword.VAR || keyword == Keyword.FINAL) { 6922 } else if (keyword == Keyword.VAR || keyword == Keyword.FINAL) {
6041 return _parseVariableDeclarationStatementAfterMetadata( 6923 return parseVariableDeclarationStatementAfterMetadata(
6042 commentAndMetadata); 6924 commentAndMetadata);
6043 } else if (keyword == Keyword.VOID) { 6925 } else if (keyword == Keyword.VOID) {
6044 TypeName returnType = 6926 TypeName returnType =
6045 new TypeName(new SimpleIdentifier(getAndAdvance()), null); 6927 new TypeName(new SimpleIdentifier(getAndAdvance()), null);
6046 Token next = _currentToken.next; 6928 Token next = _currentToken.next;
6047 if (_matchesIdentifier() && 6929 if (_matchesIdentifier() &&
6048 next.matchesAny(const <TokenType>[ 6930 next.matchesAny(const <TokenType>[
6049 TokenType.OPEN_PAREN, 6931 TokenType.OPEN_PAREN,
6050 TokenType.OPEN_CURLY_BRACKET, 6932 TokenType.OPEN_CURLY_BRACKET,
6051 TokenType.FUNCTION, 6933 TokenType.FUNCTION,
6052 TokenType.LT 6934 TokenType.LT
6053 ])) { 6935 ])) {
6054 return _parseFunctionDeclarationStatementAfterReturnType( 6936 return _parseFunctionDeclarationStatementAfterReturnType(
6055 commentAndMetadata, returnType); 6937 commentAndMetadata, returnType);
6056 } else { 6938 } else {
6057 // 6939 //
6058 // We have found an error of some kind. Try to recover. 6940 // We have found an error of some kind. Try to recover.
6059 // 6941 //
6060 if (_matchesIdentifier()) { 6942 if (_matchesIdentifier()) {
6061 if (next.matchesAny(const <TokenType>[ 6943 if (next.matchesAny(const <TokenType>[
6062 TokenType.EQ, 6944 TokenType.EQ,
6063 TokenType.COMMA, 6945 TokenType.COMMA,
6064 TokenType.SEMICOLON 6946 TokenType.SEMICOLON
6065 ])) { 6947 ])) {
6066 // 6948 //
6067 // We appear to have a variable declaration with a type of "void". 6949 // We appear to have a variable declaration with a type of "void".
6068 // 6950 //
6069 _reportErrorForNode(ParserErrorCode.VOID_VARIABLE, returnType); 6951 _reportErrorForNode(ParserErrorCode.VOID_VARIABLE, returnType);
6070 return _parseVariableDeclarationStatementAfterMetadata( 6952 return parseVariableDeclarationStatementAfterMetadata(
6071 commentAndMetadata); 6953 commentAndMetadata);
6072 } 6954 }
6073 } else if (_matches(TokenType.CLOSE_CURLY_BRACKET)) { 6955 } else if (_matches(TokenType.CLOSE_CURLY_BRACKET)) {
6074 // 6956 //
6075 // We appear to have found an incomplete statement at the end of a 6957 // We appear to have found an incomplete statement at the end of a
6076 // block. Parse it as a variable declaration. 6958 // block. Parse it as a variable declaration.
6077 // 6959 //
6078 return _parseVariableDeclarationStatementAfterType( 6960 return _parseVariableDeclarationStatementAfterType(
6079 commentAndMetadata, null, returnType); 6961 commentAndMetadata, null, returnType);
6080 } 6962 }
6081 _reportErrorForCurrentToken(ParserErrorCode.MISSING_STATEMENT); 6963 _reportErrorForCurrentToken(ParserErrorCode.MISSING_STATEMENT);
6082 // TODO(brianwilkerson) Recover from this error. 6964 // TODO(brianwilkerson) Recover from this error.
6083 return new EmptyStatement(_createSyntheticToken(TokenType.SEMICOLON)); 6965 return new EmptyStatement(_createSyntheticToken(TokenType.SEMICOLON));
6084 } 6966 }
6085 } else if (keyword == Keyword.CONST) { 6967 } else if (keyword == Keyword.CONST) {
6086 Token next = _currentToken.next; 6968 Token next = _currentToken.next;
6087 if (next.matchesAny(const <TokenType>[ 6969 if (next.matchesAny(const <TokenType>[
6088 TokenType.LT, 6970 TokenType.LT,
6089 TokenType.OPEN_CURLY_BRACKET, 6971 TokenType.OPEN_CURLY_BRACKET,
6090 TokenType.OPEN_SQUARE_BRACKET, 6972 TokenType.OPEN_SQUARE_BRACKET,
6091 TokenType.INDEX 6973 TokenType.INDEX
6092 ])) { 6974 ])) {
6093 return new ExpressionStatement( 6975 return new ExpressionStatement(
6094 parseExpression2(), _expect(TokenType.SEMICOLON)); 6976 parseExpression2(), _expect(TokenType.SEMICOLON));
6095 } else if (_tokenMatches(next, TokenType.IDENTIFIER)) { 6977 } else if (_tokenMatches(next, TokenType.IDENTIFIER)) {
6096 Token afterType = _skipTypeName(next); 6978 Token afterType = skipTypeName(next);
6097 if (afterType != null) { 6979 if (afterType != null) {
6098 if (_tokenMatches(afterType, TokenType.OPEN_PAREN) || 6980 if (_tokenMatches(afterType, TokenType.OPEN_PAREN) ||
6099 (_tokenMatches(afterType, TokenType.PERIOD) && 6981 (_tokenMatches(afterType, TokenType.PERIOD) &&
6100 _tokenMatches(afterType.next, TokenType.IDENTIFIER) && 6982 _tokenMatches(afterType.next, TokenType.IDENTIFIER) &&
6101 _tokenMatches(afterType.next.next, TokenType.OPEN_PAREN))) { 6983 _tokenMatches(afterType.next.next, TokenType.OPEN_PAREN))) {
6102 return new ExpressionStatement( 6984 return new ExpressionStatement(
6103 parseExpression2(), _expect(TokenType.SEMICOLON)); 6985 parseExpression2(), _expect(TokenType.SEMICOLON));
6104 } 6986 }
6105 } 6987 }
6106 } 6988 }
6107 return _parseVariableDeclarationStatementAfterMetadata( 6989 return parseVariableDeclarationStatementAfterMetadata(
6108 commentAndMetadata); 6990 commentAndMetadata);
6109 } else if (keyword == Keyword.NEW || 6991 } else if (keyword == Keyword.NEW ||
6110 keyword == Keyword.TRUE || 6992 keyword == Keyword.TRUE ||
6111 keyword == Keyword.FALSE || 6993 keyword == Keyword.FALSE ||
6112 keyword == Keyword.NULL || 6994 keyword == Keyword.NULL ||
6113 keyword == Keyword.SUPER || 6995 keyword == Keyword.SUPER ||
6114 keyword == Keyword.THIS) { 6996 keyword == Keyword.THIS) {
6115 return new ExpressionStatement( 6997 return new ExpressionStatement(
6116 parseExpression2(), _expect(TokenType.SEMICOLON)); 6998 parseExpression2(), _expect(TokenType.SEMICOLON));
6117 } else { 6999 } else {
6118 // 7000 //
6119 // We have found an error of some kind. Try to recover. 7001 // We have found an error of some kind. Try to recover.
6120 // 7002 //
6121 _reportErrorForCurrentToken(ParserErrorCode.MISSING_STATEMENT); 7003 _reportErrorForCurrentToken(ParserErrorCode.MISSING_STATEMENT);
6122 return new EmptyStatement(_createSyntheticToken(TokenType.SEMICOLON)); 7004 return new EmptyStatement(_createSyntheticToken(TokenType.SEMICOLON));
6123 } 7005 }
6124 } else if (_inGenerator && _matchesString(_YIELD)) { 7006 } else if (_inGenerator && _matchesString(_YIELD)) {
6125 return _parseYieldStatement(); 7007 return parseYieldStatement();
6126 } else if (_inAsync && _matchesString(_AWAIT)) { 7008 } else if (_inAsync && _matchesString(_AWAIT)) {
6127 if (_tokenMatchesKeyword(_peek(), Keyword.FOR)) { 7009 if (_tokenMatchesKeyword(_peek(), Keyword.FOR)) {
6128 return _parseForStatement(); 7010 return parseForStatement();
6129 } 7011 }
6130 return new ExpressionStatement( 7012 return new ExpressionStatement(
6131 parseExpression2(), _expect(TokenType.SEMICOLON)); 7013 parseExpression2(), _expect(TokenType.SEMICOLON));
6132 } else if (_matchesString(_AWAIT) && 7014 } else if (_matchesString(_AWAIT) &&
6133 _tokenMatchesKeyword(_peek(), Keyword.FOR)) { 7015 _tokenMatchesKeyword(_peek(), Keyword.FOR)) {
6134 Token awaitToken = _currentToken; 7016 Token awaitToken = _currentToken;
6135 Statement statement = _parseForStatement(); 7017 Statement statement = parseForStatement();
6136 if (statement is! ForStatement) { 7018 if (statement is! ForStatement) {
6137 _reportErrorForToken( 7019 _reportErrorForToken(
6138 CompileTimeErrorCode.ASYNC_FOR_IN_WRONG_CONTEXT, awaitToken); 7020 CompileTimeErrorCode.ASYNC_FOR_IN_WRONG_CONTEXT, awaitToken);
6139 } 7021 }
6140 return statement; 7022 return statement;
6141 } else if (type == TokenType.SEMICOLON) { 7023 } else if (type == TokenType.SEMICOLON) {
6142 return _parseEmptyStatement(); 7024 return parseEmptyStatement();
6143 } else if (_isInitializedVariableDeclaration()) { 7025 } else if (isInitializedVariableDeclaration()) {
6144 return _parseVariableDeclarationStatementAfterMetadata( 7026 return parseVariableDeclarationStatementAfterMetadata(commentAndMetadata);
6145 commentAndMetadata); 7027 } else if (isFunctionDeclaration()) {
6146 } else if (_isFunctionDeclaration()) { 7028 return parseFunctionDeclarationStatement();
6147 return _parseFunctionDeclarationStatement();
6148 } else if (type == TokenType.CLOSE_CURLY_BRACKET) { 7029 } else if (type == TokenType.CLOSE_CURLY_BRACKET) {
6149 _reportErrorForCurrentToken(ParserErrorCode.MISSING_STATEMENT); 7030 _reportErrorForCurrentToken(ParserErrorCode.MISSING_STATEMENT);
6150 return new EmptyStatement(_createSyntheticToken(TokenType.SEMICOLON)); 7031 return new EmptyStatement(_createSyntheticToken(TokenType.SEMICOLON));
6151 } else { 7032 } else {
6152 return new ExpressionStatement( 7033 return new ExpressionStatement(
6153 parseExpression2(), _expect(TokenType.SEMICOLON)); 7034 parseExpression2(), _expect(TokenType.SEMICOLON));
6154 } 7035 }
6155 } 7036 }
6156 7037
6157 /** 7038 /**
6158 * Parse an operator declaration. The [commentAndMetadata] is the
6159 * documentation comment and metadata to be associated with the declaration.
6160 * The [externalKeyword] is the 'external' token. The [returnType] is the
6161 * return type that has already been parsed, or `null` if there was no return
6162 * type. Return the operator declaration that was parsed.
6163 *
6164 * operatorDeclaration ::=
6165 * operatorSignature (';' | functionBody)
6166 *
6167 * operatorSignature ::=
6168 * 'external'? returnType? 'operator' operator formalParameterList
6169 */
6170 MethodDeclaration _parseOperator(CommentAndMetadata commentAndMetadata,
6171 Token externalKeyword, TypeName returnType) {
6172 Token operatorKeyword;
6173 if (_matchesKeyword(Keyword.OPERATOR)) {
6174 operatorKeyword = getAndAdvance();
6175 } else {
6176 _reportErrorForToken(
6177 ParserErrorCode.MISSING_KEYWORD_OPERATOR, _currentToken);
6178 operatorKeyword = _createSyntheticKeyword(Keyword.OPERATOR);
6179 }
6180 return _parseOperatorAfterKeyword(
6181 commentAndMetadata, externalKeyword, returnType, operatorKeyword);
6182 }
6183
6184 /**
6185 * Parse an operator declaration starting after the 'operator' keyword. The 7039 * Parse an operator declaration starting after the 'operator' keyword. The
6186 * [commentAndMetadata] is the documentation comment and metadata to be 7040 * [commentAndMetadata] is the documentation comment and metadata to be
6187 * associated with the declaration. The [externalKeyword] is the 'external' 7041 * associated with the declaration. The [externalKeyword] is the 'external'
6188 * token. The [returnType] is the return type that has already been parsed, or 7042 * token. The [returnType] is the return type that has already been parsed, or
6189 * `null` if there was no return type. The [operatorKeyword] is the 'operator' 7043 * `null` if there was no return type. The [operatorKeyword] is the 'operator'
6190 * keyword. Return the operator declaration that was parsed. 7044 * keyword. Return the operator declaration that was parsed.
6191 * 7045 *
6192 * operatorDeclaration ::= 7046 * operatorDeclaration ::=
6193 * operatorSignature (';' | functionBody) 7047 * operatorSignature (';' | functionBody)
6194 * 7048 *
(...skipping 17 matching lines...) Expand all
6212 _tokenMatches(previous, TokenType.BANG_EQ)) && 7066 _tokenMatches(previous, TokenType.BANG_EQ)) &&
6213 _currentToken.offset == previous.offset + 2) { 7067 _currentToken.offset == previous.offset + 2) {
6214 _reportErrorForCurrentToken(ParserErrorCode.INVALID_OPERATOR, 7068 _reportErrorForCurrentToken(ParserErrorCode.INVALID_OPERATOR,
6215 ["${previous.lexeme}${_currentToken.lexeme}"]); 7069 ["${previous.lexeme}${_currentToken.lexeme}"]);
6216 _advance(); 7070 _advance();
6217 } 7071 }
6218 } 7072 }
6219 FormalParameterList parameters = parseFormalParameterList(); 7073 FormalParameterList parameters = parseFormalParameterList();
6220 _validateFormalParameterList(parameters); 7074 _validateFormalParameterList(parameters);
6221 FunctionBody body = 7075 FunctionBody body =
6222 _parseFunctionBody(true, ParserErrorCode.MISSING_FUNCTION_BODY, false); 7076 parseFunctionBody(true, ParserErrorCode.MISSING_FUNCTION_BODY, false);
6223 if (externalKeyword != null && body is! EmptyFunctionBody) { 7077 if (externalKeyword != null && body is! EmptyFunctionBody) {
6224 _reportErrorForCurrentToken(ParserErrorCode.EXTERNAL_OPERATOR_WITH_BODY); 7078 _reportErrorForCurrentToken(ParserErrorCode.EXTERNAL_OPERATOR_WITH_BODY);
6225 } 7079 }
6226 return new MethodDeclaration( 7080 return new MethodDeclaration(
6227 commentAndMetadata.comment, 7081 commentAndMetadata.comment,
6228 commentAndMetadata.metadata, 7082 commentAndMetadata.metadata,
6229 externalKeyword, 7083 externalKeyword,
6230 null, 7084 null,
6231 returnType, 7085 returnType,
6232 null, 7086 null,
(...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after
6357 * 7211 *
6358 * postfixExpression ::= 7212 * postfixExpression ::=
6359 * assignableExpression postfixOperator 7213 * assignableExpression postfixOperator
6360 * | primary selector* 7214 * | primary selector*
6361 * 7215 *
6362 * selector ::= 7216 * selector ::=
6363 * assignableSelector 7217 * assignableSelector
6364 * | argumentList 7218 * | argumentList
6365 */ 7219 */
6366 Expression _parsePostfixExpression() { 7220 Expression _parsePostfixExpression() {
6367 Expression operand = _parseAssignableExpression(true); 7221 Expression operand = parseAssignableExpression(true);
6368 TokenType type = _currentToken.type; 7222 TokenType type = _currentToken.type;
6369 if (type == TokenType.OPEN_SQUARE_BRACKET || 7223 if (type == TokenType.OPEN_SQUARE_BRACKET ||
6370 type == TokenType.PERIOD || 7224 type == TokenType.PERIOD ||
6371 type == TokenType.QUESTION_PERIOD || 7225 type == TokenType.QUESTION_PERIOD ||
6372 type == TokenType.OPEN_PAREN || 7226 type == TokenType.OPEN_PAREN ||
6373 (parseGenericMethods && type == TokenType.LT)) { 7227 (parseGenericMethods && type == TokenType.LT)) {
6374 do { 7228 do {
6375 if (_isLikelyArgumentList()) { 7229 if (_isLikelyArgumentList()) {
6376 TypeArgumentList typeArguments = _parseOptionalTypeArguments(); 7230 TypeArgumentList typeArguments = _parseOptionalTypeArguments();
6377 ArgumentList argumentList = parseArgumentList(); 7231 ArgumentList argumentList = parseArgumentList();
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after
6430 * 7284 *
6431 * prefixedIdentifier ::= 7285 * prefixedIdentifier ::=
6432 * identifier ('.' identifier)? 7286 * identifier ('.' identifier)?
6433 */ 7287 */
6434 Identifier _parsePrefixedIdentifierUnchecked() { 7288 Identifier _parsePrefixedIdentifierUnchecked() {
6435 return _parsePrefixedIdentifierAfterIdentifier( 7289 return _parsePrefixedIdentifierAfterIdentifier(
6436 _parseSimpleIdentifierUnchecked()); 7290 _parseSimpleIdentifierUnchecked());
6437 } 7291 }
6438 7292
6439 /** 7293 /**
6440 * Parse a primary expression. Return the primary expression that was parsed.
6441 *
6442 * primary ::=
6443 * thisExpression
6444 * | 'super' unconditionalAssignableSelector
6445 * | functionExpression
6446 * | literal
6447 * | identifier
6448 * | newExpression
6449 * | constObjectExpression
6450 * | '(' expression ')'
6451 * | argumentDefinitionTest
6452 *
6453 * literal ::=
6454 * nullLiteral
6455 * | booleanLiteral
6456 * | numericLiteral
6457 * | stringLiteral
6458 * | symbolLiteral
6459 * | mapLiteral
6460 * | listLiteral
6461 */
6462 Expression _parsePrimaryExpression() {
6463 if (_matchesIdentifier()) {
6464 // TODO(brianwilkerson) The code below was an attempt to recover from an
6465 // error case, but it needs to be applied as a recovery only after we
6466 // know that parsing it as an identifier doesn't work. Leaving the code as
6467 // a reminder of how to recover.
6468 // if (isFunctionExpression(_peek())) {
6469 // //
6470 // // Function expressions were allowed to have names at one point, but t his is now illegal.
6471 // //
6472 // reportError(ParserErrorCode.NAMED_FUNCTION_EXPRESSION, getAndAdvance() );
6473 // return parseFunctionExpression();
6474 // }
6475 return _parsePrefixedIdentifierUnchecked();
6476 }
6477 TokenType type = _currentToken.type;
6478 if (type == TokenType.STRING) {
6479 return parseStringLiteral();
6480 } else if (type == TokenType.INT) {
6481 Token token = getAndAdvance();
6482 int value = null;
6483 try {
6484 value = int.parse(token.lexeme);
6485 } on FormatException {
6486 // The invalid format should have been reported by the scanner.
6487 }
6488 return new IntegerLiteral(token, value);
6489 }
6490 Keyword keyword = _currentToken.keyword;
6491 if (keyword == Keyword.NULL) {
6492 return new NullLiteral(getAndAdvance());
6493 } else if (keyword == Keyword.NEW) {
6494 return _parseNewExpression();
6495 } else if (keyword == Keyword.THIS) {
6496 return new ThisExpression(getAndAdvance());
6497 } else if (keyword == Keyword.SUPER) {
6498 // TODO(paulberry): verify with Gilad that "super" must be followed by
6499 // unconditionalAssignableSelector in this case.
6500 return _parseAssignableSelector(
6501 new SuperExpression(getAndAdvance()), false,
6502 allowConditional: false);
6503 } else if (keyword == Keyword.FALSE) {
6504 return new BooleanLiteral(getAndAdvance(), false);
6505 } else if (keyword == Keyword.TRUE) {
6506 return new BooleanLiteral(getAndAdvance(), true);
6507 }
6508 if (type == TokenType.DOUBLE) {
6509 Token token = getAndAdvance();
6510 double value = 0.0;
6511 try {
6512 value = double.parse(token.lexeme);
6513 } on FormatException {
6514 // The invalid format should have been reported by the scanner.
6515 }
6516 return new DoubleLiteral(token, value);
6517 } else if (type == TokenType.HEXADECIMAL) {
6518 Token token = getAndAdvance();
6519 int value = null;
6520 try {
6521 value = int.parse(token.lexeme.substring(2), radix: 16);
6522 } on FormatException {
6523 // The invalid format should have been reported by the scanner.
6524 }
6525 return new IntegerLiteral(token, value);
6526 } else if (keyword == Keyword.CONST) {
6527 return _parseConstExpression();
6528 } else if (type == TokenType.OPEN_PAREN) {
6529 if (_isFunctionExpression(_currentToken)) {
6530 return parseFunctionExpression();
6531 }
6532 Token leftParenthesis = getAndAdvance();
6533 bool wasInInitializer = _inInitializer;
6534 _inInitializer = false;
6535 try {
6536 Expression expression = parseExpression2();
6537 Token rightParenthesis = _expect(TokenType.CLOSE_PAREN);
6538 return new ParenthesizedExpression(
6539 leftParenthesis, expression, rightParenthesis);
6540 } finally {
6541 _inInitializer = wasInInitializer;
6542 }
6543 } else if (type == TokenType.LT || _injectGenericCommentTypeList()) {
6544 return _parseListOrMapLiteral(null);
6545 } else if (type == TokenType.OPEN_CURLY_BRACKET) {
6546 return _parseMapLiteral(null, null);
6547 } else if (type == TokenType.OPEN_SQUARE_BRACKET ||
6548 type == TokenType.INDEX) {
6549 return _parseListLiteral(null, null);
6550 } else if (type == TokenType.QUESTION &&
6551 _tokenMatches(_peek(), TokenType.IDENTIFIER)) {
6552 _reportErrorForCurrentToken(
6553 ParserErrorCode.UNEXPECTED_TOKEN, [_currentToken.lexeme]);
6554 _advance();
6555 return _parsePrimaryExpression();
6556 } else if (keyword == Keyword.VOID) {
6557 //
6558 // Recover from having a return type of "void" where a return type is not
6559 // expected.
6560 //
6561 // TODO(brianwilkerson) Improve this error message.
6562 _reportErrorForCurrentToken(
6563 ParserErrorCode.UNEXPECTED_TOKEN, [_currentToken.lexeme]);
6564 _advance();
6565 return _parsePrimaryExpression();
6566 } else if (type == TokenType.HASH) {
6567 return _parseSymbolLiteral();
6568 } else {
6569 _reportErrorForCurrentToken(ParserErrorCode.MISSING_IDENTIFIER);
6570 return _createSyntheticIdentifier();
6571 }
6572 }
6573
6574 /**
6575 * Parse a redirecting constructor invocation. The flag [hasPeriod] should be 7294 * Parse a redirecting constructor invocation. The flag [hasPeriod] should be
6576 * `true` if the `this` is followed by a period. Return the redirecting 7295 * `true` if the `this` is followed by a period. Return the redirecting
6577 * constructor invocation that was parsed. 7296 * constructor invocation that was parsed.
6578 * 7297 *
6579 * This method assumes that the current token matches `Keyword.THIS`. 7298 * This method assumes that the current token matches `Keyword.THIS`.
6580 * 7299 *
6581 * redirectingConstructorInvocation ::= 7300 * redirectingConstructorInvocation ::=
6582 * 'this' ('.' identifier)? arguments 7301 * 'this' ('.' identifier)? arguments
6583 */ 7302 */
6584 RedirectingConstructorInvocation _parseRedirectingConstructorInvocation( 7303 RedirectingConstructorInvocation _parseRedirectingConstructorInvocation(
6585 bool hasPeriod) { 7304 bool hasPeriod) {
6586 Token keyword = getAndAdvance(); 7305 Token keyword = getAndAdvance();
6587 Token period = null; 7306 Token period = null;
6588 SimpleIdentifier constructorName = null; 7307 SimpleIdentifier constructorName = null;
6589 if (hasPeriod) { 7308 if (hasPeriod) {
6590 period = getAndAdvance(); 7309 period = getAndAdvance();
6591 if (_matchesIdentifier()) { 7310 if (_matchesIdentifier()) {
6592 constructorName = _parseSimpleIdentifierUnchecked(isDeclaration: false); 7311 constructorName = _parseSimpleIdentifierUnchecked(isDeclaration: false);
6593 } else { 7312 } else {
6594 _reportErrorForCurrentToken(ParserErrorCode.MISSING_IDENTIFIER); 7313 _reportErrorForCurrentToken(ParserErrorCode.MISSING_IDENTIFIER);
6595 constructorName = _createSyntheticIdentifier(isDeclaration: false); 7314 constructorName = createSyntheticIdentifier(isDeclaration: false);
6596 _advance(); 7315 _advance();
6597 } 7316 }
6598 } 7317 }
6599 ArgumentList argumentList = _parseArgumentListChecked(); 7318 ArgumentList argumentList = _parseArgumentListChecked();
6600 return new RedirectingConstructorInvocation( 7319 return new RedirectingConstructorInvocation(
6601 keyword, period, constructorName, argumentList); 7320 keyword, period, constructorName, argumentList);
6602 } 7321 }
6603 7322
6604 /** 7323 /**
6605 * Parse a relational expression. Return the relational expression that was
6606 * parsed.
6607 *
6608 * relationalExpression ::=
6609 * bitwiseOrExpression ('is' '!'? type | 'as' type | relationalOperato r bitwiseOrExpression)?
6610 * | 'super' relationalOperator bitwiseOrExpression
6611 */
6612 Expression _parseRelationalExpression() {
6613 if (_currentToken.keyword == Keyword.SUPER &&
6614 _currentToken.next.type.isRelationalOperator) {
6615 Expression expression = new SuperExpression(getAndAdvance());
6616 Token operator = getAndAdvance();
6617 return new BinaryExpression(
6618 expression, operator, parseBitwiseOrExpression());
6619 }
6620 Expression expression = parseBitwiseOrExpression();
6621 Keyword keyword = _currentToken.keyword;
6622 if (keyword == Keyword.AS) {
6623 Token asOperator = getAndAdvance();
6624 return new AsExpression(expression, asOperator, parseTypeName(true));
6625 } else if (keyword == Keyword.IS) {
6626 Token isOperator = getAndAdvance();
6627 Token notOperator = null;
6628 if (_matches(TokenType.BANG)) {
6629 notOperator = getAndAdvance();
6630 }
6631 return new IsExpression(
6632 expression, isOperator, notOperator, parseTypeName(true));
6633 } else if (_currentToken.type.isRelationalOperator) {
6634 Token operator = getAndAdvance();
6635 return new BinaryExpression(
6636 expression, operator, parseBitwiseOrExpression());
6637 }
6638 return expression;
6639 }
6640
6641 /**
6642 * Parse a rethrow expression. Return the rethrow expression that was parsed.
6643 *
6644 * This method assumes that the current token matches `Keyword.RETHROW`.
6645 *
6646 * rethrowExpression ::=
6647 * 'rethrow'
6648 */
6649 Expression _parseRethrowExpression() =>
6650 new RethrowExpression(getAndAdvance());
6651
6652 /**
6653 * Parse a return statement. Return the return statement that was parsed.
6654 *
6655 * This method assumes that the current token matches `Keyword.RETURN`.
6656 *
6657 * returnStatement ::=
6658 * 'return' expression? ';'
6659 */
6660 Statement _parseReturnStatement() {
6661 Token returnKeyword = getAndAdvance();
6662 if (_matches(TokenType.SEMICOLON)) {
6663 return new ReturnStatement(returnKeyword, null, getAndAdvance());
6664 }
6665 Expression expression = parseExpression2();
6666 Token semicolon = _expect(TokenType.SEMICOLON);
6667 return new ReturnStatement(returnKeyword, expression, semicolon);
6668 }
6669
6670 /**
6671 * Parse a setter. The [commentAndMetadata] is the documentation comment and 7324 * Parse a setter. The [commentAndMetadata] is the documentation comment and
6672 * metadata to be associated with the declaration. The [externalKeyword] is 7325 * metadata to be associated with the declaration. The [externalKeyword] is
6673 * the 'external' token. The [staticKeyword] is the static keyword, or `null` 7326 * the 'external' token. The [staticKeyword] is the static keyword, or `null`
6674 * if the setter is not static. The [returnType] is the return type that has 7327 * if the setter is not static. The [returnType] is the return type that has
6675 * already been parsed, or `null` if there was no return type. Return the 7328 * already been parsed, or `null` if there was no return type. Return the
6676 * setter that was parsed. 7329 * setter that was parsed.
6677 * 7330 *
6678 * This method assumes that the current token matches `Keyword.SET`. 7331 * This method assumes that the current token matches `Keyword.SET`.
6679 * 7332 *
6680 * setter ::= 7333 * setter ::=
6681 * setterSignature functionBody? 7334 * setterSignature functionBody?
6682 * 7335 *
6683 * setterSignature ::= 7336 * setterSignature ::=
6684 * 'external'? 'static'? returnType? 'set' identifier formalParameterL ist 7337 * 'external'? 'static'? returnType? 'set' identifier formalParameterL ist
6685 */ 7338 */
6686 MethodDeclaration _parseSetter(CommentAndMetadata commentAndMetadata, 7339 MethodDeclaration _parseSetter(CommentAndMetadata commentAndMetadata,
6687 Token externalKeyword, Token staticKeyword, TypeName returnType) { 7340 Token externalKeyword, Token staticKeyword, TypeName returnType) {
6688 Token propertyKeyword = getAndAdvance(); 7341 Token propertyKeyword = getAndAdvance();
6689 SimpleIdentifier name = parseSimpleIdentifier(isDeclaration: true); 7342 SimpleIdentifier name = parseSimpleIdentifier(isDeclaration: true);
6690 FormalParameterList parameters = parseFormalParameterList(); 7343 FormalParameterList parameters = parseFormalParameterList();
6691 _validateFormalParameterList(parameters); 7344 _validateFormalParameterList(parameters);
6692 FunctionBody body = _parseFunctionBody( 7345 FunctionBody body = parseFunctionBody(
6693 externalKeyword != null || staticKeyword == null, 7346 externalKeyword != null || staticKeyword == null,
6694 ParserErrorCode.STATIC_SETTER_WITHOUT_BODY, 7347 ParserErrorCode.STATIC_SETTER_WITHOUT_BODY,
6695 false); 7348 false);
6696 if (externalKeyword != null && body is! EmptyFunctionBody) { 7349 if (externalKeyword != null && body is! EmptyFunctionBody) {
6697 _reportErrorForCurrentToken(ParserErrorCode.EXTERNAL_SETTER_WITH_BODY); 7350 _reportErrorForCurrentToken(ParserErrorCode.EXTERNAL_SETTER_WITH_BODY);
6698 } 7351 }
6699 return new MethodDeclaration( 7352 return new MethodDeclaration(
6700 commentAndMetadata.comment, 7353 commentAndMetadata.comment,
6701 commentAndMetadata.metadata, 7354 commentAndMetadata.metadata,
6702 externalKeyword, 7355 externalKeyword,
6703 staticKeyword, 7356 staticKeyword,
6704 returnType, 7357 returnType,
6705 propertyKeyword, 7358 propertyKeyword,
6706 null, 7359 null,
6707 name, 7360 name,
6708 null, 7361 null,
6709 parameters, 7362 parameters,
6710 body); 7363 body);
6711 } 7364 }
6712 7365
6713 /** 7366 /**
6714 * Parse a shift expression. Return the shift expression that was parsed.
6715 *
6716 * shiftExpression ::=
6717 * additiveExpression (shiftOperator additiveExpression)*
6718 * | 'super' (shiftOperator additiveExpression)+
6719 */
6720 Expression _parseShiftExpression() {
6721 Expression expression;
6722 if (_currentToken.keyword == Keyword.SUPER &&
6723 _currentToken.next.type.isShiftOperator) {
6724 expression = new SuperExpression(getAndAdvance());
6725 } else {
6726 expression = _parseAdditiveExpression();
6727 }
6728 while (_currentToken.type.isShiftOperator) {
6729 expression = new BinaryExpression(
6730 expression, getAndAdvance(), _parseAdditiveExpression());
6731 }
6732 return expression;
6733 }
6734
6735 /**
6736 * Parse a simple identifier. Return the simple identifier that was parsed. 7367 * Parse a simple identifier. Return the simple identifier that was parsed.
6737 * 7368 *
6738 * This method assumes that the current token matches an identifier. 7369 * This method assumes that the current token matches an identifier.
6739 * 7370 *
6740 * identifier ::= 7371 * identifier ::=
6741 * IDENTIFIER 7372 * IDENTIFIER
6742 */ 7373 */
6743 SimpleIdentifier _parseSimpleIdentifierUnchecked( 7374 SimpleIdentifier _parseSimpleIdentifierUnchecked(
6744 {bool isDeclaration: false}) { 7375 {bool isDeclaration: false}) {
6745 String lexeme = _currentToken.lexeme; 7376 String lexeme = _currentToken.lexeme;
(...skipping 11 matching lines...) Expand all
6757 * 7388 *
6758 * statements ::= 7389 * statements ::=
6759 * statement* 7390 * statement*
6760 */ 7391 */
6761 List<Statement> _parseStatementList() { 7392 List<Statement> _parseStatementList() {
6762 List<Statement> statements = <Statement>[]; 7393 List<Statement> statements = <Statement>[];
6763 Token statementStart = _currentToken; 7394 Token statementStart = _currentToken;
6764 TokenType type = _currentToken.type; 7395 TokenType type = _currentToken.type;
6765 while (type != TokenType.EOF && 7396 while (type != TokenType.EOF &&
6766 type != TokenType.CLOSE_CURLY_BRACKET && 7397 type != TokenType.CLOSE_CURLY_BRACKET &&
6767 !_isSwitchMember()) { 7398 !isSwitchMember()) {
6768 statements.add(parseStatement2()); 7399 statements.add(parseStatement2());
6769 if (identical(_currentToken, statementStart)) { 7400 if (identical(_currentToken, statementStart)) {
6770 _reportErrorForToken(ParserErrorCode.UNEXPECTED_TOKEN, _currentToken, 7401 _reportErrorForToken(ParserErrorCode.UNEXPECTED_TOKEN, _currentToken,
6771 [_currentToken.lexeme]); 7402 [_currentToken.lexeme]);
6772 _advance(); 7403 _advance();
6773 } 7404 }
6774 statementStart = _currentToken; 7405 statementStart = _currentToken;
6775 type = _currentToken.type; 7406 type = _currentToken.type;
6776 } 7407 }
6777 return statements; 7408 return statements;
6778 } 7409 }
6779 7410
6780 /** 7411 /**
6781 * Parse a string literal that contains interpolations. Return the string 7412 * Parse a string literal that contains interpolations. Return the string
6782 * literal that was parsed. 7413 * literal that was parsed.
6783 * 7414 *
6784 * This method assumes that the current token matches either 7415 * This method assumes that the current token matches either
6785 * [TokenType.STRING_INTERPOLATION_EXPRESSION] or 7416 * [TokenType.STRING_INTERPOLATION_EXPRESSION] or
6786 * [TokenType.STRING_INTERPOLATION_IDENTIFIER]. 7417 * [TokenType.STRING_INTERPOLATION_IDENTIFIER].
6787 */ 7418 */
6788 StringInterpolation _parseStringInterpolation(Token string) { 7419 StringInterpolation _parseStringInterpolation(Token string) {
6789 List<InterpolationElement> elements = <InterpolationElement>[ 7420 List<InterpolationElement> elements = <InterpolationElement>[
6790 new InterpolationString( 7421 new InterpolationString(
6791 string, _computeStringValue(string.lexeme, true, false)) 7422 string, computeStringValue(string.lexeme, true, false))
6792 ]; 7423 ];
6793 bool hasMore = true; 7424 bool hasMore = true;
6794 bool isExpression = _matches(TokenType.STRING_INTERPOLATION_EXPRESSION); 7425 bool isExpression = _matches(TokenType.STRING_INTERPOLATION_EXPRESSION);
6795 while (hasMore) { 7426 while (hasMore) {
6796 if (isExpression) { 7427 if (isExpression) {
6797 Token openToken = getAndAdvance(); 7428 Token openToken = getAndAdvance();
6798 bool wasInInitializer = _inInitializer; 7429 bool wasInInitializer = _inInitializer;
6799 _inInitializer = false; 7430 _inInitializer = false;
6800 try { 7431 try {
6801 Expression expression = parseExpression2(); 7432 Expression expression = parseExpression2();
(...skipping 12 matching lines...) Expand all
6814 expression = parseSimpleIdentifier(); 7445 expression = parseSimpleIdentifier();
6815 } 7446 }
6816 elements.add(new InterpolationExpression(openToken, expression, null)); 7447 elements.add(new InterpolationExpression(openToken, expression, null));
6817 } 7448 }
6818 if (_matches(TokenType.STRING)) { 7449 if (_matches(TokenType.STRING)) {
6819 string = getAndAdvance(); 7450 string = getAndAdvance();
6820 isExpression = _matches(TokenType.STRING_INTERPOLATION_EXPRESSION); 7451 isExpression = _matches(TokenType.STRING_INTERPOLATION_EXPRESSION);
6821 hasMore = 7452 hasMore =
6822 isExpression || _matches(TokenType.STRING_INTERPOLATION_IDENTIFIER); 7453 isExpression || _matches(TokenType.STRING_INTERPOLATION_IDENTIFIER);
6823 elements.add(new InterpolationString( 7454 elements.add(new InterpolationString(
6824 string, _computeStringValue(string.lexeme, false, !hasMore))); 7455 string, computeStringValue(string.lexeme, false, !hasMore)));
6825 } else { 7456 } else {
6826 hasMore = false; 7457 hasMore = false;
6827 } 7458 }
6828 } 7459 }
6829 return new StringInterpolation(elements); 7460 return new StringInterpolation(elements);
6830 } 7461 }
6831 7462
6832 /** 7463 /**
6833 * Parse a string literal. Return the string literal that was parsed. 7464 * Parse a string literal. Return the string literal that was parsed.
6834 * 7465 *
6835 * This method assumes that the current token matches `TokenType.STRING`. 7466 * This method assumes that the current token matches `TokenType.STRING`.
6836 * 7467 *
6837 * stringLiteral ::= 7468 * stringLiteral ::=
6838 * MULTI_LINE_STRING+ 7469 * MULTI_LINE_STRING+
6839 * | SINGLE_LINE_STRING+ 7470 * | SINGLE_LINE_STRING+
6840 */ 7471 */
6841 StringLiteral _parseStringLiteralUnchecked() { 7472 StringLiteral _parseStringLiteralUnchecked() {
6842 List<StringLiteral> strings = <StringLiteral>[]; 7473 List<StringLiteral> strings = <StringLiteral>[];
6843 do { 7474 do {
6844 Token string = getAndAdvance(); 7475 Token string = getAndAdvance();
6845 if (_matches(TokenType.STRING_INTERPOLATION_EXPRESSION) || 7476 if (_matches(TokenType.STRING_INTERPOLATION_EXPRESSION) ||
6846 _matches(TokenType.STRING_INTERPOLATION_IDENTIFIER)) { 7477 _matches(TokenType.STRING_INTERPOLATION_IDENTIFIER)) {
6847 strings.add(_parseStringInterpolation(string)); 7478 strings.add(_parseStringInterpolation(string));
6848 } else { 7479 } else {
6849 strings.add(new SimpleStringLiteral( 7480 strings.add(new SimpleStringLiteral(
6850 string, _computeStringValue(string.lexeme, true, true))); 7481 string, computeStringValue(string.lexeme, true, true)));
6851 } 7482 }
6852 } while (_matches(TokenType.STRING)); 7483 } while (_matches(TokenType.STRING));
6853 return strings.length == 1 ? strings[0] : new AdjacentStrings(strings); 7484 return strings.length == 1 ? strings[0] : new AdjacentStrings(strings);
6854 } 7485 }
6855 7486
6856 /** 7487 /**
6857 * Parse a super constructor invocation. Return the super constructor
6858 * invocation that was parsed.
6859 *
6860 * This method assumes that the current token matches [Keyword.SUPER].
6861 *
6862 * superConstructorInvocation ::=
6863 * 'super' ('.' identifier)? arguments
6864 */
6865 SuperConstructorInvocation _parseSuperConstructorInvocation() {
6866 Token keyword = getAndAdvance();
6867 Token period = null;
6868 SimpleIdentifier constructorName = null;
6869 if (_matches(TokenType.PERIOD)) {
6870 period = getAndAdvance();
6871 constructorName = parseSimpleIdentifier();
6872 }
6873 ArgumentList argumentList = _parseArgumentListChecked();
6874 return new SuperConstructorInvocation(
6875 keyword, period, constructorName, argumentList);
6876 }
6877
6878 /**
6879 * Parse a switch statement. Return the switch statement that was parsed.
6880 *
6881 * switchStatement ::=
6882 * 'switch' '(' expression ')' '{' switchCase* defaultCase? '}'
6883 *
6884 * switchCase ::=
6885 * label* ('case' expression ':') statements
6886 *
6887 * defaultCase ::=
6888 * label* 'default' ':' statements
6889 */
6890 SwitchStatement _parseSwitchStatement() {
6891 bool wasInSwitch = _inSwitch;
6892 _inSwitch = true;
6893 try {
6894 HashSet<String> definedLabels = new HashSet<String>();
6895 Token keyword = _expectKeyword(Keyword.SWITCH);
6896 Token leftParenthesis = _expect(TokenType.OPEN_PAREN);
6897 Expression expression = parseExpression2();
6898 Token rightParenthesis = _expect(TokenType.CLOSE_PAREN);
6899 Token leftBracket = _expect(TokenType.OPEN_CURLY_BRACKET);
6900 Token defaultKeyword = null;
6901 List<SwitchMember> members = <SwitchMember>[];
6902 TokenType type = _currentToken.type;
6903 while (type != TokenType.EOF && type != TokenType.CLOSE_CURLY_BRACKET) {
6904 List<Label> labels = <Label>[];
6905 while (
6906 _matchesIdentifier() && _tokenMatches(_peek(), TokenType.COLON)) {
6907 SimpleIdentifier identifier =
6908 _parseSimpleIdentifierUnchecked(isDeclaration: true);
6909 String label = identifier.token.lexeme;
6910 if (definedLabels.contains(label)) {
6911 _reportErrorForToken(
6912 ParserErrorCode.DUPLICATE_LABEL_IN_SWITCH_STATEMENT,
6913 identifier.token,
6914 [label]);
6915 } else {
6916 definedLabels.add(label);
6917 }
6918 Token colon = getAndAdvance();
6919 labels.add(new Label(identifier, colon));
6920 }
6921 Keyword keyword = _currentToken.keyword;
6922 if (keyword == Keyword.CASE) {
6923 Token caseKeyword = getAndAdvance();
6924 Expression caseExpression = parseExpression2();
6925 Token colon = _expect(TokenType.COLON);
6926 members.add(new SwitchCase(labels, caseKeyword, caseExpression, colon,
6927 _parseStatementList()));
6928 if (defaultKeyword != null) {
6929 _reportErrorForToken(
6930 ParserErrorCode.SWITCH_HAS_CASE_AFTER_DEFAULT_CASE,
6931 caseKeyword);
6932 }
6933 } else if (keyword == Keyword.DEFAULT) {
6934 if (defaultKeyword != null) {
6935 _reportErrorForToken(
6936 ParserErrorCode.SWITCH_HAS_MULTIPLE_DEFAULT_CASES, _peek());
6937 }
6938 defaultKeyword = getAndAdvance();
6939 Token colon = _expect(TokenType.COLON);
6940 members.add(new SwitchDefault(
6941 labels, defaultKeyword, colon, _parseStatementList()));
6942 } else {
6943 // We need to advance, otherwise we could end up in an infinite loop,
6944 // but this could be a lot smarter about recovering from the error.
6945 _reportErrorForCurrentToken(ParserErrorCode.EXPECTED_CASE_OR_DEFAULT);
6946 bool atEndOrNextMember() {
6947 TokenType type = _currentToken.type;
6948 if (type == TokenType.EOF ||
6949 type == TokenType.CLOSE_CURLY_BRACKET) {
6950 return true;
6951 }
6952 Keyword keyword = _currentToken.keyword;
6953 return keyword == Keyword.CASE || keyword == Keyword.DEFAULT;
6954 }
6955
6956 while (!atEndOrNextMember()) {
6957 _advance();
6958 }
6959 }
6960 type = _currentToken.type;
6961 }
6962 Token rightBracket = _expect(TokenType.CLOSE_CURLY_BRACKET);
6963 return new SwitchStatement(keyword, leftParenthesis, expression,
6964 rightParenthesis, leftBracket, members, rightBracket);
6965 } finally {
6966 _inSwitch = wasInSwitch;
6967 }
6968 }
6969
6970 /**
6971 * Parse a symbol literal. Return the symbol literal that was parsed.
6972 *
6973 * This method assumes that the current token matches [TokenType.HASH].
6974 *
6975 * symbolLiteral ::=
6976 * '#' identifier ('.' identifier)*
6977 */
6978 SymbolLiteral _parseSymbolLiteral() {
6979 Token poundSign = getAndAdvance();
6980 List<Token> components = <Token>[];
6981 if (_matchesIdentifier()) {
6982 components.add(getAndAdvance());
6983 while (_optional(TokenType.PERIOD)) {
6984 if (_matchesIdentifier()) {
6985 components.add(getAndAdvance());
6986 } else {
6987 _reportErrorForCurrentToken(ParserErrorCode.MISSING_IDENTIFIER);
6988 components.add(_createSyntheticToken(TokenType.IDENTIFIER));
6989 break;
6990 }
6991 }
6992 } else if (_currentToken.isOperator) {
6993 components.add(getAndAdvance());
6994 } else if (_matchesKeyword(Keyword.VOID)) {
6995 components.add(getAndAdvance());
6996 } else {
6997 _reportErrorForCurrentToken(ParserErrorCode.MISSING_IDENTIFIER);
6998 components.add(_createSyntheticToken(TokenType.IDENTIFIER));
6999 }
7000 return new SymbolLiteral(poundSign, components);
7001 }
7002
7003 /**
7004 * Parse a throw expression. Return the throw expression that was parsed.
7005 *
7006 * This method assumes that the current token matches [Keyword.THROW].
7007 *
7008 * throwExpression ::=
7009 * 'throw' expression
7010 */
7011 Expression _parseThrowExpression() {
7012 Token keyword = getAndAdvance();
7013 TokenType type = _currentToken.type;
7014 if (type == TokenType.SEMICOLON || type == TokenType.CLOSE_PAREN) {
7015 _reportErrorForToken(
7016 ParserErrorCode.MISSING_EXPRESSION_IN_THROW, _currentToken);
7017 return new ThrowExpression(keyword, _createSyntheticIdentifier());
7018 }
7019 Expression expression = parseExpression2();
7020 return new ThrowExpression(keyword, expression);
7021 }
7022
7023 /**
7024 * Parse a throw expression. Return the throw expression that was parsed.
7025 *
7026 * This method assumes that the current token matches [Keyword.THROW].
7027 *
7028 * throwExpressionWithoutCascade ::=
7029 * 'throw' expressionWithoutCascade
7030 */
7031 Expression _parseThrowExpressionWithoutCascade() {
7032 Token keyword = getAndAdvance();
7033 TokenType type = _currentToken.type;
7034 if (type == TokenType.SEMICOLON || type == TokenType.CLOSE_PAREN) {
7035 _reportErrorForToken(
7036 ParserErrorCode.MISSING_EXPRESSION_IN_THROW, _currentToken);
7037 return new ThrowExpression(keyword, _createSyntheticIdentifier());
7038 }
7039 Expression expression = parseExpressionWithoutCascade();
7040 return new ThrowExpression(keyword, expression);
7041 }
7042
7043 /**
7044 * Parse a try statement. Return the try statement that was parsed.
7045 *
7046 * This method assumes that the current token matches [Keyword.TRY].
7047 *
7048 * tryStatement ::=
7049 * 'try' block (onPart+ finallyPart? | finallyPart)
7050 *
7051 * onPart ::=
7052 * catchPart block
7053 * | 'on' type catchPart? block
7054 *
7055 * catchPart ::=
7056 * 'catch' '(' identifier (',' identifier)? ')'
7057 *
7058 * finallyPart ::=
7059 * 'finally' block
7060 */
7061 Statement _parseTryStatement() {
7062 Token tryKeyword = getAndAdvance();
7063 Block body = _parseBlockChecked();
7064 List<CatchClause> catchClauses = <CatchClause>[];
7065 Block finallyClause = null;
7066 while (_matchesString(_ON) || _matchesKeyword(Keyword.CATCH)) {
7067 Token onKeyword = null;
7068 TypeName exceptionType = null;
7069 if (_matchesString(_ON)) {
7070 onKeyword = getAndAdvance();
7071 exceptionType = parseTypeName(false);
7072 }
7073 Token catchKeyword = null;
7074 Token leftParenthesis = null;
7075 SimpleIdentifier exceptionParameter = null;
7076 Token comma = null;
7077 SimpleIdentifier stackTraceParameter = null;
7078 Token rightParenthesis = null;
7079 if (_matchesKeyword(Keyword.CATCH)) {
7080 catchKeyword = getAndAdvance();
7081 leftParenthesis = _expect(TokenType.OPEN_PAREN);
7082 exceptionParameter = parseSimpleIdentifier(isDeclaration: true);
7083 if (_matches(TokenType.COMMA)) {
7084 comma = getAndAdvance();
7085 stackTraceParameter = parseSimpleIdentifier(isDeclaration: true);
7086 }
7087 rightParenthesis = _expect(TokenType.CLOSE_PAREN);
7088 }
7089 Block catchBody = _parseBlockChecked();
7090 catchClauses.add(new CatchClause(
7091 onKeyword,
7092 exceptionType,
7093 catchKeyword,
7094 leftParenthesis,
7095 exceptionParameter,
7096 comma,
7097 stackTraceParameter,
7098 rightParenthesis,
7099 catchBody));
7100 }
7101 Token finallyKeyword = null;
7102 if (_matchesKeyword(Keyword.FINALLY)) {
7103 finallyKeyword = getAndAdvance();
7104 finallyClause = _parseBlockChecked();
7105 } else if (catchClauses.isEmpty) {
7106 _reportErrorForCurrentToken(ParserErrorCode.MISSING_CATCH_OR_FINALLY);
7107 }
7108 return new TryStatement(
7109 tryKeyword, body, catchClauses, finallyKeyword, finallyClause);
7110 }
7111
7112 /**
7113 * Parse a type alias. The [commentAndMetadata] is the metadata to be 7488 * Parse a type alias. The [commentAndMetadata] is the metadata to be
7114 * associated with the member. Return the type alias that was parsed. 7489 * associated with the member. Return the type alias that was parsed.
7115 * 7490 *
7116 * This method assumes that the current token matches [Keyword.TYPEDEF]. 7491 * This method assumes that the current token matches [Keyword.TYPEDEF].
7117 * 7492 *
7118 * typeAlias ::= 7493 * typeAlias ::=
7119 * 'typedef' typeAliasBody 7494 * 'typedef' typeAliasBody
7120 * 7495 *
7121 * typeAliasBody ::= 7496 * typeAliasBody ::=
7122 * classTypeAlias 7497 * classTypeAlias
(...skipping 12 matching lines...) Expand all
7135 * returnType? name 7510 * returnType? name
7136 */ 7511 */
7137 TypeAlias _parseTypeAlias(CommentAndMetadata commentAndMetadata) { 7512 TypeAlias _parseTypeAlias(CommentAndMetadata commentAndMetadata) {
7138 Token keyword = getAndAdvance(); 7513 Token keyword = getAndAdvance();
7139 if (_matchesIdentifier()) { 7514 if (_matchesIdentifier()) {
7140 Token next = _peek(); 7515 Token next = _peek();
7141 if (_tokenMatches(next, TokenType.LT)) { 7516 if (_tokenMatches(next, TokenType.LT)) {
7142 next = _skipTypeParameterList(next); 7517 next = _skipTypeParameterList(next);
7143 if (next != null && _tokenMatches(next, TokenType.EQ)) { 7518 if (next != null && _tokenMatches(next, TokenType.EQ)) {
7144 TypeAlias typeAlias = 7519 TypeAlias typeAlias =
7145 _parseClassTypeAlias(commentAndMetadata, null, keyword); 7520 parseClassTypeAlias(commentAndMetadata, null, keyword);
7146 _reportErrorForToken( 7521 _reportErrorForToken(
7147 ParserErrorCode.DEPRECATED_CLASS_TYPE_ALIAS, keyword); 7522 ParserErrorCode.DEPRECATED_CLASS_TYPE_ALIAS, keyword);
7148 return typeAlias; 7523 return typeAlias;
7149 } 7524 }
7150 } else if (_tokenMatches(next, TokenType.EQ)) { 7525 } else if (_tokenMatches(next, TokenType.EQ)) {
7151 TypeAlias typeAlias = 7526 TypeAlias typeAlias =
7152 _parseClassTypeAlias(commentAndMetadata, null, keyword); 7527 parseClassTypeAlias(commentAndMetadata, null, keyword);
7153 _reportErrorForToken( 7528 _reportErrorForToken(
7154 ParserErrorCode.DEPRECATED_CLASS_TYPE_ALIAS, keyword); 7529 ParserErrorCode.DEPRECATED_CLASS_TYPE_ALIAS, keyword);
7155 return typeAlias; 7530 return typeAlias;
7156 } 7531 }
7157 } 7532 }
7158 return _parseFunctionTypeAlias(commentAndMetadata, keyword); 7533 return _parseFunctionTypeAlias(commentAndMetadata, keyword);
7159 } 7534 }
7160 7535
7161 TypeName _parseTypeName(bool inExpression) { 7536 TypeName _parseTypeName(bool inExpression) {
7162 Identifier typeName; 7537 Identifier typeName;
7163 if (_matchesIdentifier()) { 7538 if (_matchesIdentifier()) {
7164 typeName = _parsePrefixedIdentifierUnchecked(); 7539 typeName = _parsePrefixedIdentifierUnchecked();
7165 } else if (_matchesKeyword(Keyword.VAR)) { 7540 } else if (_matchesKeyword(Keyword.VAR)) {
7166 _reportErrorForCurrentToken(ParserErrorCode.VAR_AS_TYPE_NAME); 7541 _reportErrorForCurrentToken(ParserErrorCode.VAR_AS_TYPE_NAME);
7167 typeName = new SimpleIdentifier(getAndAdvance()); 7542 typeName = new SimpleIdentifier(getAndAdvance());
7168 } else { 7543 } else {
7169 typeName = _createSyntheticIdentifier(); 7544 typeName = createSyntheticIdentifier();
7170 _reportErrorForCurrentToken(ParserErrorCode.EXPECTED_TYPE_NAME); 7545 _reportErrorForCurrentToken(ParserErrorCode.EXPECTED_TYPE_NAME);
7171 } 7546 }
7172 TypeArgumentList typeArguments = _parseOptionalTypeArguments(); 7547 TypeArgumentList typeArguments = _parseOptionalTypeArguments();
7173 Token question = null; 7548 Token question = null;
7174 if (enableNnbd && _matches(TokenType.QUESTION)) { 7549 if (enableNnbd && _matches(TokenType.QUESTION)) {
7175 if (!inExpression || !_isConditionalOperator()) { 7550 if (!inExpression || !_isConditionalOperator()) {
7176 question = getAndAdvance(); 7551 question = getAndAdvance();
7177 } 7552 }
7178 } 7553 }
7179 return new TypeName(typeName, typeArguments, question: question); 7554 return new TypeName(typeName, typeArguments, question: question);
(...skipping 12 matching lines...) Expand all
7192 TypeArgumentList typeArguments = _parseOptionalTypeArguments(); 7567 TypeArgumentList typeArguments = _parseOptionalTypeArguments();
7193 // If this is followed by a generic method type comment, allow the comment 7568 // If this is followed by a generic method type comment, allow the comment
7194 // type to replace the real type name. 7569 // type to replace the real type name.
7195 // TODO(jmesserly): this feels like a big hammer. Can we restrict it to 7570 // TODO(jmesserly): this feels like a big hammer. Can we restrict it to
7196 // only work inside generic methods? 7571 // only work inside generic methods?
7197 TypeName typeFromComment = _parseOptionalTypeNameComment(); 7572 TypeName typeFromComment = _parseOptionalTypeNameComment();
7198 return typeFromComment ?? new TypeName(typeName, typeArguments); 7573 return typeFromComment ?? new TypeName(typeName, typeArguments);
7199 } 7574 }
7200 7575
7201 /** 7576 /**
7202 * Parse a unary expression. Return the unary expression that was parsed.
7203 *
7204 * unaryExpression ::=
7205 * prefixOperator unaryExpression
7206 * | awaitExpression
7207 * | postfixExpression
7208 * | unaryOperator 'super'
7209 * | '-' 'super'
7210 * | incrementOperator assignableExpression
7211 */
7212 Expression _parseUnaryExpression() {
7213 TokenType type = _currentToken.type;
7214 if (type == TokenType.MINUS ||
7215 type == TokenType.BANG ||
7216 type == TokenType.TILDE) {
7217 Token operator = getAndAdvance();
7218 if (_matchesKeyword(Keyword.SUPER)) {
7219 TokenType nextType = _peek().type;
7220 if (nextType == TokenType.OPEN_SQUARE_BRACKET ||
7221 nextType == TokenType.PERIOD) {
7222 // "prefixOperator unaryExpression"
7223 // --> "prefixOperator postfixExpression"
7224 // --> "prefixOperator primary selector*"
7225 // --> "prefixOperator 'super' assignableSelector selector*"
7226 return new PrefixExpression(operator, _parseUnaryExpression());
7227 }
7228 return new PrefixExpression(
7229 operator, new SuperExpression(getAndAdvance()));
7230 }
7231 return new PrefixExpression(operator, _parseUnaryExpression());
7232 } else if (_currentToken.type.isIncrementOperator) {
7233 Token operator = getAndAdvance();
7234 if (_matchesKeyword(Keyword.SUPER)) {
7235 TokenType nextType = _peek().type;
7236 if (nextType == TokenType.OPEN_SQUARE_BRACKET ||
7237 nextType == TokenType.PERIOD) {
7238 // --> "prefixOperator 'super' assignableSelector selector*"
7239 return new PrefixExpression(operator, _parseUnaryExpression());
7240 }
7241 //
7242 // Even though it is not valid to use an incrementing operator
7243 // ('++' or '--') before 'super', we can (and therefore must) interpret
7244 // "--super" as semantically equivalent to "-(-super)". Unfortunately,
7245 // we cannot do the same for "++super" because "+super" is also not
7246 // valid.
7247 //
7248 if (type == TokenType.MINUS_MINUS) {
7249 Token firstOperator = _createToken(operator, TokenType.MINUS);
7250 Token secondOperator =
7251 new Token(TokenType.MINUS, operator.offset + 1);
7252 secondOperator.setNext(_currentToken);
7253 firstOperator.setNext(secondOperator);
7254 operator.previous.setNext(firstOperator);
7255 return new PrefixExpression(
7256 firstOperator,
7257 new PrefixExpression(
7258 secondOperator, new SuperExpression(getAndAdvance())));
7259 }
7260 // Invalid operator before 'super'
7261 _reportErrorForCurrentToken(
7262 ParserErrorCode.INVALID_OPERATOR_FOR_SUPER, [operator.lexeme]);
7263 return new PrefixExpression(
7264 operator, new SuperExpression(getAndAdvance()));
7265 }
7266 return new PrefixExpression(
7267 operator, _parseAssignableExpressionNotStartingWithSuper(false));
7268 } else if (type == TokenType.PLUS) {
7269 _reportErrorForCurrentToken(ParserErrorCode.MISSING_IDENTIFIER);
7270 return _createSyntheticIdentifier();
7271 } else if (_inAsync && _matchesString(_AWAIT)) {
7272 return _parseAwaitExpression();
7273 }
7274 return _parsePostfixExpression();
7275 }
7276
7277 /**
7278 * Parse a string literal representing a URI. Return the string literal that 7577 * Parse a string literal representing a URI. Return the string literal that
7279 * was parsed. 7578 * was parsed.
7280 */ 7579 */
7281 StringLiteral _parseUri() { 7580 StringLiteral _parseUri() {
7282 // TODO(brianwilkerson) Should this function also return true for valid 7581 // TODO(brianwilkerson) Should this function also return true for valid
7283 // top-level keywords? 7582 // top-level keywords?
7284 bool isKeywordAfterUri(Token token) => 7583 bool isKeywordAfterUri(Token token) =>
7285 token.lexeme == Keyword.AS.syntax || 7584 token.lexeme == Keyword.AS.syntax ||
7286 token.lexeme == _HIDE || 7585 token.lexeme == _HIDE ||
7287 token.lexeme == _SHOW; 7586 token.lexeme == _SHOW;
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
7328 _reportErrorForToken( 7627 _reportErrorForToken(
7329 ParserErrorCode.NON_STRING_LITERAL_AS_URI, newToken); 7628 ParserErrorCode.NON_STRING_LITERAL_AS_URI, newToken);
7330 _currentToken = endToken.next; 7629 _currentToken = endToken.next;
7331 return new SimpleStringLiteral(newToken, value); 7630 return new SimpleStringLiteral(newToken, value);
7332 } 7631 }
7333 } 7632 }
7334 return parseStringLiteral(); 7633 return parseStringLiteral();
7335 } 7634 }
7336 7635
7337 /** 7636 /**
7338 * Parse a variable declaration. Return the variable declaration that was
7339 * parsed.
7340 *
7341 * variableDeclaration ::=
7342 * identifier ('=' expression)?
7343 */
7344 VariableDeclaration _parseVariableDeclaration() {
7345 // TODO(paulberry): prior to the fix for bug 23204, we permitted
7346 // annotations before variable declarations (e.g. "String @deprecated s;").
7347 // Although such constructions are prohibited by the spec, we may want to
7348 // consider handling them anyway to allow for better parser recovery in the
7349 // event that the user erroneously tries to use them. However, as a
7350 // counterargument, this would likely degrade parser recovery in the event
7351 // of a construct like "class C { int @deprecated foo() {} }" (i.e. the
7352 // user is in the middle of inserting "int bar;" prior to
7353 // "@deprecated foo() {}").
7354 SimpleIdentifier name = parseSimpleIdentifier(isDeclaration: true);
7355 Token equals = null;
7356 Expression initializer = null;
7357 if (_matches(TokenType.EQ)) {
7358 equals = getAndAdvance();
7359 initializer = parseExpression2();
7360 }
7361 return new VariableDeclaration(name, equals, initializer);
7362 }
7363
7364 /**
7365 * Parse a variable declaration list. The [commentAndMetadata] is the metadata
7366 * to be associated with the variable declaration list. Return the variable
7367 * declaration list that was parsed.
7368 *
7369 * variableDeclarationList ::=
7370 * finalConstVarOrType variableDeclaration (',' variableDeclaration)*
7371 */
7372 VariableDeclarationList _parseVariableDeclarationListAfterMetadata(
7373 CommentAndMetadata commentAndMetadata) {
7374 FinalConstVarOrType holder = _parseFinalConstVarOrType(false);
7375 return _parseVariableDeclarationListAfterType(
7376 commentAndMetadata, holder.keyword, holder.type);
7377 }
7378
7379 /**
7380 * Parse a variable declaration list. The [commentAndMetadata] is the metadata
7381 * to be associated with the variable declaration list, or `null` if there is
7382 * no attempt at parsing the comment and metadata. The [keyword] is the token
7383 * representing the 'final', 'const' or 'var' keyword, or `null` if there is
7384 * no keyword. The [type] is the type of the variables in the list. Return the
7385 * variable declaration list that was parsed.
7386 *
7387 * variableDeclarationList ::=
7388 * finalConstVarOrType variableDeclaration (',' variableDeclaration)*
7389 */
7390 VariableDeclarationList _parseVariableDeclarationListAfterType(
7391 CommentAndMetadata commentAndMetadata, Token keyword, TypeName type) {
7392 if (type != null &&
7393 keyword != null &&
7394 _tokenMatchesKeyword(keyword, Keyword.VAR)) {
7395 _reportErrorForToken(ParserErrorCode.VAR_AND_TYPE, keyword);
7396 }
7397 List<VariableDeclaration> variables = <VariableDeclaration>[
7398 _parseVariableDeclaration()
7399 ];
7400 while (_optional(TokenType.COMMA)) {
7401 variables.add(_parseVariableDeclaration());
7402 }
7403 return new VariableDeclarationList(commentAndMetadata?.comment,
7404 commentAndMetadata?.metadata, keyword, type, variables);
7405 }
7406
7407 /**
7408 * Parse a variable declaration statement. The [commentAndMetadata] is the
7409 * metadata to be associated with the variable declaration statement, or
7410 * `null` if there is no attempt at parsing the comment and metadata. Return
7411 * the variable declaration statement that was parsed.
7412 *
7413 * variableDeclarationStatement ::=
7414 * variableDeclarationList ';'
7415 */
7416 VariableDeclarationStatement _parseVariableDeclarationStatementAfterMetadata(
7417 CommentAndMetadata commentAndMetadata) {
7418 // Token startToken = currentToken;
7419 VariableDeclarationList variableList =
7420 _parseVariableDeclarationListAfterMetadata(commentAndMetadata);
7421 // if (!matches(TokenType.SEMICOLON)) {
7422 // if (matches(startToken, Keyword.VAR) && isTypedIdentifier(startToken .getNext())) {
7423 // // TODO(brianwilkerson) This appears to be of the form "var type v ariable". We should do
7424 // // a better job of recovering in this case.
7425 // }
7426 // }
7427 Token semicolon = _expect(TokenType.SEMICOLON);
7428 return new VariableDeclarationStatement(variableList, semicolon);
7429 }
7430
7431 /**
7432 * Parse a variable declaration statement. The [commentAndMetadata] is the 7637 * Parse a variable declaration statement. The [commentAndMetadata] is the
7433 * metadata to be associated with the variable declaration statement, or 7638 * metadata to be associated with the variable declaration statement, or
7434 * `null` if there is no attempt at parsing the comment and metadata. The 7639 * `null` if there is no attempt at parsing the comment and metadata. The
7435 * [keyword] is the token representing the 'final', 'const' or 'var' keyword, 7640 * [keyword] is the token representing the 'final', 'const' or 'var' keyword,
7436 * or `null` if there is no keyword. The [type] is the type of the variables 7641 * or `null` if there is no keyword. The [type] is the type of the variables
7437 * in the list. Return the variable declaration statement that was parsed. 7642 * in the list. Return the variable declaration statement that was parsed.
7438 * 7643 *
7439 * variableDeclarationStatement ::= 7644 * variableDeclarationStatement ::=
7440 * variableDeclarationList ';' 7645 * variableDeclarationList ';'
7441 */ 7646 */
7442 VariableDeclarationStatement _parseVariableDeclarationStatementAfterType( 7647 VariableDeclarationStatement _parseVariableDeclarationStatementAfterType(
7443 CommentAndMetadata commentAndMetadata, Token keyword, TypeName type) { 7648 CommentAndMetadata commentAndMetadata, Token keyword, TypeName type) {
7444 VariableDeclarationList variableList = 7649 VariableDeclarationList variableList =
7445 _parseVariableDeclarationListAfterType( 7650 parseVariableDeclarationListAfterType(
7446 commentAndMetadata, keyword, type); 7651 commentAndMetadata, keyword, type);
7447 Token semicolon = _expect(TokenType.SEMICOLON); 7652 Token semicolon = _expect(TokenType.SEMICOLON);
7448 return new VariableDeclarationStatement(variableList, semicolon); 7653 return new VariableDeclarationStatement(variableList, semicolon);
7449 } 7654 }
7450 7655
7451 /** 7656 /**
7452 * Parse a while statement. Return the while statement that was parsed.
7453 *
7454 * This method assumes that the current token matches [Keyword.WHILE].
7455 *
7456 * whileStatement ::=
7457 * 'while' '(' expression ')' statement
7458 */
7459 Statement _parseWhileStatement() {
7460 bool wasInLoop = _inLoop;
7461 _inLoop = true;
7462 try {
7463 Token keyword = getAndAdvance();
7464 Token leftParenthesis = _expect(TokenType.OPEN_PAREN);
7465 Expression condition = parseExpression2();
7466 Token rightParenthesis = _expect(TokenType.CLOSE_PAREN);
7467 Statement body = parseStatement2();
7468 return new WhileStatement(
7469 keyword, leftParenthesis, condition, rightParenthesis, body);
7470 } finally {
7471 _inLoop = wasInLoop;
7472 }
7473 }
7474
7475 /**
7476 * Parse a yield statement. Return the yield statement that was parsed.
7477 *
7478 * This method assumes that the current token matches [Keyword.YIELD].
7479 *
7480 * yieldStatement ::=
7481 * 'yield' '*'? expression ';'
7482 */
7483 YieldStatement _parseYieldStatement() {
7484 Token yieldToken = getAndAdvance();
7485 Token star = null;
7486 if (_matches(TokenType.STAR)) {
7487 star = getAndAdvance();
7488 }
7489 Expression expression = parseExpression2();
7490 Token semicolon = _expect(TokenType.SEMICOLON);
7491 return new YieldStatement(yieldToken, star, expression, semicolon);
7492 }
7493
7494 /**
7495 * Return the token that is immediately after the current token. This is 7657 * Return the token that is immediately after the current token. This is
7496 * equivalent to [_peekAt](1). 7658 * equivalent to [_peekAt](1).
7497 */ 7659 */
7498 Token _peek() => _currentToken.next; 7660 Token _peek() => _currentToken.next;
7499 7661
7500 /** 7662 /**
7501 * Return the token that is the given [distance] after the current token, 7663 * Return the token that is the given [distance] after the current token,
7502 * where the distance is the number of tokens to look ahead. A distance of `0` 7664 * where the distance is the number of tokens to look ahead. A distance of `0`
7503 * is the current token, `1` is the next token, etc. 7665 * is the current token, `1` is the next token, etc.
7504 */ 7666 */
(...skipping 151 matching lines...) Expand 10 before | Expand all | Expand 10 after
7656 Token _skipFinalConstVarOrType(Token startToken) { 7818 Token _skipFinalConstVarOrType(Token startToken) {
7657 Keyword keyword = startToken.keyword; 7819 Keyword keyword = startToken.keyword;
7658 if (keyword == Keyword.FINAL || keyword == Keyword.CONST) { 7820 if (keyword == Keyword.FINAL || keyword == Keyword.CONST) {
7659 Token next = startToken.next; 7821 Token next = startToken.next;
7660 if (_tokenMatchesIdentifier(next)) { 7822 if (_tokenMatchesIdentifier(next)) {
7661 Token next2 = next.next; 7823 Token next2 = next.next;
7662 // "Type parameter" or "Type<" or "prefix.Type" 7824 // "Type parameter" or "Type<" or "prefix.Type"
7663 if (_tokenMatchesIdentifier(next2) || 7825 if (_tokenMatchesIdentifier(next2) ||
7664 _tokenMatches(next2, TokenType.LT) || 7826 _tokenMatches(next2, TokenType.LT) ||
7665 _tokenMatches(next2, TokenType.PERIOD)) { 7827 _tokenMatches(next2, TokenType.PERIOD)) {
7666 return _skipTypeName(next); 7828 return skipTypeName(next);
7667 } 7829 }
7668 // "parameter" 7830 // "parameter"
7669 return next; 7831 return next;
7670 } 7832 }
7671 } else if (keyword == Keyword.VAR) { 7833 } else if (keyword == Keyword.VAR) {
7672 return startToken.next; 7834 return startToken.next;
7673 } else if (_tokenMatchesIdentifier(startToken)) { 7835 } else if (_tokenMatchesIdentifier(startToken)) {
7674 Token next = startToken.next; 7836 Token next = startToken.next;
7675 if (_tokenMatchesIdentifier(next) || 7837 if (_tokenMatchesIdentifier(next) ||
7676 _tokenMatches(next, TokenType.LT) || 7838 _tokenMatches(next, TokenType.LT) ||
7677 _tokenMatchesKeyword(next, Keyword.THIS) || 7839 _tokenMatchesKeyword(next, Keyword.THIS) ||
7678 (_tokenMatches(next, TokenType.PERIOD) && 7840 (_tokenMatches(next, TokenType.PERIOD) &&
7679 _tokenMatchesIdentifier(next.next) && 7841 _tokenMatchesIdentifier(next.next) &&
7680 (_tokenMatchesIdentifier(next.next.next) || 7842 (_tokenMatchesIdentifier(next.next.next) ||
7681 _tokenMatches(next.next.next, TokenType.LT) || 7843 _tokenMatches(next.next.next, TokenType.LT) ||
7682 _tokenMatchesKeyword(next.next.next, Keyword.THIS)))) { 7844 _tokenMatchesKeyword(next.next.next, Keyword.THIS)))) {
7683 return _skipReturnType(startToken); 7845 return skipReturnType(startToken);
7684 } 7846 }
7685 } 7847 }
7686 return null; 7848 return null;
7687 } 7849 }
7688 7850
7689 /** 7851 /**
7690 * Parse a list of formal parameters, starting at the [startToken], without 7852 * Parse a list of formal parameters, starting at the [startToken], without
7691 * actually creating a formal parameter list or changing the current token. 7853 * actually creating a formal parameter list or changing the current token.
7692 * Return the token following the formal parameter list that was parsed, or 7854 * Return the token following the formal parameter list that was parsed, or
7693 * `null` if the given token is not the first token in a valid list of formal 7855 * `null` if the given token is not the first token in a valid list of formal
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after
7757 } 7919 }
7758 } 7920 }
7759 // 7921 //
7760 // Look to see whether the first parameter has a type or is a function typed 7922 // Look to see whether the first parameter has a type or is a function typed
7761 // parameter with a return type. 7923 // parameter with a return type.
7762 // 7924 //
7763 Token afterType = _skipFinalConstVarOrType(next); 7925 Token afterType = _skipFinalConstVarOrType(next);
7764 if (afterType == null) { 7926 if (afterType == null) {
7765 return null; 7927 return null;
7766 } 7928 }
7767 if (_skipSimpleIdentifier(afterType) == null) { 7929 if (skipSimpleIdentifier(afterType) == null) {
7768 return null; 7930 return null;
7769 } 7931 }
7770 return _skipPastMatchingToken(startToken); 7932 return _skipPastMatchingToken(startToken);
7771 } 7933 }
7772 7934
7773 /** 7935 /**
7774 * If the [startToken] is a begin token with an associated end token, then 7936 * If the [startToken] is a begin token with an associated end token, then
7775 * return the token following the end token. Otherwise, return `null`. 7937 * return the token following the end token. Otherwise, return `null`.
7776 */ 7938 */
7777 Token _skipPastMatchingToken(Token startToken) { 7939 Token _skipPastMatchingToken(Token startToken) {
7778 if (startToken is! BeginToken) { 7940 if (startToken is! BeginToken) {
7779 return null; 7941 return null;
7780 } 7942 }
7781 Token closeParen = (startToken as BeginToken).endToken; 7943 Token closeParen = (startToken as BeginToken).endToken;
7782 if (closeParen == null) { 7944 if (closeParen == null) {
7783 return null; 7945 return null;
7784 } 7946 }
7785 return closeParen.next; 7947 return closeParen.next;
7786 } 7948 }
7787 7949
7788 /** 7950 /**
7789 * Parse a prefixed identifier, starting at the [startToken], without actually
7790 * creating a prefixed identifier or changing the current token. Return the
7791 * token following the prefixed identifier that was parsed, or `null` if the
7792 * given token is not the first token in a valid prefixed identifier.
7793 *
7794 * This method must be kept in sync with [parsePrefixedIdentifier].
7795 *
7796 * prefixedIdentifier ::=
7797 * identifier ('.' identifier)?
7798 */
7799 Token _skipPrefixedIdentifier(Token startToken) {
7800 Token token = _skipSimpleIdentifier(startToken);
7801 if (token == null) {
7802 return null;
7803 } else if (!_tokenMatches(token, TokenType.PERIOD)) {
7804 return token;
7805 }
7806 token = token.next;
7807 Token nextToken = _skipSimpleIdentifier(token);
7808 if (nextToken != null) {
7809 return nextToken;
7810 } else if (_tokenMatches(token, TokenType.CLOSE_PAREN) ||
7811 _tokenMatches(token, TokenType.COMMA)) {
7812 // If the `id.` is followed by something that cannot produce a valid
7813 // structure then assume this is a prefixed identifier but missing the
7814 // trailing identifier
7815 return token;
7816 }
7817 return null;
7818 }
7819
7820 /**
7821 * Parse a return type, starting at the [startToken], without actually
7822 * creating a return type or changing the current token. Return the token
7823 * following the return type that was parsed, or `null` if the given token is
7824 * not the first token in a valid return type.
7825 *
7826 * This method must be kept in sync with [parseReturnType].
7827 *
7828 * returnType ::=
7829 * 'void'
7830 * | type
7831 */
7832 Token _skipReturnType(Token startToken) {
7833 if (_tokenMatchesKeyword(startToken, Keyword.VOID)) {
7834 return startToken.next;
7835 } else {
7836 return _skipTypeName(startToken);
7837 }
7838 }
7839
7840 /**
7841 * Parse a simple identifier, starting at the [startToken], without actually
7842 * creating a simple identifier or changing the current token. Return the
7843 * token following the simple identifier that was parsed, or `null` if the
7844 * given token is not the first token in a valid simple identifier.
7845 *
7846 * This method must be kept in sync with [parseSimpleIdentifier].
7847 *
7848 * identifier ::=
7849 * IDENTIFIER
7850 */
7851 Token _skipSimpleIdentifier(Token startToken) {
7852 if (_tokenMatches(startToken, TokenType.IDENTIFIER) ||
7853 _tokenMatchesPseudoKeyword(startToken)) {
7854 return startToken.next;
7855 }
7856 return null;
7857 }
7858
7859 /**
7860 * Parse a string literal that contains interpolations, starting at the 7951 * Parse a string literal that contains interpolations, starting at the
7861 * [startToken], without actually creating a string literal or changing the 7952 * [startToken], without actually creating a string literal or changing the
7862 * current token. Return the token following the string literal that was 7953 * current token. Return the token following the string literal that was
7863 * parsed, or `null` if the given token is not the first token in a valid 7954 * parsed, or `null` if the given token is not the first token in a valid
7864 * string literal. 7955 * string literal.
7865 * 7956 *
7866 * This method must be kept in sync with [parseStringInterpolation]. 7957 * This method must be kept in sync with [parseStringInterpolation].
7867 */ 7958 */
7868 Token _skipStringInterpolation(Token startToken) { 7959 Token _skipStringInterpolation(Token startToken) {
7869 Token token = startToken; 7960 Token token = startToken;
(...skipping 12 matching lines...) Expand all
7882 while (bracketNestingLevel > 0) { 7973 while (bracketNestingLevel > 0) {
7883 if (type == TokenType.EOF) { 7974 if (type == TokenType.EOF) {
7884 return null; 7975 return null;
7885 } else if (type == TokenType.OPEN_CURLY_BRACKET) { 7976 } else if (type == TokenType.OPEN_CURLY_BRACKET) {
7886 bracketNestingLevel++; 7977 bracketNestingLevel++;
7887 token = token.next; 7978 token = token.next;
7888 } else if (type == TokenType.CLOSE_CURLY_BRACKET) { 7979 } else if (type == TokenType.CLOSE_CURLY_BRACKET) {
7889 bracketNestingLevel--; 7980 bracketNestingLevel--;
7890 token = token.next; 7981 token = token.next;
7891 } else if (type == TokenType.STRING) { 7982 } else if (type == TokenType.STRING) {
7892 token = _skipStringLiteral(token); 7983 token = skipStringLiteral(token);
7893 if (token == null) { 7984 if (token == null) {
7894 return null; 7985 return null;
7895 } 7986 }
7896 } else { 7987 } else {
7897 token = token.next; 7988 token = token.next;
7898 } 7989 }
7899 type = token.type; 7990 type = token.type;
7900 } 7991 }
7901 token = token.next; 7992 token = token.next;
7902 type = token.type; 7993 type = token.type;
7903 } else { 7994 } else {
7904 token = token.next; 7995 token = token.next;
7905 if (token.type != TokenType.IDENTIFIER) { 7996 if (token.type != TokenType.IDENTIFIER) {
7906 return null; 7997 return null;
7907 } 7998 }
7908 token = token.next; 7999 token = token.next;
7909 } 8000 }
7910 type = token.type; 8001 type = token.type;
7911 if (type == TokenType.STRING) { 8002 if (type == TokenType.STRING) {
7912 token = token.next; 8003 token = token.next;
7913 type = token.type; 8004 type = token.type;
7914 } 8005 }
7915 } 8006 }
7916 return token; 8007 return token;
7917 } 8008 }
7918 8009
7919 /** 8010 /**
7920 * Parse a string literal, starting at the [startToken], without actually
7921 * creating a string literal or changing the current token. Return the token
7922 * following the string literal that was parsed, or `null` if the given token
7923 * is not the first token in a valid string literal.
7924 *
7925 * This method must be kept in sync with [parseStringLiteral].
7926 *
7927 * stringLiteral ::=
7928 * MULTI_LINE_STRING+
7929 * | SINGLE_LINE_STRING+
7930 */
7931 Token _skipStringLiteral(Token startToken) {
7932 Token token = startToken;
7933 while (token != null && _tokenMatches(token, TokenType.STRING)) {
7934 token = token.next;
7935 TokenType type = token.type;
7936 if (type == TokenType.STRING_INTERPOLATION_EXPRESSION ||
7937 type == TokenType.STRING_INTERPOLATION_IDENTIFIER) {
7938 token = _skipStringInterpolation(token);
7939 }
7940 }
7941 if (identical(token, startToken)) {
7942 return null;
7943 }
7944 return token;
7945 }
7946
7947 /**
7948 * Parse a list of type arguments, starting at the [startToken], without
7949 * actually creating a type argument list or changing the current token.
7950 * Return the token following the type argument list that was parsed, or
7951 * `null` if the given token is not the first token in a valid type argument
7952 * list.
7953 *
7954 * This method must be kept in sync with [parseTypeArgumentList].
7955 *
7956 * typeArguments ::=
7957 * '<' typeList '>'
7958 *
7959 * typeList ::=
7960 * type (',' type)*
7961 */
7962 Token _skipTypeArgumentList(Token startToken) {
7963 Token token = startToken;
7964 if (!_tokenMatches(token, TokenType.LT) &&
7965 !_injectGenericCommentTypeList()) {
7966 return null;
7967 }
7968 token = _skipTypeName(token.next);
7969 if (token == null) {
7970 // If the start token '<' is followed by '>'
7971 // then assume this should be type argument list but is missing a type
7972 token = startToken.next;
7973 if (_tokenMatches(token, TokenType.GT)) {
7974 return token.next;
7975 }
7976 return null;
7977 }
7978 while (_tokenMatches(token, TokenType.COMMA)) {
7979 token = _skipTypeName(token.next);
7980 if (token == null) {
7981 return null;
7982 }
7983 }
7984 if (token.type == TokenType.GT) {
7985 return token.next;
7986 } else if (token.type == TokenType.GT_GT) {
7987 Token second = new Token(TokenType.GT, token.offset + 1);
7988 second.setNextWithoutSettingPrevious(token.next);
7989 return second;
7990 }
7991 return null;
7992 }
7993
7994 /**
7995 * Parse a type name, starting at the [startToken], without actually creating
7996 * a type name or changing the current token. Return the token following the
7997 * type name that was parsed, or `null` if the given token is not the first
7998 * token in a valid type name.
7999 *
8000 * This method must be kept in sync with [parseTypeName].
8001 *
8002 * type ::=
8003 * qualified typeArguments?
8004 */
8005 Token _skipTypeName(Token startToken) {
8006 Token token = _skipPrefixedIdentifier(startToken);
8007 if (token == null) {
8008 return null;
8009 }
8010 if (_tokenMatches(token, TokenType.LT)) {
8011 token = _skipTypeArgumentList(token);
8012 }
8013 return token;
8014 }
8015
8016 /**
8017 * Parse a list of type parameters, starting at the [startToken], without 8011 * Parse a list of type parameters, starting at the [startToken], without
8018 * actually creating a type parameter list or changing the current token. 8012 * actually creating a type parameter list or changing the current token.
8019 * Return the token following the type parameter list that was parsed, or 8013 * Return the token following the type parameter list that was parsed, or
8020 * `null` if the given token is not the first token in a valid type parameter 8014 * `null` if the given token is not the first token in a valid type parameter
8021 * list. 8015 * list.
8022 * 8016 *
8023 * This method must be kept in sync with [parseTypeParameterList]. 8017 * This method must be kept in sync with [parseTypeParameterList].
8024 * 8018 *
8025 * typeParameterList ::= 8019 * typeParameterList ::=
8026 * '<' typeParameter (',' typeParameter)* '>' 8020 * '<' typeParameter (',' typeParameter)* '>'
(...skipping 1163 matching lines...) Expand 10 before | Expand all | Expand 10 after
9190 */ 9184 */
9191 const ParserErrorCode(String name, String message, [String correction]) 9185 const ParserErrorCode(String name, String message, [String correction])
9192 : super(name, message, correction); 9186 : super(name, message, correction);
9193 9187
9194 @override 9188 @override
9195 ErrorSeverity get errorSeverity => ErrorSeverity.ERROR; 9189 ErrorSeverity get errorSeverity => ErrorSeverity.ERROR;
9196 9190
9197 @override 9191 @override
9198 ErrorType get type => ErrorType.SYNTACTIC_ERROR; 9192 ErrorType get type => ErrorType.SYNTACTIC_ERROR;
9199 } 9193 }
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