OLD | NEW |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 } |
OLD | NEW |