OLD | NEW |
(Empty) | |
| 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 |
| 3 // BSD-style license that can be found in the LICENSE file. |
| 4 |
| 5 library engine.parser; |
| 6 |
| 7 import 'dart:collection'; |
| 8 import "dart:math" as math; |
| 9 |
| 10 import 'ast.dart'; |
| 11 import 'engine.dart' show AnalysisEngine, AnalysisOptionsImpl; |
| 12 import 'error.dart'; |
| 13 import 'java_core.dart'; |
| 14 import 'java_engine.dart'; |
| 15 import 'scanner.dart'; |
| 16 import 'source.dart'; |
| 17 import 'utilities_collection.dart' show TokenMap; |
| 18 import 'utilities_dart.dart'; |
| 19 |
| 20 Map<String, MethodTrampoline> methodTable_Parser = <String, MethodTrampoline>{ |
| 21 'parseCompilationUnit_1': new MethodTrampoline( |
| 22 1, (Parser target, arg0) => target.parseCompilationUnit(arg0)), |
| 23 'parseDirectives_1': new MethodTrampoline( |
| 24 1, (Parser target, arg0) => target.parseDirectives(arg0)), |
| 25 'parseExpression_1': new MethodTrampoline( |
| 26 1, (Parser target, arg0) => target.parseExpression(arg0)), |
| 27 'parseStatement_1': new MethodTrampoline( |
| 28 1, (Parser target, arg0) => target.parseStatement(arg0)), |
| 29 'parseStatements_1': new MethodTrampoline( |
| 30 1, (Parser target, arg0) => target.parseStatements(arg0)), |
| 31 'parseAnnotation_0': |
| 32 new MethodTrampoline(0, (Parser target) => target.parseAnnotation()), |
| 33 'parseArgument_0': |
| 34 new MethodTrampoline(0, (Parser target) => target.parseArgument()), |
| 35 'parseArgumentList_0': |
| 36 new MethodTrampoline(0, (Parser target) => target.parseArgumentList()), |
| 37 'parseBitwiseOrExpression_0': new MethodTrampoline( |
| 38 0, (Parser target) => target.parseBitwiseOrExpression()), |
| 39 'parseBlock_0': |
| 40 new MethodTrampoline(0, (Parser target) => target.parseBlock()), |
| 41 'parseClassMember_1': new MethodTrampoline( |
| 42 1, (Parser target, arg0) => target.parseClassMember(arg0)), |
| 43 'parseCompilationUnit_0': new MethodTrampoline( |
| 44 0, (Parser target) => target.parseCompilationUnit2()), |
| 45 'parseConditionalExpression_0': new MethodTrampoline( |
| 46 0, (Parser target) => target.parseConditionalExpression()), |
| 47 'parseConstructorName_0': |
| 48 new MethodTrampoline(0, (Parser target) => target.parseConstructorName()), |
| 49 'parseExpression_0': |
| 50 new MethodTrampoline(0, (Parser target) => target.parseExpression2()), |
| 51 'parseExpressionWithoutCascade_0': new MethodTrampoline( |
| 52 0, (Parser target) => target.parseExpressionWithoutCascade()), |
| 53 'parseExtendsClause_0': |
| 54 new MethodTrampoline(0, (Parser target) => target.parseExtendsClause()), |
| 55 'parseFormalParameterList_0': new MethodTrampoline( |
| 56 0, (Parser target) => target.parseFormalParameterList()), |
| 57 'parseFunctionExpression_0': new MethodTrampoline( |
| 58 0, (Parser target) => target.parseFunctionExpression()), |
| 59 'parseImplementsClause_0': new MethodTrampoline( |
| 60 0, (Parser target) => target.parseImplementsClause()), |
| 61 'parseLabel_0': |
| 62 new MethodTrampoline(0, (Parser target) => target.parseLabel()), |
| 63 'parseLibraryIdentifier_0': new MethodTrampoline( |
| 64 0, (Parser target) => target.parseLibraryIdentifier()), |
| 65 'parseLogicalOrExpression_0': new MethodTrampoline( |
| 66 0, (Parser target) => target.parseLogicalOrExpression()), |
| 67 'parseMapLiteralEntry_0': |
| 68 new MethodTrampoline(0, (Parser target) => target.parseMapLiteralEntry()), |
| 69 'parseNormalFormalParameter_0': new MethodTrampoline( |
| 70 0, (Parser target) => target.parseNormalFormalParameter()), |
| 71 'parsePrefixedIdentifier_0': new MethodTrampoline( |
| 72 0, (Parser target) => target.parsePrefixedIdentifier()), |
| 73 'parseReturnType_0': |
| 74 new MethodTrampoline(0, (Parser target) => target.parseReturnType()), |
| 75 'parseSimpleIdentifier_0': new MethodTrampoline( |
| 76 0, (Parser target) => target.parseSimpleIdentifier()), |
| 77 'parseStatement_0': |
| 78 new MethodTrampoline(0, (Parser target) => target.parseStatement2()), |
| 79 'parseStringLiteral_0': |
| 80 new MethodTrampoline(0, (Parser target) => target.parseStringLiteral()), |
| 81 'parseTypeArgumentList_0': new MethodTrampoline( |
| 82 0, (Parser target) => target.parseTypeArgumentList()), |
| 83 'parseTypeName_0': |
| 84 new MethodTrampoline(0, (Parser target) => target.parseTypeName()), |
| 85 'parseTypeParameter_0': |
| 86 new MethodTrampoline(0, (Parser target) => target.parseTypeParameter()), |
| 87 'parseTypeParameterList_0': new MethodTrampoline( |
| 88 0, (Parser target) => target.parseTypeParameterList()), |
| 89 'parseWithClause_0': |
| 90 new MethodTrampoline(0, (Parser target) => target.parseWithClause()), |
| 91 'advance_0': new MethodTrampoline(0, (Parser target) => target._advance()), |
| 92 'appendScalarValue_5': new MethodTrampoline(5, (Parser target, arg0, arg1, |
| 93 arg2, arg3, |
| 94 arg4) => target._appendScalarValue(arg0, arg1, arg2, arg3, arg4)), |
| 95 'computeStringValue_3': new MethodTrampoline(3, (Parser target, arg0, arg1, |
| 96 arg2) => target._computeStringValue(arg0, arg1, arg2)), |
| 97 'convertToFunctionDeclaration_1': new MethodTrampoline( |
| 98 1, (Parser target, arg0) => target._convertToFunctionDeclaration(arg0)), |
| 99 'couldBeStartOfCompilationUnitMember_0': new MethodTrampoline( |
| 100 0, (Parser target) => target._couldBeStartOfCompilationUnitMember()), |
| 101 'createSyntheticIdentifier_0': new MethodTrampoline( |
| 102 0, (Parser target) => target._createSyntheticIdentifier()), |
| 103 'createSyntheticKeyword_1': new MethodTrampoline( |
| 104 1, (Parser target, arg0) => target._createSyntheticKeyword(arg0)), |
| 105 'createSyntheticStringLiteral_0': new MethodTrampoline( |
| 106 0, (Parser target) => target._createSyntheticStringLiteral()), |
| 107 'createSyntheticToken_1': new MethodTrampoline( |
| 108 1, (Parser target, arg0) => target._createSyntheticToken(arg0)), |
| 109 'ensureAssignable_1': new MethodTrampoline( |
| 110 1, (Parser target, arg0) => target._ensureAssignable(arg0)), |
| 111 'expect_1': |
| 112 new MethodTrampoline(1, (Parser target, arg0) => target._expect(arg0)), |
| 113 'expectGt_0': new MethodTrampoline(0, (Parser target) => target._expectGt()), |
| 114 'expectKeyword_1': new MethodTrampoline( |
| 115 1, (Parser target, arg0) => target._expectKeyword(arg0)), |
| 116 'expectSemicolon_0': |
| 117 new MethodTrampoline(0, (Parser target) => target._expectSemicolon()), |
| 118 'findRange_2': new MethodTrampoline( |
| 119 2, (Parser target, arg0, arg1) => target._findRange(arg0, arg1)), |
| 120 'getCodeBlockRanges_1': new MethodTrampoline( |
| 121 1, (Parser target, arg0) => target._getCodeBlockRanges(arg0)), |
| 122 'getEndToken_1': new MethodTrampoline( |
| 123 1, (Parser target, arg0) => target._getEndToken(arg0)), |
| 124 'injectToken_1': new MethodTrampoline( |
| 125 1, (Parser target, arg0) => target._injectToken(arg0)), |
| 126 'isFunctionDeclaration_0': new MethodTrampoline( |
| 127 0, (Parser target) => target._isFunctionDeclaration()), |
| 128 'isFunctionExpression_1': new MethodTrampoline( |
| 129 1, (Parser target, arg0) => target._isFunctionExpression(arg0)), |
| 130 'isHexDigit_1': new MethodTrampoline( |
| 131 1, (Parser target, arg0) => target._isHexDigit(arg0)), |
| 132 'isInitializedVariableDeclaration_0': new MethodTrampoline( |
| 133 0, (Parser target) => target._isInitializedVariableDeclaration()), |
| 134 'isLinkText_2': new MethodTrampoline( |
| 135 2, (Parser target, arg0, arg1) => target._isLinkText(arg0, arg1)), |
| 136 'isOperator_1': new MethodTrampoline( |
| 137 1, (Parser target, arg0) => target._isOperator(arg0)), |
| 138 'isSwitchMember_0': |
| 139 new MethodTrampoline(0, (Parser target) => target._isSwitchMember()), |
| 140 'isTypedIdentifier_1': new MethodTrampoline( |
| 141 1, (Parser target, arg0) => target._isTypedIdentifier(arg0)), |
| 142 'lockErrorListener_0': |
| 143 new MethodTrampoline(0, (Parser target) => target._lockErrorListener()), |
| 144 'matches_1': |
| 145 new MethodTrampoline(1, (Parser target, arg0) => target._matches(arg0)), |
| 146 'matchesGt_0': |
| 147 new MethodTrampoline(0, (Parser target) => target._matchesGt()), |
| 148 'matchesIdentifier_0': |
| 149 new MethodTrampoline(0, (Parser target) => target._matchesIdentifier()), |
| 150 'matchesKeyword_1': new MethodTrampoline( |
| 151 1, (Parser target, arg0) => target._matchesKeyword(arg0)), |
| 152 'matchesString_1': new MethodTrampoline( |
| 153 1, (Parser target, arg0) => target._matchesString(arg0)), |
| 154 'optional_1': |
| 155 new MethodTrampoline(1, (Parser target, arg0) => target._optional(arg0)), |
| 156 'parseAdditiveExpression_0': new MethodTrampoline( |
| 157 0, (Parser target) => target._parseAdditiveExpression()), |
| 158 'parseAssertStatement_0': new MethodTrampoline( |
| 159 0, (Parser target) => target._parseAssertStatement()), |
| 160 'parseAssignableExpression_1': new MethodTrampoline( |
| 161 1, (Parser target, arg0) => target._parseAssignableExpression(arg0)), |
| 162 'parseAssignableSelector_2': new MethodTrampoline(2, (Parser target, arg0, |
| 163 arg1) => target._parseAssignableSelector(arg0, arg1)), |
| 164 'parseAwaitExpression_0': new MethodTrampoline( |
| 165 0, (Parser target) => target._parseAwaitExpression()), |
| 166 'parseBitwiseAndExpression_0': new MethodTrampoline( |
| 167 0, (Parser target) => target._parseBitwiseAndExpression()), |
| 168 'parseBitwiseXorExpression_0': new MethodTrampoline( |
| 169 0, (Parser target) => target._parseBitwiseXorExpression()), |
| 170 'parseBreakStatement_0': |
| 171 new MethodTrampoline(0, (Parser target) => target._parseBreakStatement()), |
| 172 'parseCascadeSection_0': |
| 173 new MethodTrampoline(0, (Parser target) => target._parseCascadeSection()), |
| 174 'parseClassDeclaration_2': new MethodTrampoline(2, |
| 175 (Parser target, arg0, arg1) => target._parseClassDeclaration(arg0, arg1)), |
| 176 'parseClassMembers_2': new MethodTrampoline( |
| 177 2, (Parser target, arg0, arg1) => target._parseClassMembers(arg0, arg1)), |
| 178 'parseClassTypeAlias_3': new MethodTrampoline(3, (Parser target, arg0, arg1, |
| 179 arg2) => target._parseClassTypeAlias(arg0, arg1, arg2)), |
| 180 'parseCombinator_0': |
| 181 new MethodTrampoline(0, (Parser target) => target.parseCombinator()), |
| 182 'parseCombinators_0': |
| 183 new MethodTrampoline(0, (Parser target) => target._parseCombinators()), |
| 184 'parseCommentAndMetadata_0': new MethodTrampoline( |
| 185 0, (Parser target) => target._parseCommentAndMetadata()), |
| 186 'parseCommentReference_2': new MethodTrampoline(2, |
| 187 (Parser target, arg0, arg1) => target._parseCommentReference(arg0, arg1)), |
| 188 'parseCommentReferences_1': new MethodTrampoline( |
| 189 1, (Parser target, arg0) => target._parseCommentReferences(arg0)), |
| 190 'parseCompilationUnitMember_1': new MethodTrampoline( |
| 191 1, (Parser target, arg0) => target._parseCompilationUnitMember(arg0)), |
| 192 'parseConstExpression_0': new MethodTrampoline( |
| 193 0, (Parser target) => target._parseConstExpression()), |
| 194 'parseConstructor_8': new MethodTrampoline(8, (Parser target, arg0, arg1, |
| 195 arg2, arg3, arg4, arg5, arg6, arg7) => |
| 196 target._parseConstructor(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7)), |
| 197 'parseConstructorFieldInitializer_0': new MethodTrampoline( |
| 198 0, (Parser target) => target._parseConstructorFieldInitializer()), |
| 199 'parseContinueStatement_0': new MethodTrampoline( |
| 200 0, (Parser target) => target._parseContinueStatement()), |
| 201 'parseDirective_1': new MethodTrampoline( |
| 202 1, (Parser target, arg0) => target._parseDirective(arg0)), |
| 203 'parseDirectives_0': |
| 204 new MethodTrampoline(0, (Parser target) => target._parseDirectives()), |
| 205 'parseDocumentationComment_0': new MethodTrampoline( |
| 206 0, (Parser target) => target._parseDocumentationComment()), |
| 207 'parseDoStatement_0': |
| 208 new MethodTrampoline(0, (Parser target) => target._parseDoStatement()), |
| 209 'parseEmptyStatement_0': |
| 210 new MethodTrampoline(0, (Parser target) => target._parseEmptyStatement()), |
| 211 'parseEnumConstantDeclaration_0': new MethodTrampoline( |
| 212 0, (Parser target) => target._parseEnumConstantDeclaration()), |
| 213 'parseEnumDeclaration_1': new MethodTrampoline( |
| 214 1, (Parser target, arg0) => target._parseEnumDeclaration(arg0)), |
| 215 'parseEqualityExpression_0': new MethodTrampoline( |
| 216 0, (Parser target) => target._parseEqualityExpression()), |
| 217 'parseExportDirective_1': new MethodTrampoline( |
| 218 1, (Parser target, arg0) => target._parseExportDirective(arg0)), |
| 219 'parseExpressionList_0': |
| 220 new MethodTrampoline(0, (Parser target) => target._parseExpressionList()), |
| 221 'parseFinalConstVarOrType_1': new MethodTrampoline( |
| 222 1, (Parser target, arg0) => target._parseFinalConstVarOrType(arg0)), |
| 223 'parseFormalParameter_1': new MethodTrampoline( |
| 224 1, (Parser target, arg0) => target._parseFormalParameter(arg0)), |
| 225 'parseForStatement_0': |
| 226 new MethodTrampoline(0, (Parser target) => target._parseForStatement()), |
| 227 'parseFunctionBody_3': new MethodTrampoline(3, (Parser target, arg0, arg1, |
| 228 arg2) => target._parseFunctionBody(arg0, arg1, arg2)), |
| 229 'parseFunctionDeclaration_3': new MethodTrampoline(3, (Parser target, arg0, |
| 230 arg1, arg2) => target._parseFunctionDeclaration(arg0, arg1, arg2)), |
| 231 'parseFunctionDeclarationStatement_0': new MethodTrampoline( |
| 232 0, (Parser target) => target._parseFunctionDeclarationStatement()), |
| 233 'parseFunctionDeclarationStatementAfterReturnType_2': new MethodTrampoline(2, |
| 234 (Parser target, arg0, arg1) => |
| 235 target._parseFunctionDeclarationStatementAfterReturnType(arg0, arg1)), |
| 236 'parseFunctionTypeAlias_2': new MethodTrampoline(2, (Parser target, arg0, |
| 237 arg1) => target._parseFunctionTypeAlias(arg0, arg1)), |
| 238 'parseGetter_4': new MethodTrampoline(4, (Parser target, arg0, arg1, arg2, |
| 239 arg3) => target._parseGetter(arg0, arg1, arg2, arg3)), |
| 240 'parseIdentifierList_0': |
| 241 new MethodTrampoline(0, (Parser target) => target._parseIdentifierList()), |
| 242 'parseIfStatement_0': |
| 243 new MethodTrampoline(0, (Parser target) => target._parseIfStatement()), |
| 244 'parseImportDirective_1': new MethodTrampoline( |
| 245 1, (Parser target, arg0) => target._parseImportDirective(arg0)), |
| 246 'parseInitializedIdentifierList_4': new MethodTrampoline(4, |
| 247 (Parser target, arg0, arg1, arg2, arg3) => |
| 248 target._parseInitializedIdentifierList(arg0, arg1, arg2, arg3)), |
| 249 'parseInstanceCreationExpression_1': new MethodTrampoline(1, |
| 250 (Parser target, arg0) => target._parseInstanceCreationExpression(arg0)), |
| 251 'parseLibraryDirective_1': new MethodTrampoline( |
| 252 1, (Parser target, arg0) => target._parseLibraryDirective(arg0)), |
| 253 'parseLibraryName_2': new MethodTrampoline( |
| 254 2, (Parser target, arg0, arg1) => target._parseLibraryName(arg0, arg1)), |
| 255 'parseListLiteral_2': new MethodTrampoline( |
| 256 2, (Parser target, arg0, arg1) => target._parseListLiteral(arg0, arg1)), |
| 257 'parseListOrMapLiteral_1': new MethodTrampoline( |
| 258 1, (Parser target, arg0) => target._parseListOrMapLiteral(arg0)), |
| 259 'parseLogicalAndExpression_0': new MethodTrampoline( |
| 260 0, (Parser target) => target._parseLogicalAndExpression()), |
| 261 'parseMapLiteral_2': new MethodTrampoline( |
| 262 2, (Parser target, arg0, arg1) => target._parseMapLiteral(arg0, arg1)), |
| 263 'parseMethodDeclarationAfterParameters_7': new MethodTrampoline(7, |
| 264 (Parser target, arg0, arg1, arg2, arg3, arg4, arg5, arg6) => target |
| 265 ._parseMethodDeclarationAfterParameters( |
| 266 arg0, arg1, arg2, arg3, arg4, arg5, arg6)), |
| 267 'parseMethodDeclarationAfterReturnType_4': new MethodTrampoline(4, |
| 268 (Parser target, arg0, arg1, arg2, arg3) => target |
| 269 ._parseMethodDeclarationAfterReturnType(arg0, arg1, arg2, arg3)), |
| 270 'parseModifiers_0': |
| 271 new MethodTrampoline(0, (Parser target) => target._parseModifiers()), |
| 272 'parseMultiplicativeExpression_0': new MethodTrampoline( |
| 273 0, (Parser target) => target._parseMultiplicativeExpression()), |
| 274 'parseNativeClause_0': |
| 275 new MethodTrampoline(0, (Parser target) => target._parseNativeClause()), |
| 276 'parseNewExpression_0': |
| 277 new MethodTrampoline(0, (Parser target) => target._parseNewExpression()), |
| 278 'parseNonLabeledStatement_0': new MethodTrampoline( |
| 279 0, (Parser target) => target._parseNonLabeledStatement()), |
| 280 'parseOperator_3': new MethodTrampoline(3, (Parser target, arg0, arg1, |
| 281 arg2) => target._parseOperator(arg0, arg1, arg2)), |
| 282 'parseOptionalReturnType_0': new MethodTrampoline( |
| 283 0, (Parser target) => target._parseOptionalReturnType()), |
| 284 'parsePartDirective_1': new MethodTrampoline( |
| 285 1, (Parser target, arg0) => target._parsePartDirective(arg0)), |
| 286 'parsePostfixExpression_0': new MethodTrampoline( |
| 287 0, (Parser target) => target._parsePostfixExpression()), |
| 288 'parsePrimaryExpression_0': new MethodTrampoline( |
| 289 0, (Parser target) => target._parsePrimaryExpression()), |
| 290 'parseRedirectingConstructorInvocation_0': new MethodTrampoline( |
| 291 0, (Parser target) => target._parseRedirectingConstructorInvocation()), |
| 292 'parseRelationalExpression_0': new MethodTrampoline( |
| 293 0, (Parser target) => target._parseRelationalExpression()), |
| 294 'parseRethrowExpression_0': new MethodTrampoline( |
| 295 0, (Parser target) => target._parseRethrowExpression()), |
| 296 'parseReturnStatement_0': new MethodTrampoline( |
| 297 0, (Parser target) => target._parseReturnStatement()), |
| 298 'parseSetter_4': new MethodTrampoline(4, (Parser target, arg0, arg1, arg2, |
| 299 arg3) => target._parseSetter(arg0, arg1, arg2, arg3)), |
| 300 'parseShiftExpression_0': new MethodTrampoline( |
| 301 0, (Parser target) => target._parseShiftExpression()), |
| 302 'parseStatementList_0': |
| 303 new MethodTrampoline(0, (Parser target) => target._parseStatementList()), |
| 304 'parseStringInterpolation_1': new MethodTrampoline( |
| 305 1, (Parser target, arg0) => target._parseStringInterpolation(arg0)), |
| 306 'parseSuperConstructorInvocation_0': new MethodTrampoline( |
| 307 0, (Parser target) => target._parseSuperConstructorInvocation()), |
| 308 'parseSwitchStatement_0': new MethodTrampoline( |
| 309 0, (Parser target) => target._parseSwitchStatement()), |
| 310 'parseSymbolLiteral_0': |
| 311 new MethodTrampoline(0, (Parser target) => target._parseSymbolLiteral()), |
| 312 'parseThrowExpression_0': new MethodTrampoline( |
| 313 0, (Parser target) => target._parseThrowExpression()), |
| 314 'parseThrowExpressionWithoutCascade_0': new MethodTrampoline( |
| 315 0, (Parser target) => target._parseThrowExpressionWithoutCascade()), |
| 316 'parseTryStatement_0': |
| 317 new MethodTrampoline(0, (Parser target) => target._parseTryStatement()), |
| 318 'parseTypeAlias_1': new MethodTrampoline( |
| 319 1, (Parser target, arg0) => target._parseTypeAlias(arg0)), |
| 320 'parseUnaryExpression_0': new MethodTrampoline( |
| 321 0, (Parser target) => target._parseUnaryExpression()), |
| 322 'parseVariableDeclaration_0': new MethodTrampoline( |
| 323 0, (Parser target) => target._parseVariableDeclaration()), |
| 324 'parseVariableDeclarationListAfterMetadata_1': new MethodTrampoline(1, |
| 325 (Parser target, arg0) => |
| 326 target._parseVariableDeclarationListAfterMetadata(arg0)), |
| 327 'parseVariableDeclarationListAfterType_3': new MethodTrampoline(3, |
| 328 (Parser target, arg0, arg1, arg2) => |
| 329 target._parseVariableDeclarationListAfterType(arg0, arg1, arg2)), |
| 330 'parseVariableDeclarationStatementAfterMetadata_1': new MethodTrampoline(1, |
| 331 (Parser target, arg0) => |
| 332 target._parseVariableDeclarationStatementAfterMetadata(arg0)), |
| 333 'parseVariableDeclarationStatementAfterType_3': new MethodTrampoline(3, |
| 334 (Parser target, arg0, arg1, arg2) => |
| 335 target._parseVariableDeclarationStatementAfterType(arg0, arg1, arg2)), |
| 336 'parseWhileStatement_0': |
| 337 new MethodTrampoline(0, (Parser target) => target._parseWhileStatement()), |
| 338 'parseYieldStatement_0': |
| 339 new MethodTrampoline(0, (Parser target) => target._parseYieldStatement()), |
| 340 'peek_0': new MethodTrampoline(0, (Parser target) => target._peek()), |
| 341 'peekAt_1': |
| 342 new MethodTrampoline(1, (Parser target, arg0) => target._peekAt(arg0)), |
| 343 'reportError_1': new MethodTrampoline( |
| 344 1, (Parser target, arg0) => target._reportError(arg0)), |
| 345 'reportErrorForCurrentToken_2': new MethodTrampoline(2, (Parser target, arg0, |
| 346 arg1) => target._reportErrorForCurrentToken(arg0, arg1)), |
| 347 'reportErrorForNode_3': new MethodTrampoline(3, (Parser target, arg0, arg1, |
| 348 arg2) => target._reportErrorForNode(arg0, arg1, arg2)), |
| 349 'reportErrorForToken_3': new MethodTrampoline(3, (Parser target, arg0, arg1, |
| 350 arg2) => target._reportErrorForToken(arg0, arg1, arg2)), |
| 351 'skipBlock_0': |
| 352 new MethodTrampoline(0, (Parser target) => target._skipBlock()), |
| 353 'skipFinalConstVarOrType_1': new MethodTrampoline( |
| 354 1, (Parser target, arg0) => target._skipFinalConstVarOrType(arg0)), |
| 355 'skipFormalParameterList_1': new MethodTrampoline( |
| 356 1, (Parser target, arg0) => target._skipFormalParameterList(arg0)), |
| 357 'skipPastMatchingToken_1': new MethodTrampoline( |
| 358 1, (Parser target, arg0) => target._skipPastMatchingToken(arg0)), |
| 359 'skipPrefixedIdentifier_1': new MethodTrampoline( |
| 360 1, (Parser target, arg0) => target._skipPrefixedIdentifier(arg0)), |
| 361 'skipReturnType_1': new MethodTrampoline( |
| 362 1, (Parser target, arg0) => target._skipReturnType(arg0)), |
| 363 'skipSimpleIdentifier_1': new MethodTrampoline( |
| 364 1, (Parser target, arg0) => target._skipSimpleIdentifier(arg0)), |
| 365 'skipStringInterpolation_1': new MethodTrampoline( |
| 366 1, (Parser target, arg0) => target._skipStringInterpolation(arg0)), |
| 367 'skipStringLiteral_1': new MethodTrampoline( |
| 368 1, (Parser target, arg0) => target._skipStringLiteral(arg0)), |
| 369 'skipTypeArgumentList_1': new MethodTrampoline( |
| 370 1, (Parser target, arg0) => target._skipTypeArgumentList(arg0)), |
| 371 'skipTypeName_1': new MethodTrampoline( |
| 372 1, (Parser target, arg0) => target._skipTypeName(arg0)), |
| 373 'skipTypeParameterList_1': new MethodTrampoline( |
| 374 1, (Parser target, arg0) => target._skipTypeParameterList(arg0)), |
| 375 'tokenMatches_2': new MethodTrampoline( |
| 376 2, (Parser target, arg0, arg1) => target._tokenMatches(arg0, arg1)), |
| 377 'tokenMatchesIdentifier_1': new MethodTrampoline( |
| 378 1, (Parser target, arg0) => target._tokenMatchesIdentifier(arg0)), |
| 379 'tokenMatchesKeyword_2': new MethodTrampoline(2, |
| 380 (Parser target, arg0, arg1) => target._tokenMatchesKeyword(arg0, arg1)), |
| 381 'tokenMatchesString_2': new MethodTrampoline( |
| 382 2, (Parser target, arg0, arg1) => target._tokenMatchesString(arg0, arg1)), |
| 383 'translateCharacter_3': new MethodTrampoline(3, (Parser target, arg0, arg1, |
| 384 arg2) => target._translateCharacter(arg0, arg1, arg2)), |
| 385 'unlockErrorListener_0': |
| 386 new MethodTrampoline(0, (Parser target) => target._unlockErrorListener()), |
| 387 'validateFormalParameterList_1': new MethodTrampoline( |
| 388 1, (Parser target, arg0) => target._validateFormalParameterList(arg0)), |
| 389 'validateModifiersForClass_1': new MethodTrampoline( |
| 390 1, (Parser target, arg0) => target._validateModifiersForClass(arg0)), |
| 391 'validateModifiersForConstructor_1': new MethodTrampoline(1, |
| 392 (Parser target, arg0) => target._validateModifiersForConstructor(arg0)), |
| 393 'validateModifiersForEnum_1': new MethodTrampoline( |
| 394 1, (Parser target, arg0) => target._validateModifiersForEnum(arg0)), |
| 395 'validateModifiersForField_1': new MethodTrampoline( |
| 396 1, (Parser target, arg0) => target._validateModifiersForField(arg0)), |
| 397 'validateModifiersForFunctionDeclarationStatement_1': new MethodTrampoline(1, |
| 398 (Parser target, arg0) => |
| 399 target._validateModifiersForFunctionDeclarationStatement(arg0)), |
| 400 'validateModifiersForGetterOrSetterOrMethod_1': new MethodTrampoline(1, |
| 401 (Parser target, arg0) => |
| 402 target._validateModifiersForGetterOrSetterOrMethod(arg0)), |
| 403 'validateModifiersForOperator_1': new MethodTrampoline( |
| 404 1, (Parser target, arg0) => target._validateModifiersForOperator(arg0)), |
| 405 'validateModifiersForTopLevelDeclaration_1': new MethodTrampoline(1, |
| 406 (Parser target, arg0) => |
| 407 target._validateModifiersForTopLevelDeclaration(arg0)), |
| 408 'validateModifiersForTopLevelFunction_1': new MethodTrampoline(1, |
| 409 (Parser target, arg0) => |
| 410 target._validateModifiersForTopLevelFunction(arg0)), |
| 411 'validateModifiersForTopLevelVariable_1': new MethodTrampoline(1, |
| 412 (Parser target, arg0) => |
| 413 target._validateModifiersForTopLevelVariable(arg0)), |
| 414 'validateModifiersForTypedef_1': new MethodTrampoline( |
| 415 1, (Parser target, arg0) => target._validateModifiersForTypedef(arg0)), |
| 416 }; |
| 417 |
| 418 Object invokeParserMethodImpl( |
| 419 Parser parser, String methodName, List<Object> objects, Token tokenStream) { |
| 420 parser.currentToken = tokenStream; |
| 421 MethodTrampoline method = |
| 422 methodTable_Parser['${methodName}_${objects.length}']; |
| 423 if (method == null) { |
| 424 throw new IllegalArgumentException('There is no method named $methodName'); |
| 425 } |
| 426 return method.invoke(parser, objects); |
| 427 } |
| 428 |
| 429 /** |
| 430 * A simple data-holder for a method that needs to return multiple values. |
| 431 */ |
| 432 class CommentAndMetadata { |
| 433 /** |
| 434 * The documentation comment that was parsed, or `null` if none was given. |
| 435 */ |
| 436 final Comment comment; |
| 437 |
| 438 /** |
| 439 * The metadata that was parsed. |
| 440 */ |
| 441 final List<Annotation> metadata; |
| 442 |
| 443 /** |
| 444 * Initialize a newly created holder with the given [comment] and [metadata]. |
| 445 */ |
| 446 CommentAndMetadata(this.comment, this.metadata); |
| 447 } |
| 448 |
| 449 /** |
| 450 * A simple data-holder for a method that needs to return multiple values. |
| 451 */ |
| 452 class FinalConstVarOrType { |
| 453 /** |
| 454 * The 'final', 'const' or 'var' keyword, or `null` if none was given. |
| 455 */ |
| 456 final Token keyword; |
| 457 |
| 458 /** |
| 459 * The type, of `null` if no type was specified. |
| 460 */ |
| 461 final TypeName type; |
| 462 |
| 463 /** |
| 464 * Initialize a newly created holder with the given [keyword] and [type]. |
| 465 */ |
| 466 FinalConstVarOrType(this.keyword, this.type); |
| 467 } |
| 468 |
| 469 /** |
| 470 * A dispatcher that will invoke the right parse method when re-parsing a |
| 471 * specified child of the visited node. All of the methods in this class assume |
| 472 * that the parser is positioned to parse the replacement for the node. All of |
| 473 * the methods will throw an [IncrementalParseException] if the node could not |
| 474 * be parsed for some reason. |
| 475 */ |
| 476 class IncrementalParseDispatcher implements AstVisitor<AstNode> { |
| 477 /** |
| 478 * The parser used to parse the replacement for the node. |
| 479 */ |
| 480 final Parser _parser; |
| 481 |
| 482 /** |
| 483 * The node that is to be replaced. |
| 484 */ |
| 485 final AstNode _oldNode; |
| 486 |
| 487 /** |
| 488 * Initialize a newly created dispatcher to parse a single node that will |
| 489 * use the [_parser] to replace the [_oldNode]. |
| 490 */ |
| 491 IncrementalParseDispatcher(this._parser, this._oldNode); |
| 492 |
| 493 @override |
| 494 AstNode visitAdjacentStrings(AdjacentStrings node) { |
| 495 if (node.strings.contains(_oldNode)) { |
| 496 return _parser.parseStringLiteral(); |
| 497 } |
| 498 return _notAChild(node); |
| 499 } |
| 500 |
| 501 @override |
| 502 AstNode visitAnnotation(Annotation node) { |
| 503 if (identical(_oldNode, node.name)) { |
| 504 throw new InsufficientContextException(); |
| 505 } else if (identical(_oldNode, node.constructorName)) { |
| 506 throw new InsufficientContextException(); |
| 507 } else if (identical(_oldNode, node.arguments)) { |
| 508 return _parser.parseArgumentList(); |
| 509 } |
| 510 return _notAChild(node); |
| 511 } |
| 512 |
| 513 @override |
| 514 AstNode visitArgumentList(ArgumentList node) { |
| 515 if (node.arguments.contains(_oldNode)) { |
| 516 return _parser.parseArgument(); |
| 517 } |
| 518 return _notAChild(node); |
| 519 } |
| 520 |
| 521 @override |
| 522 AstNode visitAsExpression(AsExpression node) { |
| 523 if (identical(_oldNode, node.expression)) { |
| 524 return _parser.parseBitwiseOrExpression(); |
| 525 } else if (identical(_oldNode, node.type)) { |
| 526 return _parser.parseTypeName(); |
| 527 } |
| 528 return _notAChild(node); |
| 529 } |
| 530 |
| 531 @override |
| 532 AstNode visitAssertStatement(AssertStatement node) { |
| 533 if (identical(_oldNode, node.condition)) { |
| 534 return _parser.parseExpression2(); |
| 535 } |
| 536 return _notAChild(node); |
| 537 } |
| 538 |
| 539 @override |
| 540 AstNode visitAssignmentExpression(AssignmentExpression node) { |
| 541 if (identical(_oldNode, node.leftHandSide)) { |
| 542 // TODO(brianwilkerson) If the assignment is part of a cascade section, |
| 543 // then we don't have a single parse method that will work. |
| 544 // Otherwise, we can parse a conditional expression, but need to ensure |
| 545 // that the resulting expression is assignable. |
| 546 // return parser.parseConditionalExpression(); |
| 547 throw new InsufficientContextException(); |
| 548 } else if (identical(_oldNode, node.rightHandSide)) { |
| 549 if (_isCascadeAllowedInAssignment(node)) { |
| 550 return _parser.parseExpression2(); |
| 551 } |
| 552 return _parser.parseExpressionWithoutCascade(); |
| 553 } |
| 554 return _notAChild(node); |
| 555 } |
| 556 |
| 557 @override |
| 558 AstNode visitAwaitExpression(AwaitExpression node) { |
| 559 if (identical(_oldNode, node.expression)) { |
| 560 // TODO(brianwilkerson) Depending on precedence, |
| 561 // this might not be sufficient. |
| 562 return _parser.parseExpression2(); |
| 563 } |
| 564 return _notAChild(node); |
| 565 } |
| 566 |
| 567 @override |
| 568 AstNode visitBinaryExpression(BinaryExpression node) { |
| 569 if (identical(_oldNode, node.leftOperand)) { |
| 570 throw new InsufficientContextException(); |
| 571 } else if (identical(_oldNode, node.rightOperand)) { |
| 572 throw new InsufficientContextException(); |
| 573 } |
| 574 return _notAChild(node); |
| 575 } |
| 576 |
| 577 @override |
| 578 AstNode visitBlock(Block node) { |
| 579 if (node.statements.contains(_oldNode)) { |
| 580 return _parser.parseStatement2(); |
| 581 } |
| 582 return _notAChild(node); |
| 583 } |
| 584 |
| 585 @override |
| 586 AstNode visitBlockFunctionBody(BlockFunctionBody node) { |
| 587 if (identical(_oldNode, node.block)) { |
| 588 return _parser.parseBlock(); |
| 589 } |
| 590 return _notAChild(node); |
| 591 } |
| 592 |
| 593 @override |
| 594 AstNode visitBooleanLiteral(BooleanLiteral node) => _notAChild(node); |
| 595 |
| 596 @override |
| 597 AstNode visitBreakStatement(BreakStatement node) { |
| 598 if (identical(_oldNode, node.label)) { |
| 599 return _parser.parseSimpleIdentifier(); |
| 600 } |
| 601 return _notAChild(node); |
| 602 } |
| 603 |
| 604 @override |
| 605 AstNode visitCascadeExpression(CascadeExpression node) { |
| 606 if (identical(_oldNode, node.target)) { |
| 607 return _parser.parseConditionalExpression(); |
| 608 } else if (node.cascadeSections.contains(_oldNode)) { |
| 609 throw new InsufficientContextException(); |
| 610 } |
| 611 return _notAChild(node); |
| 612 } |
| 613 |
| 614 @override |
| 615 AstNode visitCatchClause(CatchClause node) { |
| 616 if (identical(_oldNode, node.exceptionType)) { |
| 617 return _parser.parseTypeName(); |
| 618 } else if (identical(_oldNode, node.exceptionParameter)) { |
| 619 return _parser.parseSimpleIdentifier(); |
| 620 } else if (identical(_oldNode, node.stackTraceParameter)) { |
| 621 return _parser.parseSimpleIdentifier(); |
| 622 } else if (identical(_oldNode, node.body)) { |
| 623 return _parser.parseBlock(); |
| 624 } |
| 625 return _notAChild(node); |
| 626 } |
| 627 |
| 628 @override |
| 629 AstNode visitClassDeclaration(ClassDeclaration node) { |
| 630 if (identical(_oldNode, node.documentationComment)) { |
| 631 throw new InsufficientContextException(); |
| 632 } else if (node.metadata.contains(_oldNode)) { |
| 633 return _parser.parseAnnotation(); |
| 634 } else if (identical(_oldNode, node.name)) { |
| 635 // Changing the class name changes whether a member is interpreted as a |
| 636 // constructor or not, so we'll just have to re-parse the entire class. |
| 637 throw new InsufficientContextException(); |
| 638 } else if (identical(_oldNode, node.typeParameters)) { |
| 639 return _parser.parseTypeParameterList(); |
| 640 } else if (identical(_oldNode, node.extendsClause)) { |
| 641 return _parser.parseExtendsClause(); |
| 642 } else if (identical(_oldNode, node.withClause)) { |
| 643 return _parser.parseWithClause(); |
| 644 } else if (identical(_oldNode, node.implementsClause)) { |
| 645 return _parser.parseImplementsClause(); |
| 646 } else if (node.members.contains(_oldNode)) { |
| 647 ClassMember member = _parser.parseClassMember(node.name.name); |
| 648 if (member == null) { |
| 649 throw new InsufficientContextException(); |
| 650 } |
| 651 return member; |
| 652 } |
| 653 return _notAChild(node); |
| 654 } |
| 655 |
| 656 @override |
| 657 AstNode visitClassTypeAlias(ClassTypeAlias node) { |
| 658 if (identical(_oldNode, node.documentationComment)) { |
| 659 throw new InsufficientContextException(); |
| 660 } else if (node.metadata.contains(_oldNode)) { |
| 661 return _parser.parseAnnotation(); |
| 662 } else if (identical(_oldNode, node.name)) { |
| 663 return _parser.parseSimpleIdentifier(); |
| 664 } else if (identical(_oldNode, node.typeParameters)) { |
| 665 return _parser.parseTypeParameterList(); |
| 666 } else if (identical(_oldNode, node.superclass)) { |
| 667 return _parser.parseTypeName(); |
| 668 } else if (identical(_oldNode, node.withClause)) { |
| 669 return _parser.parseWithClause(); |
| 670 } else if (identical(_oldNode, node.implementsClause)) { |
| 671 return _parser.parseImplementsClause(); |
| 672 } |
| 673 return _notAChild(node); |
| 674 } |
| 675 |
| 676 @override |
| 677 AstNode visitComment(Comment node) { |
| 678 throw new InsufficientContextException(); |
| 679 } |
| 680 |
| 681 @override |
| 682 AstNode visitCommentReference(CommentReference node) { |
| 683 if (identical(_oldNode, node.identifier)) { |
| 684 return _parser.parsePrefixedIdentifier(); |
| 685 } |
| 686 return _notAChild(node); |
| 687 } |
| 688 |
| 689 @override |
| 690 AstNode visitCompilationUnit(CompilationUnit node) { |
| 691 throw new InsufficientContextException(); |
| 692 } |
| 693 |
| 694 @override |
| 695 AstNode visitConditionalExpression(ConditionalExpression node) { |
| 696 if (identical(_oldNode, node.condition)) { |
| 697 return _parser.parseIfNullExpression(); |
| 698 } else if (identical(_oldNode, node.thenExpression)) { |
| 699 return _parser.parseExpressionWithoutCascade(); |
| 700 } else if (identical(_oldNode, node.elseExpression)) { |
| 701 return _parser.parseExpressionWithoutCascade(); |
| 702 } |
| 703 return _notAChild(node); |
| 704 } |
| 705 |
| 706 @override |
| 707 AstNode visitConstructorDeclaration(ConstructorDeclaration node) { |
| 708 if (identical(_oldNode, node.documentationComment)) { |
| 709 throw new InsufficientContextException(); |
| 710 } else if (node.metadata.contains(_oldNode)) { |
| 711 return _parser.parseAnnotation(); |
| 712 } else if (identical(_oldNode, node.returnType)) { |
| 713 throw new InsufficientContextException(); |
| 714 } else if (identical(_oldNode, node.name)) { |
| 715 throw new InsufficientContextException(); |
| 716 } else if (identical(_oldNode, node.parameters)) { |
| 717 return _parser.parseFormalParameterList(); |
| 718 } else if (identical(_oldNode, node.redirectedConstructor)) { |
| 719 throw new InsufficientContextException(); |
| 720 } else if (node.initializers.contains(_oldNode)) { |
| 721 throw new InsufficientContextException(); |
| 722 } else if (identical(_oldNode, node.body)) { |
| 723 throw new InsufficientContextException(); |
| 724 } |
| 725 return _notAChild(node); |
| 726 } |
| 727 |
| 728 @override |
| 729 AstNode visitConstructorFieldInitializer(ConstructorFieldInitializer node) { |
| 730 if (identical(_oldNode, node.fieldName)) { |
| 731 return _parser.parseSimpleIdentifier(); |
| 732 } else if (identical(_oldNode, node.expression)) { |
| 733 throw new InsufficientContextException(); |
| 734 } |
| 735 return _notAChild(node); |
| 736 } |
| 737 |
| 738 @override |
| 739 AstNode visitConstructorName(ConstructorName node) { |
| 740 if (identical(_oldNode, node.type)) { |
| 741 return _parser.parseTypeName(); |
| 742 } else if (identical(_oldNode, node.name)) { |
| 743 return _parser.parseSimpleIdentifier(); |
| 744 } |
| 745 return _notAChild(node); |
| 746 } |
| 747 |
| 748 @override |
| 749 AstNode visitContinueStatement(ContinueStatement node) { |
| 750 if (identical(_oldNode, node.label)) { |
| 751 return _parser.parseSimpleIdentifier(); |
| 752 } |
| 753 return _notAChild(node); |
| 754 } |
| 755 |
| 756 @override |
| 757 AstNode visitDeclaredIdentifier(DeclaredIdentifier node) { |
| 758 if (identical(_oldNode, node.documentationComment)) { |
| 759 throw new InsufficientContextException(); |
| 760 } else if (node.metadata.contains(_oldNode)) { |
| 761 return _parser.parseAnnotation(); |
| 762 } else if (identical(_oldNode, node.type)) { |
| 763 throw new InsufficientContextException(); |
| 764 } else if (identical(_oldNode, node.identifier)) { |
| 765 return _parser.parseSimpleIdentifier(); |
| 766 } |
| 767 return _notAChild(node); |
| 768 } |
| 769 |
| 770 @override |
| 771 AstNode visitDefaultFormalParameter(DefaultFormalParameter node) { |
| 772 if (identical(_oldNode, node.parameter)) { |
| 773 return _parser.parseNormalFormalParameter(); |
| 774 } else if (identical(_oldNode, node.defaultValue)) { |
| 775 return _parser.parseExpression2(); |
| 776 } |
| 777 return _notAChild(node); |
| 778 } |
| 779 |
| 780 @override |
| 781 AstNode visitDoStatement(DoStatement node) { |
| 782 if (identical(_oldNode, node.body)) { |
| 783 return _parser.parseStatement2(); |
| 784 } else if (identical(_oldNode, node.condition)) { |
| 785 return _parser.parseExpression2(); |
| 786 } |
| 787 return _notAChild(node); |
| 788 } |
| 789 |
| 790 @override |
| 791 AstNode visitDoubleLiteral(DoubleLiteral node) => _notAChild(node); |
| 792 |
| 793 @override |
| 794 AstNode visitEmptyFunctionBody(EmptyFunctionBody node) => _notAChild(node); |
| 795 |
| 796 @override |
| 797 AstNode visitEmptyStatement(EmptyStatement node) => _notAChild(node); |
| 798 |
| 799 @override |
| 800 AstNode visitEnumConstantDeclaration(EnumConstantDeclaration node) { |
| 801 if (identical(_oldNode, node.documentationComment)) { |
| 802 throw new InsufficientContextException(); |
| 803 } else if (node.metadata.contains(_oldNode)) { |
| 804 return _parser.parseAnnotation(); |
| 805 } else if (identical(_oldNode, node.name)) { |
| 806 return _parser.parseSimpleIdentifier(); |
| 807 } |
| 808 return _notAChild(node); |
| 809 } |
| 810 |
| 811 @override |
| 812 AstNode visitEnumDeclaration(EnumDeclaration node) { |
| 813 if (identical(_oldNode, node.documentationComment)) { |
| 814 throw new InsufficientContextException(); |
| 815 } else if (node.metadata.contains(_oldNode)) { |
| 816 return _parser.parseAnnotation(); |
| 817 } else if (identical(_oldNode, node.name)) { |
| 818 return _parser.parseSimpleIdentifier(); |
| 819 } else if (node.constants.contains(_oldNode)) { |
| 820 throw new InsufficientContextException(); |
| 821 } |
| 822 return _notAChild(node); |
| 823 } |
| 824 |
| 825 @override |
| 826 AstNode visitExportDirective(ExportDirective node) { |
| 827 if (identical(_oldNode, node.documentationComment)) { |
| 828 throw new InsufficientContextException(); |
| 829 } else if (node.metadata.contains(_oldNode)) { |
| 830 return _parser.parseAnnotation(); |
| 831 } else if (identical(_oldNode, node.uri)) { |
| 832 return _parser.parseStringLiteral(); |
| 833 } else if (node.combinators.contains(_oldNode)) { |
| 834 throw new IncrementalParseException(); |
| 835 //return parser.parseCombinator(); |
| 836 } |
| 837 return _notAChild(node); |
| 838 } |
| 839 |
| 840 @override |
| 841 AstNode visitExpressionFunctionBody(ExpressionFunctionBody node) { |
| 842 if (identical(_oldNode, node.expression)) { |
| 843 return _parser.parseExpression2(); |
| 844 } |
| 845 return _notAChild(node); |
| 846 } |
| 847 |
| 848 @override |
| 849 AstNode visitExpressionStatement(ExpressionStatement node) { |
| 850 if (identical(_oldNode, node.expression)) { |
| 851 return _parser.parseExpression2(); |
| 852 } |
| 853 return _notAChild(node); |
| 854 } |
| 855 |
| 856 @override |
| 857 AstNode visitExtendsClause(ExtendsClause node) { |
| 858 if (identical(_oldNode, node.superclass)) { |
| 859 return _parser.parseTypeName(); |
| 860 } |
| 861 return _notAChild(node); |
| 862 } |
| 863 |
| 864 @override |
| 865 AstNode visitFieldDeclaration(FieldDeclaration node) { |
| 866 if (identical(_oldNode, node.documentationComment)) { |
| 867 throw new InsufficientContextException(); |
| 868 } else if (node.metadata.contains(_oldNode)) { |
| 869 return _parser.parseAnnotation(); |
| 870 } else if (identical(_oldNode, node.fields)) { |
| 871 throw new InsufficientContextException(); |
| 872 } |
| 873 return _notAChild(node); |
| 874 } |
| 875 |
| 876 @override |
| 877 AstNode visitFieldFormalParameter(FieldFormalParameter node) { |
| 878 if (identical(_oldNode, node.documentationComment)) { |
| 879 throw new InsufficientContextException(); |
| 880 } else if (node.metadata.contains(_oldNode)) { |
| 881 return _parser.parseAnnotation(); |
| 882 } else if (identical(_oldNode, node.type)) { |
| 883 return _parser.parseTypeName(); |
| 884 } else if (identical(_oldNode, node.identifier)) { |
| 885 return _parser.parseSimpleIdentifier(); |
| 886 } else if (identical(_oldNode, node.parameters)) { |
| 887 return _parser.parseFormalParameterList(); |
| 888 } |
| 889 return _notAChild(node); |
| 890 } |
| 891 |
| 892 @override |
| 893 AstNode visitForEachStatement(ForEachStatement node) { |
| 894 if (identical(_oldNode, node.loopVariable)) { |
| 895 throw new InsufficientContextException(); |
| 896 //return parser.parseDeclaredIdentifier(); |
| 897 } else if (identical(_oldNode, node.identifier)) { |
| 898 return _parser.parseSimpleIdentifier(); |
| 899 } else if (identical(_oldNode, node.body)) { |
| 900 return _parser.parseStatement2(); |
| 901 } |
| 902 return _notAChild(node); |
| 903 } |
| 904 |
| 905 @override |
| 906 AstNode visitFormalParameterList(FormalParameterList node) { |
| 907 // We don't know which kind of parameter to parse. |
| 908 throw new InsufficientContextException(); |
| 909 } |
| 910 |
| 911 @override |
| 912 AstNode visitForStatement(ForStatement node) { |
| 913 if (identical(_oldNode, node.variables)) { |
| 914 throw new InsufficientContextException(); |
| 915 } else if (identical(_oldNode, node.initialization)) { |
| 916 throw new InsufficientContextException(); |
| 917 } else if (identical(_oldNode, node.condition)) { |
| 918 return _parser.parseExpression2(); |
| 919 } else if (node.updaters.contains(_oldNode)) { |
| 920 return _parser.parseExpression2(); |
| 921 } else if (identical(_oldNode, node.body)) { |
| 922 return _parser.parseStatement2(); |
| 923 } |
| 924 return _notAChild(node); |
| 925 } |
| 926 |
| 927 @override |
| 928 AstNode visitFunctionDeclaration(FunctionDeclaration node) { |
| 929 if (identical(_oldNode, node.documentationComment)) { |
| 930 throw new InsufficientContextException(); |
| 931 } else if (node.metadata.contains(_oldNode)) { |
| 932 return _parser.parseAnnotation(); |
| 933 } else if (identical(_oldNode, node.returnType)) { |
| 934 return _parser.parseReturnType(); |
| 935 } else if (identical(_oldNode, node.name)) { |
| 936 return _parser.parseSimpleIdentifier(); |
| 937 } else if (identical(_oldNode, node.functionExpression)) { |
| 938 throw new InsufficientContextException(); |
| 939 } |
| 940 return _notAChild(node); |
| 941 } |
| 942 |
| 943 @override |
| 944 AstNode visitFunctionDeclarationStatement(FunctionDeclarationStatement node) { |
| 945 if (identical(_oldNode, node.functionDeclaration)) { |
| 946 throw new InsufficientContextException(); |
| 947 } |
| 948 return _notAChild(node); |
| 949 } |
| 950 |
| 951 @override |
| 952 AstNode visitFunctionExpression(FunctionExpression node) { |
| 953 if (identical(_oldNode, node.parameters)) { |
| 954 return _parser.parseFormalParameterList(); |
| 955 } else if (identical(_oldNode, node.body)) { |
| 956 throw new InsufficientContextException(); |
| 957 } |
| 958 return _notAChild(node); |
| 959 } |
| 960 |
| 961 @override |
| 962 AstNode visitFunctionExpressionInvocation(FunctionExpressionInvocation node) { |
| 963 if (identical(_oldNode, node.function)) { |
| 964 throw new InsufficientContextException(); |
| 965 } else if (identical(_oldNode, node.argumentList)) { |
| 966 return _parser.parseArgumentList(); |
| 967 } |
| 968 return _notAChild(node); |
| 969 } |
| 970 |
| 971 @override |
| 972 AstNode visitFunctionTypeAlias(FunctionTypeAlias node) { |
| 973 if (identical(_oldNode, node.documentationComment)) { |
| 974 throw new InsufficientContextException(); |
| 975 } else if (node.metadata.contains(_oldNode)) { |
| 976 return _parser.parseAnnotation(); |
| 977 } else if (identical(_oldNode, node.returnType)) { |
| 978 return _parser.parseReturnType(); |
| 979 } else if (identical(_oldNode, node.name)) { |
| 980 return _parser.parseSimpleIdentifier(); |
| 981 } else if (identical(_oldNode, node.typeParameters)) { |
| 982 return _parser.parseTypeParameterList(); |
| 983 } else if (identical(_oldNode, node.parameters)) { |
| 984 return _parser.parseFormalParameterList(); |
| 985 } |
| 986 return _notAChild(node); |
| 987 } |
| 988 |
| 989 @override |
| 990 AstNode visitFunctionTypedFormalParameter(FunctionTypedFormalParameter node) { |
| 991 if (identical(_oldNode, node.documentationComment)) { |
| 992 throw new InsufficientContextException(); |
| 993 } else if (node.metadata.contains(_oldNode)) { |
| 994 return _parser.parseAnnotation(); |
| 995 } else if (identical(_oldNode, node.returnType)) { |
| 996 return _parser.parseReturnType(); |
| 997 } else if (identical(_oldNode, node.identifier)) { |
| 998 return _parser.parseSimpleIdentifier(); |
| 999 } else if (identical(_oldNode, node.parameters)) { |
| 1000 return _parser.parseFormalParameterList(); |
| 1001 } |
| 1002 return _notAChild(node); |
| 1003 } |
| 1004 |
| 1005 @override |
| 1006 AstNode visitHideCombinator(HideCombinator node) { |
| 1007 if (node.hiddenNames.contains(_oldNode)) { |
| 1008 return _parser.parseSimpleIdentifier(); |
| 1009 } |
| 1010 return _notAChild(node); |
| 1011 } |
| 1012 |
| 1013 @override |
| 1014 AstNode visitIfStatement(IfStatement node) { |
| 1015 if (identical(_oldNode, node.condition)) { |
| 1016 return _parser.parseExpression2(); |
| 1017 } else if (identical(_oldNode, node.thenStatement)) { |
| 1018 return _parser.parseStatement2(); |
| 1019 } else if (identical(_oldNode, node.elseStatement)) { |
| 1020 return _parser.parseStatement2(); |
| 1021 } |
| 1022 return _notAChild(node); |
| 1023 } |
| 1024 |
| 1025 @override |
| 1026 AstNode visitImplementsClause(ImplementsClause node) { |
| 1027 if (node.interfaces.contains(node)) { |
| 1028 return _parser.parseTypeName(); |
| 1029 } |
| 1030 return _notAChild(node); |
| 1031 } |
| 1032 |
| 1033 @override |
| 1034 AstNode visitImportDirective(ImportDirective node) { |
| 1035 if (identical(_oldNode, node.documentationComment)) { |
| 1036 throw new InsufficientContextException(); |
| 1037 } else if (node.metadata.contains(_oldNode)) { |
| 1038 return _parser.parseAnnotation(); |
| 1039 } else if (identical(_oldNode, node.uri)) { |
| 1040 return _parser.parseStringLiteral(); |
| 1041 } else if (identical(_oldNode, node.prefix)) { |
| 1042 return _parser.parseSimpleIdentifier(); |
| 1043 } else if (node.combinators.contains(_oldNode)) { |
| 1044 return _parser.parseCombinator(); |
| 1045 } |
| 1046 return _notAChild(node); |
| 1047 } |
| 1048 |
| 1049 @override |
| 1050 AstNode visitIndexExpression(IndexExpression node) { |
| 1051 if (identical(_oldNode, node.target)) { |
| 1052 throw new InsufficientContextException(); |
| 1053 } else if (identical(_oldNode, node.index)) { |
| 1054 return _parser.parseExpression2(); |
| 1055 } |
| 1056 return _notAChild(node); |
| 1057 } |
| 1058 |
| 1059 @override |
| 1060 AstNode visitInstanceCreationExpression(InstanceCreationExpression node) { |
| 1061 if (identical(_oldNode, node.constructorName)) { |
| 1062 return _parser.parseConstructorName(); |
| 1063 } else if (identical(_oldNode, node.argumentList)) { |
| 1064 return _parser.parseArgumentList(); |
| 1065 } |
| 1066 return _notAChild(node); |
| 1067 } |
| 1068 |
| 1069 @override |
| 1070 AstNode visitIntegerLiteral(IntegerLiteral node) => _notAChild(node); |
| 1071 |
| 1072 @override |
| 1073 AstNode visitInterpolationExpression(InterpolationExpression node) { |
| 1074 if (identical(_oldNode, node.expression)) { |
| 1075 if (node.leftBracket == null) { |
| 1076 throw new InsufficientContextException(); |
| 1077 //return parser.parseThisOrSimpleIdentifier(); |
| 1078 } |
| 1079 return _parser.parseExpression2(); |
| 1080 } |
| 1081 return _notAChild(node); |
| 1082 } |
| 1083 |
| 1084 @override |
| 1085 AstNode visitInterpolationString(InterpolationString node) { |
| 1086 throw new InsufficientContextException(); |
| 1087 } |
| 1088 |
| 1089 @override |
| 1090 AstNode visitIsExpression(IsExpression node) { |
| 1091 if (identical(_oldNode, node.expression)) { |
| 1092 return _parser.parseBitwiseOrExpression(); |
| 1093 } else if (identical(_oldNode, node.type)) { |
| 1094 return _parser.parseTypeName(); |
| 1095 } |
| 1096 return _notAChild(node); |
| 1097 } |
| 1098 |
| 1099 @override |
| 1100 AstNode visitLabel(Label node) { |
| 1101 if (identical(_oldNode, node.label)) { |
| 1102 return _parser.parseSimpleIdentifier(); |
| 1103 } |
| 1104 return _notAChild(node); |
| 1105 } |
| 1106 |
| 1107 @override |
| 1108 AstNode visitLabeledStatement(LabeledStatement node) { |
| 1109 if (node.labels.contains(_oldNode)) { |
| 1110 return _parser.parseLabel(); |
| 1111 } else if (identical(_oldNode, node.statement)) { |
| 1112 return _parser.parseStatement2(); |
| 1113 } |
| 1114 return _notAChild(node); |
| 1115 } |
| 1116 |
| 1117 @override |
| 1118 AstNode visitLibraryDirective(LibraryDirective node) { |
| 1119 if (identical(_oldNode, node.documentationComment)) { |
| 1120 throw new InsufficientContextException(); |
| 1121 } else if (node.metadata.contains(_oldNode)) { |
| 1122 return _parser.parseAnnotation(); |
| 1123 } else if (identical(_oldNode, node.name)) { |
| 1124 return _parser.parseLibraryIdentifier(); |
| 1125 } |
| 1126 return _notAChild(node); |
| 1127 } |
| 1128 |
| 1129 @override |
| 1130 AstNode visitLibraryIdentifier(LibraryIdentifier node) { |
| 1131 if (node.components.contains(_oldNode)) { |
| 1132 return _parser.parseSimpleIdentifier(); |
| 1133 } |
| 1134 return _notAChild(node); |
| 1135 } |
| 1136 |
| 1137 @override |
| 1138 AstNode visitListLiteral(ListLiteral node) { |
| 1139 if (identical(_oldNode, node.typeArguments)) { |
| 1140 return _parser.parseTypeArgumentList(); |
| 1141 } else if (node.elements.contains(_oldNode)) { |
| 1142 return _parser.parseExpression2(); |
| 1143 } |
| 1144 return _notAChild(node); |
| 1145 } |
| 1146 |
| 1147 @override |
| 1148 AstNode visitMapLiteral(MapLiteral node) { |
| 1149 if (identical(_oldNode, node.typeArguments)) { |
| 1150 return _parser.parseTypeArgumentList(); |
| 1151 } else if (node.entries.contains(_oldNode)) { |
| 1152 return _parser.parseMapLiteralEntry(); |
| 1153 } |
| 1154 return _notAChild(node); |
| 1155 } |
| 1156 |
| 1157 @override |
| 1158 AstNode visitMapLiteralEntry(MapLiteralEntry node) { |
| 1159 if (identical(_oldNode, node.key)) { |
| 1160 return _parser.parseExpression2(); |
| 1161 } else if (identical(_oldNode, node.value)) { |
| 1162 return _parser.parseExpression2(); |
| 1163 } |
| 1164 return _notAChild(node); |
| 1165 } |
| 1166 |
| 1167 @override |
| 1168 AstNode visitMethodDeclaration(MethodDeclaration node) { |
| 1169 if (identical(_oldNode, node.documentationComment)) { |
| 1170 throw new InsufficientContextException(); |
| 1171 } else if (node.metadata.contains(_oldNode)) { |
| 1172 return _parser.parseAnnotation(); |
| 1173 } else if (identical(_oldNode, node.returnType)) { |
| 1174 throw new InsufficientContextException(); |
| 1175 //return parser.parseTypeName(); |
| 1176 //return parser.parseReturnType(); |
| 1177 } else if (identical(_oldNode, node.name)) { |
| 1178 if (node.operatorKeyword != null) { |
| 1179 throw new InsufficientContextException(); |
| 1180 } |
| 1181 return _parser.parseSimpleIdentifier(); |
| 1182 } else if (identical(_oldNode, node.body)) { |
| 1183 //return parser.parseFunctionBody(); |
| 1184 throw new InsufficientContextException(); |
| 1185 } else if (identical(_oldNode, node.parameters)) { |
| 1186 // TODO(paulberry): if we want errors to be correct, we'll need to also |
| 1187 // call _validateFormalParameterList, and sometimes |
| 1188 // _validateModifiersForGetterOrSetterOrMethod. |
| 1189 return _parser.parseFormalParameterList(); |
| 1190 } |
| 1191 return _notAChild(node); |
| 1192 } |
| 1193 |
| 1194 @override |
| 1195 AstNode visitMethodInvocation(MethodInvocation node) { |
| 1196 if (identical(_oldNode, node.target)) { |
| 1197 throw new IncrementalParseException(); |
| 1198 } else if (identical(_oldNode, node.methodName)) { |
| 1199 return _parser.parseSimpleIdentifier(); |
| 1200 } else if (identical(_oldNode, node.argumentList)) { |
| 1201 return _parser.parseArgumentList(); |
| 1202 } |
| 1203 return _notAChild(node); |
| 1204 } |
| 1205 |
| 1206 @override |
| 1207 AstNode visitNamedExpression(NamedExpression node) { |
| 1208 if (identical(_oldNode, node.name)) { |
| 1209 return _parser.parseLabel(); |
| 1210 } else if (identical(_oldNode, node.expression)) { |
| 1211 return _parser.parseExpression2(); |
| 1212 } |
| 1213 return _notAChild(node); |
| 1214 } |
| 1215 |
| 1216 @override |
| 1217 AstNode visitNativeClause(NativeClause node) { |
| 1218 if (identical(_oldNode, node.name)) { |
| 1219 return _parser.parseStringLiteral(); |
| 1220 } |
| 1221 return _notAChild(node); |
| 1222 } |
| 1223 |
| 1224 @override |
| 1225 AstNode visitNativeFunctionBody(NativeFunctionBody node) { |
| 1226 if (identical(_oldNode, node.stringLiteral)) { |
| 1227 return _parser.parseStringLiteral(); |
| 1228 } |
| 1229 return _notAChild(node); |
| 1230 } |
| 1231 |
| 1232 @override |
| 1233 AstNode visitNullLiteral(NullLiteral node) => _notAChild(node); |
| 1234 |
| 1235 @override |
| 1236 AstNode visitParenthesizedExpression(ParenthesizedExpression node) { |
| 1237 if (identical(_oldNode, node.expression)) { |
| 1238 return _parser.parseExpression2(); |
| 1239 } |
| 1240 return _notAChild(node); |
| 1241 } |
| 1242 |
| 1243 @override |
| 1244 AstNode visitPartDirective(PartDirective node) { |
| 1245 if (identical(_oldNode, node.documentationComment)) { |
| 1246 throw new InsufficientContextException(); |
| 1247 } else if (node.metadata.contains(_oldNode)) { |
| 1248 return _parser.parseAnnotation(); |
| 1249 } else if (identical(_oldNode, node.uri)) { |
| 1250 return _parser.parseStringLiteral(); |
| 1251 } |
| 1252 return _notAChild(node); |
| 1253 } |
| 1254 |
| 1255 @override |
| 1256 AstNode visitPartOfDirective(PartOfDirective node) { |
| 1257 if (identical(_oldNode, node.documentationComment)) { |
| 1258 throw new InsufficientContextException(); |
| 1259 } else if (node.metadata.contains(_oldNode)) { |
| 1260 return _parser.parseAnnotation(); |
| 1261 } else if (identical(_oldNode, node.libraryName)) { |
| 1262 return _parser.parseLibraryIdentifier(); |
| 1263 } |
| 1264 return _notAChild(node); |
| 1265 } |
| 1266 |
| 1267 @override |
| 1268 AstNode visitPostfixExpression(PostfixExpression node) { |
| 1269 if (identical(_oldNode, node.operand)) { |
| 1270 throw new InsufficientContextException(); |
| 1271 } |
| 1272 return _notAChild(node); |
| 1273 } |
| 1274 |
| 1275 @override |
| 1276 AstNode visitPrefixedIdentifier(PrefixedIdentifier node) { |
| 1277 if (identical(_oldNode, node.prefix)) { |
| 1278 return _parser.parseSimpleIdentifier(); |
| 1279 } else if (identical(_oldNode, node.identifier)) { |
| 1280 return _parser.parseSimpleIdentifier(); |
| 1281 } |
| 1282 return _notAChild(node); |
| 1283 } |
| 1284 |
| 1285 @override |
| 1286 AstNode visitPrefixExpression(PrefixExpression node) { |
| 1287 if (identical(_oldNode, node.operand)) { |
| 1288 throw new InsufficientContextException(); |
| 1289 } |
| 1290 return _notAChild(node); |
| 1291 } |
| 1292 |
| 1293 @override |
| 1294 AstNode visitPropertyAccess(PropertyAccess node) { |
| 1295 if (identical(_oldNode, node.target)) { |
| 1296 throw new InsufficientContextException(); |
| 1297 } else if (identical(_oldNode, node.propertyName)) { |
| 1298 return _parser.parseSimpleIdentifier(); |
| 1299 } |
| 1300 return _notAChild(node); |
| 1301 } |
| 1302 |
| 1303 @override |
| 1304 AstNode visitRedirectingConstructorInvocation( |
| 1305 RedirectingConstructorInvocation node) { |
| 1306 if (identical(_oldNode, node.constructorName)) { |
| 1307 return _parser.parseSimpleIdentifier(); |
| 1308 } else if (identical(_oldNode, node.argumentList)) { |
| 1309 return _parser.parseArgumentList(); |
| 1310 } |
| 1311 return _notAChild(node); |
| 1312 } |
| 1313 |
| 1314 @override |
| 1315 AstNode visitRethrowExpression(RethrowExpression node) => _notAChild(node); |
| 1316 |
| 1317 @override |
| 1318 AstNode visitReturnStatement(ReturnStatement node) { |
| 1319 if (identical(_oldNode, node.expression)) { |
| 1320 return _parser.parseExpression2(); |
| 1321 } |
| 1322 return _notAChild(node); |
| 1323 } |
| 1324 |
| 1325 @override |
| 1326 AstNode visitScriptTag(ScriptTag node) => _notAChild(node); |
| 1327 |
| 1328 @override |
| 1329 AstNode visitShowCombinator(ShowCombinator node) { |
| 1330 if (node.shownNames.contains(_oldNode)) { |
| 1331 return _parser.parseSimpleIdentifier(); |
| 1332 } |
| 1333 return _notAChild(node); |
| 1334 } |
| 1335 |
| 1336 @override |
| 1337 AstNode visitSimpleFormalParameter(SimpleFormalParameter node) { |
| 1338 if (identical(_oldNode, node.documentationComment)) { |
| 1339 throw new InsufficientContextException(); |
| 1340 } else if (node.metadata.contains(_oldNode)) { |
| 1341 return _parser.parseAnnotation(); |
| 1342 } else if (identical(_oldNode, node.type)) { |
| 1343 throw new InsufficientContextException(); |
| 1344 } else if (identical(_oldNode, node.identifier)) { |
| 1345 throw new InsufficientContextException(); |
| 1346 } |
| 1347 return _notAChild(node); |
| 1348 } |
| 1349 |
| 1350 @override |
| 1351 AstNode visitSimpleIdentifier(SimpleIdentifier node) => _notAChild(node); |
| 1352 |
| 1353 @override |
| 1354 AstNode visitSimpleStringLiteral(SimpleStringLiteral node) => |
| 1355 _notAChild(node); |
| 1356 |
| 1357 @override |
| 1358 AstNode visitStringInterpolation(StringInterpolation node) { |
| 1359 if (node.elements.contains(_oldNode)) { |
| 1360 throw new InsufficientContextException(); |
| 1361 } |
| 1362 return _notAChild(node); |
| 1363 } |
| 1364 |
| 1365 @override |
| 1366 AstNode visitSuperConstructorInvocation(SuperConstructorInvocation node) { |
| 1367 if (identical(_oldNode, node.constructorName)) { |
| 1368 return _parser.parseSimpleIdentifier(); |
| 1369 } else if (identical(_oldNode, node.argumentList)) { |
| 1370 return _parser.parseArgumentList(); |
| 1371 } |
| 1372 return _notAChild(node); |
| 1373 } |
| 1374 |
| 1375 @override |
| 1376 AstNode visitSuperExpression(SuperExpression node) => _notAChild(node); |
| 1377 |
| 1378 @override |
| 1379 AstNode visitSwitchCase(SwitchCase node) { |
| 1380 if (node.labels.contains(_oldNode)) { |
| 1381 return _parser.parseLabel(); |
| 1382 } else if (identical(_oldNode, node.expression)) { |
| 1383 return _parser.parseExpression2(); |
| 1384 } else if (node.statements.contains(_oldNode)) { |
| 1385 return _parser.parseStatement2(); |
| 1386 } |
| 1387 return _notAChild(node); |
| 1388 } |
| 1389 |
| 1390 @override |
| 1391 AstNode visitSwitchDefault(SwitchDefault node) { |
| 1392 if (node.labels.contains(_oldNode)) { |
| 1393 return _parser.parseLabel(); |
| 1394 } else if (node.statements.contains(_oldNode)) { |
| 1395 return _parser.parseStatement2(); |
| 1396 } |
| 1397 return _notAChild(node); |
| 1398 } |
| 1399 |
| 1400 @override |
| 1401 AstNode visitSwitchStatement(SwitchStatement node) { |
| 1402 if (identical(_oldNode, node.expression)) { |
| 1403 return _parser.parseExpression2(); |
| 1404 } else if (node.members.contains(_oldNode)) { |
| 1405 throw new InsufficientContextException(); |
| 1406 } |
| 1407 return _notAChild(node); |
| 1408 } |
| 1409 |
| 1410 @override |
| 1411 AstNode visitSymbolLiteral(SymbolLiteral node) => _notAChild(node); |
| 1412 |
| 1413 @override |
| 1414 AstNode visitThisExpression(ThisExpression node) => _notAChild(node); |
| 1415 |
| 1416 @override |
| 1417 AstNode visitThrowExpression(ThrowExpression node) { |
| 1418 if (identical(_oldNode, node.expression)) { |
| 1419 if (_isCascadeAllowedInThrow(node)) { |
| 1420 return _parser.parseExpression2(); |
| 1421 } |
| 1422 return _parser.parseExpressionWithoutCascade(); |
| 1423 } |
| 1424 return _notAChild(node); |
| 1425 } |
| 1426 |
| 1427 @override |
| 1428 AstNode visitTopLevelVariableDeclaration(TopLevelVariableDeclaration node) { |
| 1429 if (identical(_oldNode, node.documentationComment)) { |
| 1430 throw new InsufficientContextException(); |
| 1431 } else if (node.metadata.contains(_oldNode)) { |
| 1432 return _parser.parseAnnotation(); |
| 1433 } else if (identical(_oldNode, node.variables)) { |
| 1434 throw new InsufficientContextException(); |
| 1435 } |
| 1436 return _notAChild(node); |
| 1437 } |
| 1438 |
| 1439 @override |
| 1440 AstNode visitTryStatement(TryStatement node) { |
| 1441 if (identical(_oldNode, node.body)) { |
| 1442 return _parser.parseBlock(); |
| 1443 } else if (node.catchClauses.contains(_oldNode)) { |
| 1444 throw new InsufficientContextException(); |
| 1445 } else if (identical(_oldNode, node.finallyBlock)) { |
| 1446 throw new InsufficientContextException(); |
| 1447 } |
| 1448 return _notAChild(node); |
| 1449 } |
| 1450 |
| 1451 @override |
| 1452 AstNode visitTypeArgumentList(TypeArgumentList node) { |
| 1453 if (node.arguments.contains(_oldNode)) { |
| 1454 return _parser.parseTypeName(); |
| 1455 } |
| 1456 return _notAChild(node); |
| 1457 } |
| 1458 |
| 1459 @override |
| 1460 AstNode visitTypeName(TypeName node) { |
| 1461 if (identical(_oldNode, node.name)) { |
| 1462 return _parser.parsePrefixedIdentifier(); |
| 1463 } else if (identical(_oldNode, node.typeArguments)) { |
| 1464 return _parser.parseTypeArgumentList(); |
| 1465 } |
| 1466 return _notAChild(node); |
| 1467 } |
| 1468 |
| 1469 @override |
| 1470 AstNode visitTypeParameter(TypeParameter node) { |
| 1471 if (identical(_oldNode, node.documentationComment)) { |
| 1472 throw new InsufficientContextException(); |
| 1473 } else if (node.metadata.contains(_oldNode)) { |
| 1474 return _parser.parseAnnotation(); |
| 1475 } else if (identical(_oldNode, node.name)) { |
| 1476 return _parser.parseSimpleIdentifier(); |
| 1477 } else if (identical(_oldNode, node.bound)) { |
| 1478 return _parser.parseTypeName(); |
| 1479 } |
| 1480 return _notAChild(node); |
| 1481 } |
| 1482 |
| 1483 @override |
| 1484 AstNode visitTypeParameterList(TypeParameterList node) { |
| 1485 if (node.typeParameters.contains(node)) { |
| 1486 return _parser.parseTypeParameter(); |
| 1487 } |
| 1488 return _notAChild(node); |
| 1489 } |
| 1490 |
| 1491 @override |
| 1492 AstNode visitVariableDeclaration(VariableDeclaration node) { |
| 1493 if (identical(_oldNode, node.documentationComment)) { |
| 1494 throw new InsufficientContextException(); |
| 1495 } else if (node.metadata.contains(_oldNode)) { |
| 1496 return _parser.parseAnnotation(); |
| 1497 } else if (identical(_oldNode, node.name)) { |
| 1498 throw new InsufficientContextException(); |
| 1499 } else if (identical(_oldNode, node.initializer)) { |
| 1500 throw new InsufficientContextException(); |
| 1501 } |
| 1502 return _notAChild(node); |
| 1503 } |
| 1504 |
| 1505 @override |
| 1506 AstNode visitVariableDeclarationList(VariableDeclarationList node) { |
| 1507 if (identical(_oldNode, node.documentationComment)) { |
| 1508 throw new InsufficientContextException(); |
| 1509 } else if (node.metadata.contains(_oldNode)) { |
| 1510 return _parser.parseAnnotation(); |
| 1511 } else if (identical(_oldNode, node.type)) { |
| 1512 // There is not enough context to know whether we should reparse the type |
| 1513 // using parseReturnType() (which allows 'void') or parseTypeName() |
| 1514 // (which doesn't). Note that even though the language disallows |
| 1515 // variables of type 'void', the parser sometimes accepts them in the |
| 1516 // course of error recovery (e.g. "class C { void v; }" |
| 1517 throw new InsufficientContextException(); |
| 1518 } else if (node.variables.contains(_oldNode)) { |
| 1519 throw new InsufficientContextException(); |
| 1520 } |
| 1521 return _notAChild(node); |
| 1522 } |
| 1523 |
| 1524 @override |
| 1525 AstNode visitVariableDeclarationStatement(VariableDeclarationStatement node) { |
| 1526 if (identical(_oldNode, node.variables)) { |
| 1527 throw new InsufficientContextException(); |
| 1528 } |
| 1529 return _notAChild(node); |
| 1530 } |
| 1531 |
| 1532 @override |
| 1533 AstNode visitWhileStatement(WhileStatement node) { |
| 1534 if (identical(_oldNode, node.condition)) { |
| 1535 return _parser.parseExpression2(); |
| 1536 } else if (identical(_oldNode, node.body)) { |
| 1537 return _parser.parseStatement2(); |
| 1538 } |
| 1539 return _notAChild(node); |
| 1540 } |
| 1541 |
| 1542 @override |
| 1543 AstNode visitWithClause(WithClause node) { |
| 1544 if (node.mixinTypes.contains(node)) { |
| 1545 return _parser.parseTypeName(); |
| 1546 } |
| 1547 return _notAChild(node); |
| 1548 } |
| 1549 |
| 1550 @override |
| 1551 AstNode visitYieldStatement(YieldStatement node) { |
| 1552 if (identical(_oldNode, node.expression)) { |
| 1553 return _parser.parseExpression2(); |
| 1554 } |
| 1555 return _notAChild(node); |
| 1556 } |
| 1557 |
| 1558 /** |
| 1559 * Return `true` if the given assignment [expression] can have a cascade |
| 1560 * expression on the right-hand side. |
| 1561 */ |
| 1562 bool _isCascadeAllowedInAssignment(AssignmentExpression expression) { |
| 1563 // TODO(brianwilkerson) Implement this method. |
| 1564 throw new InsufficientContextException(); |
| 1565 } |
| 1566 |
| 1567 /** |
| 1568 * Return `true` if the given throw [expression] can have a cascade |
| 1569 * expression. |
| 1570 */ |
| 1571 bool _isCascadeAllowedInThrow(ThrowExpression expression) { |
| 1572 // TODO(brianwilkerson) Implement this method. |
| 1573 throw new InsufficientContextException(); |
| 1574 } |
| 1575 |
| 1576 /** |
| 1577 * Throw an exception indicating that the visited [node] was not the parent of |
| 1578 * the node to be replaced. |
| 1579 */ |
| 1580 AstNode _notAChild(AstNode node) { |
| 1581 throw new IncrementalParseException.con1( |
| 1582 "Internal error: the visited node (a ${node.runtimeType}) was not the pa
rent of the node to be replaced (a ${_oldNode.runtimeType})"); |
| 1583 } |
| 1584 } |
| 1585 |
| 1586 /** |
| 1587 * An exception that occurred while attempting to parse a replacement for a |
| 1588 * specified node in an existing AST structure. |
| 1589 */ |
| 1590 class IncrementalParseException extends RuntimeException { |
| 1591 /** |
| 1592 * Initialize a newly created exception to have no message and to be its own |
| 1593 * cause. |
| 1594 */ |
| 1595 IncrementalParseException() : super(); |
| 1596 |
| 1597 /** |
| 1598 * Initialize a newly created exception to have the given [message] and to be |
| 1599 * its own cause. |
| 1600 */ |
| 1601 IncrementalParseException.con1(String message) : super(message: message); |
| 1602 |
| 1603 /** |
| 1604 * Initialize a newly created exception to have no message and to have the |
| 1605 * given [cause]. |
| 1606 */ |
| 1607 IncrementalParseException.con2(Exception cause) : super(cause: cause); |
| 1608 } |
| 1609 |
| 1610 /** |
| 1611 * An object used to re-parse a single AST structure within a larger AST |
| 1612 * structure. |
| 1613 */ |
| 1614 class IncrementalParser { |
| 1615 /** |
| 1616 * The source being parsed. |
| 1617 */ |
| 1618 final Source _source; |
| 1619 |
| 1620 /** |
| 1621 * A map from old tokens to new tokens used during the cloning process. |
| 1622 */ |
| 1623 final TokenMap _tokenMap; |
| 1624 |
| 1625 /** |
| 1626 * The error listener that will be informed of any errors that are found |
| 1627 * during the parse. |
| 1628 */ |
| 1629 final AnalysisErrorListener _errorListener; |
| 1630 |
| 1631 /** |
| 1632 * The node in the AST structure that contains the revised content. |
| 1633 */ |
| 1634 AstNode _updatedNode; |
| 1635 |
| 1636 /** |
| 1637 * Initialize a newly created incremental parser to parse a portion of the |
| 1638 * content of the given [_source]. The [_tokenMap] is a map from old tokens to |
| 1639 * new tokens that is used during the cloning process. The [_errorListener] |
| 1640 * will be informed of any errors that are found during the parse. |
| 1641 */ |
| 1642 IncrementalParser(this._source, this._tokenMap, this._errorListener); |
| 1643 |
| 1644 /** |
| 1645 * Return the node in the AST structure that contains the revised content. |
| 1646 */ |
| 1647 AstNode get updatedNode => _updatedNode; |
| 1648 |
| 1649 /** |
| 1650 * Given a range of tokens that were re-scanned, re-parse the minimum number |
| 1651 * of tokens to produce a consistent AST structure. The range is represented |
| 1652 * by the first and last tokens in the range. |
| 1653 * |
| 1654 * More specifically, the [leftToken] is the token in the new token stream |
| 1655 * immediately to the left of the range of tokens that were inserted and the |
| 1656 * [rightToken] is the token in the new token stream immediately to the right |
| 1657 * of the range of tokens that were inserted. The [originalStart] and |
| 1658 * [originalEnd] are the offsets in the original source of the first and last |
| 1659 * characters that were modified. |
| 1660 * |
| 1661 * The tokens are assumed to be contained in the same token stream. |
| 1662 */ |
| 1663 AstNode reparse(AstNode originalStructure, Token leftToken, Token rightToken, |
| 1664 int originalStart, int originalEnd) { |
| 1665 AstNode oldNode = null; |
| 1666 AstNode newNode = null; |
| 1667 // |
| 1668 // Find the first token that needs to be re-parsed. |
| 1669 // |
| 1670 Token firstToken = leftToken.next; |
| 1671 if (identical(firstToken, rightToken)) { |
| 1672 // If there are no new tokens, then we need to include at least one copied |
| 1673 // node in the range. |
| 1674 firstToken = leftToken; |
| 1675 } |
| 1676 // |
| 1677 // Find the smallest AST node that encompasses the range of re-scanned |
| 1678 // tokens. |
| 1679 // |
| 1680 if (originalEnd < originalStart) { |
| 1681 oldNode = new NodeLocator(originalStart).searchWithin(originalStructure); |
| 1682 } else { |
| 1683 oldNode = new NodeLocator(originalStart, originalEnd) |
| 1684 .searchWithin(originalStructure); |
| 1685 } |
| 1686 // |
| 1687 // Find the token at which parsing is to begin. |
| 1688 // |
| 1689 int originalOffset = oldNode.offset; |
| 1690 Token parseToken = _findTokenAt(firstToken, originalOffset); |
| 1691 if (parseToken == null) { |
| 1692 return null; |
| 1693 } |
| 1694 // |
| 1695 // Parse the appropriate AST structure starting at the appropriate place. |
| 1696 // |
| 1697 Parser parser = new Parser(_source, _errorListener); |
| 1698 parser.currentToken = parseToken; |
| 1699 while (newNode == null) { |
| 1700 AstNode parent = oldNode.parent; |
| 1701 if (parent == null) { |
| 1702 parseToken = _findFirstToken(parseToken); |
| 1703 parser.currentToken = parseToken; |
| 1704 return parser.parseCompilationUnit2(); |
| 1705 } |
| 1706 bool advanceToParent = false; |
| 1707 try { |
| 1708 IncrementalParseDispatcher dispatcher = |
| 1709 new IncrementalParseDispatcher(parser, oldNode); |
| 1710 IncrementalParseStateBuilder contextBuilder = |
| 1711 new IncrementalParseStateBuilder(parser); |
| 1712 contextBuilder.buildState(oldNode); |
| 1713 newNode = parent.accept(dispatcher); |
| 1714 // |
| 1715 // Validate that the new node can replace the old node. |
| 1716 // |
| 1717 Token mappedToken = _tokenMap.get(oldNode.endToken.next); |
| 1718 if (mappedToken == null || |
| 1719 newNode == null || |
| 1720 mappedToken.offset != newNode.endToken.next.offset || |
| 1721 newNode.offset != oldNode.offset) { |
| 1722 advanceToParent = true; |
| 1723 } |
| 1724 } on InsufficientContextException { |
| 1725 advanceToParent = true; |
| 1726 } catch (exception) { |
| 1727 return null; |
| 1728 } |
| 1729 if (advanceToParent) { |
| 1730 newNode = null; |
| 1731 oldNode = parent; |
| 1732 originalOffset = oldNode.offset; |
| 1733 parseToken = _findTokenAt(parseToken, originalOffset); |
| 1734 parser.currentToken = parseToken; |
| 1735 } |
| 1736 } |
| 1737 _updatedNode = newNode; |
| 1738 // |
| 1739 // Replace the old node with the new node in a copy of the original AST |
| 1740 // structure. |
| 1741 // |
| 1742 if (identical(oldNode, originalStructure)) { |
| 1743 // We ended up re-parsing the whole structure, so there's no need for a |
| 1744 // copy. |
| 1745 ResolutionCopier.copyResolutionData(oldNode, newNode); |
| 1746 return newNode; |
| 1747 } |
| 1748 ResolutionCopier.copyResolutionData(oldNode, newNode); |
| 1749 IncrementalAstCloner cloner = |
| 1750 new IncrementalAstCloner(oldNode, newNode, _tokenMap); |
| 1751 return originalStructure.accept(cloner) as AstNode; |
| 1752 } |
| 1753 |
| 1754 /** |
| 1755 * Return the first (non-EOF) token in the token stream containing the |
| 1756 * [firstToken]. |
| 1757 */ |
| 1758 Token _findFirstToken(Token firstToken) { |
| 1759 while (firstToken.type != TokenType.EOF) { |
| 1760 firstToken = firstToken.previous; |
| 1761 } |
| 1762 return firstToken.next; |
| 1763 } |
| 1764 |
| 1765 /** |
| 1766 * Find the token at or before the [firstToken] with the given [offset], or |
| 1767 * `null` if there is no such token. |
| 1768 */ |
| 1769 Token _findTokenAt(Token firstToken, int offset) { |
| 1770 while (firstToken.offset > offset && firstToken.type != TokenType.EOF) { |
| 1771 firstToken = firstToken.previous; |
| 1772 } |
| 1773 return firstToken; |
| 1774 } |
| 1775 } |
| 1776 |
| 1777 /** |
| 1778 * A visitor capable of inferring the correct parser state for incremental |
| 1779 * parsing. This visitor visits each parent/child relationship in the chain of |
| 1780 * ancestors of the node to be replaced (starting with the root of the parse |
| 1781 * tree), updating the parser to the correct state for parsing the child of the |
| 1782 * given parent. Once it has visited all of these relationships, the parser |
| 1783 * will be in the correct state for reparsing the node to be replaced. |
| 1784 */ |
| 1785 class IncrementalParseStateBuilder extends SimpleAstVisitor { |
| 1786 // TODO(paulberry): add support for other pieces of parser state (_inAsync, |
| 1787 // _inGenerator, _inLoop, and _inSwitch). Note that _inLoop and _inSwitch |
| 1788 // only affect error message generation. |
| 1789 |
| 1790 /** |
| 1791 * The parser whose state should be built. |
| 1792 */ |
| 1793 final Parser _parser; |
| 1794 |
| 1795 /** |
| 1796 * The child node in the parent/child relationship currently being visited. |
| 1797 * (The corresponding parent is the node passed to the visit...() function.) |
| 1798 */ |
| 1799 AstNode _childNode; |
| 1800 |
| 1801 /** |
| 1802 * Create an IncrementalParseStateBuilder which will build the correct state |
| 1803 * for [_parser]. |
| 1804 */ |
| 1805 IncrementalParseStateBuilder(this._parser); |
| 1806 |
| 1807 /** |
| 1808 * Build the correct parser state for parsing a replacement for [node]. |
| 1809 */ |
| 1810 void buildState(AstNode node) { |
| 1811 List<AstNode> ancestors = <AstNode>[]; |
| 1812 while (node != null) { |
| 1813 ancestors.add(node); |
| 1814 node = node.parent; |
| 1815 } |
| 1816 _parser._inInitializer = false; |
| 1817 for (int i = ancestors.length - 2; i >= 0; i--) { |
| 1818 _childNode = ancestors[i]; |
| 1819 ancestors[i + 1].accept(this); |
| 1820 } |
| 1821 } |
| 1822 |
| 1823 @override |
| 1824 void visitArgumentList(ArgumentList node) { |
| 1825 _parser._inInitializer = false; |
| 1826 } |
| 1827 |
| 1828 @override |
| 1829 void visitConstructorFieldInitializer(ConstructorFieldInitializer node) { |
| 1830 if (identical(_childNode, node.expression)) { |
| 1831 _parser._inInitializer = true; |
| 1832 } |
| 1833 } |
| 1834 |
| 1835 @override |
| 1836 void visitIndexExpression(IndexExpression node) { |
| 1837 if (identical(_childNode, node.index)) { |
| 1838 _parser._inInitializer = false; |
| 1839 } |
| 1840 } |
| 1841 |
| 1842 @override |
| 1843 void visitInterpolationExpression(InterpolationExpression node) { |
| 1844 if (identical(_childNode, node.expression)) { |
| 1845 _parser._inInitializer = false; |
| 1846 } |
| 1847 } |
| 1848 |
| 1849 @override |
| 1850 void visitListLiteral(ListLiteral node) { |
| 1851 if (node.elements.contains(_childNode)) { |
| 1852 _parser._inInitializer = false; |
| 1853 } |
| 1854 } |
| 1855 |
| 1856 @override |
| 1857 void visitMapLiteral(MapLiteral node) { |
| 1858 if (node.entries.contains(_childNode)) { |
| 1859 _parser._inInitializer = false; |
| 1860 } |
| 1861 } |
| 1862 |
| 1863 @override |
| 1864 void visitParenthesizedExpression(ParenthesizedExpression node) { |
| 1865 if (identical(_childNode, node.expression)) { |
| 1866 _parser._inInitializer = false; |
| 1867 } |
| 1868 } |
| 1869 } |
| 1870 |
| 1871 /** |
| 1872 * An exception indicating that an AST node cannot be re-parsed because there is |
| 1873 * not enough context to know how to re-parse the node. Clients can attempt to |
| 1874 * re-parse the parent of the node. |
| 1875 */ |
| 1876 class InsufficientContextException extends IncrementalParseException { |
| 1877 /** |
| 1878 * Initialize a newly created exception to have no message and to be its own |
| 1879 * cause. |
| 1880 */ |
| 1881 InsufficientContextException() : super(); |
| 1882 |
| 1883 /** |
| 1884 * Initialize a newly created exception to have the given [message] and to be |
| 1885 * its own cause. |
| 1886 */ |
| 1887 InsufficientContextException.con1(String message) : super.con1(message); |
| 1888 |
| 1889 /** |
| 1890 * Initialize a newly created exception to have no message and to have the |
| 1891 * given [cause]. |
| 1892 */ |
| 1893 InsufficientContextException.con2(Exception cause) : super.con2(cause); |
| 1894 } |
| 1895 |
| 1896 /** |
| 1897 * Wrapper around [Function] which should be called with "target" and |
| 1898 * "arguments". |
| 1899 */ |
| 1900 class MethodTrampoline { |
| 1901 int parameterCount; |
| 1902 Function trampoline; |
| 1903 MethodTrampoline(this.parameterCount, this.trampoline); |
| 1904 Object invoke(target, List arguments) { |
| 1905 if (arguments.length != parameterCount) { |
| 1906 throw new IllegalArgumentException( |
| 1907 "${arguments.length} != $parameterCount"); |
| 1908 } |
| 1909 switch (parameterCount) { |
| 1910 case 0: |
| 1911 return trampoline(target); |
| 1912 case 1: |
| 1913 return trampoline(target, arguments[0]); |
| 1914 case 2: |
| 1915 return trampoline(target, arguments[0], arguments[1]); |
| 1916 case 3: |
| 1917 return trampoline(target, arguments[0], arguments[1], arguments[2]); |
| 1918 case 4: |
| 1919 return trampoline( |
| 1920 target, arguments[0], arguments[1], arguments[2], arguments[3]); |
| 1921 default: |
| 1922 throw new IllegalArgumentException("Not implemented for > 4 arguments"); |
| 1923 } |
| 1924 } |
| 1925 } |
| 1926 |
| 1927 /** |
| 1928 * A simple data-holder for a method that needs to return multiple values. |
| 1929 */ |
| 1930 class Modifiers { |
| 1931 /** |
| 1932 * The token representing the keyword 'abstract', or `null` if the keyword was |
| 1933 * not found. |
| 1934 */ |
| 1935 Token abstractKeyword; |
| 1936 |
| 1937 /** |
| 1938 * The token representing the keyword 'const', or `null` if the keyword was |
| 1939 * not found. |
| 1940 */ |
| 1941 Token constKeyword; |
| 1942 |
| 1943 /** |
| 1944 * The token representing the keyword 'external', or `null` if the keyword was |
| 1945 * not found. |
| 1946 */ |
| 1947 Token externalKeyword; |
| 1948 |
| 1949 /** |
| 1950 * The token representing the keyword 'factory', or `null` if the keyword was |
| 1951 * not found. |
| 1952 */ |
| 1953 Token factoryKeyword; |
| 1954 |
| 1955 /** |
| 1956 * The token representing the keyword 'final', or `null` if the keyword was |
| 1957 * not found. |
| 1958 */ |
| 1959 Token finalKeyword; |
| 1960 |
| 1961 /** |
| 1962 * The token representing the keyword 'static', or `null` if the keyword was |
| 1963 * not found. |
| 1964 */ |
| 1965 Token staticKeyword; |
| 1966 |
| 1967 /** |
| 1968 * The token representing the keyword 'var', or `null` if the keyword was not |
| 1969 * found. |
| 1970 */ |
| 1971 Token varKeyword; |
| 1972 |
| 1973 @override |
| 1974 String toString() { |
| 1975 StringBuffer buffer = new StringBuffer(); |
| 1976 bool needsSpace = _appendKeyword(buffer, false, abstractKeyword); |
| 1977 needsSpace = _appendKeyword(buffer, needsSpace, constKeyword); |
| 1978 needsSpace = _appendKeyword(buffer, needsSpace, externalKeyword); |
| 1979 needsSpace = _appendKeyword(buffer, needsSpace, factoryKeyword); |
| 1980 needsSpace = _appendKeyword(buffer, needsSpace, finalKeyword); |
| 1981 needsSpace = _appendKeyword(buffer, needsSpace, staticKeyword); |
| 1982 _appendKeyword(buffer, needsSpace, varKeyword); |
| 1983 return buffer.toString(); |
| 1984 } |
| 1985 |
| 1986 /** |
| 1987 * If the given [keyword] is not `null`, append it to the given [builder], |
| 1988 * prefixing it with a space if [needsSpace] is `true`. Return `true` if |
| 1989 * subsequent keywords need to be prefixed with a space. |
| 1990 */ |
| 1991 bool _appendKeyword(StringBuffer buffer, bool needsSpace, Token keyword) { |
| 1992 if (keyword != null) { |
| 1993 if (needsSpace) { |
| 1994 buffer.writeCharCode(0x20); |
| 1995 } |
| 1996 buffer.write(keyword.lexeme); |
| 1997 return true; |
| 1998 } |
| 1999 return needsSpace; |
| 2000 } |
| 2001 } |
| 2002 |
| 2003 /** |
| 2004 * A parser used to parse tokens into an AST structure. |
| 2005 */ |
| 2006 class Parser { |
| 2007 static String ASYNC = "async"; |
| 2008 |
| 2009 static String _AWAIT = "await"; |
| 2010 |
| 2011 static String _HIDE = "hide"; |
| 2012 |
| 2013 static String _OF = "of"; |
| 2014 |
| 2015 static String _ON = "on"; |
| 2016 |
| 2017 static String _NATIVE = "native"; |
| 2018 |
| 2019 static String _SHOW = "show"; |
| 2020 |
| 2021 static String SYNC = "sync"; |
| 2022 |
| 2023 static String _YIELD = "yield"; |
| 2024 |
| 2025 /** |
| 2026 * The source being parsed. |
| 2027 */ |
| 2028 final Source _source; |
| 2029 |
| 2030 /** |
| 2031 * The error listener that will be informed of any errors that are found |
| 2032 * during the parse. |
| 2033 */ |
| 2034 final AnalysisErrorListener _errorListener; |
| 2035 |
| 2036 /** |
| 2037 * An [errorListener] lock, if more than `0`, then errors are not reported. |
| 2038 */ |
| 2039 int _errorListenerLock = 0; |
| 2040 |
| 2041 /** |
| 2042 * A flag indicating whether parser is to parse function bodies. |
| 2043 */ |
| 2044 bool _parseFunctionBodies = true; |
| 2045 |
| 2046 /** |
| 2047 * The next token to be parsed. |
| 2048 */ |
| 2049 Token _currentToken; |
| 2050 |
| 2051 /** |
| 2052 * A flag indicating whether the parser is currently in a function body marked |
| 2053 * as being 'async'. |
| 2054 */ |
| 2055 bool _inAsync = false; |
| 2056 |
| 2057 /** |
| 2058 * A flag indicating whether the parser is currently in a function body marked |
| 2059 * as being 'async'. |
| 2060 */ |
| 2061 bool _inGenerator = false; |
| 2062 |
| 2063 /** |
| 2064 * A flag indicating whether the parser is currently in the body of a loop. |
| 2065 */ |
| 2066 bool _inLoop = false; |
| 2067 |
| 2068 /** |
| 2069 * A flag indicating whether the parser is currently in a switch statement. |
| 2070 */ |
| 2071 bool _inSwitch = false; |
| 2072 |
| 2073 /** |
| 2074 * A flag indicating whether the parser is currently in a constructor field |
| 2075 * initializer, with no intervening parens, braces, or brackets. |
| 2076 */ |
| 2077 bool _inInitializer = false; |
| 2078 |
| 2079 /** |
| 2080 * A flag indicating whether the parser is to parse generic method syntax. |
| 2081 */ |
| 2082 bool parseGenericMethods = false; |
| 2083 |
| 2084 /** |
| 2085 * Initialize a newly created parser to parse the content of the given |
| 2086 * [_source] and to report any errors that are found to the given |
| 2087 * [_errorListener]. |
| 2088 */ |
| 2089 Parser(this._source, this._errorListener); |
| 2090 |
| 2091 void set currentToken(Token currentToken) { |
| 2092 this._currentToken = currentToken; |
| 2093 } |
| 2094 |
| 2095 /** |
| 2096 * Return `true` if the current token is the first token of a return type that |
| 2097 * is followed by an identifier, possibly followed by a list of type |
| 2098 * parameters, followed by a left-parenthesis. This is used by |
| 2099 * [_parseTypeAlias] to determine whether or not to parse a return type. |
| 2100 */ |
| 2101 bool get hasReturnTypeInTypeAlias { |
| 2102 Token next = _skipReturnType(_currentToken); |
| 2103 if (next == null) { |
| 2104 return false; |
| 2105 } |
| 2106 return _tokenMatchesIdentifier(next); |
| 2107 } |
| 2108 |
| 2109 /** |
| 2110 * Set whether the parser is to parse the async support. |
| 2111 */ |
| 2112 @deprecated |
| 2113 void set parseAsync(bool parseAsync) { |
| 2114 // Async support cannot be disabled |
| 2115 } |
| 2116 |
| 2117 /** |
| 2118 * Set whether the parser is to parse deferred libraries. |
| 2119 */ |
| 2120 @deprecated |
| 2121 void set parseDeferredLibraries(bool parseDeferredLibraries) { |
| 2122 // Deferred libraries support cannot be disabled |
| 2123 } |
| 2124 |
| 2125 /** |
| 2126 * Set whether the parser is to parse enum declarations. |
| 2127 */ |
| 2128 @deprecated |
| 2129 void set parseEnum(bool parseEnum) { |
| 2130 // Enum support cannot be disabled |
| 2131 } |
| 2132 |
| 2133 /** |
| 2134 * Set whether parser is to parse function bodies. |
| 2135 */ |
| 2136 void set parseFunctionBodies(bool parseFunctionBodies) { |
| 2137 this._parseFunctionBodies = parseFunctionBodies; |
| 2138 } |
| 2139 |
| 2140 /** |
| 2141 * Advance to the next token in the token stream, making it the new current |
| 2142 * token and return the token that was current before this method was invoked. |
| 2143 */ |
| 2144 Token getAndAdvance() { |
| 2145 Token token = _currentToken; |
| 2146 _advance(); |
| 2147 return token; |
| 2148 } |
| 2149 |
| 2150 /** |
| 2151 * Parse an annotation. Return the annotation that was parsed. |
| 2152 * |
| 2153 * annotation ::= |
| 2154 * '@' qualified ('.' identifier)? arguments? |
| 2155 * |
| 2156 */ |
| 2157 Annotation parseAnnotation() { |
| 2158 Token atSign = _expect(TokenType.AT); |
| 2159 Identifier name = parsePrefixedIdentifier(); |
| 2160 Token period = null; |
| 2161 SimpleIdentifier constructorName = null; |
| 2162 if (_matches(TokenType.PERIOD)) { |
| 2163 period = getAndAdvance(); |
| 2164 constructorName = parseSimpleIdentifier(); |
| 2165 } |
| 2166 ArgumentList arguments = null; |
| 2167 if (_matches(TokenType.OPEN_PAREN)) { |
| 2168 arguments = parseArgumentList(); |
| 2169 } |
| 2170 return new Annotation(atSign, name, period, constructorName, arguments); |
| 2171 } |
| 2172 |
| 2173 /** |
| 2174 * Parse an argument. Return the argument that was parsed. |
| 2175 * |
| 2176 * argument ::= |
| 2177 * namedArgument |
| 2178 * | expression |
| 2179 * |
| 2180 * namedArgument ::= |
| 2181 * label expression |
| 2182 */ |
| 2183 Expression parseArgument() { |
| 2184 // |
| 2185 // Both namedArgument and expression can start with an identifier, but only |
| 2186 // namedArgument can have an identifier followed by a colon. |
| 2187 // |
| 2188 if (_matchesIdentifier() && _tokenMatches(_peek(), TokenType.COLON)) { |
| 2189 return new NamedExpression(parseLabel(), parseExpression2()); |
| 2190 } else { |
| 2191 return parseExpression2(); |
| 2192 } |
| 2193 } |
| 2194 |
| 2195 /** |
| 2196 * Parse a list of arguments. Return the argument list that was parsed. |
| 2197 * |
| 2198 * arguments ::= |
| 2199 * '(' argumentList? ')' |
| 2200 * |
| 2201 * argumentList ::= |
| 2202 * namedArgument (',' namedArgument)* |
| 2203 * | expressionList (',' namedArgument)* |
| 2204 */ |
| 2205 ArgumentList parseArgumentList() { |
| 2206 Token leftParenthesis = _expect(TokenType.OPEN_PAREN); |
| 2207 List<Expression> arguments = new List<Expression>(); |
| 2208 if (_matches(TokenType.CLOSE_PAREN)) { |
| 2209 return new ArgumentList(leftParenthesis, arguments, getAndAdvance()); |
| 2210 } |
| 2211 // |
| 2212 // Even though unnamed arguments must all appear before any named arguments, |
| 2213 // we allow them to appear in any order so that we can recover faster. |
| 2214 // |
| 2215 bool wasInInitializer = _inInitializer; |
| 2216 _inInitializer = false; |
| 2217 try { |
| 2218 Expression argument = parseArgument(); |
| 2219 arguments.add(argument); |
| 2220 bool foundNamedArgument = argument is NamedExpression; |
| 2221 bool generatedError = false; |
| 2222 while (_optional(TokenType.COMMA)) { |
| 2223 argument = parseArgument(); |
| 2224 arguments.add(argument); |
| 2225 if (foundNamedArgument) { |
| 2226 bool blankArgument = |
| 2227 argument is SimpleIdentifier && argument.name.isEmpty; |
| 2228 if (!generatedError && |
| 2229 !(argument is NamedExpression && !blankArgument)) { |
| 2230 // Report the error, once, but allow the arguments to be in any |
| 2231 // order in the AST. |
| 2232 _reportErrorForCurrentToken( |
| 2233 ParserErrorCode.POSITIONAL_AFTER_NAMED_ARGUMENT); |
| 2234 generatedError = true; |
| 2235 } |
| 2236 } else if (argument is NamedExpression) { |
| 2237 foundNamedArgument = true; |
| 2238 } |
| 2239 } |
| 2240 // TODO(brianwilkerson) Recovery: Look at the left parenthesis to see |
| 2241 // whether there is a matching right parenthesis. If there is, then we're |
| 2242 // more likely missing a comma and should go back to parsing arguments. |
| 2243 Token rightParenthesis = _expect(TokenType.CLOSE_PAREN); |
| 2244 return new ArgumentList(leftParenthesis, arguments, rightParenthesis); |
| 2245 } finally { |
| 2246 _inInitializer = wasInInitializer; |
| 2247 } |
| 2248 } |
| 2249 |
| 2250 /** |
| 2251 * Parse a bitwise or expression. Return the bitwise or expression that was |
| 2252 * parsed. |
| 2253 * |
| 2254 * bitwiseOrExpression ::= |
| 2255 * bitwiseXorExpression ('|' bitwiseXorExpression)* |
| 2256 * | 'super' ('|' bitwiseXorExpression)+ |
| 2257 */ |
| 2258 Expression parseBitwiseOrExpression() { |
| 2259 Expression expression; |
| 2260 if (_matchesKeyword(Keyword.SUPER) && |
| 2261 _tokenMatches(_peek(), TokenType.BAR)) { |
| 2262 expression = new SuperExpression(getAndAdvance()); |
| 2263 } else { |
| 2264 expression = _parseBitwiseXorExpression(); |
| 2265 } |
| 2266 while (_matches(TokenType.BAR)) { |
| 2267 Token operator = getAndAdvance(); |
| 2268 expression = new BinaryExpression( |
| 2269 expression, operator, _parseBitwiseXorExpression()); |
| 2270 } |
| 2271 return expression; |
| 2272 } |
| 2273 |
| 2274 /** |
| 2275 * Parse a block. Return the block that was parsed. |
| 2276 * |
| 2277 * block ::= |
| 2278 * '{' statements '}' |
| 2279 */ |
| 2280 Block parseBlock() { |
| 2281 Token leftBracket = _expect(TokenType.OPEN_CURLY_BRACKET); |
| 2282 List<Statement> statements = new List<Statement>(); |
| 2283 Token statementStart = _currentToken; |
| 2284 while ( |
| 2285 !_matches(TokenType.EOF) && !_matches(TokenType.CLOSE_CURLY_BRACKET)) { |
| 2286 Statement statement = parseStatement2(); |
| 2287 if (statement != null) { |
| 2288 statements.add(statement); |
| 2289 } |
| 2290 if (identical(_currentToken, statementStart)) { |
| 2291 // Ensure that we are making progress and report an error if we're not. |
| 2292 _reportErrorForToken(ParserErrorCode.UNEXPECTED_TOKEN, _currentToken, |
| 2293 [_currentToken.lexeme]); |
| 2294 _advance(); |
| 2295 } |
| 2296 statementStart = _currentToken; |
| 2297 } |
| 2298 Token rightBracket = _expect(TokenType.CLOSE_CURLY_BRACKET); |
| 2299 return new Block(leftBracket, statements, rightBracket); |
| 2300 } |
| 2301 |
| 2302 /** |
| 2303 * Parse a class member. The [className] is the name of the class containing |
| 2304 * the member being parsed. Return the class member that was parsed, or `null` |
| 2305 * if what was found was not a valid class member. |
| 2306 * |
| 2307 * classMemberDefinition ::= |
| 2308 * declaration ';' |
| 2309 * | methodSignature functionBody |
| 2310 */ |
| 2311 ClassMember parseClassMember(String className) { |
| 2312 CommentAndMetadata commentAndMetadata = _parseCommentAndMetadata(); |
| 2313 Modifiers modifiers = _parseModifiers(); |
| 2314 if (_matchesKeyword(Keyword.VOID)) { |
| 2315 TypeName returnType = parseReturnType(); |
| 2316 if (_matchesKeyword(Keyword.GET) && _tokenMatchesIdentifier(_peek())) { |
| 2317 _validateModifiersForGetterOrSetterOrMethod(modifiers); |
| 2318 return _parseGetter(commentAndMetadata, modifiers.externalKeyword, |
| 2319 modifiers.staticKeyword, returnType); |
| 2320 } else if (_matchesKeyword(Keyword.SET) && |
| 2321 _tokenMatchesIdentifier(_peek())) { |
| 2322 _validateModifiersForGetterOrSetterOrMethod(modifiers); |
| 2323 return _parseSetter(commentAndMetadata, modifiers.externalKeyword, |
| 2324 modifiers.staticKeyword, returnType); |
| 2325 } else if (_matchesKeyword(Keyword.OPERATOR) && _isOperator(_peek())) { |
| 2326 _validateModifiersForOperator(modifiers); |
| 2327 return _parseOperator( |
| 2328 commentAndMetadata, modifiers.externalKeyword, returnType); |
| 2329 } else if (_matchesIdentifier() && |
| 2330 _peek().matchesAny([ |
| 2331 TokenType.OPEN_PAREN, |
| 2332 TokenType.OPEN_CURLY_BRACKET, |
| 2333 TokenType.FUNCTION, |
| 2334 TokenType.LT |
| 2335 ])) { |
| 2336 _validateModifiersForGetterOrSetterOrMethod(modifiers); |
| 2337 return _parseMethodDeclarationAfterReturnType(commentAndMetadata, |
| 2338 modifiers.externalKeyword, modifiers.staticKeyword, returnType); |
| 2339 } else { |
| 2340 // |
| 2341 // We have found an error of some kind. Try to recover. |
| 2342 // |
| 2343 if (_matchesIdentifier()) { |
| 2344 if (_peek().matchesAny( |
| 2345 [TokenType.EQ, TokenType.COMMA, TokenType.SEMICOLON])) { |
| 2346 // |
| 2347 // We appear to have a variable declaration with a type of "void". |
| 2348 // |
| 2349 _reportErrorForNode(ParserErrorCode.VOID_VARIABLE, returnType); |
| 2350 return _parseInitializedIdentifierList(commentAndMetadata, |
| 2351 modifiers.staticKeyword, _validateModifiersForField(modifiers), |
| 2352 returnType); |
| 2353 } |
| 2354 } |
| 2355 if (_isOperator(_currentToken)) { |
| 2356 // |
| 2357 // We appear to have found an operator declaration without the |
| 2358 // 'operator' keyword. |
| 2359 // |
| 2360 _validateModifiersForOperator(modifiers); |
| 2361 return _parseOperator( |
| 2362 commentAndMetadata, modifiers.externalKeyword, returnType); |
| 2363 } |
| 2364 _reportErrorForToken( |
| 2365 ParserErrorCode.EXPECTED_EXECUTABLE, _currentToken); |
| 2366 return null; |
| 2367 } |
| 2368 } else if (_matchesKeyword(Keyword.GET) && |
| 2369 _tokenMatchesIdentifier(_peek())) { |
| 2370 _validateModifiersForGetterOrSetterOrMethod(modifiers); |
| 2371 return _parseGetter(commentAndMetadata, modifiers.externalKeyword, |
| 2372 modifiers.staticKeyword, null); |
| 2373 } else if (_matchesKeyword(Keyword.SET) && |
| 2374 _tokenMatchesIdentifier(_peek())) { |
| 2375 _validateModifiersForGetterOrSetterOrMethod(modifiers); |
| 2376 return _parseSetter(commentAndMetadata, modifiers.externalKeyword, |
| 2377 modifiers.staticKeyword, null); |
| 2378 } else if (_matchesKeyword(Keyword.OPERATOR) && _isOperator(_peek())) { |
| 2379 _validateModifiersForOperator(modifiers); |
| 2380 return _parseOperator( |
| 2381 commentAndMetadata, modifiers.externalKeyword, null); |
| 2382 } else if (!_matchesIdentifier()) { |
| 2383 // |
| 2384 // Recover from an error. |
| 2385 // |
| 2386 if (_matchesKeyword(Keyword.CLASS)) { |
| 2387 _reportErrorForCurrentToken(ParserErrorCode.CLASS_IN_CLASS); |
| 2388 // TODO(brianwilkerson) We don't currently have any way to capture the |
| 2389 // class that was parsed. |
| 2390 _parseClassDeclaration(commentAndMetadata, null); |
| 2391 return null; |
| 2392 } else if (_matchesKeyword(Keyword.ABSTRACT) && |
| 2393 _tokenMatchesKeyword(_peek(), Keyword.CLASS)) { |
| 2394 _reportErrorForToken(ParserErrorCode.CLASS_IN_CLASS, _peek()); |
| 2395 // TODO(brianwilkerson) We don't currently have any way to capture the |
| 2396 // class that was parsed. |
| 2397 _parseClassDeclaration(commentAndMetadata, getAndAdvance()); |
| 2398 return null; |
| 2399 } else if (_matchesKeyword(Keyword.ENUM)) { |
| 2400 _reportErrorForToken(ParserErrorCode.ENUM_IN_CLASS, _peek()); |
| 2401 // TODO(brianwilkerson) We don't currently have any way to capture the |
| 2402 // enum that was parsed. |
| 2403 _parseEnumDeclaration(commentAndMetadata); |
| 2404 return null; |
| 2405 } else if (_isOperator(_currentToken)) { |
| 2406 // |
| 2407 // We appear to have found an operator declaration without the |
| 2408 // 'operator' keyword. |
| 2409 // |
| 2410 _validateModifiersForOperator(modifiers); |
| 2411 return _parseOperator( |
| 2412 commentAndMetadata, modifiers.externalKeyword, null); |
| 2413 } |
| 2414 Token keyword = modifiers.varKeyword; |
| 2415 if (keyword == null) { |
| 2416 keyword = modifiers.finalKeyword; |
| 2417 } |
| 2418 if (keyword == null) { |
| 2419 keyword = modifiers.constKeyword; |
| 2420 } |
| 2421 if (keyword != null) { |
| 2422 // |
| 2423 // We appear to have found an incomplete field declaration. |
| 2424 // |
| 2425 _reportErrorForCurrentToken(ParserErrorCode.MISSING_IDENTIFIER); |
| 2426 List<VariableDeclaration> variables = new List<VariableDeclaration>(); |
| 2427 variables.add( |
| 2428 new VariableDeclaration(_createSyntheticIdentifier(), null, null)); |
| 2429 return new FieldDeclaration(commentAndMetadata.comment, |
| 2430 commentAndMetadata.metadata, null, |
| 2431 new VariableDeclarationList(null, null, keyword, null, variables), |
| 2432 _expectSemicolon()); |
| 2433 } |
| 2434 _reportErrorForToken( |
| 2435 ParserErrorCode.EXPECTED_CLASS_MEMBER, _currentToken); |
| 2436 if (commentAndMetadata.comment != null || |
| 2437 !commentAndMetadata.metadata.isEmpty) { |
| 2438 // |
| 2439 // We appear to have found an incomplete declaration at the end of the |
| 2440 // class. At this point it consists of a metadata, which we don't want |
| 2441 // to loose, so we'll treat it as a method declaration with a missing |
| 2442 // name, parameters and empty body. |
| 2443 // |
| 2444 return new MethodDeclaration(commentAndMetadata.comment, |
| 2445 commentAndMetadata.metadata, null, null, null, null, null, |
| 2446 _createSyntheticIdentifier(), null, new FormalParameterList( |
| 2447 null, new List<FormalParameter>(), null, null, null), |
| 2448 new EmptyFunctionBody(_createSyntheticToken(TokenType.SEMICOLON))); |
| 2449 } |
| 2450 return null; |
| 2451 } else if (_tokenMatches(_peek(), TokenType.PERIOD) && |
| 2452 _tokenMatchesIdentifier(_peekAt(2)) && |
| 2453 _tokenMatches(_peekAt(3), TokenType.OPEN_PAREN)) { |
| 2454 return _parseConstructor(commentAndMetadata, modifiers.externalKeyword, |
| 2455 _validateModifiersForConstructor(modifiers), modifiers.factoryKeyword, |
| 2456 parseSimpleIdentifier(), getAndAdvance(), parseSimpleIdentifier(), |
| 2457 parseFormalParameterList()); |
| 2458 } else if (_tokenMatches(_peek(), TokenType.OPEN_PAREN)) { |
| 2459 SimpleIdentifier methodName = parseSimpleIdentifier(); |
| 2460 FormalParameterList parameters = parseFormalParameterList(); |
| 2461 if (_matches(TokenType.COLON) || |
| 2462 modifiers.factoryKeyword != null || |
| 2463 methodName.name == className) { |
| 2464 return _parseConstructor(commentAndMetadata, modifiers.externalKeyword, |
| 2465 _validateModifiersForConstructor(modifiers), |
| 2466 modifiers.factoryKeyword, methodName, null, null, parameters); |
| 2467 } |
| 2468 _validateModifiersForGetterOrSetterOrMethod(modifiers); |
| 2469 _validateFormalParameterList(parameters); |
| 2470 return _parseMethodDeclarationAfterParameters(commentAndMetadata, |
| 2471 modifiers.externalKeyword, modifiers.staticKeyword, null, methodName, |
| 2472 null, parameters); |
| 2473 } else if (_peek() |
| 2474 .matchesAny([TokenType.EQ, TokenType.COMMA, TokenType.SEMICOLON])) { |
| 2475 if (modifiers.constKeyword == null && |
| 2476 modifiers.finalKeyword == null && |
| 2477 modifiers.varKeyword == null) { |
| 2478 _reportErrorForCurrentToken( |
| 2479 ParserErrorCode.MISSING_CONST_FINAL_VAR_OR_TYPE); |
| 2480 } |
| 2481 return _parseInitializedIdentifierList(commentAndMetadata, |
| 2482 modifiers.staticKeyword, _validateModifiersForField(modifiers), null); |
| 2483 } else if (_matchesKeyword(Keyword.TYPEDEF)) { |
| 2484 _reportErrorForCurrentToken(ParserErrorCode.TYPEDEF_IN_CLASS); |
| 2485 // TODO(brianwilkerson) We don't currently have any way to capture the |
| 2486 // function type alias that was parsed. |
| 2487 _parseFunctionTypeAlias(commentAndMetadata, getAndAdvance()); |
| 2488 return null; |
| 2489 } else if (parseGenericMethods) { |
| 2490 Token token = _skipTypeParameterList(_peek()); |
| 2491 if (token != null && _tokenMatches(token, TokenType.OPEN_PAREN)) { |
| 2492 return _parseMethodDeclarationAfterReturnType(commentAndMetadata, |
| 2493 modifiers.externalKeyword, modifiers.staticKeyword, null); |
| 2494 } |
| 2495 } |
| 2496 TypeName type = parseTypeName(); |
| 2497 if (_matchesKeyword(Keyword.GET) && _tokenMatchesIdentifier(_peek())) { |
| 2498 _validateModifiersForGetterOrSetterOrMethod(modifiers); |
| 2499 return _parseGetter(commentAndMetadata, modifiers.externalKeyword, |
| 2500 modifiers.staticKeyword, type); |
| 2501 } else if (_matchesKeyword(Keyword.SET) && |
| 2502 _tokenMatchesIdentifier(_peek())) { |
| 2503 _validateModifiersForGetterOrSetterOrMethod(modifiers); |
| 2504 return _parseSetter(commentAndMetadata, modifiers.externalKeyword, |
| 2505 modifiers.staticKeyword, type); |
| 2506 } else if (_matchesKeyword(Keyword.OPERATOR) && _isOperator(_peek())) { |
| 2507 _validateModifiersForOperator(modifiers); |
| 2508 return _parseOperator( |
| 2509 commentAndMetadata, modifiers.externalKeyword, type); |
| 2510 } else if (!_matchesIdentifier()) { |
| 2511 if (_matches(TokenType.CLOSE_CURLY_BRACKET)) { |
| 2512 // |
| 2513 // We appear to have found an incomplete declaration at the end of the |
| 2514 // class. At this point it consists of a type name, so we'll treat it as |
| 2515 // a field declaration with a missing field name and semicolon. |
| 2516 // |
| 2517 return _parseInitializedIdentifierList(commentAndMetadata, |
| 2518 modifiers.staticKeyword, _validateModifiersForField(modifiers), |
| 2519 type); |
| 2520 } |
| 2521 if (_isOperator(_currentToken)) { |
| 2522 // |
| 2523 // We appear to have found an operator declaration without the |
| 2524 // 'operator' keyword. |
| 2525 // |
| 2526 _validateModifiersForOperator(modifiers); |
| 2527 return _parseOperator( |
| 2528 commentAndMetadata, modifiers.externalKeyword, type); |
| 2529 } |
| 2530 // |
| 2531 // We appear to have found an incomplete declaration before another |
| 2532 // declaration. At this point it consists of a type name, so we'll treat |
| 2533 // it as a field declaration with a missing field name and semicolon. |
| 2534 // |
| 2535 _reportErrorForToken( |
| 2536 ParserErrorCode.EXPECTED_CLASS_MEMBER, _currentToken); |
| 2537 try { |
| 2538 _lockErrorListener(); |
| 2539 return _parseInitializedIdentifierList(commentAndMetadata, |
| 2540 modifiers.staticKeyword, _validateModifiersForField(modifiers), |
| 2541 type); |
| 2542 } finally { |
| 2543 _unlockErrorListener(); |
| 2544 } |
| 2545 } else if (_tokenMatches(_peek(), TokenType.OPEN_PAREN)) { |
| 2546 SimpleIdentifier methodName = parseSimpleIdentifier(); |
| 2547 FormalParameterList parameters = parseFormalParameterList(); |
| 2548 if (methodName.name == className) { |
| 2549 _reportErrorForNode(ParserErrorCode.CONSTRUCTOR_WITH_RETURN_TYPE, type); |
| 2550 return _parseConstructor(commentAndMetadata, modifiers.externalKeyword, |
| 2551 _validateModifiersForConstructor(modifiers), |
| 2552 modifiers.factoryKeyword, methodName, null, null, parameters); |
| 2553 } |
| 2554 _validateModifiersForGetterOrSetterOrMethod(modifiers); |
| 2555 _validateFormalParameterList(parameters); |
| 2556 return _parseMethodDeclarationAfterParameters(commentAndMetadata, |
| 2557 modifiers.externalKeyword, modifiers.staticKeyword, type, methodName, |
| 2558 null, parameters); |
| 2559 } else if (parseGenericMethods && _tokenMatches(_peek(), TokenType.LT)) { |
| 2560 return _parseMethodDeclarationAfterReturnType(commentAndMetadata, |
| 2561 modifiers.externalKeyword, modifiers.staticKeyword, type); |
| 2562 } else if (_tokenMatches(_peek(), TokenType.OPEN_CURLY_BRACKET)) { |
| 2563 // We have found "TypeName identifier {", and are guessing that this is a |
| 2564 // getter without the keyword 'get'. |
| 2565 _validateModifiersForGetterOrSetterOrMethod(modifiers); |
| 2566 _reportErrorForCurrentToken(ParserErrorCode.MISSING_GET); |
| 2567 _currentToken = _injectToken( |
| 2568 new Parser_SyntheticKeywordToken(Keyword.GET, _currentToken.offset)); |
| 2569 return _parseGetter(commentAndMetadata, modifiers.externalKeyword, |
| 2570 modifiers.staticKeyword, type); |
| 2571 } |
| 2572 return _parseInitializedIdentifierList(commentAndMetadata, |
| 2573 modifiers.staticKeyword, _validateModifiersForField(modifiers), type); |
| 2574 } |
| 2575 |
| 2576 /** |
| 2577 * Parse a single combinator. Return the combinator that was parsed, or `null` |
| 2578 * if no combinator is found. |
| 2579 * |
| 2580 * combinator ::= |
| 2581 * 'show' identifier (',' identifier)* |
| 2582 * | 'hide' identifier (',' identifier)* |
| 2583 */ |
| 2584 Combinator parseCombinator() { |
| 2585 if (_matchesString(_SHOW) || _matchesString(_HIDE)) { |
| 2586 Token keyword = getAndAdvance(); |
| 2587 List<SimpleIdentifier> names = _parseIdentifierList(); |
| 2588 if (keyword.lexeme == _SHOW) { |
| 2589 return new ShowCombinator(keyword, names); |
| 2590 } else { |
| 2591 return new HideCombinator(keyword, names); |
| 2592 } |
| 2593 } |
| 2594 return null; |
| 2595 } |
| 2596 |
| 2597 /** |
| 2598 * Parse a compilation unit, starting with the given [token]. Return the |
| 2599 * compilation unit that was parsed. |
| 2600 */ |
| 2601 CompilationUnit parseCompilationUnit(Token token) { |
| 2602 _currentToken = token; |
| 2603 return parseCompilationUnit2(); |
| 2604 } |
| 2605 |
| 2606 /** |
| 2607 * Parse a compilation unit. Return the compilation unit that was parsed. |
| 2608 * |
| 2609 * Specified: |
| 2610 * |
| 2611 * compilationUnit ::= |
| 2612 * scriptTag? directive* topLevelDeclaration* |
| 2613 * |
| 2614 * Actual: |
| 2615 * |
| 2616 * compilationUnit ::= |
| 2617 * scriptTag? topLevelElement* |
| 2618 * |
| 2619 * topLevelElement ::= |
| 2620 * directive |
| 2621 * | topLevelDeclaration |
| 2622 */ |
| 2623 CompilationUnit parseCompilationUnit2() { |
| 2624 Token firstToken = _currentToken; |
| 2625 ScriptTag scriptTag = null; |
| 2626 if (_matches(TokenType.SCRIPT_TAG)) { |
| 2627 scriptTag = new ScriptTag(getAndAdvance()); |
| 2628 } |
| 2629 // |
| 2630 // Even though all directives must appear before declarations and must occur |
| 2631 // in a given order, we allow directives and declarations to occur in any |
| 2632 // order so that we can recover better. |
| 2633 // |
| 2634 bool libraryDirectiveFound = false; |
| 2635 bool partOfDirectiveFound = false; |
| 2636 bool partDirectiveFound = false; |
| 2637 bool directiveFoundAfterDeclaration = false; |
| 2638 List<Directive> directives = new List<Directive>(); |
| 2639 List<CompilationUnitMember> declarations = |
| 2640 new List<CompilationUnitMember>(); |
| 2641 Token memberStart = _currentToken; |
| 2642 while (!_matches(TokenType.EOF)) { |
| 2643 CommentAndMetadata commentAndMetadata = _parseCommentAndMetadata(); |
| 2644 if ((_matchesKeyword(Keyword.IMPORT) || |
| 2645 _matchesKeyword(Keyword.EXPORT) || |
| 2646 _matchesKeyword(Keyword.LIBRARY) || |
| 2647 _matchesKeyword(Keyword.PART)) && |
| 2648 !_tokenMatches(_peek(), TokenType.PERIOD) && |
| 2649 !_tokenMatches(_peek(), TokenType.LT) && |
| 2650 !_tokenMatches(_peek(), TokenType.OPEN_PAREN)) { |
| 2651 Directive directive = _parseDirective(commentAndMetadata); |
| 2652 if (declarations.length > 0 && !directiveFoundAfterDeclaration) { |
| 2653 _reportErrorForToken(ParserErrorCode.DIRECTIVE_AFTER_DECLARATION, |
| 2654 directive.beginToken); |
| 2655 directiveFoundAfterDeclaration = true; |
| 2656 } |
| 2657 if (directive is LibraryDirective) { |
| 2658 if (libraryDirectiveFound) { |
| 2659 _reportErrorForCurrentToken( |
| 2660 ParserErrorCode.MULTIPLE_LIBRARY_DIRECTIVES); |
| 2661 } else { |
| 2662 if (directives.length > 0) { |
| 2663 _reportErrorForToken(ParserErrorCode.LIBRARY_DIRECTIVE_NOT_FIRST, |
| 2664 directive.libraryKeyword); |
| 2665 } |
| 2666 libraryDirectiveFound = true; |
| 2667 } |
| 2668 } else if (directive is PartDirective) { |
| 2669 partDirectiveFound = true; |
| 2670 } else if (partDirectiveFound) { |
| 2671 if (directive is ExportDirective) { |
| 2672 _reportErrorForToken( |
| 2673 ParserErrorCode.EXPORT_DIRECTIVE_AFTER_PART_DIRECTIVE, |
| 2674 directive.keyword); |
| 2675 } else if (directive is ImportDirective) { |
| 2676 _reportErrorForToken( |
| 2677 ParserErrorCode.IMPORT_DIRECTIVE_AFTER_PART_DIRECTIVE, |
| 2678 directive.keyword); |
| 2679 } |
| 2680 } |
| 2681 if (directive is PartOfDirective) { |
| 2682 if (partOfDirectiveFound) { |
| 2683 _reportErrorForCurrentToken( |
| 2684 ParserErrorCode.MULTIPLE_PART_OF_DIRECTIVES); |
| 2685 } else { |
| 2686 int directiveCount = directives.length; |
| 2687 for (int i = 0; i < directiveCount; i++) { |
| 2688 _reportErrorForToken( |
| 2689 ParserErrorCode.NON_PART_OF_DIRECTIVE_IN_PART, |
| 2690 directives[i].keyword); |
| 2691 } |
| 2692 partOfDirectiveFound = true; |
| 2693 } |
| 2694 } else { |
| 2695 if (partOfDirectiveFound) { |
| 2696 _reportErrorForToken(ParserErrorCode.NON_PART_OF_DIRECTIVE_IN_PART, |
| 2697 directive.keyword); |
| 2698 } |
| 2699 } |
| 2700 directives.add(directive); |
| 2701 } else if (_matches(TokenType.SEMICOLON)) { |
| 2702 _reportErrorForToken(ParserErrorCode.UNEXPECTED_TOKEN, _currentToken, |
| 2703 [_currentToken.lexeme]); |
| 2704 _advance(); |
| 2705 } else { |
| 2706 CompilationUnitMember member = |
| 2707 _parseCompilationUnitMember(commentAndMetadata); |
| 2708 if (member != null) { |
| 2709 declarations.add(member); |
| 2710 } |
| 2711 } |
| 2712 if (identical(_currentToken, memberStart)) { |
| 2713 _reportErrorForToken(ParserErrorCode.UNEXPECTED_TOKEN, _currentToken, |
| 2714 [_currentToken.lexeme]); |
| 2715 _advance(); |
| 2716 while (!_matches(TokenType.EOF) && |
| 2717 !_couldBeStartOfCompilationUnitMember()) { |
| 2718 _advance(); |
| 2719 } |
| 2720 } |
| 2721 memberStart = _currentToken; |
| 2722 } |
| 2723 return new CompilationUnit( |
| 2724 firstToken, scriptTag, directives, declarations, _currentToken); |
| 2725 } |
| 2726 |
| 2727 /** |
| 2728 * Parse a conditional expression. Return the conditional expression that was |
| 2729 * parsed. |
| 2730 * |
| 2731 * conditionalExpression ::= |
| 2732 * ifNullExpression ('?' expressionWithoutCascade ':' expressionWithou
tCascade)? |
| 2733 */ |
| 2734 Expression parseConditionalExpression() { |
| 2735 Expression condition = parseIfNullExpression(); |
| 2736 if (!_matches(TokenType.QUESTION)) { |
| 2737 return condition; |
| 2738 } |
| 2739 Token question = getAndAdvance(); |
| 2740 Expression thenExpression = parseExpressionWithoutCascade(); |
| 2741 Token colon = _expect(TokenType.COLON); |
| 2742 Expression elseExpression = parseExpressionWithoutCascade(); |
| 2743 return new ConditionalExpression( |
| 2744 condition, question, thenExpression, colon, elseExpression); |
| 2745 } |
| 2746 |
| 2747 /** |
| 2748 * Parse the name of a constructor. Return the constructor name that was |
| 2749 * parsed. |
| 2750 * |
| 2751 * constructorName: |
| 2752 * type ('.' identifier)? |
| 2753 */ |
| 2754 ConstructorName parseConstructorName() { |
| 2755 TypeName type = parseTypeName(); |
| 2756 Token period = null; |
| 2757 SimpleIdentifier name = null; |
| 2758 if (_matches(TokenType.PERIOD)) { |
| 2759 period = getAndAdvance(); |
| 2760 name = parseSimpleIdentifier(); |
| 2761 } |
| 2762 return new ConstructorName(type, period, name); |
| 2763 } |
| 2764 |
| 2765 /** |
| 2766 * Parse the script tag and directives in a compilation unit, starting with |
| 2767 * the given [token], until the first non-directive is encountered. The |
| 2768 * remainder of the compilation unit will not be parsed. Specifically, if |
| 2769 * there are directives later in the file, they will not be parsed. Return the |
| 2770 * compilation unit that was parsed. |
| 2771 */ |
| 2772 CompilationUnit parseDirectives(Token token) { |
| 2773 _currentToken = token; |
| 2774 return _parseDirectives(); |
| 2775 } |
| 2776 |
| 2777 /** |
| 2778 * Parse an expression, starting with the given [token]. Return the expression |
| 2779 * that was parsed, or `null` if the tokens do not represent a recognizable |
| 2780 * expression. |
| 2781 */ |
| 2782 Expression parseExpression(Token token) { |
| 2783 _currentToken = token; |
| 2784 return parseExpression2(); |
| 2785 } |
| 2786 |
| 2787 /** |
| 2788 * Parse an expression that might contain a cascade. Return the expression |
| 2789 * that was parsed. |
| 2790 * |
| 2791 * expression ::= |
| 2792 * assignableExpression assignmentOperator expression |
| 2793 * | conditionalExpression cascadeSection* |
| 2794 * | throwExpression |
| 2795 */ |
| 2796 Expression parseExpression2() { |
| 2797 if (_matchesKeyword(Keyword.THROW)) { |
| 2798 return _parseThrowExpression(); |
| 2799 } else if (_matchesKeyword(Keyword.RETHROW)) { |
| 2800 // TODO(brianwilkerson) Rethrow is a statement again. |
| 2801 return _parseRethrowExpression(); |
| 2802 } |
| 2803 // |
| 2804 // assignableExpression is a subset of conditionalExpression, so we can |
| 2805 // parse a conditional expression and then determine whether it is followed |
| 2806 // by an assignmentOperator, checking for conformance to the restricted |
| 2807 // grammar after making that determination. |
| 2808 // |
| 2809 Expression expression = parseConditionalExpression(); |
| 2810 TokenType tokenType = _currentToken.type; |
| 2811 if (tokenType == TokenType.PERIOD_PERIOD) { |
| 2812 List<Expression> cascadeSections = new List<Expression>(); |
| 2813 while (tokenType == TokenType.PERIOD_PERIOD) { |
| 2814 Expression section = _parseCascadeSection(); |
| 2815 if (section != null) { |
| 2816 cascadeSections.add(section); |
| 2817 } |
| 2818 tokenType = _currentToken.type; |
| 2819 } |
| 2820 return new CascadeExpression(expression, cascadeSections); |
| 2821 } else if (tokenType.isAssignmentOperator) { |
| 2822 Token operator = getAndAdvance(); |
| 2823 _ensureAssignable(expression); |
| 2824 return new AssignmentExpression(expression, operator, parseExpression2()); |
| 2825 } |
| 2826 return expression; |
| 2827 } |
| 2828 |
| 2829 /** |
| 2830 * Parse an expression that does not contain any cascades. Return the |
| 2831 * expression that was parsed. |
| 2832 * |
| 2833 * expressionWithoutCascade ::= |
| 2834 * assignableExpression assignmentOperator expressionWithoutCascade |
| 2835 * | conditionalExpression |
| 2836 * | throwExpressionWithoutCascade |
| 2837 */ |
| 2838 Expression parseExpressionWithoutCascade() { |
| 2839 if (_matchesKeyword(Keyword.THROW)) { |
| 2840 return _parseThrowExpressionWithoutCascade(); |
| 2841 } else if (_matchesKeyword(Keyword.RETHROW)) { |
| 2842 return _parseRethrowExpression(); |
| 2843 } |
| 2844 // |
| 2845 // assignableExpression is a subset of conditionalExpression, so we can |
| 2846 // parse a conditional expression and then determine whether it is followed |
| 2847 // by an assignmentOperator, checking for conformance to the restricted |
| 2848 // grammar after making that determination. |
| 2849 // |
| 2850 Expression expression = parseConditionalExpression(); |
| 2851 if (_currentToken.type.isAssignmentOperator) { |
| 2852 Token operator = getAndAdvance(); |
| 2853 _ensureAssignable(expression); |
| 2854 expression = new AssignmentExpression( |
| 2855 expression, operator, parseExpressionWithoutCascade()); |
| 2856 } |
| 2857 return expression; |
| 2858 } |
| 2859 |
| 2860 /** |
| 2861 * Parse a class extends clause. Return the class extends clause that was |
| 2862 * parsed. |
| 2863 * |
| 2864 * classExtendsClause ::= |
| 2865 * 'extends' type |
| 2866 */ |
| 2867 ExtendsClause parseExtendsClause() { |
| 2868 Token keyword = _expectKeyword(Keyword.EXTENDS); |
| 2869 TypeName superclass = parseTypeName(); |
| 2870 return new ExtendsClause(keyword, superclass); |
| 2871 } |
| 2872 |
| 2873 /** |
| 2874 * Parse a list of formal parameters. Return the formal parameters that were |
| 2875 * parsed. |
| 2876 * |
| 2877 * formalParameterList ::= |
| 2878 * '(' ')' |
| 2879 * | '(' normalFormalParameters (',' optionalFormalParameters)? ')' |
| 2880 * | '(' optionalFormalParameters ')' |
| 2881 * |
| 2882 * normalFormalParameters ::= |
| 2883 * normalFormalParameter (',' normalFormalParameter)* |
| 2884 * |
| 2885 * optionalFormalParameters ::= |
| 2886 * optionalPositionalFormalParameters |
| 2887 * | namedFormalParameters |
| 2888 * |
| 2889 * optionalPositionalFormalParameters ::= |
| 2890 * '[' defaultFormalParameter (',' defaultFormalParameter)* ']' |
| 2891 * |
| 2892 * namedFormalParameters ::= |
| 2893 * '{' defaultNamedParameter (',' defaultNamedParameter)* '}' |
| 2894 */ |
| 2895 FormalParameterList parseFormalParameterList() { |
| 2896 Token leftParenthesis = _expect(TokenType.OPEN_PAREN); |
| 2897 if (_matches(TokenType.CLOSE_PAREN)) { |
| 2898 return new FormalParameterList( |
| 2899 leftParenthesis, null, null, null, getAndAdvance()); |
| 2900 } |
| 2901 // |
| 2902 // Even though it is invalid to have default parameters outside of brackets, |
| 2903 // required parameters inside of brackets, or multiple groups of default and |
| 2904 // named parameters, we allow all of these cases so that we can recover |
| 2905 // better. |
| 2906 // |
| 2907 List<FormalParameter> parameters = new List<FormalParameter>(); |
| 2908 List<FormalParameter> normalParameters = new List<FormalParameter>(); |
| 2909 List<FormalParameter> positionalParameters = new List<FormalParameter>(); |
| 2910 List<FormalParameter> namedParameters = new List<FormalParameter>(); |
| 2911 List<FormalParameter> currentParameters = normalParameters; |
| 2912 Token leftSquareBracket = null; |
| 2913 Token rightSquareBracket = null; |
| 2914 Token leftCurlyBracket = null; |
| 2915 Token rightCurlyBracket = null; |
| 2916 ParameterKind kind = ParameterKind.REQUIRED; |
| 2917 bool firstParameter = true; |
| 2918 bool reportedMuliplePositionalGroups = false; |
| 2919 bool reportedMulipleNamedGroups = false; |
| 2920 bool reportedMixedGroups = false; |
| 2921 bool wasOptionalParameter = false; |
| 2922 Token initialToken = null; |
| 2923 do { |
| 2924 if (firstParameter) { |
| 2925 firstParameter = false; |
| 2926 } else if (!_optional(TokenType.COMMA)) { |
| 2927 // TODO(brianwilkerson) The token is wrong, we need to recover from this |
| 2928 // case. |
| 2929 if (_getEndToken(leftParenthesis) != null) { |
| 2930 _reportErrorForCurrentToken( |
| 2931 ParserErrorCode.EXPECTED_TOKEN, [TokenType.COMMA.lexeme]); |
| 2932 } else { |
| 2933 _reportErrorForToken(ParserErrorCode.MISSING_CLOSING_PARENTHESIS, |
| 2934 _currentToken.previous); |
| 2935 break; |
| 2936 } |
| 2937 } |
| 2938 initialToken = _currentToken; |
| 2939 // |
| 2940 // Handle the beginning of parameter groups. |
| 2941 // |
| 2942 if (_matches(TokenType.OPEN_SQUARE_BRACKET)) { |
| 2943 wasOptionalParameter = true; |
| 2944 if (leftSquareBracket != null && !reportedMuliplePositionalGroups) { |
| 2945 _reportErrorForCurrentToken( |
| 2946 ParserErrorCode.MULTIPLE_POSITIONAL_PARAMETER_GROUPS); |
| 2947 reportedMuliplePositionalGroups = true; |
| 2948 } |
| 2949 if (leftCurlyBracket != null && !reportedMixedGroups) { |
| 2950 _reportErrorForCurrentToken(ParserErrorCode.MIXED_PARAMETER_GROUPS); |
| 2951 reportedMixedGroups = true; |
| 2952 } |
| 2953 leftSquareBracket = getAndAdvance(); |
| 2954 currentParameters = positionalParameters; |
| 2955 kind = ParameterKind.POSITIONAL; |
| 2956 } else if (_matches(TokenType.OPEN_CURLY_BRACKET)) { |
| 2957 wasOptionalParameter = true; |
| 2958 if (leftCurlyBracket != null && !reportedMulipleNamedGroups) { |
| 2959 _reportErrorForCurrentToken( |
| 2960 ParserErrorCode.MULTIPLE_NAMED_PARAMETER_GROUPS); |
| 2961 reportedMulipleNamedGroups = true; |
| 2962 } |
| 2963 if (leftSquareBracket != null && !reportedMixedGroups) { |
| 2964 _reportErrorForCurrentToken(ParserErrorCode.MIXED_PARAMETER_GROUPS); |
| 2965 reportedMixedGroups = true; |
| 2966 } |
| 2967 leftCurlyBracket = getAndAdvance(); |
| 2968 currentParameters = namedParameters; |
| 2969 kind = ParameterKind.NAMED; |
| 2970 } |
| 2971 // |
| 2972 // Parse and record the parameter. |
| 2973 // |
| 2974 FormalParameter parameter = _parseFormalParameter(kind); |
| 2975 parameters.add(parameter); |
| 2976 currentParameters.add(parameter); |
| 2977 if (kind == ParameterKind.REQUIRED && wasOptionalParameter) { |
| 2978 _reportErrorForNode( |
| 2979 ParserErrorCode.NORMAL_BEFORE_OPTIONAL_PARAMETERS, parameter); |
| 2980 } |
| 2981 // |
| 2982 // Handle the end of parameter groups. |
| 2983 // |
| 2984 // TODO(brianwilkerson) Improve the detection and reporting of missing and |
| 2985 // mismatched delimiters. |
| 2986 if (_matches(TokenType.CLOSE_SQUARE_BRACKET)) { |
| 2987 rightSquareBracket = getAndAdvance(); |
| 2988 currentParameters = normalParameters; |
| 2989 if (leftSquareBracket == null) { |
| 2990 if (leftCurlyBracket != null) { |
| 2991 _reportErrorForCurrentToken( |
| 2992 ParserErrorCode.WRONG_TERMINATOR_FOR_PARAMETER_GROUP, ["}"]); |
| 2993 rightCurlyBracket = rightSquareBracket; |
| 2994 rightSquareBracket = null; |
| 2995 } else { |
| 2996 _reportErrorForCurrentToken( |
| 2997 ParserErrorCode.UNEXPECTED_TERMINATOR_FOR_PARAMETER_GROUP, |
| 2998 ["["]); |
| 2999 } |
| 3000 } |
| 3001 kind = ParameterKind.REQUIRED; |
| 3002 } else if (_matches(TokenType.CLOSE_CURLY_BRACKET)) { |
| 3003 rightCurlyBracket = getAndAdvance(); |
| 3004 currentParameters = normalParameters; |
| 3005 if (leftCurlyBracket == null) { |
| 3006 if (leftSquareBracket != null) { |
| 3007 _reportErrorForCurrentToken( |
| 3008 ParserErrorCode.WRONG_TERMINATOR_FOR_PARAMETER_GROUP, ["]"]); |
| 3009 rightSquareBracket = rightCurlyBracket; |
| 3010 rightCurlyBracket = null; |
| 3011 } else { |
| 3012 _reportErrorForCurrentToken( |
| 3013 ParserErrorCode.UNEXPECTED_TERMINATOR_FOR_PARAMETER_GROUP, |
| 3014 ["{"]); |
| 3015 } |
| 3016 } |
| 3017 kind = ParameterKind.REQUIRED; |
| 3018 } |
| 3019 } while (!_matches(TokenType.CLOSE_PAREN) && |
| 3020 !identical(initialToken, _currentToken)); |
| 3021 Token rightParenthesis = _expect(TokenType.CLOSE_PAREN); |
| 3022 // |
| 3023 // Check that the groups were closed correctly. |
| 3024 // |
| 3025 if (leftSquareBracket != null && rightSquareBracket == null) { |
| 3026 _reportErrorForCurrentToken( |
| 3027 ParserErrorCode.MISSING_TERMINATOR_FOR_PARAMETER_GROUP, ["]"]); |
| 3028 } |
| 3029 if (leftCurlyBracket != null && rightCurlyBracket == null) { |
| 3030 _reportErrorForCurrentToken( |
| 3031 ParserErrorCode.MISSING_TERMINATOR_FOR_PARAMETER_GROUP, ["}"]); |
| 3032 } |
| 3033 // |
| 3034 // Build the parameter list. |
| 3035 // |
| 3036 if (leftSquareBracket == null) { |
| 3037 leftSquareBracket = leftCurlyBracket; |
| 3038 } |
| 3039 if (rightSquareBracket == null) { |
| 3040 rightSquareBracket = rightCurlyBracket; |
| 3041 } |
| 3042 return new FormalParameterList(leftParenthesis, parameters, |
| 3043 leftSquareBracket, rightSquareBracket, rightParenthesis); |
| 3044 } |
| 3045 |
| 3046 /** |
| 3047 * Parse a function expression. Return the function expression that was |
| 3048 * parsed. |
| 3049 * |
| 3050 * functionExpression ::= |
| 3051 * typeParameters? formalParameterList functionExpressionBody |
| 3052 */ |
| 3053 FunctionExpression parseFunctionExpression() { |
| 3054 TypeParameterList typeParameters = null; |
| 3055 if (parseGenericMethods && _matches(TokenType.LT)) { |
| 3056 typeParameters = parseTypeParameterList(); |
| 3057 } |
| 3058 FormalParameterList parameters = parseFormalParameterList(); |
| 3059 _validateFormalParameterList(parameters); |
| 3060 FunctionBody body = |
| 3061 _parseFunctionBody(false, ParserErrorCode.MISSING_FUNCTION_BODY, true); |
| 3062 return new FunctionExpression(typeParameters, parameters, body); |
| 3063 } |
| 3064 |
| 3065 /** |
| 3066 * Parse an if-null expression. Return the if-null expression that was |
| 3067 * parsed. |
| 3068 * |
| 3069 * ifNullExpression ::= logicalOrExpression ('??' logicalOrExpression)* |
| 3070 */ |
| 3071 Expression parseIfNullExpression() { |
| 3072 Expression expression = parseLogicalOrExpression(); |
| 3073 while (_matches(TokenType.QUESTION_QUESTION)) { |
| 3074 Token operator = getAndAdvance(); |
| 3075 expression = new BinaryExpression( |
| 3076 expression, operator, parseLogicalOrExpression()); |
| 3077 } |
| 3078 return expression; |
| 3079 } |
| 3080 |
| 3081 /** |
| 3082 * Parse an implements clause. Return the implements clause that was parsed. |
| 3083 * |
| 3084 * implementsClause ::= |
| 3085 * 'implements' type (',' type)* |
| 3086 */ |
| 3087 ImplementsClause parseImplementsClause() { |
| 3088 Token keyword = _expectKeyword(Keyword.IMPLEMENTS); |
| 3089 List<TypeName> interfaces = new List<TypeName>(); |
| 3090 interfaces.add(parseTypeName()); |
| 3091 while (_optional(TokenType.COMMA)) { |
| 3092 interfaces.add(parseTypeName()); |
| 3093 } |
| 3094 return new ImplementsClause(keyword, interfaces); |
| 3095 } |
| 3096 |
| 3097 /** |
| 3098 * Parse a label. Return the label that was parsed. |
| 3099 * |
| 3100 * label ::= |
| 3101 * identifier ':' |
| 3102 */ |
| 3103 Label parseLabel() { |
| 3104 SimpleIdentifier label = parseSimpleIdentifier(); |
| 3105 Token colon = _expect(TokenType.COLON); |
| 3106 return new Label(label, colon); |
| 3107 } |
| 3108 |
| 3109 /** |
| 3110 * Parse a library identifier. Return the library identifier that was parsed. |
| 3111 * |
| 3112 * libraryIdentifier ::= |
| 3113 * identifier ('.' identifier)* |
| 3114 */ |
| 3115 LibraryIdentifier parseLibraryIdentifier() { |
| 3116 List<SimpleIdentifier> components = new List<SimpleIdentifier>(); |
| 3117 components.add(parseSimpleIdentifier()); |
| 3118 while (_matches(TokenType.PERIOD)) { |
| 3119 _advance(); |
| 3120 components.add(parseSimpleIdentifier()); |
| 3121 } |
| 3122 return new LibraryIdentifier(components); |
| 3123 } |
| 3124 |
| 3125 /** |
| 3126 * Parse a logical or expression. Return the logical or expression that was |
| 3127 * parsed. |
| 3128 * |
| 3129 * logicalOrExpression ::= |
| 3130 * logicalAndExpression ('||' logicalAndExpression)* |
| 3131 */ |
| 3132 Expression parseLogicalOrExpression() { |
| 3133 Expression expression = _parseLogicalAndExpression(); |
| 3134 while (_matches(TokenType.BAR_BAR)) { |
| 3135 Token operator = getAndAdvance(); |
| 3136 expression = new BinaryExpression( |
| 3137 expression, operator, _parseLogicalAndExpression()); |
| 3138 } |
| 3139 return expression; |
| 3140 } |
| 3141 |
| 3142 /** |
| 3143 * Parse a map literal entry. Return the map literal entry that was parsed. |
| 3144 * |
| 3145 * mapLiteralEntry ::= |
| 3146 * expression ':' expression |
| 3147 */ |
| 3148 MapLiteralEntry parseMapLiteralEntry() { |
| 3149 Expression key = parseExpression2(); |
| 3150 Token separator = _expect(TokenType.COLON); |
| 3151 Expression value = parseExpression2(); |
| 3152 return new MapLiteralEntry(key, separator, value); |
| 3153 } |
| 3154 |
| 3155 /** |
| 3156 * Parse a normal formal parameter. Return the normal formal parameter that |
| 3157 * was parsed. |
| 3158 * |
| 3159 * normalFormalParameter ::= |
| 3160 * functionSignature |
| 3161 * | fieldFormalParameter |
| 3162 * | simpleFormalParameter |
| 3163 * |
| 3164 * functionSignature: |
| 3165 * metadata returnType? identifier typeParameters? formalParameterList |
| 3166 * |
| 3167 * fieldFormalParameter ::= |
| 3168 * metadata finalConstVarOrType? 'this' '.' identifier |
| 3169 * |
| 3170 * simpleFormalParameter ::= |
| 3171 * declaredIdentifier |
| 3172 * | metadata identifier |
| 3173 */ |
| 3174 NormalFormalParameter parseNormalFormalParameter() { |
| 3175 CommentAndMetadata commentAndMetadata = _parseCommentAndMetadata(); |
| 3176 FinalConstVarOrType holder = _parseFinalConstVarOrType(true); |
| 3177 Token thisKeyword = null; |
| 3178 Token period = null; |
| 3179 if (_matchesKeyword(Keyword.THIS)) { |
| 3180 thisKeyword = getAndAdvance(); |
| 3181 period = _expect(TokenType.PERIOD); |
| 3182 } |
| 3183 SimpleIdentifier identifier = parseSimpleIdentifier(); |
| 3184 TypeParameterList typeParameters = null; |
| 3185 if (parseGenericMethods && _matches(TokenType.LT)) { |
| 3186 typeParameters = parseTypeParameterList(); |
| 3187 } |
| 3188 if (_matches(TokenType.OPEN_PAREN)) { |
| 3189 FormalParameterList parameters = parseFormalParameterList(); |
| 3190 if (thisKeyword == null) { |
| 3191 if (holder.keyword != null) { |
| 3192 _reportErrorForToken( |
| 3193 ParserErrorCode.FUNCTION_TYPED_PARAMETER_VAR, holder.keyword); |
| 3194 } |
| 3195 return new FunctionTypedFormalParameter(commentAndMetadata.comment, |
| 3196 commentAndMetadata.metadata, holder.type, identifier, |
| 3197 typeParameters, parameters); |
| 3198 } else { |
| 3199 return new FieldFormalParameter(commentAndMetadata.comment, |
| 3200 commentAndMetadata.metadata, holder.keyword, holder.type, |
| 3201 thisKeyword, period, identifier, typeParameters, parameters); |
| 3202 } |
| 3203 } else if (typeParameters != null) { |
| 3204 // TODO(brianwilkerson) Report an error. It looks like a function-typed |
| 3205 // parameter with no parameter list. |
| 3206 //_reportErrorForToken(ParserErrorCode.MISSING_PARAMETERS, typeParameters.
endToken); |
| 3207 } |
| 3208 TypeName type = holder.type; |
| 3209 if (type != null) { |
| 3210 if (_tokenMatchesKeyword(type.name.beginToken, Keyword.VOID)) { |
| 3211 _reportErrorForToken( |
| 3212 ParserErrorCode.VOID_PARAMETER, type.name.beginToken); |
| 3213 } else if (holder.keyword != null && |
| 3214 _tokenMatchesKeyword(holder.keyword, Keyword.VAR)) { |
| 3215 _reportErrorForToken(ParserErrorCode.VAR_AND_TYPE, holder.keyword); |
| 3216 } |
| 3217 } |
| 3218 if (thisKeyword != null) { |
| 3219 // TODO(brianwilkerson) If there are type parameters but no parameters, |
| 3220 // should we create a synthetic empty parameter list here so we can |
| 3221 // capture the type parameters? |
| 3222 return new FieldFormalParameter(commentAndMetadata.comment, |
| 3223 commentAndMetadata.metadata, holder.keyword, holder.type, thisKeyword, |
| 3224 period, identifier, null, null); |
| 3225 } |
| 3226 return new SimpleFormalParameter(commentAndMetadata.comment, |
| 3227 commentAndMetadata.metadata, holder.keyword, holder.type, identifier); |
| 3228 } |
| 3229 |
| 3230 /** |
| 3231 * Parse a prefixed identifier. Return the prefixed identifier that was |
| 3232 * parsed. |
| 3233 * |
| 3234 * prefixedIdentifier ::= |
| 3235 * identifier ('.' identifier)? |
| 3236 */ |
| 3237 Identifier parsePrefixedIdentifier() { |
| 3238 SimpleIdentifier qualifier = parseSimpleIdentifier(); |
| 3239 if (!_matches(TokenType.PERIOD)) { |
| 3240 return qualifier; |
| 3241 } |
| 3242 Token period = getAndAdvance(); |
| 3243 SimpleIdentifier qualified = parseSimpleIdentifier(); |
| 3244 return new PrefixedIdentifier(qualifier, period, qualified); |
| 3245 } |
| 3246 |
| 3247 /** |
| 3248 * Parse a return type. Return the return type that was parsed. |
| 3249 * |
| 3250 * returnType ::= |
| 3251 * 'void' |
| 3252 * | type |
| 3253 */ |
| 3254 TypeName parseReturnType() { |
| 3255 if (_matchesKeyword(Keyword.VOID)) { |
| 3256 return new TypeName(new SimpleIdentifier(getAndAdvance()), null); |
| 3257 } else { |
| 3258 return parseTypeName(); |
| 3259 } |
| 3260 } |
| 3261 |
| 3262 /** |
| 3263 * Parse a simple identifier. Return the simple identifier that was parsed. |
| 3264 * |
| 3265 * identifier ::= |
| 3266 * IDENTIFIER |
| 3267 */ |
| 3268 SimpleIdentifier parseSimpleIdentifier() { |
| 3269 if (_matchesIdentifier()) { |
| 3270 String lexeme = _currentToken.lexeme; |
| 3271 if ((_inAsync || _inGenerator) && |
| 3272 (lexeme == 'async' || lexeme == 'await' || lexeme == 'yield')) { |
| 3273 _reportErrorForCurrentToken( |
| 3274 ParserErrorCode.ASYNC_KEYWORD_USED_AS_IDENTIFIER); |
| 3275 } |
| 3276 return new SimpleIdentifier(getAndAdvance()); |
| 3277 } |
| 3278 _reportErrorForCurrentToken(ParserErrorCode.MISSING_IDENTIFIER); |
| 3279 return _createSyntheticIdentifier(); |
| 3280 } |
| 3281 |
| 3282 /** |
| 3283 * Parse a statement, starting with the given [token]. Return the statement |
| 3284 * that was parsed, or `null` if the tokens do not represent a recognizable |
| 3285 * statement. |
| 3286 */ |
| 3287 Statement parseStatement(Token token) { |
| 3288 _currentToken = token; |
| 3289 return parseStatement2(); |
| 3290 } |
| 3291 |
| 3292 /** |
| 3293 * Parse a statement. Return the statement that was parsed. |
| 3294 * |
| 3295 * statement ::= |
| 3296 * label* nonLabeledStatement |
| 3297 */ |
| 3298 Statement parseStatement2() { |
| 3299 List<Label> labels = new List<Label>(); |
| 3300 while (_matchesIdentifier() && _tokenMatches(_peek(), TokenType.COLON)) { |
| 3301 labels.add(parseLabel()); |
| 3302 } |
| 3303 Statement statement = _parseNonLabeledStatement(); |
| 3304 if (labels.isEmpty) { |
| 3305 return statement; |
| 3306 } |
| 3307 return new LabeledStatement(labels, statement); |
| 3308 } |
| 3309 |
| 3310 /** |
| 3311 * Parse a sequence of statements, starting with the given [token]. Return the |
| 3312 * statements that were parsed, or `null` if the tokens do not represent a |
| 3313 * recognizable sequence of statements. |
| 3314 */ |
| 3315 List<Statement> parseStatements(Token token) { |
| 3316 _currentToken = token; |
| 3317 return _parseStatementList(); |
| 3318 } |
| 3319 |
| 3320 /** |
| 3321 * Parse a string literal. Return the string literal that was parsed. |
| 3322 * |
| 3323 * stringLiteral ::= |
| 3324 * MULTI_LINE_STRING+ |
| 3325 * | SINGLE_LINE_STRING+ |
| 3326 */ |
| 3327 StringLiteral parseStringLiteral() { |
| 3328 List<StringLiteral> strings = new List<StringLiteral>(); |
| 3329 while (_matches(TokenType.STRING)) { |
| 3330 Token string = getAndAdvance(); |
| 3331 if (_matches(TokenType.STRING_INTERPOLATION_EXPRESSION) || |
| 3332 _matches(TokenType.STRING_INTERPOLATION_IDENTIFIER)) { |
| 3333 strings.add(_parseStringInterpolation(string)); |
| 3334 } else { |
| 3335 strings.add(new SimpleStringLiteral( |
| 3336 string, _computeStringValue(string.lexeme, true, true))); |
| 3337 } |
| 3338 } |
| 3339 if (strings.length < 1) { |
| 3340 _reportErrorForCurrentToken(ParserErrorCode.EXPECTED_STRING_LITERAL); |
| 3341 return _createSyntheticStringLiteral(); |
| 3342 } else if (strings.length == 1) { |
| 3343 return strings[0]; |
| 3344 } else { |
| 3345 return new AdjacentStrings(strings); |
| 3346 } |
| 3347 } |
| 3348 |
| 3349 /** |
| 3350 * Parse a list of type arguments. Return the type argument list that was |
| 3351 * parsed. |
| 3352 * |
| 3353 * typeArguments ::= |
| 3354 * '<' typeList '>' |
| 3355 * |
| 3356 * typeList ::= |
| 3357 * type (',' type)* |
| 3358 */ |
| 3359 TypeArgumentList parseTypeArgumentList() { |
| 3360 Token leftBracket = _expect(TokenType.LT); |
| 3361 List<TypeName> arguments = new List<TypeName>(); |
| 3362 arguments.add(parseTypeName()); |
| 3363 while (_optional(TokenType.COMMA)) { |
| 3364 arguments.add(parseTypeName()); |
| 3365 } |
| 3366 Token rightBracket = _expectGt(); |
| 3367 return new TypeArgumentList(leftBracket, arguments, rightBracket); |
| 3368 } |
| 3369 |
| 3370 /** |
| 3371 * Parse a type name. Return the type name that was parsed. |
| 3372 * |
| 3373 * type ::= |
| 3374 * qualified typeArguments? |
| 3375 */ |
| 3376 TypeName parseTypeName() { |
| 3377 Identifier typeName; |
| 3378 if (_matchesKeyword(Keyword.VAR)) { |
| 3379 _reportErrorForCurrentToken(ParserErrorCode.VAR_AS_TYPE_NAME); |
| 3380 typeName = new SimpleIdentifier(getAndAdvance()); |
| 3381 } else if (_matchesIdentifier()) { |
| 3382 typeName = parsePrefixedIdentifier(); |
| 3383 } else { |
| 3384 typeName = _createSyntheticIdentifier(); |
| 3385 _reportErrorForCurrentToken(ParserErrorCode.EXPECTED_TYPE_NAME); |
| 3386 } |
| 3387 TypeArgumentList typeArguments = null; |
| 3388 if (_matches(TokenType.LT)) { |
| 3389 typeArguments = parseTypeArgumentList(); |
| 3390 } |
| 3391 return new TypeName(typeName, typeArguments); |
| 3392 } |
| 3393 |
| 3394 /** |
| 3395 * Parse a type parameter. Return the type parameter that was parsed. |
| 3396 * |
| 3397 * typeParameter ::= |
| 3398 * metadata name ('extends' bound)? |
| 3399 */ |
| 3400 TypeParameter parseTypeParameter() { |
| 3401 CommentAndMetadata commentAndMetadata = _parseCommentAndMetadata(); |
| 3402 SimpleIdentifier name = parseSimpleIdentifier(); |
| 3403 if (_matchesKeyword(Keyword.EXTENDS)) { |
| 3404 Token keyword = getAndAdvance(); |
| 3405 TypeName bound = parseTypeName(); |
| 3406 return new TypeParameter(commentAndMetadata.comment, |
| 3407 commentAndMetadata.metadata, name, keyword, bound); |
| 3408 } |
| 3409 return new TypeParameter(commentAndMetadata.comment, |
| 3410 commentAndMetadata.metadata, name, null, null); |
| 3411 } |
| 3412 |
| 3413 /** |
| 3414 * Parse a list of type parameters. Return the list of type parameters that |
| 3415 * were parsed. |
| 3416 * |
| 3417 * typeParameterList ::= |
| 3418 * '<' typeParameter (',' typeParameter)* '>' |
| 3419 */ |
| 3420 TypeParameterList parseTypeParameterList() { |
| 3421 Token leftBracket = _expect(TokenType.LT); |
| 3422 List<TypeParameter> typeParameters = new List<TypeParameter>(); |
| 3423 typeParameters.add(parseTypeParameter()); |
| 3424 while (_optional(TokenType.COMMA)) { |
| 3425 typeParameters.add(parseTypeParameter()); |
| 3426 } |
| 3427 Token rightBracket = _expectGt(); |
| 3428 return new TypeParameterList(leftBracket, typeParameters, rightBracket); |
| 3429 } |
| 3430 |
| 3431 /** |
| 3432 * Parse a with clause. Return the with clause that was parsed. |
| 3433 * |
| 3434 * withClause ::= |
| 3435 * 'with' typeName (',' typeName)* |
| 3436 */ |
| 3437 WithClause parseWithClause() { |
| 3438 Token with2 = _expectKeyword(Keyword.WITH); |
| 3439 List<TypeName> types = new List<TypeName>(); |
| 3440 types.add(parseTypeName()); |
| 3441 while (_optional(TokenType.COMMA)) { |
| 3442 types.add(parseTypeName()); |
| 3443 } |
| 3444 return new WithClause(with2, types); |
| 3445 } |
| 3446 |
| 3447 /** |
| 3448 * Advance to the next token in the token stream. |
| 3449 */ |
| 3450 void _advance() { |
| 3451 _currentToken = _currentToken.next; |
| 3452 } |
| 3453 |
| 3454 /** |
| 3455 * Append the character equivalent of the given [scalarValue] to the given |
| 3456 * [builder]. Use the [startIndex] and [endIndex] to report an error, and |
| 3457 * don't append anything to the builder, if the scalar value is invalid. The |
| 3458 * [escapeSequence] is the escape sequence that was parsed to produce the |
| 3459 * scalar value (used for error reporting). |
| 3460 */ |
| 3461 void _appendScalarValue(StringBuffer buffer, String escapeSequence, |
| 3462 int scalarValue, int startIndex, int endIndex) { |
| 3463 if (scalarValue < 0 || |
| 3464 scalarValue > Character.MAX_CODE_POINT || |
| 3465 (scalarValue >= 0xD800 && scalarValue <= 0xDFFF)) { |
| 3466 _reportErrorForCurrentToken( |
| 3467 ParserErrorCode.INVALID_CODE_POINT, [escapeSequence]); |
| 3468 return; |
| 3469 } |
| 3470 if (scalarValue < Character.MAX_VALUE) { |
| 3471 buffer.writeCharCode(scalarValue); |
| 3472 } else { |
| 3473 buffer.write(Character.toChars(scalarValue)); |
| 3474 } |
| 3475 } |
| 3476 |
| 3477 /** |
| 3478 * Return the content of a string with the given literal representation. The |
| 3479 * [lexeme] is the literal representation of the string. The flag [isFirst] is |
| 3480 * `true` if this is the first token in a string literal. The flag [isLast] is |
| 3481 * `true` if this is the last token in a string literal. |
| 3482 */ |
| 3483 String _computeStringValue(String lexeme, bool isFirst, bool isLast) { |
| 3484 StringLexemeHelper helper = new StringLexemeHelper(lexeme, isFirst, isLast); |
| 3485 int start = helper.start; |
| 3486 int end = helper.end; |
| 3487 bool stringEndsAfterStart = end >= start; |
| 3488 assert(stringEndsAfterStart); |
| 3489 if (!stringEndsAfterStart) { |
| 3490 AnalysisEngine.instance.logger.logError( |
| 3491 "Internal error: computeStringValue($lexeme, $isFirst, $isLast)"); |
| 3492 return ""; |
| 3493 } |
| 3494 if (helper.isRaw) { |
| 3495 return lexeme.substring(start, end); |
| 3496 } |
| 3497 StringBuffer buffer = new StringBuffer(); |
| 3498 int index = start; |
| 3499 while (index < end) { |
| 3500 index = _translateCharacter(buffer, lexeme, index); |
| 3501 } |
| 3502 return buffer.toString(); |
| 3503 } |
| 3504 |
| 3505 /** |
| 3506 * Convert the given [method] declaration into the nearest valid top-level |
| 3507 * function declaration (that is, the function declaration that most closely |
| 3508 * captures the components of the given method declaration). |
| 3509 */ |
| 3510 FunctionDeclaration _convertToFunctionDeclaration(MethodDeclaration method) => |
| 3511 new FunctionDeclaration(method.documentationComment, method.metadata, |
| 3512 method.externalKeyword, method.returnType, method.propertyKeyword, |
| 3513 method.name, new FunctionExpression( |
| 3514 method.typeParameters, method.parameters, method.body)); |
| 3515 |
| 3516 /** |
| 3517 * Return `true` if the current token could be the start of a compilation unit |
| 3518 * member. This method is used for recovery purposes to decide when to stop |
| 3519 * skipping tokens after finding an error while parsing a compilation unit |
| 3520 * member. |
| 3521 */ |
| 3522 bool _couldBeStartOfCompilationUnitMember() { |
| 3523 if ((_matchesKeyword(Keyword.IMPORT) || |
| 3524 _matchesKeyword(Keyword.EXPORT) || |
| 3525 _matchesKeyword(Keyword.LIBRARY) || |
| 3526 _matchesKeyword(Keyword.PART)) && |
| 3527 !_tokenMatches(_peek(), TokenType.PERIOD) && |
| 3528 !_tokenMatches(_peek(), TokenType.LT)) { |
| 3529 // This looks like the start of a directive |
| 3530 return true; |
| 3531 } else if (_matchesKeyword(Keyword.CLASS)) { |
| 3532 // This looks like the start of a class definition |
| 3533 return true; |
| 3534 } else if (_matchesKeyword(Keyword.TYPEDEF) && |
| 3535 !_tokenMatches(_peek(), TokenType.PERIOD) && |
| 3536 !_tokenMatches(_peek(), TokenType.LT)) { |
| 3537 // This looks like the start of a typedef |
| 3538 return true; |
| 3539 } else if (_matchesKeyword(Keyword.VOID) || |
| 3540 ((_matchesKeyword(Keyword.GET) || _matchesKeyword(Keyword.SET)) && |
| 3541 _tokenMatchesIdentifier(_peek())) || |
| 3542 (_matchesKeyword(Keyword.OPERATOR) && _isOperator(_peek()))) { |
| 3543 // This looks like the start of a function |
| 3544 return true; |
| 3545 } else if (_matchesIdentifier()) { |
| 3546 if (_tokenMatches(_peek(), TokenType.OPEN_PAREN)) { |
| 3547 // This looks like the start of a function |
| 3548 return true; |
| 3549 } |
| 3550 Token token = _skipReturnType(_currentToken); |
| 3551 if (token == null) { |
| 3552 return false; |
| 3553 } |
| 3554 if (_matchesKeyword(Keyword.GET) || |
| 3555 _matchesKeyword(Keyword.SET) || |
| 3556 (_matchesKeyword(Keyword.OPERATOR) && _isOperator(_peek())) || |
| 3557 _matchesIdentifier()) { |
| 3558 return true; |
| 3559 } |
| 3560 } |
| 3561 return false; |
| 3562 } |
| 3563 |
| 3564 /** |
| 3565 * Return a synthetic identifier. |
| 3566 */ |
| 3567 SimpleIdentifier _createSyntheticIdentifier() { |
| 3568 Token syntheticToken; |
| 3569 if (_currentToken.type == TokenType.KEYWORD) { |
| 3570 // Consider current keyword token as an identifier. |
| 3571 // It is not always true, e.g. "^is T" where "^" is place the place for |
| 3572 // synthetic identifier. By creating SyntheticStringToken we can |
| 3573 // distinguish a real identifier from synthetic. In the code completion |
| 3574 // behavior will depend on a cursor position - before or on "is". |
| 3575 syntheticToken = _injectToken(new SyntheticStringToken( |
| 3576 TokenType.IDENTIFIER, _currentToken.lexeme, _currentToken.offset)); |
| 3577 } else { |
| 3578 syntheticToken = _createSyntheticToken(TokenType.IDENTIFIER); |
| 3579 } |
| 3580 return new SimpleIdentifier(syntheticToken); |
| 3581 } |
| 3582 |
| 3583 /** |
| 3584 * Return a synthetic token representing the given [keyword]. |
| 3585 */ |
| 3586 Token _createSyntheticKeyword(Keyword keyword) => _injectToken( |
| 3587 new Parser_SyntheticKeywordToken(keyword, _currentToken.offset)); |
| 3588 |
| 3589 /** |
| 3590 * Return a synthetic string literal. |
| 3591 */ |
| 3592 SimpleStringLiteral _createSyntheticStringLiteral() => |
| 3593 new SimpleStringLiteral(_createSyntheticToken(TokenType.STRING), ""); |
| 3594 |
| 3595 /** |
| 3596 * Return a synthetic token with the given [type]. |
| 3597 */ |
| 3598 Token _createSyntheticToken(TokenType type) => |
| 3599 _injectToken(new StringToken(type, "", _currentToken.offset)); |
| 3600 |
| 3601 /** |
| 3602 * Create and return a new token with the given [type]. The token will replace |
| 3603 * the first portion of the given [token], so it will have the same offset and |
| 3604 * will have any comments that might have preceeded the token. |
| 3605 */ |
| 3606 Token _createToken(Token token, TokenType type, {bool isBegin: false}) { |
| 3607 CommentToken comments = token.precedingComments; |
| 3608 if (comments == null) { |
| 3609 if (isBegin) { |
| 3610 return new BeginToken(type, token.offset); |
| 3611 } |
| 3612 return new Token(type, token.offset); |
| 3613 } else if (isBegin) { |
| 3614 return new BeginTokenWithComment(type, token.offset, comments); |
| 3615 } |
| 3616 return new TokenWithComment(type, token.offset, comments); |
| 3617 } |
| 3618 |
| 3619 /** |
| 3620 * Check that the given [expression] is assignable and report an error if it |
| 3621 * isn't. |
| 3622 * |
| 3623 * assignableExpression ::= |
| 3624 * primary (arguments* assignableSelector)+ |
| 3625 * | 'super' unconditionalAssignableSelector |
| 3626 * | identifier |
| 3627 * |
| 3628 * unconditionalAssignableSelector ::= |
| 3629 * '[' expression ']' |
| 3630 * | '.' identifier |
| 3631 * |
| 3632 * assignableSelector ::= |
| 3633 * unconditionalAssignableSelector |
| 3634 * | '?.' identifier |
| 3635 */ |
| 3636 void _ensureAssignable(Expression expression) { |
| 3637 if (expression != null && !expression.isAssignable) { |
| 3638 _reportErrorForCurrentToken( |
| 3639 ParserErrorCode.ILLEGAL_ASSIGNMENT_TO_NON_ASSIGNABLE); |
| 3640 } |
| 3641 } |
| 3642 |
| 3643 /** |
| 3644 * If the current token has the expected type, return it after advancing to |
| 3645 * the next token. Otherwise report an error and return the current token |
| 3646 * without advancing. |
| 3647 * |
| 3648 * Note that the method [_expectGt] should be used if the argument to this |
| 3649 * method would be [TokenType.GT]. |
| 3650 * |
| 3651 * The [type] is the type of token that is expected. |
| 3652 */ |
| 3653 Token _expect(TokenType type) { |
| 3654 if (_matches(type)) { |
| 3655 return getAndAdvance(); |
| 3656 } |
| 3657 // Remove uses of this method in favor of matches? |
| 3658 // Pass in the error code to use to report the error? |
| 3659 if (type == TokenType.SEMICOLON) { |
| 3660 if (_tokenMatches(_currentToken.next, TokenType.SEMICOLON)) { |
| 3661 _reportErrorForCurrentToken( |
| 3662 ParserErrorCode.UNEXPECTED_TOKEN, [_currentToken.lexeme]); |
| 3663 _advance(); |
| 3664 return getAndAdvance(); |
| 3665 } |
| 3666 _reportErrorForToken(ParserErrorCode.EXPECTED_TOKEN, |
| 3667 _currentToken.previous, [type.lexeme]); |
| 3668 } else { |
| 3669 _reportErrorForCurrentToken( |
| 3670 ParserErrorCode.EXPECTED_TOKEN, [type.lexeme]); |
| 3671 } |
| 3672 return _currentToken; |
| 3673 } |
| 3674 |
| 3675 /** |
| 3676 * If the current token has the type [TokenType.GT], return it after advancing |
| 3677 * to the next token. Otherwise report an error and return the current token |
| 3678 * without advancing. |
| 3679 */ |
| 3680 Token _expectGt() { |
| 3681 if (_matchesGt()) { |
| 3682 return getAndAdvance(); |
| 3683 } |
| 3684 _reportErrorForCurrentToken( |
| 3685 ParserErrorCode.EXPECTED_TOKEN, [TokenType.GT.lexeme]); |
| 3686 return _currentToken; |
| 3687 } |
| 3688 |
| 3689 /** |
| 3690 * If the current token is a keyword matching the given [keyword], return it |
| 3691 * after advancing to the next token. Otherwise report an error and return the |
| 3692 * current token without advancing. |
| 3693 */ |
| 3694 Token _expectKeyword(Keyword keyword) { |
| 3695 if (_matchesKeyword(keyword)) { |
| 3696 return getAndAdvance(); |
| 3697 } |
| 3698 // Remove uses of this method in favor of matches? |
| 3699 // Pass in the error code to use to report the error? |
| 3700 _reportErrorForCurrentToken( |
| 3701 ParserErrorCode.EXPECTED_TOKEN, [keyword.syntax]); |
| 3702 return _currentToken; |
| 3703 } |
| 3704 |
| 3705 /** |
| 3706 * If the current token is a semicolon, return it after advancing to the next |
| 3707 * token. Otherwise report an error and create a synthetic semicolon. |
| 3708 */ |
| 3709 Token _expectSemicolon() { |
| 3710 // TODO(scheglov) consider pushing this behavior into [_expect] |
| 3711 if (_matches(TokenType.SEMICOLON)) { |
| 3712 return getAndAdvance(); |
| 3713 } else { |
| 3714 _reportErrorForToken( |
| 3715 ParserErrorCode.EXPECTED_TOKEN, _currentToken.previous, [";"]); |
| 3716 return _createSyntheticToken(TokenType.SEMICOLON); |
| 3717 } |
| 3718 } |
| 3719 |
| 3720 /** |
| 3721 * Search the given list of [ranges] for a range that contains the given |
| 3722 * [index]. Return the range that was found, or `null` if none of the ranges |
| 3723 * contain the index. |
| 3724 */ |
| 3725 List<int> _findRange(List<List<int>> ranges, int index) { |
| 3726 int rangeCount = ranges.length; |
| 3727 for (int i = 0; i < rangeCount; i++) { |
| 3728 List<int> range = ranges[i]; |
| 3729 if (range[0] <= index && index <= range[1]) { |
| 3730 return range; |
| 3731 } else if (index < range[0]) { |
| 3732 return null; |
| 3733 } |
| 3734 } |
| 3735 return null; |
| 3736 } |
| 3737 |
| 3738 /** |
| 3739 * Return a list of the ranges of characters in the given [comment] that |
| 3740 * should be treated as code blocks. |
| 3741 */ |
| 3742 List<List<int>> _getCodeBlockRanges(String comment) { |
| 3743 List<List<int>> ranges = new List<List<int>>(); |
| 3744 int length = comment.length; |
| 3745 if (length < 3) { |
| 3746 return ranges; |
| 3747 } |
| 3748 int index = 0; |
| 3749 int firstChar = comment.codeUnitAt(0); |
| 3750 if (firstChar == 0x2F) { |
| 3751 int secondChar = comment.codeUnitAt(1); |
| 3752 int thirdChar = comment.codeUnitAt(2); |
| 3753 if ((secondChar == 0x2A && thirdChar == 0x2A) || |
| 3754 (secondChar == 0x2F && thirdChar == 0x2F)) { |
| 3755 index = 3; |
| 3756 } |
| 3757 } |
| 3758 while (index < length) { |
| 3759 int currentChar = comment.codeUnitAt(index); |
| 3760 if (currentChar == 0xD || currentChar == 0xA) { |
| 3761 index = index + 1; |
| 3762 while (index < length && |
| 3763 Character.isWhitespace(comment.codeUnitAt(index))) { |
| 3764 index = index + 1; |
| 3765 } |
| 3766 if (StringUtilities.startsWith6( |
| 3767 comment, index, 0x2A, 0x20, 0x20, 0x20, 0x20, 0x20)) { |
| 3768 int end = index + 6; |
| 3769 while (end < length && |
| 3770 comment.codeUnitAt(end) != 0xD && |
| 3771 comment.codeUnitAt(end) != 0xA) { |
| 3772 end = end + 1; |
| 3773 } |
| 3774 ranges.add(<int>[index, end]); |
| 3775 index = end; |
| 3776 } |
| 3777 } else if (index + 1 < length && |
| 3778 currentChar == 0x5B && |
| 3779 comment.codeUnitAt(index + 1) == 0x3A) { |
| 3780 int end = StringUtilities.indexOf2(comment, index + 2, 0x3A, 0x5D); |
| 3781 if (end < 0) { |
| 3782 end = length; |
| 3783 } |
| 3784 ranges.add(<int>[index, end]); |
| 3785 index = end + 1; |
| 3786 } else { |
| 3787 index = index + 1; |
| 3788 } |
| 3789 } |
| 3790 return ranges; |
| 3791 } |
| 3792 |
| 3793 /** |
| 3794 * Return the end token associated with the given [beginToken], or `null` if |
| 3795 * either the given token is not a begin token or it does not have an end |
| 3796 * token associated with it. |
| 3797 */ |
| 3798 Token _getEndToken(Token beginToken) { |
| 3799 if (beginToken is BeginToken) { |
| 3800 return beginToken.endToken; |
| 3801 } |
| 3802 return null; |
| 3803 } |
| 3804 |
| 3805 /** |
| 3806 * Inject the given [token] into the token stream immediately before the |
| 3807 * current token. |
| 3808 */ |
| 3809 Token _injectToken(Token token) { |
| 3810 Token previous = _currentToken.previous; |
| 3811 token.setNext(_currentToken); |
| 3812 previous.setNext(token); |
| 3813 return token; |
| 3814 } |
| 3815 |
| 3816 /** |
| 3817 * Return `true` if the current token appears to be the beginning of a |
| 3818 * function declaration. |
| 3819 */ |
| 3820 bool _isFunctionDeclaration() { |
| 3821 if (_matchesKeyword(Keyword.VOID)) { |
| 3822 return true; |
| 3823 } |
| 3824 Token afterReturnType = _skipTypeName(_currentToken); |
| 3825 if (afterReturnType == null) { |
| 3826 // There was no return type, but it is optional, so go back to where we |
| 3827 // started. |
| 3828 afterReturnType = _currentToken; |
| 3829 } |
| 3830 Token afterIdentifier = _skipSimpleIdentifier(afterReturnType); |
| 3831 if (afterIdentifier == null) { |
| 3832 // It's possible that we parsed the function name as if it were a type |
| 3833 // name, so see whether it makes sense if we assume that there is no type. |
| 3834 afterIdentifier = _skipSimpleIdentifier(_currentToken); |
| 3835 } |
| 3836 if (afterIdentifier == null) { |
| 3837 return false; |
| 3838 } |
| 3839 if (_isFunctionExpression(afterIdentifier)) { |
| 3840 return true; |
| 3841 } |
| 3842 // It's possible that we have found a getter. While this isn't valid at this |
| 3843 // point we test for it in order to recover better. |
| 3844 if (_matchesKeyword(Keyword.GET)) { |
| 3845 Token afterName = _skipSimpleIdentifier(_currentToken.next); |
| 3846 if (afterName == null) { |
| 3847 return false; |
| 3848 } |
| 3849 return _tokenMatches(afterName, TokenType.FUNCTION) || |
| 3850 _tokenMatches(afterName, TokenType.OPEN_CURLY_BRACKET); |
| 3851 } else if (_tokenMatchesKeyword(afterReturnType, Keyword.GET)) { |
| 3852 Token afterName = _skipSimpleIdentifier(afterReturnType.next); |
| 3853 if (afterName == null) { |
| 3854 return false; |
| 3855 } |
| 3856 return _tokenMatches(afterName, TokenType.FUNCTION) || |
| 3857 _tokenMatches(afterName, TokenType.OPEN_CURLY_BRACKET); |
| 3858 } |
| 3859 return false; |
| 3860 } |
| 3861 |
| 3862 /** |
| 3863 * Return `true` if the given [token] appears to be the beginning of a |
| 3864 * function expression. |
| 3865 */ |
| 3866 bool _isFunctionExpression(Token token) { |
| 3867 // Function expressions aren't allowed in initializer lists. |
| 3868 if (_inInitializer) { |
| 3869 return false; |
| 3870 } |
| 3871 Token afterTypeParameters = _skipTypeParameterList(token); |
| 3872 if (afterTypeParameters == null) { |
| 3873 afterTypeParameters = token; |
| 3874 } |
| 3875 Token afterParameters = _skipFormalParameterList(afterTypeParameters); |
| 3876 if (afterParameters == null) { |
| 3877 return false; |
| 3878 } |
| 3879 if (afterParameters |
| 3880 .matchesAny([TokenType.OPEN_CURLY_BRACKET, TokenType.FUNCTION])) { |
| 3881 return true; |
| 3882 } |
| 3883 String lexeme = afterParameters.lexeme; |
| 3884 return lexeme == ASYNC || lexeme == SYNC; |
| 3885 } |
| 3886 |
| 3887 /** |
| 3888 * Return `true` if the given [character] is a valid hexadecimal digit. |
| 3889 */ |
| 3890 bool _isHexDigit(int character) => (0x30 <= character && character <= 0x39) || |
| 3891 (0x41 <= character && character <= 0x46) || |
| 3892 (0x61 <= character && character <= 0x66); |
| 3893 |
| 3894 /** |
| 3895 * Return `true` if the current token is the first token in an initialized |
| 3896 * variable declaration rather than an expression. This method assumes that we |
| 3897 * have already skipped past any metadata that might be associated with the |
| 3898 * declaration. |
| 3899 * |
| 3900 * initializedVariableDeclaration ::= |
| 3901 * declaredIdentifier ('=' expression)? (',' initializedIdentifier)* |
| 3902 * |
| 3903 * declaredIdentifier ::= |
| 3904 * metadata finalConstVarOrType identifier |
| 3905 * |
| 3906 * finalConstVarOrType ::= |
| 3907 * 'final' type? |
| 3908 * | 'const' type? |
| 3909 * | 'var' |
| 3910 * | type |
| 3911 * |
| 3912 * type ::= |
| 3913 * qualified typeArguments? |
| 3914 * |
| 3915 * initializedIdentifier ::= |
| 3916 * identifier ('=' expression)? |
| 3917 */ |
| 3918 bool _isInitializedVariableDeclaration() { |
| 3919 if (_matchesKeyword(Keyword.FINAL) || _matchesKeyword(Keyword.VAR)) { |
| 3920 // An expression cannot start with a keyword other than 'const', |
| 3921 // 'rethrow', or 'throw'. |
| 3922 return true; |
| 3923 } |
| 3924 if (_matchesKeyword(Keyword.CONST)) { |
| 3925 // Look to see whether we might be at the start of a list or map literal, |
| 3926 // otherwise this should be the start of a variable declaration. |
| 3927 return !_peek().matchesAny([ |
| 3928 TokenType.LT, |
| 3929 TokenType.OPEN_CURLY_BRACKET, |
| 3930 TokenType.OPEN_SQUARE_BRACKET, |
| 3931 TokenType.INDEX |
| 3932 ]); |
| 3933 } |
| 3934 // We know that we have an identifier, and need to see whether it might be |
| 3935 // a type name. |
| 3936 Token token = _skipTypeName(_currentToken); |
| 3937 if (token == null) { |
| 3938 // There was no type name, so this can't be a declaration. |
| 3939 return false; |
| 3940 } |
| 3941 token = _skipSimpleIdentifier(token); |
| 3942 if (token == null) { |
| 3943 return false; |
| 3944 } |
| 3945 TokenType type = token.type; |
| 3946 return type == TokenType.EQ || |
| 3947 type == TokenType.COMMA || |
| 3948 type == TokenType.SEMICOLON || |
| 3949 _tokenMatchesKeyword(token, Keyword.IN); |
| 3950 } |
| 3951 |
| 3952 bool _isLikelyParameterList() { |
| 3953 if (_matches(TokenType.OPEN_PAREN)) { |
| 3954 return true; |
| 3955 } |
| 3956 if (!parseGenericMethods) { |
| 3957 return false; |
| 3958 } |
| 3959 Token token = _skipTypeArgumentList(_currentToken); |
| 3960 return token != null && _tokenMatches(token, TokenType.OPEN_PAREN); |
| 3961 } |
| 3962 |
| 3963 /** |
| 3964 * Given that we have just found bracketed text within the given [comment], |
| 3965 * look to see whether that text is (a) followed by a parenthesized link |
| 3966 * address, (b) followed by a colon, or (c) followed by optional whitespace |
| 3967 * and another square bracket. The [rightIndex] is the index of the right |
| 3968 * bracket. Return `true` if the bracketed text is followed by a link address. |
| 3969 * |
| 3970 * This method uses the syntax described by the |
| 3971 * <a href="http://daringfireball.net/projects/markdown/syntax">markdown</a> |
| 3972 * project. |
| 3973 */ |
| 3974 bool _isLinkText(String comment, int rightIndex) { |
| 3975 int length = comment.length; |
| 3976 int index = rightIndex + 1; |
| 3977 if (index >= length) { |
| 3978 return false; |
| 3979 } |
| 3980 int nextChar = comment.codeUnitAt(index); |
| 3981 if (nextChar == 0x28 || nextChar == 0x3A) { |
| 3982 return true; |
| 3983 } |
| 3984 while (Character.isWhitespace(nextChar)) { |
| 3985 index = index + 1; |
| 3986 if (index >= length) { |
| 3987 return false; |
| 3988 } |
| 3989 nextChar = comment.codeUnitAt(index); |
| 3990 } |
| 3991 return nextChar == 0x5B; |
| 3992 } |
| 3993 |
| 3994 /** |
| 3995 * Return `true` if the given [startToken] appears to be the beginning of an |
| 3996 * operator declaration. |
| 3997 */ |
| 3998 bool _isOperator(Token startToken) { |
| 3999 // Accept any operator here, even if it is not user definable. |
| 4000 if (!startToken.isOperator) { |
| 4001 return false; |
| 4002 } |
| 4003 // Token "=" means that it is actually field initializer. |
| 4004 if (startToken.type == TokenType.EQ) { |
| 4005 return false; |
| 4006 } |
| 4007 // Consume all operator tokens. |
| 4008 Token token = startToken.next; |
| 4009 while (token.isOperator) { |
| 4010 token = token.next; |
| 4011 } |
| 4012 // Formal parameter list is expect now. |
| 4013 return _tokenMatches(token, TokenType.OPEN_PAREN); |
| 4014 } |
| 4015 |
| 4016 /** |
| 4017 * Return `true` if the current token appears to be the beginning of a switch |
| 4018 * member. |
| 4019 */ |
| 4020 bool _isSwitchMember() { |
| 4021 Token token = _currentToken; |
| 4022 while (_tokenMatches(token, TokenType.IDENTIFIER) && |
| 4023 _tokenMatches(token.next, TokenType.COLON)) { |
| 4024 token = token.next.next; |
| 4025 } |
| 4026 if (token.type == TokenType.KEYWORD) { |
| 4027 Keyword keyword = (token as KeywordToken).keyword; |
| 4028 return keyword == Keyword.CASE || keyword == Keyword.DEFAULT; |
| 4029 } |
| 4030 return false; |
| 4031 } |
| 4032 |
| 4033 /** |
| 4034 * Return `true` if the [startToken] appears to be the first token of a type |
| 4035 * name that is followed by a variable or field formal parameter. |
| 4036 */ |
| 4037 bool _isTypedIdentifier(Token startToken) { |
| 4038 Token token = _skipReturnType(startToken); |
| 4039 if (token == null) { |
| 4040 return false; |
| 4041 } else if (_tokenMatchesIdentifier(token)) { |
| 4042 return true; |
| 4043 } else if (_tokenMatchesKeyword(token, Keyword.THIS) && |
| 4044 _tokenMatches(token.next, TokenType.PERIOD) && |
| 4045 _tokenMatchesIdentifier(token.next.next)) { |
| 4046 return true; |
| 4047 } else if (_tokenMatchesKeyword(startToken, Keyword.VOID)) { |
| 4048 // The keyword 'void' isn't a valid identifier, so it should be assumed to |
| 4049 // be a type name. |
| 4050 return true; |
| 4051 } else if (startToken.next != token && |
| 4052 !_tokenMatches(token, TokenType.OPEN_PAREN)) { |
| 4053 // The type is more than a simple identifier, so it should be assumed to |
| 4054 // be a type name. |
| 4055 return true; |
| 4056 } |
| 4057 return false; |
| 4058 } |
| 4059 |
| 4060 /** |
| 4061 * Increments the error reporting lock level. If level is more than `0`, then |
| 4062 * [reportError] wont report any error. |
| 4063 */ |
| 4064 void _lockErrorListener() { |
| 4065 _errorListenerLock++; |
| 4066 } |
| 4067 |
| 4068 /** |
| 4069 * Return `true` if the current token has the given [type]. Note that the |
| 4070 * method [_matchesGt] should be used if the argument to this method would be |
| 4071 * [TokenType.GT]. |
| 4072 */ |
| 4073 bool _matches(TokenType type) => _currentToken.type == type; |
| 4074 |
| 4075 /** |
| 4076 * Return `true` if the current token has a type of [TokenType.GT]. Note that |
| 4077 * this method, unlike other variants, will modify the token stream if |
| 4078 * possible to match desired type. In particular, if the next token is either |
| 4079 * a '>>' or '>>>', the token stream will be re-written and `true` will be |
| 4080 * returned. |
| 4081 */ |
| 4082 bool _matchesGt() { |
| 4083 TokenType currentType = _currentToken.type; |
| 4084 if (currentType == TokenType.GT) { |
| 4085 return true; |
| 4086 } else if (currentType == TokenType.GT_GT) { |
| 4087 Token first = _createToken(_currentToken, TokenType.GT); |
| 4088 Token second = new Token(TokenType.GT, _currentToken.offset + 1); |
| 4089 second.setNext(_currentToken.next); |
| 4090 first.setNext(second); |
| 4091 _currentToken.previous.setNext(first); |
| 4092 _currentToken = first; |
| 4093 return true; |
| 4094 } else if (currentType == TokenType.GT_EQ) { |
| 4095 Token first = _createToken(_currentToken, TokenType.GT); |
| 4096 Token second = new Token(TokenType.EQ, _currentToken.offset + 1); |
| 4097 second.setNext(_currentToken.next); |
| 4098 first.setNext(second); |
| 4099 _currentToken.previous.setNext(first); |
| 4100 _currentToken = first; |
| 4101 return true; |
| 4102 } else if (currentType == TokenType.GT_GT_EQ) { |
| 4103 int offset = _currentToken.offset; |
| 4104 Token first = _createToken(_currentToken, TokenType.GT); |
| 4105 Token second = new Token(TokenType.GT, offset + 1); |
| 4106 Token third = new Token(TokenType.EQ, offset + 2); |
| 4107 third.setNext(_currentToken.next); |
| 4108 second.setNext(third); |
| 4109 first.setNext(second); |
| 4110 _currentToken.previous.setNext(first); |
| 4111 _currentToken = first; |
| 4112 return true; |
| 4113 } |
| 4114 return false; |
| 4115 } |
| 4116 |
| 4117 /** |
| 4118 * Return `true` if the current token is a valid identifier. Valid identifiers |
| 4119 * include built-in identifiers (pseudo-keywords). |
| 4120 */ |
| 4121 bool _matchesIdentifier() => _tokenMatchesIdentifier(_currentToken); |
| 4122 |
| 4123 /** |
| 4124 * Return `true` if the current token matches the given [keyword]. |
| 4125 */ |
| 4126 bool _matchesKeyword(Keyword keyword) => |
| 4127 _tokenMatchesKeyword(_currentToken, keyword); |
| 4128 |
| 4129 /** |
| 4130 * Return `true` if the current token matches the given [identifier]. |
| 4131 */ |
| 4132 bool _matchesString(String identifier) => |
| 4133 _currentToken.type == TokenType.IDENTIFIER && |
| 4134 _currentToken.lexeme == identifier; |
| 4135 |
| 4136 /** |
| 4137 * If the current token has the given [type], then advance to the next token |
| 4138 * and return `true`. Otherwise, return `false` without advancing. This method |
| 4139 * should not be invoked with an argument value of [TokenType.GT]. |
| 4140 */ |
| 4141 bool _optional(TokenType type) { |
| 4142 if (_matches(type)) { |
| 4143 _advance(); |
| 4144 return true; |
| 4145 } |
| 4146 return false; |
| 4147 } |
| 4148 |
| 4149 /** |
| 4150 * Parse an additive expression. Return the additive expression that was |
| 4151 * parsed. |
| 4152 * |
| 4153 * additiveExpression ::= |
| 4154 * multiplicativeExpression (additiveOperator multiplicativeExpression
)* |
| 4155 * | 'super' (additiveOperator multiplicativeExpression)+ |
| 4156 */ |
| 4157 Expression _parseAdditiveExpression() { |
| 4158 Expression expression; |
| 4159 if (_matchesKeyword(Keyword.SUPER) && |
| 4160 _currentToken.next.type.isAdditiveOperator) { |
| 4161 expression = new SuperExpression(getAndAdvance()); |
| 4162 } else { |
| 4163 expression = _parseMultiplicativeExpression(); |
| 4164 } |
| 4165 while (_currentToken.type.isAdditiveOperator) { |
| 4166 Token operator = getAndAdvance(); |
| 4167 expression = new BinaryExpression( |
| 4168 expression, operator, _parseMultiplicativeExpression()); |
| 4169 } |
| 4170 return expression; |
| 4171 } |
| 4172 |
| 4173 /** |
| 4174 * Parse an assert statement. Return the assert statement. |
| 4175 * |
| 4176 * assertStatement ::= |
| 4177 * 'assert' '(' conditionalExpression ')' ';' |
| 4178 */ |
| 4179 AssertStatement _parseAssertStatement() { |
| 4180 Token keyword = _expectKeyword(Keyword.ASSERT); |
| 4181 Token leftParen = _expect(TokenType.OPEN_PAREN); |
| 4182 Expression expression = parseExpression2(); |
| 4183 if (expression is AssignmentExpression) { |
| 4184 _reportErrorForNode( |
| 4185 ParserErrorCode.ASSERT_DOES_NOT_TAKE_ASSIGNMENT, expression); |
| 4186 } else if (expression is CascadeExpression) { |
| 4187 _reportErrorForNode( |
| 4188 ParserErrorCode.ASSERT_DOES_NOT_TAKE_CASCADE, expression); |
| 4189 } else if (expression is ThrowExpression) { |
| 4190 _reportErrorForNode( |
| 4191 ParserErrorCode.ASSERT_DOES_NOT_TAKE_THROW, expression); |
| 4192 } else if (expression is RethrowExpression) { |
| 4193 _reportErrorForNode( |
| 4194 ParserErrorCode.ASSERT_DOES_NOT_TAKE_RETHROW, expression); |
| 4195 } |
| 4196 Token rightParen = _expect(TokenType.CLOSE_PAREN); |
| 4197 Token semicolon = _expect(TokenType.SEMICOLON); |
| 4198 return new AssertStatement( |
| 4199 keyword, leftParen, expression, rightParen, semicolon); |
| 4200 } |
| 4201 |
| 4202 /** |
| 4203 * Parse an assignable expression. The [primaryAllowed] is `true` if the |
| 4204 * expression is allowed to be a primary without any assignable selector. |
| 4205 * Return the assignable expression that was parsed. |
| 4206 * |
| 4207 * assignableExpression ::= |
| 4208 * primary (arguments* assignableSelector)+ |
| 4209 * | 'super' unconditionalAssignableSelector |
| 4210 * | identifier |
| 4211 */ |
| 4212 Expression _parseAssignableExpression(bool primaryAllowed) { |
| 4213 if (_matchesKeyword(Keyword.SUPER)) { |
| 4214 return _parseAssignableSelector( |
| 4215 new SuperExpression(getAndAdvance()), false, allowConditional: false); |
| 4216 } |
| 4217 // |
| 4218 // A primary expression can start with an identifier. We resolve the |
| 4219 // ambiguity by determining whether the primary consists of anything other |
| 4220 // than an identifier and/or is followed by an assignableSelector. |
| 4221 // |
| 4222 Expression expression = _parsePrimaryExpression(); |
| 4223 bool isOptional = primaryAllowed || expression is SimpleIdentifier; |
| 4224 while (true) { |
| 4225 while (_isLikelyParameterList()) { |
| 4226 TypeArgumentList typeArguments = null; |
| 4227 if (_matches(TokenType.LT)) { |
| 4228 typeArguments = parseTypeArgumentList(); |
| 4229 } |
| 4230 ArgumentList argumentList = parseArgumentList(); |
| 4231 if (expression is SimpleIdentifier) { |
| 4232 expression = new MethodInvocation(null, null, |
| 4233 expression as SimpleIdentifier, typeArguments, argumentList); |
| 4234 } else if (expression is PrefixedIdentifier) { |
| 4235 PrefixedIdentifier identifier = expression as PrefixedIdentifier; |
| 4236 expression = new MethodInvocation(identifier.prefix, |
| 4237 identifier.period, identifier.identifier, typeArguments, |
| 4238 argumentList); |
| 4239 } else if (expression is PropertyAccess) { |
| 4240 PropertyAccess access = expression as PropertyAccess; |
| 4241 expression = new MethodInvocation(access.target, access.operator, |
| 4242 access.propertyName, typeArguments, argumentList); |
| 4243 } else { |
| 4244 expression = new FunctionExpressionInvocation( |
| 4245 expression, typeArguments, argumentList); |
| 4246 } |
| 4247 if (!primaryAllowed) { |
| 4248 isOptional = false; |
| 4249 } |
| 4250 } |
| 4251 Expression selectorExpression = _parseAssignableSelector( |
| 4252 expression, isOptional || (expression is PrefixedIdentifier)); |
| 4253 if (identical(selectorExpression, expression)) { |
| 4254 if (!isOptional && (expression is PrefixedIdentifier)) { |
| 4255 PrefixedIdentifier identifier = expression as PrefixedIdentifier; |
| 4256 expression = new PropertyAccess( |
| 4257 identifier.prefix, identifier.period, identifier.identifier); |
| 4258 } |
| 4259 return expression; |
| 4260 } |
| 4261 expression = selectorExpression; |
| 4262 isOptional = true; |
| 4263 } |
| 4264 } |
| 4265 |
| 4266 /** |
| 4267 * Parse an assignable selector. The [prefix] is the expression preceding the |
| 4268 * selector. The [optional] is `true` if the selector is optional. Return the |
| 4269 * assignable selector that was parsed, or the original prefix if there was no |
| 4270 * assignable selector. If [allowConditional] is false, then the '?.' |
| 4271 * operator will still be parsed, but a parse error will be generated. |
| 4272 * |
| 4273 * unconditionalAssignableSelector ::= |
| 4274 * '[' expression ']' |
| 4275 * | '.' identifier |
| 4276 * |
| 4277 * assignableSelector ::= |
| 4278 * unconditionalAssignableSelector |
| 4279 * | '?.' identifier |
| 4280 */ |
| 4281 Expression _parseAssignableSelector(Expression prefix, bool optional, |
| 4282 {bool allowConditional: true}) { |
| 4283 if (_matches(TokenType.OPEN_SQUARE_BRACKET)) { |
| 4284 Token leftBracket = getAndAdvance(); |
| 4285 bool wasInInitializer = _inInitializer; |
| 4286 _inInitializer = false; |
| 4287 try { |
| 4288 Expression index = parseExpression2(); |
| 4289 Token rightBracket = _expect(TokenType.CLOSE_SQUARE_BRACKET); |
| 4290 return new IndexExpression.forTarget( |
| 4291 prefix, leftBracket, index, rightBracket); |
| 4292 } finally { |
| 4293 _inInitializer = wasInInitializer; |
| 4294 } |
| 4295 } else if (_matches(TokenType.PERIOD) || |
| 4296 _matches(TokenType.QUESTION_PERIOD)) { |
| 4297 if (_matches(TokenType.QUESTION_PERIOD) && !allowConditional) { |
| 4298 _reportErrorForCurrentToken( |
| 4299 ParserErrorCode.INVALID_OPERATOR_FOR_SUPER, [_currentToken.lexeme]); |
| 4300 } |
| 4301 Token operator = getAndAdvance(); |
| 4302 return new PropertyAccess(prefix, operator, parseSimpleIdentifier()); |
| 4303 } else { |
| 4304 if (!optional) { |
| 4305 // Report the missing selector. |
| 4306 _reportErrorForCurrentToken( |
| 4307 ParserErrorCode.MISSING_ASSIGNABLE_SELECTOR); |
| 4308 } |
| 4309 return prefix; |
| 4310 } |
| 4311 } |
| 4312 |
| 4313 /** |
| 4314 * Parse a await expression. Return the await expression that was parsed. |
| 4315 * |
| 4316 * awaitExpression ::= |
| 4317 * 'await' unaryExpression |
| 4318 */ |
| 4319 AwaitExpression _parseAwaitExpression() { |
| 4320 Token awaitToken = getAndAdvance(); |
| 4321 Expression expression = _parseUnaryExpression(); |
| 4322 return new AwaitExpression(awaitToken, expression); |
| 4323 } |
| 4324 |
| 4325 /** |
| 4326 * Parse a bitwise and expression. Return the bitwise and expression that was |
| 4327 * parsed. |
| 4328 * |
| 4329 * bitwiseAndExpression ::= |
| 4330 * shiftExpression ('&' shiftExpression)* |
| 4331 * | 'super' ('&' shiftExpression)+ |
| 4332 */ |
| 4333 Expression _parseBitwiseAndExpression() { |
| 4334 Expression expression; |
| 4335 if (_matchesKeyword(Keyword.SUPER) && |
| 4336 _tokenMatches(_peek(), TokenType.AMPERSAND)) { |
| 4337 expression = new SuperExpression(getAndAdvance()); |
| 4338 } else { |
| 4339 expression = _parseShiftExpression(); |
| 4340 } |
| 4341 while (_matches(TokenType.AMPERSAND)) { |
| 4342 Token operator = getAndAdvance(); |
| 4343 expression = |
| 4344 new BinaryExpression(expression, operator, _parseShiftExpression()); |
| 4345 } |
| 4346 return expression; |
| 4347 } |
| 4348 |
| 4349 /** |
| 4350 * Parse a bitwise exclusive-or expression. Return the bitwise exclusive-or |
| 4351 * expression that was parsed. |
| 4352 * |
| 4353 * bitwiseXorExpression ::= |
| 4354 * bitwiseAndExpression ('^' bitwiseAndExpression)* |
| 4355 * | 'super' ('^' bitwiseAndExpression)+ |
| 4356 */ |
| 4357 Expression _parseBitwiseXorExpression() { |
| 4358 Expression expression; |
| 4359 if (_matchesKeyword(Keyword.SUPER) && |
| 4360 _tokenMatches(_peek(), TokenType.CARET)) { |
| 4361 expression = new SuperExpression(getAndAdvance()); |
| 4362 } else { |
| 4363 expression = _parseBitwiseAndExpression(); |
| 4364 } |
| 4365 while (_matches(TokenType.CARET)) { |
| 4366 Token operator = getAndAdvance(); |
| 4367 expression = new BinaryExpression( |
| 4368 expression, operator, _parseBitwiseAndExpression()); |
| 4369 } |
| 4370 return expression; |
| 4371 } |
| 4372 |
| 4373 /** |
| 4374 * Parse a break statement. Return the break statement that was parsed. |
| 4375 * |
| 4376 * breakStatement ::= |
| 4377 * 'break' identifier? ';' |
| 4378 */ |
| 4379 Statement _parseBreakStatement() { |
| 4380 Token breakKeyword = _expectKeyword(Keyword.BREAK); |
| 4381 SimpleIdentifier label = null; |
| 4382 if (_matchesIdentifier()) { |
| 4383 label = parseSimpleIdentifier(); |
| 4384 } |
| 4385 if (!_inLoop && !_inSwitch && label == null) { |
| 4386 _reportErrorForToken(ParserErrorCode.BREAK_OUTSIDE_OF_LOOP, breakKeyword); |
| 4387 } |
| 4388 Token semicolon = _expect(TokenType.SEMICOLON); |
| 4389 return new BreakStatement(breakKeyword, label, semicolon); |
| 4390 } |
| 4391 |
| 4392 /** |
| 4393 * Parse a cascade section. Return the expression representing the cascaded |
| 4394 * method invocation. |
| 4395 * |
| 4396 * cascadeSection ::= |
| 4397 * '..' (cascadeSelector typeArguments? arguments*) |
| 4398 * (assignableSelector typeArguments? arguments*)* cascadeAssignment? |
| 4399 * |
| 4400 * cascadeSelector ::= |
| 4401 * '[' expression ']' |
| 4402 * | identifier |
| 4403 * |
| 4404 * cascadeAssignment ::= |
| 4405 * assignmentOperator expressionWithoutCascade |
| 4406 */ |
| 4407 Expression _parseCascadeSection() { |
| 4408 Token period = _expect(TokenType.PERIOD_PERIOD); |
| 4409 Expression expression = null; |
| 4410 SimpleIdentifier functionName = null; |
| 4411 if (_matchesIdentifier()) { |
| 4412 functionName = parseSimpleIdentifier(); |
| 4413 } else if (_currentToken.type == TokenType.OPEN_SQUARE_BRACKET) { |
| 4414 Token leftBracket = getAndAdvance(); |
| 4415 bool wasInInitializer = _inInitializer; |
| 4416 _inInitializer = false; |
| 4417 try { |
| 4418 Expression index = parseExpression2(); |
| 4419 Token rightBracket = _expect(TokenType.CLOSE_SQUARE_BRACKET); |
| 4420 expression = new IndexExpression.forCascade( |
| 4421 period, leftBracket, index, rightBracket); |
| 4422 period = null; |
| 4423 } finally { |
| 4424 _inInitializer = wasInInitializer; |
| 4425 } |
| 4426 } else { |
| 4427 _reportErrorForToken(ParserErrorCode.MISSING_IDENTIFIER, _currentToken, |
| 4428 [_currentToken.lexeme]); |
| 4429 functionName = _createSyntheticIdentifier(); |
| 4430 } |
| 4431 assert((expression == null && functionName != null) || |
| 4432 (expression != null && functionName == null)); |
| 4433 if (_isLikelyParameterList()) { |
| 4434 while (_isLikelyParameterList()) { |
| 4435 TypeArgumentList typeArguments = null; |
| 4436 if (_matches(TokenType.LT)) { |
| 4437 typeArguments = parseTypeArgumentList(); |
| 4438 } |
| 4439 if (functionName != null) { |
| 4440 expression = new MethodInvocation(expression, period, functionName, |
| 4441 typeArguments, parseArgumentList()); |
| 4442 period = null; |
| 4443 functionName = null; |
| 4444 } else if (expression == null) { |
| 4445 // It should not be possible to get here. |
| 4446 expression = new MethodInvocation(expression, period, |
| 4447 _createSyntheticIdentifier(), typeArguments, parseArgumentList()); |
| 4448 } else { |
| 4449 expression = new FunctionExpressionInvocation( |
| 4450 expression, typeArguments, parseArgumentList()); |
| 4451 } |
| 4452 } |
| 4453 } else if (functionName != null) { |
| 4454 expression = new PropertyAccess(expression, period, functionName); |
| 4455 period = null; |
| 4456 } |
| 4457 assert(expression != null); |
| 4458 bool progress = true; |
| 4459 while (progress) { |
| 4460 progress = false; |
| 4461 Expression selector = _parseAssignableSelector(expression, true); |
| 4462 if (!identical(selector, expression)) { |
| 4463 expression = selector; |
| 4464 progress = true; |
| 4465 while (_isLikelyParameterList()) { |
| 4466 TypeArgumentList typeArguments = null; |
| 4467 if (_matches(TokenType.LT)) { |
| 4468 typeArguments = parseTypeArgumentList(); |
| 4469 } |
| 4470 if (expression is PropertyAccess) { |
| 4471 PropertyAccess propertyAccess = expression as PropertyAccess; |
| 4472 expression = new MethodInvocation(propertyAccess.target, |
| 4473 propertyAccess.operator, propertyAccess.propertyName, |
| 4474 typeArguments, parseArgumentList()); |
| 4475 } else { |
| 4476 expression = new FunctionExpressionInvocation( |
| 4477 expression, typeArguments, parseArgumentList()); |
| 4478 } |
| 4479 } |
| 4480 } |
| 4481 } |
| 4482 if (_currentToken.type.isAssignmentOperator) { |
| 4483 Token operator = getAndAdvance(); |
| 4484 _ensureAssignable(expression); |
| 4485 expression = new AssignmentExpression( |
| 4486 expression, operator, parseExpressionWithoutCascade()); |
| 4487 } |
| 4488 return expression; |
| 4489 } |
| 4490 |
| 4491 /** |
| 4492 * Parse a class declaration. The [commentAndMetadata] is the metadata to be |
| 4493 * associated with the member. The [abstractKeyword] is the token for the |
| 4494 * keyword 'abstract', or `null` if the keyword was not given. Return the |
| 4495 * class declaration that was parsed. |
| 4496 * |
| 4497 * classDeclaration ::= |
| 4498 * metadata 'abstract'? 'class' name typeParameterList? (extendsClause
withClause?)? implementsClause? '{' classMembers '}' | |
| 4499 * metadata 'abstract'? 'class' mixinApplicationClass |
| 4500 */ |
| 4501 CompilationUnitMember _parseClassDeclaration( |
| 4502 CommentAndMetadata commentAndMetadata, Token abstractKeyword) { |
| 4503 Token keyword = _expectKeyword(Keyword.CLASS); |
| 4504 if (_matchesIdentifier()) { |
| 4505 Token next = _peek(); |
| 4506 if (_tokenMatches(next, TokenType.LT)) { |
| 4507 next = _skipTypeParameterList(next); |
| 4508 if (next != null && _tokenMatches(next, TokenType.EQ)) { |
| 4509 return _parseClassTypeAlias( |
| 4510 commentAndMetadata, abstractKeyword, keyword); |
| 4511 } |
| 4512 } else if (_tokenMatches(next, TokenType.EQ)) { |
| 4513 return _parseClassTypeAlias( |
| 4514 commentAndMetadata, abstractKeyword, keyword); |
| 4515 } |
| 4516 } |
| 4517 SimpleIdentifier name = parseSimpleIdentifier(); |
| 4518 String className = name.name; |
| 4519 TypeParameterList typeParameters = null; |
| 4520 if (_matches(TokenType.LT)) { |
| 4521 typeParameters = parseTypeParameterList(); |
| 4522 } |
| 4523 // |
| 4524 // Parse the clauses. The parser accepts clauses in any order, but will |
| 4525 // generate errors if they are not in the order required by the |
| 4526 // specification. |
| 4527 // |
| 4528 ExtendsClause extendsClause = null; |
| 4529 WithClause withClause = null; |
| 4530 ImplementsClause implementsClause = null; |
| 4531 bool foundClause = true; |
| 4532 while (foundClause) { |
| 4533 if (_matchesKeyword(Keyword.EXTENDS)) { |
| 4534 if (extendsClause == null) { |
| 4535 extendsClause = parseExtendsClause(); |
| 4536 if (withClause != null) { |
| 4537 _reportErrorForToken( |
| 4538 ParserErrorCode.WITH_BEFORE_EXTENDS, withClause.withKeyword); |
| 4539 } else if (implementsClause != null) { |
| 4540 _reportErrorForToken(ParserErrorCode.IMPLEMENTS_BEFORE_EXTENDS, |
| 4541 implementsClause.implementsKeyword); |
| 4542 } |
| 4543 } else { |
| 4544 _reportErrorForToken(ParserErrorCode.MULTIPLE_EXTENDS_CLAUSES, |
| 4545 extendsClause.extendsKeyword); |
| 4546 parseExtendsClause(); |
| 4547 } |
| 4548 } else if (_matchesKeyword(Keyword.WITH)) { |
| 4549 if (withClause == null) { |
| 4550 withClause = parseWithClause(); |
| 4551 if (implementsClause != null) { |
| 4552 _reportErrorForToken(ParserErrorCode.IMPLEMENTS_BEFORE_WITH, |
| 4553 implementsClause.implementsKeyword); |
| 4554 } |
| 4555 } else { |
| 4556 _reportErrorForToken( |
| 4557 ParserErrorCode.MULTIPLE_WITH_CLAUSES, withClause.withKeyword); |
| 4558 parseWithClause(); |
| 4559 // TODO(brianwilkerson) Should we merge the list of applied mixins |
| 4560 // into a single list? |
| 4561 } |
| 4562 } else if (_matchesKeyword(Keyword.IMPLEMENTS)) { |
| 4563 if (implementsClause == null) { |
| 4564 implementsClause = parseImplementsClause(); |
| 4565 } else { |
| 4566 _reportErrorForToken(ParserErrorCode.MULTIPLE_IMPLEMENTS_CLAUSES, |
| 4567 implementsClause.implementsKeyword); |
| 4568 parseImplementsClause(); |
| 4569 // TODO(brianwilkerson) Should we merge the list of implemented |
| 4570 // classes into a single list? |
| 4571 } |
| 4572 } else { |
| 4573 foundClause = false; |
| 4574 } |
| 4575 } |
| 4576 if (withClause != null && extendsClause == null) { |
| 4577 _reportErrorForToken( |
| 4578 ParserErrorCode.WITH_WITHOUT_EXTENDS, withClause.withKeyword); |
| 4579 } |
| 4580 // |
| 4581 // Look for and skip over the extra-lingual 'native' specification. |
| 4582 // |
| 4583 NativeClause nativeClause = null; |
| 4584 if (_matchesString(_NATIVE) && _tokenMatches(_peek(), TokenType.STRING)) { |
| 4585 nativeClause = _parseNativeClause(); |
| 4586 } |
| 4587 // |
| 4588 // Parse the body of the class. |
| 4589 // |
| 4590 Token leftBracket = null; |
| 4591 List<ClassMember> members = null; |
| 4592 Token rightBracket = null; |
| 4593 if (_matches(TokenType.OPEN_CURLY_BRACKET)) { |
| 4594 leftBracket = _expect(TokenType.OPEN_CURLY_BRACKET); |
| 4595 members = _parseClassMembers(className, _getEndToken(leftBracket)); |
| 4596 rightBracket = _expect(TokenType.CLOSE_CURLY_BRACKET); |
| 4597 } else { |
| 4598 leftBracket = _createSyntheticToken(TokenType.OPEN_CURLY_BRACKET); |
| 4599 rightBracket = _createSyntheticToken(TokenType.CLOSE_CURLY_BRACKET); |
| 4600 _reportErrorForCurrentToken(ParserErrorCode.MISSING_CLASS_BODY); |
| 4601 } |
| 4602 ClassDeclaration classDeclaration = new ClassDeclaration( |
| 4603 commentAndMetadata.comment, commentAndMetadata.metadata, |
| 4604 abstractKeyword, keyword, name, typeParameters, extendsClause, |
| 4605 withClause, implementsClause, leftBracket, members, rightBracket); |
| 4606 classDeclaration.nativeClause = nativeClause; |
| 4607 return classDeclaration; |
| 4608 } |
| 4609 |
| 4610 /** |
| 4611 * Parse a list of class members. The [className] is the name of the class |
| 4612 * whose members are being parsed. The [closingBracket] is the closing bracket |
| 4613 * for the class, or `null` if the closing bracket is missing. Return the list |
| 4614 * of class members that were parsed. |
| 4615 * |
| 4616 * classMembers ::= |
| 4617 * (metadata memberDefinition)* |
| 4618 */ |
| 4619 List<ClassMember> _parseClassMembers(String className, Token closingBracket) { |
| 4620 List<ClassMember> members = new List<ClassMember>(); |
| 4621 Token memberStart = _currentToken; |
| 4622 while (!_matches(TokenType.EOF) && |
| 4623 !_matches(TokenType.CLOSE_CURLY_BRACKET) && |
| 4624 (closingBracket != null || |
| 4625 (!_matchesKeyword(Keyword.CLASS) && |
| 4626 !_matchesKeyword(Keyword.TYPEDEF)))) { |
| 4627 if (_matches(TokenType.SEMICOLON)) { |
| 4628 _reportErrorForToken(ParserErrorCode.UNEXPECTED_TOKEN, _currentToken, |
| 4629 [_currentToken.lexeme]); |
| 4630 _advance(); |
| 4631 } else { |
| 4632 ClassMember member = parseClassMember(className); |
| 4633 if (member != null) { |
| 4634 members.add(member); |
| 4635 } |
| 4636 } |
| 4637 if (identical(_currentToken, memberStart)) { |
| 4638 _reportErrorForToken(ParserErrorCode.UNEXPECTED_TOKEN, _currentToken, |
| 4639 [_currentToken.lexeme]); |
| 4640 _advance(); |
| 4641 } |
| 4642 memberStart = _currentToken; |
| 4643 } |
| 4644 return members; |
| 4645 } |
| 4646 |
| 4647 /** |
| 4648 * Parse a class type alias. The [commentAndMetadata] is the metadata to be |
| 4649 * associated with the member. The [abstractKeyword] is the token representing |
| 4650 * the 'abstract' keyword. The [classKeyword] is the token representing the |
| 4651 * 'class' keyword. Return the class type alias that was parsed. |
| 4652 * |
| 4653 * classTypeAlias ::= |
| 4654 * identifier typeParameters? '=' 'abstract'? mixinApplication |
| 4655 * |
| 4656 * mixinApplication ::= |
| 4657 * type withClause implementsClause? ';' |
| 4658 */ |
| 4659 ClassTypeAlias _parseClassTypeAlias(CommentAndMetadata commentAndMetadata, |
| 4660 Token abstractKeyword, Token classKeyword) { |
| 4661 SimpleIdentifier className = parseSimpleIdentifier(); |
| 4662 TypeParameterList typeParameters = null; |
| 4663 if (_matches(TokenType.LT)) { |
| 4664 typeParameters = parseTypeParameterList(); |
| 4665 } |
| 4666 Token equals = _expect(TokenType.EQ); |
| 4667 TypeName superclass = parseTypeName(); |
| 4668 WithClause withClause = null; |
| 4669 if (_matchesKeyword(Keyword.WITH)) { |
| 4670 withClause = parseWithClause(); |
| 4671 } else { |
| 4672 _reportErrorForCurrentToken( |
| 4673 ParserErrorCode.EXPECTED_TOKEN, [Keyword.WITH.syntax]); |
| 4674 } |
| 4675 ImplementsClause implementsClause = null; |
| 4676 if (_matchesKeyword(Keyword.IMPLEMENTS)) { |
| 4677 implementsClause = parseImplementsClause(); |
| 4678 } |
| 4679 Token semicolon; |
| 4680 if (_matches(TokenType.SEMICOLON)) { |
| 4681 semicolon = getAndAdvance(); |
| 4682 } else { |
| 4683 if (_matches(TokenType.OPEN_CURLY_BRACKET)) { |
| 4684 _reportErrorForCurrentToken( |
| 4685 ParserErrorCode.EXPECTED_TOKEN, [TokenType.SEMICOLON.lexeme]); |
| 4686 Token leftBracket = getAndAdvance(); |
| 4687 _parseClassMembers(className.name, _getEndToken(leftBracket)); |
| 4688 _expect(TokenType.CLOSE_CURLY_BRACKET); |
| 4689 } else { |
| 4690 _reportErrorForToken(ParserErrorCode.EXPECTED_TOKEN, |
| 4691 _currentToken.previous, [TokenType.SEMICOLON.lexeme]); |
| 4692 } |
| 4693 semicolon = _createSyntheticToken(TokenType.SEMICOLON); |
| 4694 } |
| 4695 return new ClassTypeAlias(commentAndMetadata.comment, |
| 4696 commentAndMetadata.metadata, classKeyword, className, typeParameters, |
| 4697 equals, abstractKeyword, superclass, withClause, implementsClause, |
| 4698 semicolon); |
| 4699 } |
| 4700 |
| 4701 /** |
| 4702 * Parse a list of combinators in a directive. Return the combinators that |
| 4703 * were parsed. |
| 4704 * |
| 4705 * combinator ::= |
| 4706 * 'show' identifier (',' identifier)* |
| 4707 * | 'hide' identifier (',' identifier)* |
| 4708 */ |
| 4709 List<Combinator> _parseCombinators() { |
| 4710 List<Combinator> combinators = new List<Combinator>(); |
| 4711 while (true) { |
| 4712 Combinator combinator = parseCombinator(); |
| 4713 if (combinator == null) { |
| 4714 break; |
| 4715 } |
| 4716 combinators.add(combinator); |
| 4717 } |
| 4718 return combinators; |
| 4719 } |
| 4720 |
| 4721 /** |
| 4722 * Parse the documentation comment and metadata preceding a declaration. This |
| 4723 * method allows any number of documentation comments to occur before, after |
| 4724 * or between the metadata, but only returns the last (right-most) |
| 4725 * documentation comment that is found. Return the documentation comment and |
| 4726 * metadata that were parsed. |
| 4727 * |
| 4728 * metadata ::= |
| 4729 * annotation* |
| 4730 */ |
| 4731 CommentAndMetadata _parseCommentAndMetadata() { |
| 4732 Comment comment = _parseDocumentationComment(); |
| 4733 List<Annotation> metadata = new List<Annotation>(); |
| 4734 while (_matches(TokenType.AT)) { |
| 4735 metadata.add(parseAnnotation()); |
| 4736 Comment optionalComment = _parseDocumentationComment(); |
| 4737 if (optionalComment != null) { |
| 4738 comment = optionalComment; |
| 4739 } |
| 4740 } |
| 4741 return new CommentAndMetadata(comment, metadata); |
| 4742 } |
| 4743 |
| 4744 /** |
| 4745 * Parse a comment reference from the source between square brackets. The |
| 4746 * [referenceSource] is the source occurring between the square brackets |
| 4747 * within a documentation comment. The [sourceOffset] is the offset of the |
| 4748 * first character of the reference source. Return the comment reference that |
| 4749 * was parsed, or `null` if no reference could be found. |
| 4750 * |
| 4751 * commentReference ::= |
| 4752 * 'new'? prefixedIdentifier |
| 4753 */ |
| 4754 CommentReference _parseCommentReference( |
| 4755 String referenceSource, int sourceOffset) { |
| 4756 // TODO(brianwilkerson) The errors are not getting the right offset/length |
| 4757 // and are being duplicated. |
| 4758 if (referenceSource.length == 0) { |
| 4759 Token syntheticToken = |
| 4760 new SyntheticStringToken(TokenType.IDENTIFIER, "", sourceOffset); |
| 4761 return new CommentReference(null, new SimpleIdentifier(syntheticToken)); |
| 4762 } |
| 4763 try { |
| 4764 BooleanErrorListener listener = new BooleanErrorListener(); |
| 4765 Scanner scanner = new Scanner( |
| 4766 null, new SubSequenceReader(referenceSource, sourceOffset), listener); |
| 4767 scanner.setSourceStart(1, 1); |
| 4768 Token firstToken = scanner.tokenize(); |
| 4769 if (listener.errorReported) { |
| 4770 return null; |
| 4771 } |
| 4772 Token newKeyword = null; |
| 4773 if (_tokenMatchesKeyword(firstToken, Keyword.NEW)) { |
| 4774 newKeyword = firstToken; |
| 4775 firstToken = firstToken.next; |
| 4776 } |
| 4777 if (_tokenMatchesIdentifier(firstToken)) { |
| 4778 Token secondToken = firstToken.next; |
| 4779 Token thirdToken = secondToken.next; |
| 4780 Token nextToken; |
| 4781 Identifier identifier; |
| 4782 if (_tokenMatches(secondToken, TokenType.PERIOD) && |
| 4783 _tokenMatchesIdentifier(thirdToken)) { |
| 4784 identifier = new PrefixedIdentifier(new SimpleIdentifier(firstToken), |
| 4785 secondToken, new SimpleIdentifier(thirdToken)); |
| 4786 nextToken = thirdToken.next; |
| 4787 } else { |
| 4788 identifier = new SimpleIdentifier(firstToken); |
| 4789 nextToken = firstToken.next; |
| 4790 } |
| 4791 if (nextToken.type != TokenType.EOF) { |
| 4792 return null; |
| 4793 } |
| 4794 return new CommentReference(newKeyword, identifier); |
| 4795 } else if (_tokenMatchesKeyword(firstToken, Keyword.THIS) || |
| 4796 _tokenMatchesKeyword(firstToken, Keyword.NULL) || |
| 4797 _tokenMatchesKeyword(firstToken, Keyword.TRUE) || |
| 4798 _tokenMatchesKeyword(firstToken, Keyword.FALSE)) { |
| 4799 // TODO(brianwilkerson) If we want to support this we will need to |
| 4800 // extend the definition of CommentReference to take an expression |
| 4801 // rather than an identifier. For now we just ignore it to reduce the |
| 4802 // number of errors produced, but that's probably not a valid long term |
| 4803 // approach. |
| 4804 return null; |
| 4805 } |
| 4806 } catch (exception) { |
| 4807 // Ignored because we assume that it wasn't a real comment reference. |
| 4808 } |
| 4809 return null; |
| 4810 } |
| 4811 |
| 4812 /** |
| 4813 * Parse all of the comment references occurring in the given array of |
| 4814 * documentation comments. The [tokens] are the comment tokens representing |
| 4815 * the documentation comments to be parsed. Return the comment references that |
| 4816 * were parsed. |
| 4817 * |
| 4818 * commentReference ::= |
| 4819 * '[' 'new'? qualified ']' libraryReference? |
| 4820 * |
| 4821 * libraryReference ::= |
| 4822 * '(' stringLiteral ')' |
| 4823 */ |
| 4824 List<CommentReference> _parseCommentReferences( |
| 4825 List<DocumentationCommentToken> tokens) { |
| 4826 List<CommentReference> references = new List<CommentReference>(); |
| 4827 for (DocumentationCommentToken token in tokens) { |
| 4828 String comment = token.lexeme; |
| 4829 int length = comment.length; |
| 4830 List<List<int>> codeBlockRanges = _getCodeBlockRanges(comment); |
| 4831 int leftIndex = comment.indexOf('['); |
| 4832 while (leftIndex >= 0 && leftIndex + 1 < length) { |
| 4833 List<int> range = _findRange(codeBlockRanges, leftIndex); |
| 4834 if (range == null) { |
| 4835 int nameOffset = token.offset + leftIndex + 1; |
| 4836 int rightIndex = JavaString.indexOf(comment, ']', leftIndex); |
| 4837 if (rightIndex >= 0) { |
| 4838 int firstChar = comment.codeUnitAt(leftIndex + 1); |
| 4839 if (firstChar != 0x27 && firstChar != 0x22) { |
| 4840 if (_isLinkText(comment, rightIndex)) { |
| 4841 // TODO(brianwilkerson) Handle the case where there's a library |
| 4842 // URI in the link text. |
| 4843 } else { |
| 4844 CommentReference reference = _parseCommentReference( |
| 4845 comment.substring(leftIndex + 1, rightIndex), nameOffset); |
| 4846 if (reference != null) { |
| 4847 references.add(reference); |
| 4848 token.references.add(reference.beginToken); |
| 4849 } |
| 4850 } |
| 4851 } |
| 4852 } else { |
| 4853 // terminating ']' is not typed yet |
| 4854 int charAfterLeft = comment.codeUnitAt(leftIndex + 1); |
| 4855 if (Character.isLetterOrDigit(charAfterLeft)) { |
| 4856 int nameEnd = StringUtilities.indexOfFirstNotLetterDigit( |
| 4857 comment, leftIndex + 1); |
| 4858 String name = comment.substring(leftIndex + 1, nameEnd); |
| 4859 Token nameToken = |
| 4860 new StringToken(TokenType.IDENTIFIER, name, nameOffset); |
| 4861 references.add( |
| 4862 new CommentReference(null, new SimpleIdentifier(nameToken))); |
| 4863 } else { |
| 4864 Token nameToken = new SyntheticStringToken( |
| 4865 TokenType.IDENTIFIER, "", nameOffset); |
| 4866 references.add( |
| 4867 new CommentReference(null, new SimpleIdentifier(nameToken))); |
| 4868 } |
| 4869 // next character |
| 4870 rightIndex = leftIndex + 1; |
| 4871 } |
| 4872 leftIndex = JavaString.indexOf(comment, '[', rightIndex); |
| 4873 } else { |
| 4874 leftIndex = JavaString.indexOf(comment, '[', range[1] + 1); |
| 4875 } |
| 4876 } |
| 4877 } |
| 4878 return references; |
| 4879 } |
| 4880 |
| 4881 /** |
| 4882 * Parse a compilation unit member. The [commentAndMetadata] is the metadata |
| 4883 * to be associated with the member. Return the compilation unit member that |
| 4884 * was parsed, or `null` if what was parsed could not be represented as a |
| 4885 * compilation unit member. |
| 4886 * |
| 4887 * compilationUnitMember ::= |
| 4888 * classDefinition |
| 4889 * | functionTypeAlias |
| 4890 * | external functionSignature |
| 4891 * | external getterSignature |
| 4892 * | external setterSignature |
| 4893 * | functionSignature functionBody |
| 4894 * | returnType? getOrSet identifier formalParameterList functionBody |
| 4895 * | (final | const) type? staticFinalDeclarationList ';' |
| 4896 * | variableDeclaration ';' |
| 4897 */ |
| 4898 CompilationUnitMember _parseCompilationUnitMember( |
| 4899 CommentAndMetadata commentAndMetadata) { |
| 4900 Modifiers modifiers = _parseModifiers(); |
| 4901 if (_matchesKeyword(Keyword.CLASS)) { |
| 4902 return _parseClassDeclaration( |
| 4903 commentAndMetadata, _validateModifiersForClass(modifiers)); |
| 4904 } else if (_matchesKeyword(Keyword.TYPEDEF) && |
| 4905 !_tokenMatches(_peek(), TokenType.PERIOD) && |
| 4906 !_tokenMatches(_peek(), TokenType.LT) && |
| 4907 !_tokenMatches(_peek(), TokenType.OPEN_PAREN)) { |
| 4908 _validateModifiersForTypedef(modifiers); |
| 4909 return _parseTypeAlias(commentAndMetadata); |
| 4910 } else if (_matchesKeyword(Keyword.ENUM)) { |
| 4911 _validateModifiersForEnum(modifiers); |
| 4912 return _parseEnumDeclaration(commentAndMetadata); |
| 4913 } |
| 4914 if (_matchesKeyword(Keyword.VOID)) { |
| 4915 TypeName returnType = parseReturnType(); |
| 4916 if ((_matchesKeyword(Keyword.GET) || _matchesKeyword(Keyword.SET)) && |
| 4917 _tokenMatchesIdentifier(_peek())) { |
| 4918 _validateModifiersForTopLevelFunction(modifiers); |
| 4919 return _parseFunctionDeclaration( |
| 4920 commentAndMetadata, modifiers.externalKeyword, returnType); |
| 4921 } else if (_matchesKeyword(Keyword.OPERATOR) && _isOperator(_peek())) { |
| 4922 _reportErrorForToken(ParserErrorCode.TOP_LEVEL_OPERATOR, _currentToken); |
| 4923 return _convertToFunctionDeclaration(_parseOperator( |
| 4924 commentAndMetadata, modifiers.externalKeyword, returnType)); |
| 4925 } else if (_matchesIdentifier() && |
| 4926 _peek().matchesAny([ |
| 4927 TokenType.OPEN_PAREN, |
| 4928 TokenType.OPEN_CURLY_BRACKET, |
| 4929 TokenType.FUNCTION |
| 4930 ])) { |
| 4931 _validateModifiersForTopLevelFunction(modifiers); |
| 4932 return _parseFunctionDeclaration( |
| 4933 commentAndMetadata, modifiers.externalKeyword, returnType); |
| 4934 } else { |
| 4935 // |
| 4936 // We have found an error of some kind. Try to recover. |
| 4937 // |
| 4938 if (_matchesIdentifier()) { |
| 4939 if (_peek().matchesAny( |
| 4940 [TokenType.EQ, TokenType.COMMA, TokenType.SEMICOLON])) { |
| 4941 // |
| 4942 // We appear to have a variable declaration with a type of "void". |
| 4943 // |
| 4944 _reportErrorForNode(ParserErrorCode.VOID_VARIABLE, returnType); |
| 4945 return new TopLevelVariableDeclaration(commentAndMetadata.comment, |
| 4946 commentAndMetadata.metadata, |
| 4947 _parseVariableDeclarationListAfterType(null, |
| 4948 _validateModifiersForTopLevelVariable(modifiers), null), |
| 4949 _expect(TokenType.SEMICOLON)); |
| 4950 } |
| 4951 } |
| 4952 _reportErrorForToken( |
| 4953 ParserErrorCode.EXPECTED_EXECUTABLE, _currentToken); |
| 4954 return null; |
| 4955 } |
| 4956 } else if ((_matchesKeyword(Keyword.GET) || _matchesKeyword(Keyword.SET)) && |
| 4957 _tokenMatchesIdentifier(_peek())) { |
| 4958 _validateModifiersForTopLevelFunction(modifiers); |
| 4959 return _parseFunctionDeclaration( |
| 4960 commentAndMetadata, modifiers.externalKeyword, null); |
| 4961 } else if (_matchesKeyword(Keyword.OPERATOR) && _isOperator(_peek())) { |
| 4962 _reportErrorForToken(ParserErrorCode.TOP_LEVEL_OPERATOR, _currentToken); |
| 4963 return _convertToFunctionDeclaration( |
| 4964 _parseOperator(commentAndMetadata, modifiers.externalKeyword, null)); |
| 4965 } else if (!_matchesIdentifier()) { |
| 4966 Token keyword = modifiers.varKeyword; |
| 4967 if (keyword == null) { |
| 4968 keyword = modifiers.finalKeyword; |
| 4969 } |
| 4970 if (keyword == null) { |
| 4971 keyword = modifiers.constKeyword; |
| 4972 } |
| 4973 if (keyword != null) { |
| 4974 // |
| 4975 // We appear to have found an incomplete top-level variable declaration. |
| 4976 // |
| 4977 _reportErrorForCurrentToken(ParserErrorCode.MISSING_IDENTIFIER); |
| 4978 List<VariableDeclaration> variables = new List<VariableDeclaration>(); |
| 4979 variables.add( |
| 4980 new VariableDeclaration(_createSyntheticIdentifier(), null, null)); |
| 4981 return new TopLevelVariableDeclaration(commentAndMetadata.comment, |
| 4982 commentAndMetadata.metadata, |
| 4983 new VariableDeclarationList(null, null, keyword, null, variables), |
| 4984 _expectSemicolon()); |
| 4985 } |
| 4986 _reportErrorForToken(ParserErrorCode.EXPECTED_EXECUTABLE, _currentToken); |
| 4987 return null; |
| 4988 } else if (_tokenMatches(_peek(), TokenType.OPEN_PAREN)) { |
| 4989 _validateModifiersForTopLevelFunction(modifiers); |
| 4990 return _parseFunctionDeclaration( |
| 4991 commentAndMetadata, modifiers.externalKeyword, null); |
| 4992 } else if (_peek() |
| 4993 .matchesAny([TokenType.EQ, TokenType.COMMA, TokenType.SEMICOLON])) { |
| 4994 if (modifiers.constKeyword == null && |
| 4995 modifiers.finalKeyword == null && |
| 4996 modifiers.varKeyword == null) { |
| 4997 _reportErrorForCurrentToken( |
| 4998 ParserErrorCode.MISSING_CONST_FINAL_VAR_OR_TYPE); |
| 4999 } |
| 5000 return new TopLevelVariableDeclaration(commentAndMetadata.comment, |
| 5001 commentAndMetadata.metadata, _parseVariableDeclarationListAfterType( |
| 5002 null, _validateModifiersForTopLevelVariable(modifiers), null), |
| 5003 _expect(TokenType.SEMICOLON)); |
| 5004 } |
| 5005 TypeName returnType = parseReturnType(); |
| 5006 if ((_matchesKeyword(Keyword.GET) || _matchesKeyword(Keyword.SET)) && |
| 5007 _tokenMatchesIdentifier(_peek())) { |
| 5008 _validateModifiersForTopLevelFunction(modifiers); |
| 5009 return _parseFunctionDeclaration( |
| 5010 commentAndMetadata, modifiers.externalKeyword, returnType); |
| 5011 } else if (_matchesKeyword(Keyword.OPERATOR) && _isOperator(_peek())) { |
| 5012 _reportErrorForToken(ParserErrorCode.TOP_LEVEL_OPERATOR, _currentToken); |
| 5013 return _convertToFunctionDeclaration(_parseOperator( |
| 5014 commentAndMetadata, modifiers.externalKeyword, returnType)); |
| 5015 } else if (_matches(TokenType.AT)) { |
| 5016 return new TopLevelVariableDeclaration(commentAndMetadata.comment, |
| 5017 commentAndMetadata.metadata, _parseVariableDeclarationListAfterType( |
| 5018 null, _validateModifiersForTopLevelVariable(modifiers), |
| 5019 returnType), _expect(TokenType.SEMICOLON)); |
| 5020 } else if (!_matchesIdentifier()) { |
| 5021 // TODO(brianwilkerson) Generalize this error. We could also be parsing a |
| 5022 // top-level variable at this point. |
| 5023 _reportErrorForToken(ParserErrorCode.EXPECTED_EXECUTABLE, _currentToken); |
| 5024 Token semicolon; |
| 5025 if (_matches(TokenType.SEMICOLON)) { |
| 5026 semicolon = getAndAdvance(); |
| 5027 } else { |
| 5028 semicolon = _createSyntheticToken(TokenType.SEMICOLON); |
| 5029 } |
| 5030 List<VariableDeclaration> variables = new List<VariableDeclaration>(); |
| 5031 variables.add( |
| 5032 new VariableDeclaration(_createSyntheticIdentifier(), null, null)); |
| 5033 return new TopLevelVariableDeclaration(commentAndMetadata.comment, |
| 5034 commentAndMetadata.metadata, |
| 5035 new VariableDeclarationList(null, null, null, returnType, variables), |
| 5036 semicolon); |
| 5037 } |
| 5038 if (_peek().matchesAny([ |
| 5039 TokenType.OPEN_PAREN, |
| 5040 TokenType.FUNCTION, |
| 5041 TokenType.OPEN_CURLY_BRACKET |
| 5042 ])) { |
| 5043 _validateModifiersForTopLevelFunction(modifiers); |
| 5044 return _parseFunctionDeclaration( |
| 5045 commentAndMetadata, modifiers.externalKeyword, returnType); |
| 5046 } |
| 5047 return new TopLevelVariableDeclaration(commentAndMetadata.comment, |
| 5048 commentAndMetadata.metadata, _parseVariableDeclarationListAfterType( |
| 5049 null, _validateModifiersForTopLevelVariable(modifiers), returnType), |
| 5050 _expect(TokenType.SEMICOLON)); |
| 5051 } |
| 5052 |
| 5053 /** |
| 5054 * Parse a const expression. Return the const expression that was parsed. |
| 5055 * |
| 5056 * constExpression ::= |
| 5057 * instanceCreationExpression |
| 5058 * | listLiteral |
| 5059 * | mapLiteral |
| 5060 */ |
| 5061 Expression _parseConstExpression() { |
| 5062 Token keyword = _expectKeyword(Keyword.CONST); |
| 5063 if (_matches(TokenType.OPEN_SQUARE_BRACKET) || _matches(TokenType.INDEX)) { |
| 5064 return _parseListLiteral(keyword, null); |
| 5065 } else if (_matches(TokenType.OPEN_CURLY_BRACKET)) { |
| 5066 return _parseMapLiteral(keyword, null); |
| 5067 } else if (_matches(TokenType.LT)) { |
| 5068 return _parseListOrMapLiteral(keyword); |
| 5069 } |
| 5070 return _parseInstanceCreationExpression(keyword); |
| 5071 } |
| 5072 |
| 5073 ConstructorDeclaration _parseConstructor( |
| 5074 CommentAndMetadata commentAndMetadata, Token externalKeyword, |
| 5075 Token constKeyword, Token factoryKeyword, SimpleIdentifier returnType, |
| 5076 Token period, SimpleIdentifier name, FormalParameterList parameters) { |
| 5077 bool bodyAllowed = externalKeyword == null; |
| 5078 Token separator = null; |
| 5079 List<ConstructorInitializer> initializers = null; |
| 5080 if (_matches(TokenType.COLON)) { |
| 5081 separator = getAndAdvance(); |
| 5082 initializers = new List<ConstructorInitializer>(); |
| 5083 do { |
| 5084 if (_matchesKeyword(Keyword.THIS)) { |
| 5085 if (_tokenMatches(_peek(), TokenType.OPEN_PAREN)) { |
| 5086 bodyAllowed = false; |
| 5087 initializers.add(_parseRedirectingConstructorInvocation()); |
| 5088 } else if (_tokenMatches(_peek(), TokenType.PERIOD) && |
| 5089 _tokenMatches(_peekAt(3), TokenType.OPEN_PAREN)) { |
| 5090 bodyAllowed = false; |
| 5091 initializers.add(_parseRedirectingConstructorInvocation()); |
| 5092 } else { |
| 5093 initializers.add(_parseConstructorFieldInitializer()); |
| 5094 } |
| 5095 } else if (_matchesKeyword(Keyword.SUPER)) { |
| 5096 initializers.add(_parseSuperConstructorInvocation()); |
| 5097 } else if (_matches(TokenType.OPEN_CURLY_BRACKET) || |
| 5098 _matches(TokenType.FUNCTION)) { |
| 5099 _reportErrorForCurrentToken(ParserErrorCode.MISSING_INITIALIZER); |
| 5100 } else { |
| 5101 initializers.add(_parseConstructorFieldInitializer()); |
| 5102 } |
| 5103 } while (_optional(TokenType.COMMA)); |
| 5104 if (factoryKeyword != null) { |
| 5105 _reportErrorForToken( |
| 5106 ParserErrorCode.FACTORY_WITH_INITIALIZERS, factoryKeyword); |
| 5107 } |
| 5108 } |
| 5109 ConstructorName redirectedConstructor = null; |
| 5110 FunctionBody body; |
| 5111 if (_matches(TokenType.EQ)) { |
| 5112 separator = getAndAdvance(); |
| 5113 redirectedConstructor = parseConstructorName(); |
| 5114 body = new EmptyFunctionBody(_expect(TokenType.SEMICOLON)); |
| 5115 if (factoryKeyword == null) { |
| 5116 _reportErrorForNode( |
| 5117 ParserErrorCode.REDIRECTION_IN_NON_FACTORY_CONSTRUCTOR, |
| 5118 redirectedConstructor); |
| 5119 } |
| 5120 } else { |
| 5121 body = _parseFunctionBody( |
| 5122 true, ParserErrorCode.MISSING_FUNCTION_BODY, false); |
| 5123 if (constKeyword != null && |
| 5124 factoryKeyword != null && |
| 5125 externalKeyword == null) { |
| 5126 _reportErrorForToken(ParserErrorCode.CONST_FACTORY, factoryKeyword); |
| 5127 } else if (body is EmptyFunctionBody) { |
| 5128 if (factoryKeyword != null && |
| 5129 externalKeyword == null && |
| 5130 _parseFunctionBodies) { |
| 5131 _reportErrorForToken( |
| 5132 ParserErrorCode.FACTORY_WITHOUT_BODY, factoryKeyword); |
| 5133 } |
| 5134 } else { |
| 5135 if (constKeyword != null) { |
| 5136 _reportErrorForNode( |
| 5137 ParserErrorCode.CONST_CONSTRUCTOR_WITH_BODY, body); |
| 5138 } else if (!bodyAllowed) { |
| 5139 _reportErrorForNode( |
| 5140 ParserErrorCode.EXTERNAL_CONSTRUCTOR_WITH_BODY, body); |
| 5141 } |
| 5142 } |
| 5143 } |
| 5144 return new ConstructorDeclaration(commentAndMetadata.comment, |
| 5145 commentAndMetadata.metadata, externalKeyword, constKeyword, |
| 5146 factoryKeyword, returnType, period, name, parameters, separator, |
| 5147 initializers, redirectedConstructor, body); |
| 5148 } |
| 5149 |
| 5150 /** |
| 5151 * Parse a field initializer within a constructor. Return the field |
| 5152 * initializer that was parsed. |
| 5153 * |
| 5154 * fieldInitializer: |
| 5155 * ('this' '.')? identifier '=' conditionalExpression cascadeSection* |
| 5156 */ |
| 5157 ConstructorFieldInitializer _parseConstructorFieldInitializer() { |
| 5158 Token keyword = null; |
| 5159 Token period = null; |
| 5160 if (_matchesKeyword(Keyword.THIS)) { |
| 5161 keyword = getAndAdvance(); |
| 5162 period = _expect(TokenType.PERIOD); |
| 5163 } |
| 5164 SimpleIdentifier fieldName = parseSimpleIdentifier(); |
| 5165 Token equals = null; |
| 5166 if (_matches(TokenType.EQ)) { |
| 5167 equals = getAndAdvance(); |
| 5168 } else if (!_matchesKeyword(Keyword.THIS) && |
| 5169 !_matchesKeyword(Keyword.SUPER) && |
| 5170 !_matches(TokenType.OPEN_CURLY_BRACKET) && |
| 5171 !_matches(TokenType.FUNCTION)) { |
| 5172 _reportErrorForCurrentToken( |
| 5173 ParserErrorCode.MISSING_ASSIGNMENT_IN_INITIALIZER); |
| 5174 equals = _createSyntheticToken(TokenType.EQ); |
| 5175 } else { |
| 5176 _reportErrorForCurrentToken( |
| 5177 ParserErrorCode.MISSING_ASSIGNMENT_IN_INITIALIZER); |
| 5178 return new ConstructorFieldInitializer(keyword, period, fieldName, |
| 5179 _createSyntheticToken(TokenType.EQ), _createSyntheticIdentifier()); |
| 5180 } |
| 5181 bool wasInInitializer = _inInitializer; |
| 5182 _inInitializer = true; |
| 5183 try { |
| 5184 Expression expression = parseConditionalExpression(); |
| 5185 TokenType tokenType = _currentToken.type; |
| 5186 if (tokenType == TokenType.PERIOD_PERIOD) { |
| 5187 List<Expression> cascadeSections = new List<Expression>(); |
| 5188 while (tokenType == TokenType.PERIOD_PERIOD) { |
| 5189 Expression section = _parseCascadeSection(); |
| 5190 if (section != null) { |
| 5191 cascadeSections.add(section); |
| 5192 } |
| 5193 tokenType = _currentToken.type; |
| 5194 } |
| 5195 expression = new CascadeExpression(expression, cascadeSections); |
| 5196 } |
| 5197 return new ConstructorFieldInitializer( |
| 5198 keyword, period, fieldName, equals, expression); |
| 5199 } finally { |
| 5200 _inInitializer = wasInInitializer; |
| 5201 } |
| 5202 } |
| 5203 |
| 5204 /** |
| 5205 * Parse a continue statement. Return the continue statement that was parsed. |
| 5206 * |
| 5207 * continueStatement ::= |
| 5208 * 'continue' identifier? ';' |
| 5209 */ |
| 5210 Statement _parseContinueStatement() { |
| 5211 Token continueKeyword = _expectKeyword(Keyword.CONTINUE); |
| 5212 if (!_inLoop && !_inSwitch) { |
| 5213 _reportErrorForToken( |
| 5214 ParserErrorCode.CONTINUE_OUTSIDE_OF_LOOP, continueKeyword); |
| 5215 } |
| 5216 SimpleIdentifier label = null; |
| 5217 if (_matchesIdentifier()) { |
| 5218 label = parseSimpleIdentifier(); |
| 5219 } |
| 5220 if (_inSwitch && !_inLoop && label == null) { |
| 5221 _reportErrorForToken( |
| 5222 ParserErrorCode.CONTINUE_WITHOUT_LABEL_IN_CASE, continueKeyword); |
| 5223 } |
| 5224 Token semicolon = _expect(TokenType.SEMICOLON); |
| 5225 return new ContinueStatement(continueKeyword, label, semicolon); |
| 5226 } |
| 5227 |
| 5228 /** |
| 5229 * Parse a directive. The [commentAndMetadata] is the metadata to be |
| 5230 * associated with the directive. Return the directive that was parsed. |
| 5231 * |
| 5232 * directive ::= |
| 5233 * exportDirective |
| 5234 * | libraryDirective |
| 5235 * | importDirective |
| 5236 * | partDirective |
| 5237 */ |
| 5238 Directive _parseDirective(CommentAndMetadata commentAndMetadata) { |
| 5239 if (_matchesKeyword(Keyword.IMPORT)) { |
| 5240 return _parseImportDirective(commentAndMetadata); |
| 5241 } else if (_matchesKeyword(Keyword.EXPORT)) { |
| 5242 return _parseExportDirective(commentAndMetadata); |
| 5243 } else if (_matchesKeyword(Keyword.LIBRARY)) { |
| 5244 return _parseLibraryDirective(commentAndMetadata); |
| 5245 } else if (_matchesKeyword(Keyword.PART)) { |
| 5246 return _parsePartDirective(commentAndMetadata); |
| 5247 } else { |
| 5248 // Internal error: this method should not have been invoked if the current |
| 5249 // token was something other than one of the above. |
| 5250 throw new IllegalStateException( |
| 5251 "parseDirective invoked in an invalid state; currentToken = $_currentT
oken"); |
| 5252 } |
| 5253 } |
| 5254 |
| 5255 /** |
| 5256 * Parse the script tag and directives in a compilation unit until the first |
| 5257 * non-directive is encountered. Return the compilation unit that was parsed. |
| 5258 * |
| 5259 * compilationUnit ::= |
| 5260 * scriptTag? directive* |
| 5261 */ |
| 5262 CompilationUnit _parseDirectives() { |
| 5263 Token firstToken = _currentToken; |
| 5264 ScriptTag scriptTag = null; |
| 5265 if (_matches(TokenType.SCRIPT_TAG)) { |
| 5266 scriptTag = new ScriptTag(getAndAdvance()); |
| 5267 } |
| 5268 List<Directive> directives = new List<Directive>(); |
| 5269 while (!_matches(TokenType.EOF)) { |
| 5270 CommentAndMetadata commentAndMetadata = _parseCommentAndMetadata(); |
| 5271 if ((_matchesKeyword(Keyword.IMPORT) || |
| 5272 _matchesKeyword(Keyword.EXPORT) || |
| 5273 _matchesKeyword(Keyword.LIBRARY) || |
| 5274 _matchesKeyword(Keyword.PART)) && |
| 5275 !_tokenMatches(_peek(), TokenType.PERIOD) && |
| 5276 !_tokenMatches(_peek(), TokenType.LT) && |
| 5277 !_tokenMatches(_peek(), TokenType.OPEN_PAREN)) { |
| 5278 directives.add(_parseDirective(commentAndMetadata)); |
| 5279 } else if (_matches(TokenType.SEMICOLON)) { |
| 5280 _advance(); |
| 5281 } else { |
| 5282 while (!_matches(TokenType.EOF)) { |
| 5283 _advance(); |
| 5284 } |
| 5285 return new CompilationUnit(firstToken, scriptTag, directives, |
| 5286 new List<CompilationUnitMember>(), _currentToken); |
| 5287 } |
| 5288 } |
| 5289 return new CompilationUnit(firstToken, scriptTag, directives, |
| 5290 new List<CompilationUnitMember>(), _currentToken); |
| 5291 } |
| 5292 |
| 5293 /** |
| 5294 * Parse a documentation comment. Return the documentation comment that was |
| 5295 * parsed, or `null` if there was no comment. |
| 5296 * |
| 5297 * documentationComment ::= |
| 5298 * multiLineComment? |
| 5299 * | singleLineComment* |
| 5300 */ |
| 5301 Comment _parseDocumentationComment() { |
| 5302 List<DocumentationCommentToken> documentationTokens = |
| 5303 <DocumentationCommentToken>[]; |
| 5304 CommentToken commentToken = _currentToken.precedingComments; |
| 5305 while (commentToken != null) { |
| 5306 if (commentToken is DocumentationCommentToken) { |
| 5307 if (documentationTokens.isNotEmpty) { |
| 5308 if (commentToken.type == TokenType.SINGLE_LINE_COMMENT) { |
| 5309 if (documentationTokens[0].type != TokenType.SINGLE_LINE_COMMENT) { |
| 5310 documentationTokens.clear(); |
| 5311 } |
| 5312 } else { |
| 5313 documentationTokens.clear(); |
| 5314 } |
| 5315 } |
| 5316 documentationTokens.add(commentToken); |
| 5317 } |
| 5318 commentToken = commentToken.next; |
| 5319 } |
| 5320 if (documentationTokens.isEmpty) { |
| 5321 return null; |
| 5322 } |
| 5323 List<CommentReference> references = |
| 5324 _parseCommentReferences(documentationTokens); |
| 5325 return Comment.createDocumentationCommentWithReferences( |
| 5326 documentationTokens, references); |
| 5327 } |
| 5328 |
| 5329 /** |
| 5330 * Parse a do statement. Return the do statement that was parsed. |
| 5331 * |
| 5332 * doStatement ::= |
| 5333 * 'do' statement 'while' '(' expression ')' ';' |
| 5334 */ |
| 5335 Statement _parseDoStatement() { |
| 5336 bool wasInLoop = _inLoop; |
| 5337 _inLoop = true; |
| 5338 try { |
| 5339 Token doKeyword = _expectKeyword(Keyword.DO); |
| 5340 Statement body = parseStatement2(); |
| 5341 Token whileKeyword = _expectKeyword(Keyword.WHILE); |
| 5342 Token leftParenthesis = _expect(TokenType.OPEN_PAREN); |
| 5343 Expression condition = parseExpression2(); |
| 5344 Token rightParenthesis = _expect(TokenType.CLOSE_PAREN); |
| 5345 Token semicolon = _expect(TokenType.SEMICOLON); |
| 5346 return new DoStatement(doKeyword, body, whileKeyword, leftParenthesis, |
| 5347 condition, rightParenthesis, semicolon); |
| 5348 } finally { |
| 5349 _inLoop = wasInLoop; |
| 5350 } |
| 5351 } |
| 5352 |
| 5353 /** |
| 5354 * Parse an empty statement. Return the empty statement that was parsed. |
| 5355 * |
| 5356 * emptyStatement ::= |
| 5357 * ';' |
| 5358 */ |
| 5359 Statement _parseEmptyStatement() => new EmptyStatement(getAndAdvance()); |
| 5360 |
| 5361 EnumConstantDeclaration _parseEnumConstantDeclaration() { |
| 5362 CommentAndMetadata commentAndMetadata = _parseCommentAndMetadata(); |
| 5363 SimpleIdentifier name; |
| 5364 if (_matchesIdentifier()) { |
| 5365 name = parseSimpleIdentifier(); |
| 5366 } else { |
| 5367 name = _createSyntheticIdentifier(); |
| 5368 } |
| 5369 if (commentAndMetadata.metadata.isNotEmpty) { |
| 5370 _reportErrorForNode(ParserErrorCode.ANNOTATION_ON_ENUM_CONSTANT, |
| 5371 commentAndMetadata.metadata[0]); |
| 5372 } |
| 5373 return new EnumConstantDeclaration( |
| 5374 commentAndMetadata.comment, commentAndMetadata.metadata, name); |
| 5375 } |
| 5376 |
| 5377 /** |
| 5378 * Parse an enum declaration. The [commentAndMetadata] is the metadata to be |
| 5379 * associated with the member. Return the enum declaration that was parsed. |
| 5380 * |
| 5381 * enumType ::= |
| 5382 * metadata 'enum' id '{' id (',' id)* (',')? '}' |
| 5383 */ |
| 5384 EnumDeclaration _parseEnumDeclaration(CommentAndMetadata commentAndMetadata) { |
| 5385 Token keyword = _expectKeyword(Keyword.ENUM); |
| 5386 SimpleIdentifier name = parseSimpleIdentifier(); |
| 5387 Token leftBracket = null; |
| 5388 List<EnumConstantDeclaration> constants = |
| 5389 new List<EnumConstantDeclaration>(); |
| 5390 Token rightBracket = null; |
| 5391 if (_matches(TokenType.OPEN_CURLY_BRACKET)) { |
| 5392 leftBracket = _expect(TokenType.OPEN_CURLY_BRACKET); |
| 5393 if (_matchesIdentifier() || _matches(TokenType.AT)) { |
| 5394 constants.add(_parseEnumConstantDeclaration()); |
| 5395 } else if (_matches(TokenType.COMMA) && |
| 5396 _tokenMatchesIdentifier(_peek())) { |
| 5397 constants.add(_parseEnumConstantDeclaration()); |
| 5398 _reportErrorForCurrentToken(ParserErrorCode.MISSING_IDENTIFIER); |
| 5399 } else { |
| 5400 constants.add(_parseEnumConstantDeclaration()); |
| 5401 _reportErrorForCurrentToken(ParserErrorCode.EMPTY_ENUM_BODY); |
| 5402 } |
| 5403 while (_optional(TokenType.COMMA)) { |
| 5404 if (_matches(TokenType.CLOSE_CURLY_BRACKET)) { |
| 5405 break; |
| 5406 } |
| 5407 constants.add(_parseEnumConstantDeclaration()); |
| 5408 } |
| 5409 rightBracket = _expect(TokenType.CLOSE_CURLY_BRACKET); |
| 5410 } else { |
| 5411 leftBracket = _createSyntheticToken(TokenType.OPEN_CURLY_BRACKET); |
| 5412 rightBracket = _createSyntheticToken(TokenType.CLOSE_CURLY_BRACKET); |
| 5413 _reportErrorForCurrentToken(ParserErrorCode.MISSING_ENUM_BODY); |
| 5414 } |
| 5415 return new EnumDeclaration(commentAndMetadata.comment, |
| 5416 commentAndMetadata.metadata, keyword, name, leftBracket, constants, |
| 5417 rightBracket); |
| 5418 } |
| 5419 |
| 5420 /** |
| 5421 * Parse an equality expression. Return the equality expression that was |
| 5422 * parsed. |
| 5423 * |
| 5424 * equalityExpression ::= |
| 5425 * relationalExpression (equalityOperator relationalExpression)? |
| 5426 * | 'super' equalityOperator relationalExpression |
| 5427 */ |
| 5428 Expression _parseEqualityExpression() { |
| 5429 Expression expression; |
| 5430 if (_matchesKeyword(Keyword.SUPER) && |
| 5431 _currentToken.next.type.isEqualityOperator) { |
| 5432 expression = new SuperExpression(getAndAdvance()); |
| 5433 } else { |
| 5434 expression = _parseRelationalExpression(); |
| 5435 } |
| 5436 bool leftEqualityExpression = false; |
| 5437 while (_currentToken.type.isEqualityOperator) { |
| 5438 Token operator = getAndAdvance(); |
| 5439 if (leftEqualityExpression) { |
| 5440 _reportErrorForNode( |
| 5441 ParserErrorCode.EQUALITY_CANNOT_BE_EQUALITY_OPERAND, expression); |
| 5442 } |
| 5443 expression = new BinaryExpression( |
| 5444 expression, operator, _parseRelationalExpression()); |
| 5445 leftEqualityExpression = true; |
| 5446 } |
| 5447 return expression; |
| 5448 } |
| 5449 |
| 5450 /** |
| 5451 * Parse an export directive. The [commentAndMetadata] is the metadata to be |
| 5452 * associated with the directive. Return the export directive that was parsed. |
| 5453 * |
| 5454 * exportDirective ::= |
| 5455 * metadata 'export' stringLiteral combinator*';' |
| 5456 */ |
| 5457 ExportDirective _parseExportDirective(CommentAndMetadata commentAndMetadata) { |
| 5458 Token exportKeyword = _expectKeyword(Keyword.EXPORT); |
| 5459 StringLiteral libraryUri = _parseUri(); |
| 5460 List<Combinator> combinators = _parseCombinators(); |
| 5461 Token semicolon = _expectSemicolon(); |
| 5462 return new ExportDirective(commentAndMetadata.comment, |
| 5463 commentAndMetadata.metadata, exportKeyword, libraryUri, combinators, |
| 5464 semicolon); |
| 5465 } |
| 5466 |
| 5467 /** |
| 5468 * Parse a list of expressions. Return the expression that was parsed. |
| 5469 * |
| 5470 * expressionList ::= |
| 5471 * expression (',' expression)* |
| 5472 */ |
| 5473 List<Expression> _parseExpressionList() { |
| 5474 List<Expression> expressions = new List<Expression>(); |
| 5475 expressions.add(parseExpression2()); |
| 5476 while (_optional(TokenType.COMMA)) { |
| 5477 expressions.add(parseExpression2()); |
| 5478 } |
| 5479 return expressions; |
| 5480 } |
| 5481 |
| 5482 /** |
| 5483 * Parse the 'final', 'const', 'var' or type preceding a variable declaration. |
| 5484 * The [optional] is `true` if the keyword and type are optional. Return the |
| 5485 * 'final', 'const', 'var' or type that was parsed. |
| 5486 * |
| 5487 * finalConstVarOrType ::= |
| 5488 * 'final' type? |
| 5489 * | 'const' type? |
| 5490 * | 'var' |
| 5491 * | type |
| 5492 */ |
| 5493 FinalConstVarOrType _parseFinalConstVarOrType(bool optional) { |
| 5494 Token keyword = null; |
| 5495 TypeName type = null; |
| 5496 if (_matchesKeyword(Keyword.FINAL) || _matchesKeyword(Keyword.CONST)) { |
| 5497 keyword = getAndAdvance(); |
| 5498 if (_isTypedIdentifier(_currentToken)) { |
| 5499 type = parseTypeName(); |
| 5500 } |
| 5501 } else if (_matchesKeyword(Keyword.VAR)) { |
| 5502 keyword = getAndAdvance(); |
| 5503 } else { |
| 5504 if (_isTypedIdentifier(_currentToken)) { |
| 5505 type = parseReturnType(); |
| 5506 } else if (!optional) { |
| 5507 _reportErrorForCurrentToken( |
| 5508 ParserErrorCode.MISSING_CONST_FINAL_VAR_OR_TYPE); |
| 5509 } |
| 5510 } |
| 5511 return new FinalConstVarOrType(keyword, type); |
| 5512 } |
| 5513 |
| 5514 /** |
| 5515 * Parse a formal parameter. At most one of `isOptional` and `isNamed` can be |
| 5516 * `true`. The [kind] is the kind of parameter being expected based on the |
| 5517 * presence or absence of group delimiters. Return the formal parameter that |
| 5518 * was parsed. |
| 5519 * |
| 5520 * defaultFormalParameter ::= |
| 5521 * normalFormalParameter ('=' expression)? |
| 5522 * |
| 5523 * defaultNamedParameter ::= |
| 5524 * normalFormalParameter (':' expression)? |
| 5525 */ |
| 5526 FormalParameter _parseFormalParameter(ParameterKind kind) { |
| 5527 NormalFormalParameter parameter = parseNormalFormalParameter(); |
| 5528 if (_matches(TokenType.EQ)) { |
| 5529 Token seperator = getAndAdvance(); |
| 5530 Expression defaultValue = parseExpression2(); |
| 5531 if (kind == ParameterKind.NAMED) { |
| 5532 _reportErrorForToken( |
| 5533 ParserErrorCode.WRONG_SEPARATOR_FOR_NAMED_PARAMETER, seperator); |
| 5534 } else if (kind == ParameterKind.REQUIRED) { |
| 5535 _reportErrorForNode( |
| 5536 ParserErrorCode.POSITIONAL_PARAMETER_OUTSIDE_GROUP, parameter); |
| 5537 } |
| 5538 return new DefaultFormalParameter( |
| 5539 parameter, kind, seperator, defaultValue); |
| 5540 } else if (_matches(TokenType.COLON)) { |
| 5541 Token seperator = getAndAdvance(); |
| 5542 Expression defaultValue = parseExpression2(); |
| 5543 if (kind == ParameterKind.POSITIONAL) { |
| 5544 _reportErrorForToken( |
| 5545 ParserErrorCode.WRONG_SEPARATOR_FOR_POSITIONAL_PARAMETER, |
| 5546 seperator); |
| 5547 } else if (kind == ParameterKind.REQUIRED) { |
| 5548 _reportErrorForNode( |
| 5549 ParserErrorCode.NAMED_PARAMETER_OUTSIDE_GROUP, parameter); |
| 5550 } |
| 5551 return new DefaultFormalParameter( |
| 5552 parameter, kind, seperator, defaultValue); |
| 5553 } else if (kind != ParameterKind.REQUIRED) { |
| 5554 return new DefaultFormalParameter(parameter, kind, null, null); |
| 5555 } |
| 5556 return parameter; |
| 5557 } |
| 5558 |
| 5559 /** |
| 5560 * Parse a for statement. Return the for statement that was parsed. |
| 5561 * |
| 5562 * forStatement ::= |
| 5563 * 'for' '(' forLoopParts ')' statement |
| 5564 * |
| 5565 * forLoopParts ::= |
| 5566 * forInitializerStatement expression? ';' expressionList? |
| 5567 * | declaredIdentifier 'in' expression |
| 5568 * | identifier 'in' expression |
| 5569 * |
| 5570 * forInitializerStatement ::= |
| 5571 * localVariableDeclaration ';' |
| 5572 * | expression? ';' |
| 5573 */ |
| 5574 Statement _parseForStatement() { |
| 5575 bool wasInLoop = _inLoop; |
| 5576 _inLoop = true; |
| 5577 try { |
| 5578 Token awaitKeyword = null; |
| 5579 if (_matchesString(_AWAIT)) { |
| 5580 awaitKeyword = getAndAdvance(); |
| 5581 } |
| 5582 Token forKeyword = _expectKeyword(Keyword.FOR); |
| 5583 Token leftParenthesis = _expect(TokenType.OPEN_PAREN); |
| 5584 VariableDeclarationList variableList = null; |
| 5585 Expression initialization = null; |
| 5586 if (!_matches(TokenType.SEMICOLON)) { |
| 5587 CommentAndMetadata commentAndMetadata = _parseCommentAndMetadata(); |
| 5588 if (_matchesIdentifier() && |
| 5589 (_tokenMatchesKeyword(_peek(), Keyword.IN) || |
| 5590 _tokenMatches(_peek(), TokenType.COLON))) { |
| 5591 List<VariableDeclaration> variables = new List<VariableDeclaration>(); |
| 5592 SimpleIdentifier variableName = parseSimpleIdentifier(); |
| 5593 variables.add(new VariableDeclaration(variableName, null, null)); |
| 5594 variableList = new VariableDeclarationList(commentAndMetadata.comment, |
| 5595 commentAndMetadata.metadata, null, null, variables); |
| 5596 } else if (_isInitializedVariableDeclaration()) { |
| 5597 variableList = |
| 5598 _parseVariableDeclarationListAfterMetadata(commentAndMetadata); |
| 5599 } else { |
| 5600 initialization = parseExpression2(); |
| 5601 } |
| 5602 if (_matchesKeyword(Keyword.IN) || _matches(TokenType.COLON)) { |
| 5603 if (_matches(TokenType.COLON)) { |
| 5604 _reportErrorForCurrentToken(ParserErrorCode.COLON_IN_PLACE_OF_IN); |
| 5605 } |
| 5606 DeclaredIdentifier loopVariable = null; |
| 5607 SimpleIdentifier identifier = null; |
| 5608 if (variableList == null) { |
| 5609 // We found: <expression> 'in' |
| 5610 _reportErrorForCurrentToken( |
| 5611 ParserErrorCode.MISSING_VARIABLE_IN_FOR_EACH); |
| 5612 } else { |
| 5613 NodeList<VariableDeclaration> variables = variableList.variables; |
| 5614 if (variables.length > 1) { |
| 5615 _reportErrorForCurrentToken( |
| 5616 ParserErrorCode.MULTIPLE_VARIABLES_IN_FOR_EACH, |
| 5617 [variables.length.toString()]); |
| 5618 } |
| 5619 VariableDeclaration variable = variables[0]; |
| 5620 if (variable.initializer != null) { |
| 5621 _reportErrorForCurrentToken( |
| 5622 ParserErrorCode.INITIALIZED_VARIABLE_IN_FOR_EACH); |
| 5623 } |
| 5624 Token keyword = variableList.keyword; |
| 5625 TypeName type = variableList.type; |
| 5626 if (keyword != null || type != null) { |
| 5627 loopVariable = new DeclaredIdentifier(commentAndMetadata.comment, |
| 5628 commentAndMetadata.metadata, keyword, type, variable.name); |
| 5629 } else { |
| 5630 if (!commentAndMetadata.metadata.isEmpty) { |
| 5631 // TODO(jwren) metadata isn't allowed before the identifier in |
| 5632 // "identifier in expression", add warning if commentAndMetadata |
| 5633 // has content |
| 5634 } |
| 5635 identifier = variable.name; |
| 5636 } |
| 5637 } |
| 5638 Token inKeyword = getAndAdvance(); |
| 5639 Expression iterator = parseExpression2(); |
| 5640 Token rightParenthesis = _expect(TokenType.CLOSE_PAREN); |
| 5641 Statement body = parseStatement2(); |
| 5642 if (loopVariable == null) { |
| 5643 return new ForEachStatement.withReference(awaitKeyword, forKeyword, |
| 5644 leftParenthesis, identifier, inKeyword, iterator, |
| 5645 rightParenthesis, body); |
| 5646 } |
| 5647 return new ForEachStatement.withDeclaration(awaitKeyword, forKeyword, |
| 5648 leftParenthesis, loopVariable, inKeyword, iterator, |
| 5649 rightParenthesis, body); |
| 5650 } |
| 5651 } |
| 5652 if (awaitKeyword != null) { |
| 5653 _reportErrorForToken( |
| 5654 ParserErrorCode.INVALID_AWAIT_IN_FOR, awaitKeyword); |
| 5655 } |
| 5656 Token leftSeparator = _expect(TokenType.SEMICOLON); |
| 5657 Expression condition = null; |
| 5658 if (!_matches(TokenType.SEMICOLON)) { |
| 5659 condition = parseExpression2(); |
| 5660 } |
| 5661 Token rightSeparator = _expect(TokenType.SEMICOLON); |
| 5662 List<Expression> updaters = null; |
| 5663 if (!_matches(TokenType.CLOSE_PAREN)) { |
| 5664 updaters = _parseExpressionList(); |
| 5665 } |
| 5666 Token rightParenthesis = _expect(TokenType.CLOSE_PAREN); |
| 5667 Statement body = parseStatement2(); |
| 5668 return new ForStatement(forKeyword, leftParenthesis, variableList, |
| 5669 initialization, leftSeparator, condition, rightSeparator, updaters, |
| 5670 rightParenthesis, body); |
| 5671 } finally { |
| 5672 _inLoop = wasInLoop; |
| 5673 } |
| 5674 } |
| 5675 |
| 5676 /** |
| 5677 * Parse a function body. The [mayBeEmpty] is `true` if the function body is |
| 5678 * allowed to be empty. The [emptyErrorCode] is the error code to report if |
| 5679 * function body expected, but not found. The [inExpression] is `true` if the |
| 5680 * function body is being parsed as part of an expression and therefore does |
| 5681 * not have a terminating semicolon. Return the function body that was parsed. |
| 5682 * |
| 5683 * functionBody ::= |
| 5684 * '=>' expression ';' |
| 5685 * | block |
| 5686 * |
| 5687 * functionExpressionBody ::= |
| 5688 * '=>' expression |
| 5689 * | block |
| 5690 */ |
| 5691 FunctionBody _parseFunctionBody( |
| 5692 bool mayBeEmpty, ParserErrorCode emptyErrorCode, bool inExpression) { |
| 5693 bool wasInAsync = _inAsync; |
| 5694 bool wasInGenerator = _inGenerator; |
| 5695 bool wasInLoop = _inLoop; |
| 5696 bool wasInSwitch = _inSwitch; |
| 5697 _inAsync = false; |
| 5698 _inGenerator = false; |
| 5699 _inLoop = false; |
| 5700 _inSwitch = false; |
| 5701 try { |
| 5702 if (_matches(TokenType.SEMICOLON)) { |
| 5703 if (!mayBeEmpty) { |
| 5704 _reportErrorForCurrentToken(emptyErrorCode); |
| 5705 } |
| 5706 return new EmptyFunctionBody(getAndAdvance()); |
| 5707 } else if (_matchesString(_NATIVE)) { |
| 5708 Token nativeToken = getAndAdvance(); |
| 5709 StringLiteral stringLiteral = null; |
| 5710 if (_matches(TokenType.STRING)) { |
| 5711 stringLiteral = parseStringLiteral(); |
| 5712 } |
| 5713 return new NativeFunctionBody( |
| 5714 nativeToken, stringLiteral, _expect(TokenType.SEMICOLON)); |
| 5715 } |
| 5716 Token keyword = null; |
| 5717 Token star = null; |
| 5718 if (_matchesString(ASYNC)) { |
| 5719 keyword = getAndAdvance(); |
| 5720 if (_matches(TokenType.STAR)) { |
| 5721 star = getAndAdvance(); |
| 5722 _inGenerator = true; |
| 5723 } |
| 5724 _inAsync = true; |
| 5725 } else if (_matchesString(SYNC)) { |
| 5726 keyword = getAndAdvance(); |
| 5727 if (_matches(TokenType.STAR)) { |
| 5728 star = getAndAdvance(); |
| 5729 _inGenerator = true; |
| 5730 } |
| 5731 } |
| 5732 if (_matches(TokenType.FUNCTION)) { |
| 5733 if (keyword != null) { |
| 5734 if (!_tokenMatchesString(keyword, ASYNC)) { |
| 5735 _reportErrorForToken(ParserErrorCode.INVALID_SYNC, keyword); |
| 5736 keyword = null; |
| 5737 } else if (star != null) { |
| 5738 _reportErrorForToken( |
| 5739 ParserErrorCode.INVALID_STAR_AFTER_ASYNC, star); |
| 5740 } |
| 5741 } |
| 5742 Token functionDefinition = getAndAdvance(); |
| 5743 if (_matchesKeyword(Keyword.RETURN)) { |
| 5744 _reportErrorForToken(ParserErrorCode.UNEXPECTED_TOKEN, _currentToken, |
| 5745 [_currentToken.lexeme]); |
| 5746 _advance(); |
| 5747 } |
| 5748 Expression expression = parseExpression2(); |
| 5749 Token semicolon = null; |
| 5750 if (!inExpression) { |
| 5751 semicolon = _expect(TokenType.SEMICOLON); |
| 5752 } |
| 5753 if (!_parseFunctionBodies) { |
| 5754 return new EmptyFunctionBody( |
| 5755 _createSyntheticToken(TokenType.SEMICOLON)); |
| 5756 } |
| 5757 return new ExpressionFunctionBody( |
| 5758 keyword, functionDefinition, expression, semicolon); |
| 5759 } else if (_matches(TokenType.OPEN_CURLY_BRACKET)) { |
| 5760 if (keyword != null) { |
| 5761 if (_tokenMatchesString(keyword, SYNC) && star == null) { |
| 5762 _reportErrorForToken( |
| 5763 ParserErrorCode.MISSING_STAR_AFTER_SYNC, keyword); |
| 5764 } |
| 5765 } |
| 5766 if (!_parseFunctionBodies) { |
| 5767 _skipBlock(); |
| 5768 return new EmptyFunctionBody( |
| 5769 _createSyntheticToken(TokenType.SEMICOLON)); |
| 5770 } |
| 5771 return new BlockFunctionBody(keyword, star, parseBlock()); |
| 5772 } else { |
| 5773 // Invalid function body |
| 5774 _reportErrorForCurrentToken(emptyErrorCode); |
| 5775 return new EmptyFunctionBody( |
| 5776 _createSyntheticToken(TokenType.SEMICOLON)); |
| 5777 } |
| 5778 } finally { |
| 5779 _inAsync = wasInAsync; |
| 5780 _inGenerator = wasInGenerator; |
| 5781 _inLoop = wasInLoop; |
| 5782 _inSwitch = wasInSwitch; |
| 5783 } |
| 5784 } |
| 5785 |
| 5786 /** |
| 5787 * Parse a function declaration. The [commentAndMetadata] is the documentation |
| 5788 * comment and metadata to be associated with the declaration. The |
| 5789 * [externalKeyword] is the 'external' keyword, or `null` if the function is |
| 5790 * not external. The [returnType] is the return type, or `null` if there is no |
| 5791 * return type. The [isStatement] is `true` if the function declaration is |
| 5792 * being parsed as a statement. Return the function declaration that was |
| 5793 * parsed. |
| 5794 * |
| 5795 * functionDeclaration ::= |
| 5796 * functionSignature functionBody |
| 5797 * | returnType? getOrSet identifier formalParameterList functionBody |
| 5798 */ |
| 5799 FunctionDeclaration _parseFunctionDeclaration( |
| 5800 CommentAndMetadata commentAndMetadata, Token externalKeyword, |
| 5801 TypeName returnType) { |
| 5802 Token keyword = null; |
| 5803 bool isGetter = false; |
| 5804 if (_matchesKeyword(Keyword.GET) && |
| 5805 !_tokenMatches(_peek(), TokenType.OPEN_PAREN)) { |
| 5806 keyword = getAndAdvance(); |
| 5807 isGetter = true; |
| 5808 } else if (_matchesKeyword(Keyword.SET) && |
| 5809 !_tokenMatches(_peek(), TokenType.OPEN_PAREN)) { |
| 5810 keyword = getAndAdvance(); |
| 5811 } |
| 5812 SimpleIdentifier name = parseSimpleIdentifier(); |
| 5813 TypeParameterList typeParameters = null; |
| 5814 if (parseGenericMethods && _matches(TokenType.LT)) { |
| 5815 typeParameters = parseTypeParameterList(); |
| 5816 } |
| 5817 FormalParameterList parameters = null; |
| 5818 if (!isGetter) { |
| 5819 if (_matches(TokenType.OPEN_PAREN)) { |
| 5820 parameters = parseFormalParameterList(); |
| 5821 _validateFormalParameterList(parameters); |
| 5822 } else { |
| 5823 _reportErrorForCurrentToken( |
| 5824 ParserErrorCode.MISSING_FUNCTION_PARAMETERS); |
| 5825 parameters = new FormalParameterList( |
| 5826 _createSyntheticToken(TokenType.OPEN_PAREN), null, null, null, |
| 5827 _createSyntheticToken(TokenType.CLOSE_PAREN)); |
| 5828 } |
| 5829 } else if (_matches(TokenType.OPEN_PAREN)) { |
| 5830 _reportErrorForCurrentToken(ParserErrorCode.GETTER_WITH_PARAMETERS); |
| 5831 parseFormalParameterList(); |
| 5832 } |
| 5833 FunctionBody body; |
| 5834 if (externalKeyword == null) { |
| 5835 body = _parseFunctionBody( |
| 5836 false, ParserErrorCode.MISSING_FUNCTION_BODY, false); |
| 5837 } else { |
| 5838 body = new EmptyFunctionBody(_expect(TokenType.SEMICOLON)); |
| 5839 } |
| 5840 // if (!isStatement && matches(TokenType.SEMICOLON)) { |
| 5841 // // TODO(brianwilkerson) Improve this error message. |
| 5842 // reportError(ParserErrorCode.UNEXPECTED_TOKEN, currentToken.getLexeme
()); |
| 5843 // advance(); |
| 5844 // } |
| 5845 return new FunctionDeclaration(commentAndMetadata.comment, |
| 5846 commentAndMetadata.metadata, externalKeyword, returnType, keyword, name, |
| 5847 new FunctionExpression(typeParameters, parameters, body)); |
| 5848 } |
| 5849 |
| 5850 /** |
| 5851 * Parse a function declaration statement. Return the function declaration |
| 5852 * statement that was parsed. |
| 5853 * |
| 5854 * functionDeclarationStatement ::= |
| 5855 * functionSignature functionBody |
| 5856 */ |
| 5857 Statement _parseFunctionDeclarationStatement() { |
| 5858 Modifiers modifiers = _parseModifiers(); |
| 5859 _validateModifiersForFunctionDeclarationStatement(modifiers); |
| 5860 return _parseFunctionDeclarationStatementAfterReturnType( |
| 5861 _parseCommentAndMetadata(), _parseOptionalReturnType()); |
| 5862 } |
| 5863 |
| 5864 /** |
| 5865 * Parse a function declaration statement. The [commentAndMetadata] is the |
| 5866 * documentation comment and metadata to be associated with the declaration. |
| 5867 * The [returnType] is the return type, or `null` if there is no return type. |
| 5868 * Return the function declaration statement that was parsed. |
| 5869 * |
| 5870 * functionDeclarationStatement ::= |
| 5871 * functionSignature functionBody |
| 5872 */ |
| 5873 Statement _parseFunctionDeclarationStatementAfterReturnType( |
| 5874 CommentAndMetadata commentAndMetadata, TypeName returnType) { |
| 5875 FunctionDeclaration declaration = |
| 5876 _parseFunctionDeclaration(commentAndMetadata, null, returnType); |
| 5877 Token propertyKeyword = declaration.propertyKeyword; |
| 5878 if (propertyKeyword != null) { |
| 5879 if ((propertyKeyword as KeywordToken).keyword == Keyword.GET) { |
| 5880 _reportErrorForToken( |
| 5881 ParserErrorCode.GETTER_IN_FUNCTION, propertyKeyword); |
| 5882 } else { |
| 5883 _reportErrorForToken( |
| 5884 ParserErrorCode.SETTER_IN_FUNCTION, propertyKeyword); |
| 5885 } |
| 5886 } |
| 5887 return new FunctionDeclarationStatement(declaration); |
| 5888 } |
| 5889 |
| 5890 /** |
| 5891 * Parse a function type alias. The [commentAndMetadata] is the metadata to be |
| 5892 * associated with the member. The [keyword] is the token representing the |
| 5893 * 'typedef' keyword. Return the function type alias that was parsed. |
| 5894 * |
| 5895 * functionTypeAlias ::= |
| 5896 * functionPrefix typeParameterList? formalParameterList ';' |
| 5897 * |
| 5898 * functionPrefix ::= |
| 5899 * returnType? name |
| 5900 */ |
| 5901 FunctionTypeAlias _parseFunctionTypeAlias( |
| 5902 CommentAndMetadata commentAndMetadata, Token keyword) { |
| 5903 TypeName returnType = null; |
| 5904 if (hasReturnTypeInTypeAlias) { |
| 5905 returnType = parseReturnType(); |
| 5906 } |
| 5907 SimpleIdentifier name = parseSimpleIdentifier(); |
| 5908 TypeParameterList typeParameters = null; |
| 5909 if (_matches(TokenType.LT)) { |
| 5910 typeParameters = parseTypeParameterList(); |
| 5911 } |
| 5912 if (_matches(TokenType.SEMICOLON) || _matches(TokenType.EOF)) { |
| 5913 _reportErrorForCurrentToken(ParserErrorCode.MISSING_TYPEDEF_PARAMETERS); |
| 5914 FormalParameterList parameters = new FormalParameterList( |
| 5915 _createSyntheticToken(TokenType.OPEN_PAREN), null, null, null, |
| 5916 _createSyntheticToken(TokenType.CLOSE_PAREN)); |
| 5917 Token semicolon = _expect(TokenType.SEMICOLON); |
| 5918 return new FunctionTypeAlias(commentAndMetadata.comment, |
| 5919 commentAndMetadata.metadata, keyword, returnType, name, |
| 5920 typeParameters, parameters, semicolon); |
| 5921 } else if (!_matches(TokenType.OPEN_PAREN)) { |
| 5922 _reportErrorForCurrentToken(ParserErrorCode.MISSING_TYPEDEF_PARAMETERS); |
| 5923 // TODO(brianwilkerson) Recover from this error. At the very least we |
| 5924 // should skip to the start of the next valid compilation unit member, |
| 5925 // allowing for the possibility of finding the typedef parameters before |
| 5926 // that point. |
| 5927 return new FunctionTypeAlias(commentAndMetadata.comment, |
| 5928 commentAndMetadata.metadata, keyword, returnType, name, |
| 5929 typeParameters, new FormalParameterList( |
| 5930 _createSyntheticToken(TokenType.OPEN_PAREN), null, null, null, |
| 5931 _createSyntheticToken(TokenType.CLOSE_PAREN)), |
| 5932 _createSyntheticToken(TokenType.SEMICOLON)); |
| 5933 } |
| 5934 FormalParameterList parameters = parseFormalParameterList(); |
| 5935 _validateFormalParameterList(parameters); |
| 5936 Token semicolon = _expect(TokenType.SEMICOLON); |
| 5937 return new FunctionTypeAlias(commentAndMetadata.comment, |
| 5938 commentAndMetadata.metadata, keyword, returnType, name, typeParameters, |
| 5939 parameters, semicolon); |
| 5940 } |
| 5941 |
| 5942 /** |
| 5943 * Parse a getter. The [commentAndMetadata] is the documentation comment and |
| 5944 * metadata to be associated with the declaration. The externalKeyword] is the |
| 5945 * 'external' token. The staticKeyword] is the static keyword, or `null` if |
| 5946 * the getter is not static. The [returnType] the return type that has already |
| 5947 * been parsed, or `null` if there was no return type. Return the getter that |
| 5948 * was parsed. |
| 5949 * |
| 5950 * getter ::= |
| 5951 * getterSignature functionBody? |
| 5952 * |
| 5953 * getterSignature ::= |
| 5954 * 'external'? 'static'? returnType? 'get' identifier |
| 5955 */ |
| 5956 MethodDeclaration _parseGetter(CommentAndMetadata commentAndMetadata, |
| 5957 Token externalKeyword, Token staticKeyword, TypeName returnType) { |
| 5958 Token propertyKeyword = _expectKeyword(Keyword.GET); |
| 5959 SimpleIdentifier name = parseSimpleIdentifier(); |
| 5960 if (_matches(TokenType.OPEN_PAREN) && |
| 5961 _tokenMatches(_peek(), TokenType.CLOSE_PAREN)) { |
| 5962 _reportErrorForCurrentToken(ParserErrorCode.GETTER_WITH_PARAMETERS); |
| 5963 _advance(); |
| 5964 _advance(); |
| 5965 } |
| 5966 FunctionBody body = _parseFunctionBody( |
| 5967 externalKeyword != null || staticKeyword == null, |
| 5968 ParserErrorCode.STATIC_GETTER_WITHOUT_BODY, false); |
| 5969 if (externalKeyword != null && body is! EmptyFunctionBody) { |
| 5970 _reportErrorForCurrentToken(ParserErrorCode.EXTERNAL_GETTER_WITH_BODY); |
| 5971 } |
| 5972 return new MethodDeclaration(commentAndMetadata.comment, |
| 5973 commentAndMetadata.metadata, externalKeyword, staticKeyword, returnType, |
| 5974 propertyKeyword, null, name, null, null, body); |
| 5975 } |
| 5976 |
| 5977 /** |
| 5978 * Parse a list of identifiers. Return the list of identifiers that were |
| 5979 * parsed. |
| 5980 * |
| 5981 * identifierList ::= |
| 5982 * identifier (',' identifier)* |
| 5983 */ |
| 5984 List<SimpleIdentifier> _parseIdentifierList() { |
| 5985 List<SimpleIdentifier> identifiers = new List<SimpleIdentifier>(); |
| 5986 identifiers.add(parseSimpleIdentifier()); |
| 5987 while (_matches(TokenType.COMMA)) { |
| 5988 _advance(); |
| 5989 identifiers.add(parseSimpleIdentifier()); |
| 5990 } |
| 5991 return identifiers; |
| 5992 } |
| 5993 |
| 5994 /** |
| 5995 * Parse an if statement. Return the if statement that was parsed. |
| 5996 * |
| 5997 * ifStatement ::= |
| 5998 * 'if' '(' expression ')' statement ('else' statement)? |
| 5999 */ |
| 6000 Statement _parseIfStatement() { |
| 6001 Token ifKeyword = _expectKeyword(Keyword.IF); |
| 6002 Token leftParenthesis = _expect(TokenType.OPEN_PAREN); |
| 6003 Expression condition = parseExpression2(); |
| 6004 Token rightParenthesis = _expect(TokenType.CLOSE_PAREN); |
| 6005 Statement thenStatement = parseStatement2(); |
| 6006 Token elseKeyword = null; |
| 6007 Statement elseStatement = null; |
| 6008 if (_matchesKeyword(Keyword.ELSE)) { |
| 6009 elseKeyword = getAndAdvance(); |
| 6010 elseStatement = parseStatement2(); |
| 6011 } |
| 6012 return new IfStatement(ifKeyword, leftParenthesis, condition, |
| 6013 rightParenthesis, thenStatement, elseKeyword, elseStatement); |
| 6014 } |
| 6015 |
| 6016 /** |
| 6017 * Parse an import directive. The [commentAndMetadata] is the metadata to be |
| 6018 * associated with the directive. Return the import directive that was parsed. |
| 6019 * |
| 6020 * importDirective ::= |
| 6021 * metadata 'import' stringLiteral (deferred)? ('as' identifier)? comb
inator*';' |
| 6022 */ |
| 6023 ImportDirective _parseImportDirective(CommentAndMetadata commentAndMetadata) { |
| 6024 Token importKeyword = _expectKeyword(Keyword.IMPORT); |
| 6025 StringLiteral libraryUri = _parseUri(); |
| 6026 Token deferredToken = null; |
| 6027 Token asToken = null; |
| 6028 SimpleIdentifier prefix = null; |
| 6029 if (_matchesKeyword(Keyword.DEFERRED)) { |
| 6030 deferredToken = getAndAdvance(); |
| 6031 } |
| 6032 if (_matchesKeyword(Keyword.AS)) { |
| 6033 asToken = getAndAdvance(); |
| 6034 prefix = parseSimpleIdentifier(); |
| 6035 } else if (deferredToken != null) { |
| 6036 _reportErrorForCurrentToken( |
| 6037 ParserErrorCode.MISSING_PREFIX_IN_DEFERRED_IMPORT); |
| 6038 } else if (!_matches(TokenType.SEMICOLON) && |
| 6039 !_matchesString(_SHOW) && |
| 6040 !_matchesString(_HIDE)) { |
| 6041 Token nextToken = _peek(); |
| 6042 if (_tokenMatchesKeyword(nextToken, Keyword.AS) || |
| 6043 _tokenMatchesString(nextToken, _SHOW) || |
| 6044 _tokenMatchesString(nextToken, _HIDE)) { |
| 6045 _reportErrorForCurrentToken( |
| 6046 ParserErrorCode.UNEXPECTED_TOKEN, [_currentToken]); |
| 6047 _advance(); |
| 6048 if (_matchesKeyword(Keyword.AS)) { |
| 6049 asToken = getAndAdvance(); |
| 6050 prefix = parseSimpleIdentifier(); |
| 6051 } |
| 6052 } |
| 6053 } |
| 6054 List<Combinator> combinators = _parseCombinators(); |
| 6055 Token semicolon = _expectSemicolon(); |
| 6056 return new ImportDirective(commentAndMetadata.comment, |
| 6057 commentAndMetadata.metadata, importKeyword, libraryUri, deferredToken, |
| 6058 asToken, prefix, combinators, semicolon); |
| 6059 } |
| 6060 |
| 6061 /** |
| 6062 * Parse a list of initialized identifiers. The [commentAndMetadata] is the |
| 6063 * documentation comment and metadata to be associated with the declaration. |
| 6064 * The [staticKeyword] is the static keyword, or `null` if the getter is not |
| 6065 * static. The [keyword] is the token representing the 'final', 'const' or |
| 6066 * 'var' keyword, or `null` if there is no keyword. The [type] is the type |
| 6067 * that has already been parsed, or `null` if 'var' was provided. Return the |
| 6068 * getter that was parsed. |
| 6069 * |
| 6070 * ?? ::= |
| 6071 * 'static'? ('var' | type) initializedIdentifierList ';' |
| 6072 * | 'final' type? initializedIdentifierList ';' |
| 6073 * |
| 6074 * initializedIdentifierList ::= |
| 6075 * initializedIdentifier (',' initializedIdentifier)* |
| 6076 * |
| 6077 * initializedIdentifier ::= |
| 6078 * identifier ('=' expression)? |
| 6079 */ |
| 6080 FieldDeclaration _parseInitializedIdentifierList( |
| 6081 CommentAndMetadata commentAndMetadata, Token staticKeyword, Token keyword, |
| 6082 TypeName type) { |
| 6083 VariableDeclarationList fieldList = |
| 6084 _parseVariableDeclarationListAfterType(null, keyword, type); |
| 6085 return new FieldDeclaration(commentAndMetadata.comment, |
| 6086 commentAndMetadata.metadata, staticKeyword, fieldList, |
| 6087 _expect(TokenType.SEMICOLON)); |
| 6088 } |
| 6089 |
| 6090 /** |
| 6091 * Parse an instance creation expression. The [keyword] is the 'new' or |
| 6092 * 'const' keyword that introduces the expression. Return the instance |
| 6093 * creation expression that was parsed. |
| 6094 * |
| 6095 * instanceCreationExpression ::= |
| 6096 * ('new' | 'const') type ('.' identifier)? argumentList |
| 6097 */ |
| 6098 InstanceCreationExpression _parseInstanceCreationExpression(Token keyword) { |
| 6099 ConstructorName constructorName = parseConstructorName(); |
| 6100 ArgumentList argumentList = parseArgumentList(); |
| 6101 return new InstanceCreationExpression( |
| 6102 keyword, constructorName, argumentList); |
| 6103 } |
| 6104 |
| 6105 /** |
| 6106 * Parse a library directive. The [commentAndMetadata] is the metadata to be |
| 6107 * associated with the directive. Return the library directive that was |
| 6108 * parsed. |
| 6109 * |
| 6110 * libraryDirective ::= |
| 6111 * metadata 'library' identifier ';' |
| 6112 */ |
| 6113 LibraryDirective _parseLibraryDirective( |
| 6114 CommentAndMetadata commentAndMetadata) { |
| 6115 Token keyword = _expectKeyword(Keyword.LIBRARY); |
| 6116 LibraryIdentifier libraryName = _parseLibraryName( |
| 6117 ParserErrorCode.MISSING_NAME_IN_LIBRARY_DIRECTIVE, keyword); |
| 6118 Token semicolon = _expect(TokenType.SEMICOLON); |
| 6119 return new LibraryDirective(commentAndMetadata.comment, |
| 6120 commentAndMetadata.metadata, keyword, libraryName, semicolon); |
| 6121 } |
| 6122 |
| 6123 /** |
| 6124 * Parse a library name. The [missingNameError] is the error code to be used |
| 6125 * if the library name is missing. The [missingNameToken] is the token |
| 6126 * associated with the error produced if the library name is missing. Return |
| 6127 * the library name that was parsed. |
| 6128 * |
| 6129 * libraryName ::= |
| 6130 * libraryIdentifier |
| 6131 */ |
| 6132 LibraryIdentifier _parseLibraryName( |
| 6133 ParserErrorCode missingNameError, Token missingNameToken) { |
| 6134 if (_matchesIdentifier()) { |
| 6135 return parseLibraryIdentifier(); |
| 6136 } else if (_matches(TokenType.STRING)) { |
| 6137 // TODO(brianwilkerson) Recovery: This should be extended to handle |
| 6138 // arbitrary tokens until we can find a token that can start a compilation |
| 6139 // unit member. |
| 6140 StringLiteral string = parseStringLiteral(); |
| 6141 _reportErrorForNode(ParserErrorCode.NON_IDENTIFIER_LIBRARY_NAME, string); |
| 6142 } else { |
| 6143 _reportErrorForToken(missingNameError, missingNameToken); |
| 6144 } |
| 6145 List<SimpleIdentifier> components = new List<SimpleIdentifier>(); |
| 6146 components.add(_createSyntheticIdentifier()); |
| 6147 return new LibraryIdentifier(components); |
| 6148 } |
| 6149 |
| 6150 /** |
| 6151 * Parse a list literal. The [modifier] is the 'const' modifier appearing |
| 6152 * before the literal, or `null` if there is no modifier. The [typeArguments] |
| 6153 * is the type arguments appearing before the literal, or `null` if there are |
| 6154 * no type arguments. Return the list literal that was parsed. |
| 6155 * |
| 6156 * listLiteral ::= |
| 6157 * 'const'? typeArguments? '[' (expressionList ','?)? ']' |
| 6158 */ |
| 6159 ListLiteral _parseListLiteral( |
| 6160 Token modifier, TypeArgumentList typeArguments) { |
| 6161 // may be empty list literal |
| 6162 if (_matches(TokenType.INDEX)) { |
| 6163 BeginToken leftBracket = _createToken( |
| 6164 _currentToken, TokenType.OPEN_SQUARE_BRACKET, isBegin: true); |
| 6165 Token rightBracket = |
| 6166 new Token(TokenType.CLOSE_SQUARE_BRACKET, _currentToken.offset + 1); |
| 6167 leftBracket.endToken = rightBracket; |
| 6168 rightBracket.setNext(_currentToken.next); |
| 6169 leftBracket.setNext(rightBracket); |
| 6170 _currentToken.previous.setNext(leftBracket); |
| 6171 _currentToken = _currentToken.next; |
| 6172 return new ListLiteral( |
| 6173 modifier, typeArguments, leftBracket, null, rightBracket); |
| 6174 } |
| 6175 // open |
| 6176 Token leftBracket = _expect(TokenType.OPEN_SQUARE_BRACKET); |
| 6177 if (_matches(TokenType.CLOSE_SQUARE_BRACKET)) { |
| 6178 return new ListLiteral( |
| 6179 modifier, typeArguments, leftBracket, null, getAndAdvance()); |
| 6180 } |
| 6181 bool wasInInitializer = _inInitializer; |
| 6182 _inInitializer = false; |
| 6183 try { |
| 6184 List<Expression> elements = new List<Expression>(); |
| 6185 elements.add(parseExpression2()); |
| 6186 while (_optional(TokenType.COMMA)) { |
| 6187 if (_matches(TokenType.CLOSE_SQUARE_BRACKET)) { |
| 6188 return new ListLiteral( |
| 6189 modifier, typeArguments, leftBracket, elements, getAndAdvance()); |
| 6190 } |
| 6191 elements.add(parseExpression2()); |
| 6192 } |
| 6193 Token rightBracket = _expect(TokenType.CLOSE_SQUARE_BRACKET); |
| 6194 return new ListLiteral( |
| 6195 modifier, typeArguments, leftBracket, elements, rightBracket); |
| 6196 } finally { |
| 6197 _inInitializer = wasInInitializer; |
| 6198 } |
| 6199 } |
| 6200 |
| 6201 /** |
| 6202 * Parse a list or map literal. The [modifier] is the 'const' modifier |
| 6203 * appearing before the literal, or `null` if there is no modifier. Return the |
| 6204 * list or map literal that was parsed. |
| 6205 * |
| 6206 * listOrMapLiteral ::= |
| 6207 * listLiteral |
| 6208 * | mapLiteral |
| 6209 */ |
| 6210 TypedLiteral _parseListOrMapLiteral(Token modifier) { |
| 6211 TypeArgumentList typeArguments = null; |
| 6212 if (_matches(TokenType.LT)) { |
| 6213 typeArguments = parseTypeArgumentList(); |
| 6214 } |
| 6215 if (_matches(TokenType.OPEN_CURLY_BRACKET)) { |
| 6216 return _parseMapLiteral(modifier, typeArguments); |
| 6217 } else if (_matches(TokenType.OPEN_SQUARE_BRACKET) || |
| 6218 _matches(TokenType.INDEX)) { |
| 6219 return _parseListLiteral(modifier, typeArguments); |
| 6220 } |
| 6221 _reportErrorForCurrentToken(ParserErrorCode.EXPECTED_LIST_OR_MAP_LITERAL); |
| 6222 return new ListLiteral(modifier, typeArguments, |
| 6223 _createSyntheticToken(TokenType.OPEN_SQUARE_BRACKET), null, |
| 6224 _createSyntheticToken(TokenType.CLOSE_SQUARE_BRACKET)); |
| 6225 } |
| 6226 |
| 6227 /** |
| 6228 * Parse a logical and expression. Return the logical and expression that was |
| 6229 * parsed. |
| 6230 * |
| 6231 * logicalAndExpression ::= |
| 6232 * equalityExpression ('&&' equalityExpression)* |
| 6233 */ |
| 6234 Expression _parseLogicalAndExpression() { |
| 6235 Expression expression = _parseEqualityExpression(); |
| 6236 while (_matches(TokenType.AMPERSAND_AMPERSAND)) { |
| 6237 Token operator = getAndAdvance(); |
| 6238 expression = new BinaryExpression( |
| 6239 expression, operator, _parseEqualityExpression()); |
| 6240 } |
| 6241 return expression; |
| 6242 } |
| 6243 |
| 6244 /** |
| 6245 * Parse a map literal. The [modifier] is the 'const' modifier appearing |
| 6246 * before the literal, or `null` if there is no modifier. The [typeArguments] |
| 6247 * is the type arguments that were declared, or `null` if there are no type |
| 6248 * arguments. Return the map literal that was parsed. |
| 6249 * |
| 6250 * mapLiteral ::= |
| 6251 * 'const'? typeArguments? '{' (mapLiteralEntry (',' mapLiteralEntry)*
','?)? '}' |
| 6252 */ |
| 6253 MapLiteral _parseMapLiteral(Token modifier, TypeArgumentList typeArguments) { |
| 6254 Token leftBracket = _expect(TokenType.OPEN_CURLY_BRACKET); |
| 6255 List<MapLiteralEntry> entries = new List<MapLiteralEntry>(); |
| 6256 if (_matches(TokenType.CLOSE_CURLY_BRACKET)) { |
| 6257 return new MapLiteral( |
| 6258 modifier, typeArguments, leftBracket, entries, getAndAdvance()); |
| 6259 } |
| 6260 bool wasInInitializer = _inInitializer; |
| 6261 _inInitializer = false; |
| 6262 try { |
| 6263 entries.add(parseMapLiteralEntry()); |
| 6264 while (_optional(TokenType.COMMA)) { |
| 6265 if (_matches(TokenType.CLOSE_CURLY_BRACKET)) { |
| 6266 return new MapLiteral( |
| 6267 modifier, typeArguments, leftBracket, entries, getAndAdvance()); |
| 6268 } |
| 6269 entries.add(parseMapLiteralEntry()); |
| 6270 } |
| 6271 Token rightBracket = _expect(TokenType.CLOSE_CURLY_BRACKET); |
| 6272 return new MapLiteral( |
| 6273 modifier, typeArguments, leftBracket, entries, rightBracket); |
| 6274 } finally { |
| 6275 _inInitializer = wasInInitializer; |
| 6276 } |
| 6277 } |
| 6278 |
| 6279 /** |
| 6280 * Parse a method declaration. The [commentAndMetadata] is the documentation |
| 6281 * comment and metadata to be associated with the declaration. The |
| 6282 * [externalKeyword] is the 'external' token. The [staticKeyword] is the |
| 6283 * static keyword, or `null` if the getter is not static. The [returnType] is |
| 6284 * the return type of the method. The [name] is the name of the method. The |
| 6285 * [parameters] is the parameters to the method. Return the method declaration |
| 6286 * that was parsed. |
| 6287 * |
| 6288 * functionDeclaration ::= |
| 6289 * ('external' 'static'?)? functionSignature functionBody |
| 6290 * | 'external'? functionSignature ';' |
| 6291 */ |
| 6292 MethodDeclaration _parseMethodDeclarationAfterParameters( |
| 6293 CommentAndMetadata commentAndMetadata, Token externalKeyword, |
| 6294 Token staticKeyword, TypeName returnType, SimpleIdentifier name, |
| 6295 TypeParameterList typeParameters, FormalParameterList parameters) { |
| 6296 FunctionBody body = _parseFunctionBody( |
| 6297 externalKeyword != null || staticKeyword == null, |
| 6298 ParserErrorCode.MISSING_FUNCTION_BODY, false); |
| 6299 if (externalKeyword != null) { |
| 6300 if (body is! EmptyFunctionBody) { |
| 6301 _reportErrorForNode(ParserErrorCode.EXTERNAL_METHOD_WITH_BODY, body); |
| 6302 } |
| 6303 } else if (staticKeyword != null) { |
| 6304 if (body is EmptyFunctionBody && _parseFunctionBodies) { |
| 6305 _reportErrorForNode(ParserErrorCode.ABSTRACT_STATIC_METHOD, body); |
| 6306 } |
| 6307 } |
| 6308 return new MethodDeclaration(commentAndMetadata.comment, |
| 6309 commentAndMetadata.metadata, externalKeyword, staticKeyword, returnType, |
| 6310 null, null, name, typeParameters, parameters, body); |
| 6311 } |
| 6312 |
| 6313 /** |
| 6314 * Parse a method declaration. The [commentAndMetadata] is the documentation |
| 6315 * comment and metadata to be associated with the declaration. The |
| 6316 * [externalKeyword] is the 'external' token. The [staticKeyword] is the |
| 6317 * static keyword, or `null` if the getter is not static. The [returnType] is |
| 6318 * the return type of the method. Return the method declaration that was |
| 6319 * parsed. |
| 6320 * |
| 6321 * functionDeclaration ::= |
| 6322 * 'external'? 'static'? functionSignature functionBody |
| 6323 * | 'external'? functionSignature ';' |
| 6324 */ |
| 6325 MethodDeclaration _parseMethodDeclarationAfterReturnType( |
| 6326 CommentAndMetadata commentAndMetadata, Token externalKeyword, |
| 6327 Token staticKeyword, TypeName returnType) { |
| 6328 SimpleIdentifier methodName = parseSimpleIdentifier(); |
| 6329 TypeParameterList typeParameters = null; |
| 6330 if (parseGenericMethods && _matches(TokenType.LT)) { |
| 6331 typeParameters = parseTypeParameterList(); |
| 6332 } |
| 6333 FormalParameterList parameters; |
| 6334 if (!_matches(TokenType.OPEN_PAREN) && |
| 6335 (_matches(TokenType.OPEN_CURLY_BRACKET) || |
| 6336 _matches(TokenType.FUNCTION))) { |
| 6337 _reportErrorForToken( |
| 6338 ParserErrorCode.MISSING_METHOD_PARAMETERS, _currentToken.previous); |
| 6339 parameters = new FormalParameterList( |
| 6340 _createSyntheticToken(TokenType.OPEN_PAREN), null, null, null, |
| 6341 _createSyntheticToken(TokenType.CLOSE_PAREN)); |
| 6342 } else { |
| 6343 parameters = parseFormalParameterList(); |
| 6344 } |
| 6345 _validateFormalParameterList(parameters); |
| 6346 return _parseMethodDeclarationAfterParameters(commentAndMetadata, |
| 6347 externalKeyword, staticKeyword, returnType, methodName, typeParameters, |
| 6348 parameters); |
| 6349 } |
| 6350 |
| 6351 /** |
| 6352 * Parse the modifiers preceding a declaration. This method allows the |
| 6353 * modifiers to appear in any order but does generate errors for duplicated |
| 6354 * modifiers. Checks for other problems, such as having the modifiers appear |
| 6355 * in the wrong order or specifying both 'const' and 'final', are reported in |
| 6356 * one of the methods whose name is prefixed with `validateModifiersFor`. |
| 6357 * Return the modifiers that were parsed. |
| 6358 * |
| 6359 * modifiers ::= |
| 6360 * ('abstract' | 'const' | 'external' | 'factory' | 'final' | 'static'
| 'var')* |
| 6361 */ |
| 6362 Modifiers _parseModifiers() { |
| 6363 Modifiers modifiers = new Modifiers(); |
| 6364 bool progress = true; |
| 6365 while (progress) { |
| 6366 if (_tokenMatches(_peek(), TokenType.PERIOD) || |
| 6367 _tokenMatches(_peek(), TokenType.LT) || |
| 6368 _tokenMatches(_peek(), TokenType.OPEN_PAREN)) { |
| 6369 return modifiers; |
| 6370 } |
| 6371 if (_matchesKeyword(Keyword.ABSTRACT)) { |
| 6372 if (modifiers.abstractKeyword != null) { |
| 6373 _reportErrorForCurrentToken( |
| 6374 ParserErrorCode.DUPLICATED_MODIFIER, [_currentToken.lexeme]); |
| 6375 _advance(); |
| 6376 } else { |
| 6377 modifiers.abstractKeyword = getAndAdvance(); |
| 6378 } |
| 6379 } else if (_matchesKeyword(Keyword.CONST)) { |
| 6380 if (modifiers.constKeyword != null) { |
| 6381 _reportErrorForCurrentToken( |
| 6382 ParserErrorCode.DUPLICATED_MODIFIER, [_currentToken.lexeme]); |
| 6383 _advance(); |
| 6384 } else { |
| 6385 modifiers.constKeyword = getAndAdvance(); |
| 6386 } |
| 6387 } else if (_matchesKeyword(Keyword.EXTERNAL) && |
| 6388 !_tokenMatches(_peek(), TokenType.PERIOD) && |
| 6389 !_tokenMatches(_peek(), TokenType.LT)) { |
| 6390 if (modifiers.externalKeyword != null) { |
| 6391 _reportErrorForCurrentToken( |
| 6392 ParserErrorCode.DUPLICATED_MODIFIER, [_currentToken.lexeme]); |
| 6393 _advance(); |
| 6394 } else { |
| 6395 modifiers.externalKeyword = getAndAdvance(); |
| 6396 } |
| 6397 } else if (_matchesKeyword(Keyword.FACTORY) && |
| 6398 !_tokenMatches(_peek(), TokenType.PERIOD) && |
| 6399 !_tokenMatches(_peek(), TokenType.LT)) { |
| 6400 if (modifiers.factoryKeyword != null) { |
| 6401 _reportErrorForCurrentToken( |
| 6402 ParserErrorCode.DUPLICATED_MODIFIER, [_currentToken.lexeme]); |
| 6403 _advance(); |
| 6404 } else { |
| 6405 modifiers.factoryKeyword = getAndAdvance(); |
| 6406 } |
| 6407 } else if (_matchesKeyword(Keyword.FINAL)) { |
| 6408 if (modifiers.finalKeyword != null) { |
| 6409 _reportErrorForCurrentToken( |
| 6410 ParserErrorCode.DUPLICATED_MODIFIER, [_currentToken.lexeme]); |
| 6411 _advance(); |
| 6412 } else { |
| 6413 modifiers.finalKeyword = getAndAdvance(); |
| 6414 } |
| 6415 } else if (_matchesKeyword(Keyword.STATIC) && |
| 6416 !_tokenMatches(_peek(), TokenType.PERIOD) && |
| 6417 !_tokenMatches(_peek(), TokenType.LT)) { |
| 6418 if (modifiers.staticKeyword != null) { |
| 6419 _reportErrorForCurrentToken( |
| 6420 ParserErrorCode.DUPLICATED_MODIFIER, [_currentToken.lexeme]); |
| 6421 _advance(); |
| 6422 } else { |
| 6423 modifiers.staticKeyword = getAndAdvance(); |
| 6424 } |
| 6425 } else if (_matchesKeyword(Keyword.VAR)) { |
| 6426 if (modifiers.varKeyword != null) { |
| 6427 _reportErrorForCurrentToken( |
| 6428 ParserErrorCode.DUPLICATED_MODIFIER, [_currentToken.lexeme]); |
| 6429 _advance(); |
| 6430 } else { |
| 6431 modifiers.varKeyword = getAndAdvance(); |
| 6432 } |
| 6433 } else { |
| 6434 progress = false; |
| 6435 } |
| 6436 } |
| 6437 return modifiers; |
| 6438 } |
| 6439 |
| 6440 /** |
| 6441 * Parse a multiplicative expression. Return the multiplicative expression |
| 6442 * that was parsed. |
| 6443 * |
| 6444 * multiplicativeExpression ::= |
| 6445 * unaryExpression (multiplicativeOperator unaryExpression)* |
| 6446 * | 'super' (multiplicativeOperator unaryExpression)+ |
| 6447 */ |
| 6448 Expression _parseMultiplicativeExpression() { |
| 6449 Expression expression; |
| 6450 if (_matchesKeyword(Keyword.SUPER) && |
| 6451 _currentToken.next.type.isMultiplicativeOperator) { |
| 6452 expression = new SuperExpression(getAndAdvance()); |
| 6453 } else { |
| 6454 expression = _parseUnaryExpression(); |
| 6455 } |
| 6456 while (_currentToken.type.isMultiplicativeOperator) { |
| 6457 Token operator = getAndAdvance(); |
| 6458 expression = |
| 6459 new BinaryExpression(expression, operator, _parseUnaryExpression()); |
| 6460 } |
| 6461 return expression; |
| 6462 } |
| 6463 |
| 6464 /** |
| 6465 * Parse a class native clause. Return the native clause that was parsed. |
| 6466 * |
| 6467 * classNativeClause ::= |
| 6468 * 'native' name |
| 6469 */ |
| 6470 NativeClause _parseNativeClause() { |
| 6471 Token keyword = getAndAdvance(); |
| 6472 StringLiteral name = parseStringLiteral(); |
| 6473 return new NativeClause(keyword, name); |
| 6474 } |
| 6475 |
| 6476 /** |
| 6477 * Parse a new expression. Return the new expression that was parsed. |
| 6478 * |
| 6479 * newExpression ::= |
| 6480 * instanceCreationExpression |
| 6481 */ |
| 6482 InstanceCreationExpression _parseNewExpression() => |
| 6483 _parseInstanceCreationExpression(_expectKeyword(Keyword.NEW)); |
| 6484 |
| 6485 /** |
| 6486 * Parse a non-labeled statement. Return the non-labeled statement that was |
| 6487 * parsed. |
| 6488 * |
| 6489 * nonLabeledStatement ::= |
| 6490 * block |
| 6491 * | assertStatement |
| 6492 * | breakStatement |
| 6493 * | continueStatement |
| 6494 * | doStatement |
| 6495 * | forStatement |
| 6496 * | ifStatement |
| 6497 * | returnStatement |
| 6498 * | switchStatement |
| 6499 * | tryStatement |
| 6500 * | whileStatement |
| 6501 * | variableDeclarationList ';' |
| 6502 * | expressionStatement |
| 6503 * | functionSignature functionBody |
| 6504 */ |
| 6505 Statement _parseNonLabeledStatement() { |
| 6506 // TODO(brianwilkerson) Pass the comment and metadata on where appropriate. |
| 6507 CommentAndMetadata commentAndMetadata = _parseCommentAndMetadata(); |
| 6508 if (_matches(TokenType.OPEN_CURLY_BRACKET)) { |
| 6509 if (_tokenMatches(_peek(), TokenType.STRING)) { |
| 6510 Token afterString = _skipStringLiteral(_currentToken.next); |
| 6511 if (afterString != null && afterString.type == TokenType.COLON) { |
| 6512 return new ExpressionStatement( |
| 6513 parseExpression2(), _expect(TokenType.SEMICOLON)); |
| 6514 } |
| 6515 } |
| 6516 return parseBlock(); |
| 6517 } else if (_matches(TokenType.KEYWORD) && |
| 6518 !(_currentToken as KeywordToken).keyword.isPseudoKeyword) { |
| 6519 Keyword keyword = (_currentToken as KeywordToken).keyword; |
| 6520 // TODO(jwren) compute some metrics to figure out a better order for this |
| 6521 // if-then sequence to optimize performance |
| 6522 if (keyword == Keyword.ASSERT) { |
| 6523 return _parseAssertStatement(); |
| 6524 } else if (keyword == Keyword.BREAK) { |
| 6525 return _parseBreakStatement(); |
| 6526 } else if (keyword == Keyword.CONTINUE) { |
| 6527 return _parseContinueStatement(); |
| 6528 } else if (keyword == Keyword.DO) { |
| 6529 return _parseDoStatement(); |
| 6530 } else if (keyword == Keyword.FOR) { |
| 6531 return _parseForStatement(); |
| 6532 } else if (keyword == Keyword.IF) { |
| 6533 return _parseIfStatement(); |
| 6534 } else if (keyword == Keyword.RETHROW) { |
| 6535 return new ExpressionStatement( |
| 6536 _parseRethrowExpression(), _expect(TokenType.SEMICOLON)); |
| 6537 } else if (keyword == Keyword.RETURN) { |
| 6538 return _parseReturnStatement(); |
| 6539 } else if (keyword == Keyword.SWITCH) { |
| 6540 return _parseSwitchStatement(); |
| 6541 } else if (keyword == Keyword.THROW) { |
| 6542 return new ExpressionStatement( |
| 6543 _parseThrowExpression(), _expect(TokenType.SEMICOLON)); |
| 6544 } else if (keyword == Keyword.TRY) { |
| 6545 return _parseTryStatement(); |
| 6546 } else if (keyword == Keyword.WHILE) { |
| 6547 return _parseWhileStatement(); |
| 6548 } else if (keyword == Keyword.VAR || keyword == Keyword.FINAL) { |
| 6549 return _parseVariableDeclarationStatementAfterMetadata( |
| 6550 commentAndMetadata); |
| 6551 } else if (keyword == Keyword.VOID) { |
| 6552 TypeName returnType = parseReturnType(); |
| 6553 if (_matchesIdentifier() && |
| 6554 _peek().matchesAny([ |
| 6555 TokenType.OPEN_PAREN, |
| 6556 TokenType.OPEN_CURLY_BRACKET, |
| 6557 TokenType.FUNCTION |
| 6558 ])) { |
| 6559 return _parseFunctionDeclarationStatementAfterReturnType( |
| 6560 commentAndMetadata, returnType); |
| 6561 } else { |
| 6562 // |
| 6563 // We have found an error of some kind. Try to recover. |
| 6564 // |
| 6565 if (_matchesIdentifier()) { |
| 6566 if (_peek().matchesAny( |
| 6567 [TokenType.EQ, TokenType.COMMA, TokenType.SEMICOLON])) { |
| 6568 // |
| 6569 // We appear to have a variable declaration with a type of "void". |
| 6570 // |
| 6571 _reportErrorForNode(ParserErrorCode.VOID_VARIABLE, returnType); |
| 6572 return _parseVariableDeclarationStatementAfterMetadata( |
| 6573 commentAndMetadata); |
| 6574 } |
| 6575 } else if (_matches(TokenType.CLOSE_CURLY_BRACKET)) { |
| 6576 // |
| 6577 // We appear to have found an incomplete statement at the end of a |
| 6578 // block. Parse it as a variable declaration. |
| 6579 // |
| 6580 return _parseVariableDeclarationStatementAfterType( |
| 6581 commentAndMetadata, null, returnType); |
| 6582 } |
| 6583 _reportErrorForCurrentToken(ParserErrorCode.MISSING_STATEMENT); |
| 6584 // TODO(brianwilkerson) Recover from this error. |
| 6585 return new EmptyStatement(_createSyntheticToken(TokenType.SEMICOLON)); |
| 6586 } |
| 6587 } else if (keyword == Keyword.CONST) { |
| 6588 if (_peek().matchesAny([ |
| 6589 TokenType.LT, |
| 6590 TokenType.OPEN_CURLY_BRACKET, |
| 6591 TokenType.OPEN_SQUARE_BRACKET, |
| 6592 TokenType.INDEX |
| 6593 ])) { |
| 6594 return new ExpressionStatement( |
| 6595 parseExpression2(), _expect(TokenType.SEMICOLON)); |
| 6596 } else if (_tokenMatches(_peek(), TokenType.IDENTIFIER)) { |
| 6597 Token afterType = _skipTypeName(_peek()); |
| 6598 if (afterType != null) { |
| 6599 if (_tokenMatches(afterType, TokenType.OPEN_PAREN) || |
| 6600 (_tokenMatches(afterType, TokenType.PERIOD) && |
| 6601 _tokenMatches(afterType.next, TokenType.IDENTIFIER) && |
| 6602 _tokenMatches(afterType.next.next, TokenType.OPEN_PAREN))) { |
| 6603 return new ExpressionStatement( |
| 6604 parseExpression2(), _expect(TokenType.SEMICOLON)); |
| 6605 } |
| 6606 } |
| 6607 } |
| 6608 return _parseVariableDeclarationStatementAfterMetadata( |
| 6609 commentAndMetadata); |
| 6610 } else if (keyword == Keyword.NEW || |
| 6611 keyword == Keyword.TRUE || |
| 6612 keyword == Keyword.FALSE || |
| 6613 keyword == Keyword.NULL || |
| 6614 keyword == Keyword.SUPER || |
| 6615 keyword == Keyword.THIS) { |
| 6616 return new ExpressionStatement( |
| 6617 parseExpression2(), _expect(TokenType.SEMICOLON)); |
| 6618 } else { |
| 6619 // |
| 6620 // We have found an error of some kind. Try to recover. |
| 6621 // |
| 6622 _reportErrorForCurrentToken(ParserErrorCode.MISSING_STATEMENT); |
| 6623 return new EmptyStatement(_createSyntheticToken(TokenType.SEMICOLON)); |
| 6624 } |
| 6625 } else if (_inGenerator && _matchesString(_YIELD)) { |
| 6626 return _parseYieldStatement(); |
| 6627 } else if (_inAsync && _matchesString(_AWAIT)) { |
| 6628 if (_tokenMatchesKeyword(_peek(), Keyword.FOR)) { |
| 6629 return _parseForStatement(); |
| 6630 } |
| 6631 return new ExpressionStatement( |
| 6632 parseExpression2(), _expect(TokenType.SEMICOLON)); |
| 6633 } else if (_matchesString(_AWAIT) && |
| 6634 _tokenMatchesKeyword(_peek(), Keyword.FOR)) { |
| 6635 Token awaitToken = _currentToken; |
| 6636 Statement statement = _parseForStatement(); |
| 6637 if (statement is! ForStatement) { |
| 6638 _reportErrorForToken( |
| 6639 CompileTimeErrorCode.ASYNC_FOR_IN_WRONG_CONTEXT, awaitToken); |
| 6640 } |
| 6641 return statement; |
| 6642 } else if (_matches(TokenType.SEMICOLON)) { |
| 6643 return _parseEmptyStatement(); |
| 6644 } else if (_isInitializedVariableDeclaration()) { |
| 6645 return _parseVariableDeclarationStatementAfterMetadata( |
| 6646 commentAndMetadata); |
| 6647 } else if (_isFunctionDeclaration()) { |
| 6648 return _parseFunctionDeclarationStatement(); |
| 6649 } else if (_matches(TokenType.CLOSE_CURLY_BRACKET)) { |
| 6650 _reportErrorForCurrentToken(ParserErrorCode.MISSING_STATEMENT); |
| 6651 return new EmptyStatement(_createSyntheticToken(TokenType.SEMICOLON)); |
| 6652 } else { |
| 6653 return new ExpressionStatement(parseExpression2(), _expectSemicolon()); |
| 6654 } |
| 6655 } |
| 6656 |
| 6657 /** |
| 6658 * Parse an operator declaration. The [commentAndMetadata] is the |
| 6659 * documentation comment and metadata to be associated with the declaration. |
| 6660 * The [externalKeyword] is the 'external' token. The [returnType] is the |
| 6661 * return type that has already been parsed, or `null` if there was no return |
| 6662 * type. Return the operator declaration that was parsed. |
| 6663 * |
| 6664 * operatorDeclaration ::= |
| 6665 * operatorSignature (';' | functionBody) |
| 6666 * |
| 6667 * operatorSignature ::= |
| 6668 * 'external'? returnType? 'operator' operator formalParameterList |
| 6669 */ |
| 6670 MethodDeclaration _parseOperator(CommentAndMetadata commentAndMetadata, |
| 6671 Token externalKeyword, TypeName returnType) { |
| 6672 Token operatorKeyword; |
| 6673 if (_matchesKeyword(Keyword.OPERATOR)) { |
| 6674 operatorKeyword = getAndAdvance(); |
| 6675 } else { |
| 6676 _reportErrorForToken( |
| 6677 ParserErrorCode.MISSING_KEYWORD_OPERATOR, _currentToken); |
| 6678 operatorKeyword = _createSyntheticKeyword(Keyword.OPERATOR); |
| 6679 } |
| 6680 if (!_currentToken.isUserDefinableOperator) { |
| 6681 _reportErrorForCurrentToken( |
| 6682 ParserErrorCode.NON_USER_DEFINABLE_OPERATOR, [_currentToken.lexeme]); |
| 6683 } |
| 6684 SimpleIdentifier name = new SimpleIdentifier(getAndAdvance()); |
| 6685 if (_matches(TokenType.EQ)) { |
| 6686 Token previous = _currentToken.previous; |
| 6687 if ((_tokenMatches(previous, TokenType.EQ_EQ) || |
| 6688 _tokenMatches(previous, TokenType.BANG_EQ)) && |
| 6689 _currentToken.offset == previous.offset + 2) { |
| 6690 _reportErrorForCurrentToken(ParserErrorCode.INVALID_OPERATOR, |
| 6691 ["${previous.lexeme}${_currentToken.lexeme}"]); |
| 6692 _advance(); |
| 6693 } |
| 6694 } |
| 6695 FormalParameterList parameters = parseFormalParameterList(); |
| 6696 _validateFormalParameterList(parameters); |
| 6697 FunctionBody body = |
| 6698 _parseFunctionBody(true, ParserErrorCode.MISSING_FUNCTION_BODY, false); |
| 6699 if (externalKeyword != null && body is! EmptyFunctionBody) { |
| 6700 _reportErrorForCurrentToken(ParserErrorCode.EXTERNAL_OPERATOR_WITH_BODY); |
| 6701 } |
| 6702 return new MethodDeclaration(commentAndMetadata.comment, |
| 6703 commentAndMetadata.metadata, externalKeyword, null, returnType, null, |
| 6704 operatorKeyword, name, null, parameters, body); |
| 6705 } |
| 6706 |
| 6707 /** |
| 6708 * Parse a return type if one is given, otherwise return `null` without |
| 6709 * advancing. Return the return type that was parsed. |
| 6710 */ |
| 6711 TypeName _parseOptionalReturnType() { |
| 6712 if (_matchesKeyword(Keyword.VOID)) { |
| 6713 return parseReturnType(); |
| 6714 } else if (_matchesIdentifier() && |
| 6715 !_matchesKeyword(Keyword.GET) && |
| 6716 !_matchesKeyword(Keyword.SET) && |
| 6717 !_matchesKeyword(Keyword.OPERATOR) && |
| 6718 (_tokenMatchesIdentifier(_peek()) || |
| 6719 _tokenMatches(_peek(), TokenType.LT))) { |
| 6720 return parseReturnType(); |
| 6721 } else if (_matchesIdentifier() && |
| 6722 _tokenMatches(_peek(), TokenType.PERIOD) && |
| 6723 _tokenMatchesIdentifier(_peekAt(2)) && |
| 6724 (_tokenMatchesIdentifier(_peekAt(3)) || |
| 6725 _tokenMatches(_peekAt(3), TokenType.LT))) { |
| 6726 return parseReturnType(); |
| 6727 } |
| 6728 return null; |
| 6729 } |
| 6730 |
| 6731 /** |
| 6732 * Parse a part or part-of directive. The [commentAndMetadata] is the metadata |
| 6733 * to be associated with the directive. Return the part or part-of directive |
| 6734 * that was parsed. |
| 6735 * |
| 6736 * partDirective ::= |
| 6737 * metadata 'part' stringLiteral ';' |
| 6738 * |
| 6739 * partOfDirective ::= |
| 6740 * metadata 'part' 'of' identifier ';' |
| 6741 */ |
| 6742 Directive _parsePartDirective(CommentAndMetadata commentAndMetadata) { |
| 6743 Token partKeyword = _expectKeyword(Keyword.PART); |
| 6744 if (_matchesString(_OF)) { |
| 6745 Token ofKeyword = getAndAdvance(); |
| 6746 LibraryIdentifier libraryName = _parseLibraryName( |
| 6747 ParserErrorCode.MISSING_NAME_IN_PART_OF_DIRECTIVE, ofKeyword); |
| 6748 Token semicolon = _expect(TokenType.SEMICOLON); |
| 6749 return new PartOfDirective(commentAndMetadata.comment, |
| 6750 commentAndMetadata.metadata, partKeyword, ofKeyword, libraryName, |
| 6751 semicolon); |
| 6752 } |
| 6753 StringLiteral partUri = _parseUri(); |
| 6754 Token semicolon = _expect(TokenType.SEMICOLON); |
| 6755 return new PartDirective(commentAndMetadata.comment, |
| 6756 commentAndMetadata.metadata, partKeyword, partUri, semicolon); |
| 6757 } |
| 6758 |
| 6759 /** |
| 6760 * Parse a postfix expression. Return the postfix expression that was parsed. |
| 6761 * |
| 6762 * postfixExpression ::= |
| 6763 * assignableExpression postfixOperator |
| 6764 * | primary selector* |
| 6765 * |
| 6766 * selector ::= |
| 6767 * assignableSelector |
| 6768 * | argumentList |
| 6769 */ |
| 6770 Expression _parsePostfixExpression() { |
| 6771 Expression operand = _parseAssignableExpression(true); |
| 6772 if (_matches(TokenType.OPEN_SQUARE_BRACKET) || |
| 6773 _matches(TokenType.PERIOD) || |
| 6774 _matches(TokenType.QUESTION_PERIOD) || |
| 6775 _matches(TokenType.OPEN_PAREN) || |
| 6776 (parseGenericMethods && _matches(TokenType.LT))) { |
| 6777 do { |
| 6778 if (_isLikelyParameterList()) { |
| 6779 TypeArgumentList typeArguments = null; |
| 6780 if (_matches(TokenType.LT)) { |
| 6781 typeArguments = parseTypeArgumentList(); |
| 6782 } |
| 6783 ArgumentList argumentList = parseArgumentList(); |
| 6784 if (operand is PropertyAccess) { |
| 6785 PropertyAccess access = operand as PropertyAccess; |
| 6786 operand = new MethodInvocation(access.target, access.operator, |
| 6787 access.propertyName, typeArguments, argumentList); |
| 6788 } else { |
| 6789 operand = new FunctionExpressionInvocation( |
| 6790 operand, typeArguments, argumentList); |
| 6791 } |
| 6792 } else { |
| 6793 operand = _parseAssignableSelector(operand, true); |
| 6794 } |
| 6795 } while (_matches(TokenType.OPEN_SQUARE_BRACKET) || |
| 6796 _matches(TokenType.PERIOD) || |
| 6797 _matches(TokenType.QUESTION_PERIOD) || |
| 6798 _matches(TokenType.OPEN_PAREN)); |
| 6799 return operand; |
| 6800 } |
| 6801 if (!_currentToken.type.isIncrementOperator) { |
| 6802 return operand; |
| 6803 } |
| 6804 _ensureAssignable(operand); |
| 6805 Token operator = getAndAdvance(); |
| 6806 return new PostfixExpression(operand, operator); |
| 6807 } |
| 6808 |
| 6809 /** |
| 6810 * Parse a primary expression. Return the primary expression that was parsed. |
| 6811 * |
| 6812 * primary ::= |
| 6813 * thisExpression |
| 6814 * | 'super' unconditionalAssignableSelector |
| 6815 * | functionExpression |
| 6816 * | literal |
| 6817 * | identifier |
| 6818 * | newExpression |
| 6819 * | constObjectExpression |
| 6820 * | '(' expression ')' |
| 6821 * | argumentDefinitionTest |
| 6822 * |
| 6823 * literal ::= |
| 6824 * nullLiteral |
| 6825 * | booleanLiteral |
| 6826 * | numericLiteral |
| 6827 * | stringLiteral |
| 6828 * | symbolLiteral |
| 6829 * | mapLiteral |
| 6830 * | listLiteral |
| 6831 */ |
| 6832 Expression _parsePrimaryExpression() { |
| 6833 if (_matchesKeyword(Keyword.THIS)) { |
| 6834 return new ThisExpression(getAndAdvance()); |
| 6835 } else if (_matchesKeyword(Keyword.SUPER)) { |
| 6836 // TODO(paulberry): verify with Gilad that "super" must be followed by |
| 6837 // unconditionalAssignableSelector in this case. |
| 6838 return _parseAssignableSelector( |
| 6839 new SuperExpression(getAndAdvance()), false, allowConditional: false); |
| 6840 } else if (_matchesKeyword(Keyword.NULL)) { |
| 6841 return new NullLiteral(getAndAdvance()); |
| 6842 } else if (_matchesKeyword(Keyword.FALSE)) { |
| 6843 return new BooleanLiteral(getAndAdvance(), false); |
| 6844 } else if (_matchesKeyword(Keyword.TRUE)) { |
| 6845 return new BooleanLiteral(getAndAdvance(), true); |
| 6846 } else if (_matches(TokenType.DOUBLE)) { |
| 6847 Token token = getAndAdvance(); |
| 6848 double value = 0.0; |
| 6849 try { |
| 6850 value = double.parse(token.lexeme); |
| 6851 } on FormatException { |
| 6852 // The invalid format should have been reported by the scanner. |
| 6853 } |
| 6854 return new DoubleLiteral(token, value); |
| 6855 } else if (_matches(TokenType.HEXADECIMAL)) { |
| 6856 Token token = getAndAdvance(); |
| 6857 int value = null; |
| 6858 try { |
| 6859 value = int.parse(token.lexeme.substring(2), radix: 16); |
| 6860 } on FormatException { |
| 6861 // The invalid format should have been reported by the scanner. |
| 6862 } |
| 6863 return new IntegerLiteral(token, value); |
| 6864 } else if (_matches(TokenType.INT)) { |
| 6865 Token token = getAndAdvance(); |
| 6866 int value = null; |
| 6867 try { |
| 6868 value = int.parse(token.lexeme); |
| 6869 } on FormatException { |
| 6870 // The invalid format should have been reported by the scanner. |
| 6871 } |
| 6872 return new IntegerLiteral(token, value); |
| 6873 } else if (_matches(TokenType.STRING)) { |
| 6874 return parseStringLiteral(); |
| 6875 } else if (_matches(TokenType.OPEN_CURLY_BRACKET)) { |
| 6876 return _parseMapLiteral(null, null); |
| 6877 } else if (_matches(TokenType.OPEN_SQUARE_BRACKET) || |
| 6878 _matches(TokenType.INDEX)) { |
| 6879 return _parseListLiteral(null, null); |
| 6880 } else if (_matchesIdentifier()) { |
| 6881 // TODO(brianwilkerson) The code below was an attempt to recover from an |
| 6882 // error case, but it needs to be applied as a recovery only after we |
| 6883 // know that parsing it as an identifier doesn't work. Leaving the code as |
| 6884 // a reminder of how to recover. |
| 6885 // if (isFunctionExpression(peek())) { |
| 6886 // // |
| 6887 // // Function expressions were allowed to have names at one point,
but this is now illegal. |
| 6888 // // |
| 6889 // reportError(ParserErrorCode.NAMED_FUNCTION_EXPRESSION, getAndAdv
ance()); |
| 6890 // return parseFunctionExpression(); |
| 6891 // } |
| 6892 return parsePrefixedIdentifier(); |
| 6893 } else if (_matchesKeyword(Keyword.NEW)) { |
| 6894 return _parseNewExpression(); |
| 6895 } else if (_matchesKeyword(Keyword.CONST)) { |
| 6896 return _parseConstExpression(); |
| 6897 } else if (_matches(TokenType.OPEN_PAREN)) { |
| 6898 if (_isFunctionExpression(_currentToken)) { |
| 6899 return parseFunctionExpression(); |
| 6900 } |
| 6901 Token leftParenthesis = getAndAdvance(); |
| 6902 bool wasInInitializer = _inInitializer; |
| 6903 _inInitializer = false; |
| 6904 try { |
| 6905 Expression expression = parseExpression2(); |
| 6906 Token rightParenthesis = _expect(TokenType.CLOSE_PAREN); |
| 6907 return new ParenthesizedExpression( |
| 6908 leftParenthesis, expression, rightParenthesis); |
| 6909 } finally { |
| 6910 _inInitializer = wasInInitializer; |
| 6911 } |
| 6912 } else if (_matches(TokenType.LT)) { |
| 6913 return _parseListOrMapLiteral(null); |
| 6914 } else if (_matches(TokenType.QUESTION) && |
| 6915 _tokenMatches(_peek(), TokenType.IDENTIFIER)) { |
| 6916 _reportErrorForCurrentToken( |
| 6917 ParserErrorCode.UNEXPECTED_TOKEN, [_currentToken.lexeme]); |
| 6918 _advance(); |
| 6919 return _parsePrimaryExpression(); |
| 6920 } else if (_matchesKeyword(Keyword.VOID)) { |
| 6921 // |
| 6922 // Recover from having a return type of "void" where a return type is not |
| 6923 // expected. |
| 6924 // |
| 6925 // TODO(brianwilkerson) Improve this error message. |
| 6926 _reportErrorForCurrentToken( |
| 6927 ParserErrorCode.UNEXPECTED_TOKEN, [_currentToken.lexeme]); |
| 6928 _advance(); |
| 6929 return _parsePrimaryExpression(); |
| 6930 } else if (_matches(TokenType.HASH)) { |
| 6931 return _parseSymbolLiteral(); |
| 6932 } else { |
| 6933 _reportErrorForCurrentToken(ParserErrorCode.MISSING_IDENTIFIER); |
| 6934 return _createSyntheticIdentifier(); |
| 6935 } |
| 6936 } |
| 6937 |
| 6938 /** |
| 6939 * Parse a redirecting constructor invocation. Return the redirecting |
| 6940 * constructor invocation that was parsed. |
| 6941 * |
| 6942 * redirectingConstructorInvocation ::= |
| 6943 * 'this' ('.' identifier)? arguments |
| 6944 */ |
| 6945 RedirectingConstructorInvocation _parseRedirectingConstructorInvocation() { |
| 6946 Token keyword = _expectKeyword(Keyword.THIS); |
| 6947 Token period = null; |
| 6948 SimpleIdentifier constructorName = null; |
| 6949 if (_matches(TokenType.PERIOD)) { |
| 6950 period = getAndAdvance(); |
| 6951 constructorName = parseSimpleIdentifier(); |
| 6952 } |
| 6953 ArgumentList argumentList = parseArgumentList(); |
| 6954 return new RedirectingConstructorInvocation( |
| 6955 keyword, period, constructorName, argumentList); |
| 6956 } |
| 6957 |
| 6958 /** |
| 6959 * Parse a relational expression. Return the relational expression that was |
| 6960 * parsed. |
| 6961 * |
| 6962 * relationalExpression ::= |
| 6963 * bitwiseOrExpression ('is' '!'? type | 'as' type | relationalOperato
r bitwiseOrExpression)? |
| 6964 * | 'super' relationalOperator bitwiseOrExpression |
| 6965 */ |
| 6966 Expression _parseRelationalExpression() { |
| 6967 if (_matchesKeyword(Keyword.SUPER) && |
| 6968 _currentToken.next.type.isRelationalOperator) { |
| 6969 Expression expression = new SuperExpression(getAndAdvance()); |
| 6970 Token operator = getAndAdvance(); |
| 6971 expression = new BinaryExpression( |
| 6972 expression, operator, parseBitwiseOrExpression()); |
| 6973 return expression; |
| 6974 } |
| 6975 Expression expression = parseBitwiseOrExpression(); |
| 6976 if (_matchesKeyword(Keyword.AS)) { |
| 6977 Token asOperator = getAndAdvance(); |
| 6978 expression = new AsExpression(expression, asOperator, parseTypeName()); |
| 6979 } else if (_matchesKeyword(Keyword.IS)) { |
| 6980 Token isOperator = getAndAdvance(); |
| 6981 Token notOperator = null; |
| 6982 if (_matches(TokenType.BANG)) { |
| 6983 notOperator = getAndAdvance(); |
| 6984 } |
| 6985 expression = new IsExpression( |
| 6986 expression, isOperator, notOperator, parseTypeName()); |
| 6987 } else if (_currentToken.type.isRelationalOperator) { |
| 6988 Token operator = getAndAdvance(); |
| 6989 expression = new BinaryExpression( |
| 6990 expression, operator, parseBitwiseOrExpression()); |
| 6991 } |
| 6992 return expression; |
| 6993 } |
| 6994 |
| 6995 /** |
| 6996 * Parse a rethrow expression. Return the rethrow expression that was parsed. |
| 6997 * |
| 6998 * rethrowExpression ::= |
| 6999 * 'rethrow' |
| 7000 */ |
| 7001 Expression _parseRethrowExpression() => |
| 7002 new RethrowExpression(_expectKeyword(Keyword.RETHROW)); |
| 7003 |
| 7004 /** |
| 7005 * Parse a return statement. Return the return statement that was parsed. |
| 7006 * |
| 7007 * returnStatement ::= |
| 7008 * 'return' expression? ';' |
| 7009 */ |
| 7010 Statement _parseReturnStatement() { |
| 7011 Token returnKeyword = _expectKeyword(Keyword.RETURN); |
| 7012 if (_matches(TokenType.SEMICOLON)) { |
| 7013 return new ReturnStatement(returnKeyword, null, getAndAdvance()); |
| 7014 } |
| 7015 Expression expression = parseExpression2(); |
| 7016 Token semicolon = _expect(TokenType.SEMICOLON); |
| 7017 return new ReturnStatement(returnKeyword, expression, semicolon); |
| 7018 } |
| 7019 |
| 7020 /** |
| 7021 * Parse a setter. The [commentAndMetadata] is the documentation comment and |
| 7022 * metadata to be associated with the declaration. The [externalKeyword] is |
| 7023 * the 'external' token. The [staticKeyword] is the static keyword, or `null` |
| 7024 * if the setter is not static. The [returnType] is the return type that has |
| 7025 * already been parsed, or `null` if there was no return type. Return the |
| 7026 * setter that was parsed. |
| 7027 * |
| 7028 * setter ::= |
| 7029 * setterSignature functionBody? |
| 7030 * |
| 7031 * setterSignature ::= |
| 7032 * 'external'? 'static'? returnType? 'set' identifier formalParameterL
ist |
| 7033 */ |
| 7034 MethodDeclaration _parseSetter(CommentAndMetadata commentAndMetadata, |
| 7035 Token externalKeyword, Token staticKeyword, TypeName returnType) { |
| 7036 Token propertyKeyword = _expectKeyword(Keyword.SET); |
| 7037 SimpleIdentifier name = parseSimpleIdentifier(); |
| 7038 FormalParameterList parameters = parseFormalParameterList(); |
| 7039 _validateFormalParameterList(parameters); |
| 7040 FunctionBody body = _parseFunctionBody( |
| 7041 externalKeyword != null || staticKeyword == null, |
| 7042 ParserErrorCode.STATIC_SETTER_WITHOUT_BODY, false); |
| 7043 if (externalKeyword != null && body is! EmptyFunctionBody) { |
| 7044 _reportErrorForCurrentToken(ParserErrorCode.EXTERNAL_SETTER_WITH_BODY); |
| 7045 } |
| 7046 return new MethodDeclaration(commentAndMetadata.comment, |
| 7047 commentAndMetadata.metadata, externalKeyword, staticKeyword, returnType, |
| 7048 propertyKeyword, null, name, null, parameters, body); |
| 7049 } |
| 7050 |
| 7051 /** |
| 7052 * Parse a shift expression. Return the shift expression that was parsed. |
| 7053 * |
| 7054 * shiftExpression ::= |
| 7055 * additiveExpression (shiftOperator additiveExpression)* |
| 7056 * | 'super' (shiftOperator additiveExpression)+ |
| 7057 */ |
| 7058 Expression _parseShiftExpression() { |
| 7059 Expression expression; |
| 7060 if (_matchesKeyword(Keyword.SUPER) && |
| 7061 _currentToken.next.type.isShiftOperator) { |
| 7062 expression = new SuperExpression(getAndAdvance()); |
| 7063 } else { |
| 7064 expression = _parseAdditiveExpression(); |
| 7065 } |
| 7066 while (_currentToken.type.isShiftOperator) { |
| 7067 Token operator = getAndAdvance(); |
| 7068 expression = new BinaryExpression( |
| 7069 expression, operator, _parseAdditiveExpression()); |
| 7070 } |
| 7071 return expression; |
| 7072 } |
| 7073 |
| 7074 /** |
| 7075 * Parse a list of statements within a switch statement. Return the statements |
| 7076 * that were parsed. |
| 7077 * |
| 7078 * statements ::= |
| 7079 * statement* |
| 7080 */ |
| 7081 List<Statement> _parseStatementList() { |
| 7082 List<Statement> statements = new List<Statement>(); |
| 7083 Token statementStart = _currentToken; |
| 7084 while (!_matches(TokenType.EOF) && |
| 7085 !_matches(TokenType.CLOSE_CURLY_BRACKET) && |
| 7086 !_isSwitchMember()) { |
| 7087 statements.add(parseStatement2()); |
| 7088 if (identical(_currentToken, statementStart)) { |
| 7089 _reportErrorForToken(ParserErrorCode.UNEXPECTED_TOKEN, _currentToken, |
| 7090 [_currentToken.lexeme]); |
| 7091 _advance(); |
| 7092 } |
| 7093 statementStart = _currentToken; |
| 7094 } |
| 7095 return statements; |
| 7096 } |
| 7097 |
| 7098 /** |
| 7099 * Parse a string literal that contains interpolations. Return the string |
| 7100 * literal that was parsed. |
| 7101 */ |
| 7102 StringInterpolation _parseStringInterpolation(Token string) { |
| 7103 List<InterpolationElement> elements = new List<InterpolationElement>(); |
| 7104 bool hasMore = _matches(TokenType.STRING_INTERPOLATION_EXPRESSION) || |
| 7105 _matches(TokenType.STRING_INTERPOLATION_IDENTIFIER); |
| 7106 elements.add(new InterpolationString( |
| 7107 string, _computeStringValue(string.lexeme, true, !hasMore))); |
| 7108 while (hasMore) { |
| 7109 if (_matches(TokenType.STRING_INTERPOLATION_EXPRESSION)) { |
| 7110 Token openToken = getAndAdvance(); |
| 7111 bool wasInInitializer = _inInitializer; |
| 7112 _inInitializer = false; |
| 7113 try { |
| 7114 Expression expression = parseExpression2(); |
| 7115 Token rightBracket = _expect(TokenType.CLOSE_CURLY_BRACKET); |
| 7116 elements.add( |
| 7117 new InterpolationExpression(openToken, expression, rightBracket)); |
| 7118 } finally { |
| 7119 _inInitializer = wasInInitializer; |
| 7120 } |
| 7121 } else { |
| 7122 Token openToken = getAndAdvance(); |
| 7123 Expression expression = null; |
| 7124 if (_matchesKeyword(Keyword.THIS)) { |
| 7125 expression = new ThisExpression(getAndAdvance()); |
| 7126 } else { |
| 7127 expression = parseSimpleIdentifier(); |
| 7128 } |
| 7129 elements.add(new InterpolationExpression(openToken, expression, null)); |
| 7130 } |
| 7131 if (_matches(TokenType.STRING)) { |
| 7132 string = getAndAdvance(); |
| 7133 hasMore = _matches(TokenType.STRING_INTERPOLATION_EXPRESSION) || |
| 7134 _matches(TokenType.STRING_INTERPOLATION_IDENTIFIER); |
| 7135 elements.add(new InterpolationString( |
| 7136 string, _computeStringValue(string.lexeme, false, !hasMore))); |
| 7137 } else { |
| 7138 hasMore = false; |
| 7139 } |
| 7140 } |
| 7141 return new StringInterpolation(elements); |
| 7142 } |
| 7143 |
| 7144 /** |
| 7145 * Parse a super constructor invocation. Return the super constructor |
| 7146 * invocation that was parsed. |
| 7147 * |
| 7148 * superConstructorInvocation ::= |
| 7149 * 'super' ('.' identifier)? arguments |
| 7150 */ |
| 7151 SuperConstructorInvocation _parseSuperConstructorInvocation() { |
| 7152 Token keyword = _expectKeyword(Keyword.SUPER); |
| 7153 Token period = null; |
| 7154 SimpleIdentifier constructorName = null; |
| 7155 if (_matches(TokenType.PERIOD)) { |
| 7156 period = getAndAdvance(); |
| 7157 constructorName = parseSimpleIdentifier(); |
| 7158 } |
| 7159 ArgumentList argumentList = parseArgumentList(); |
| 7160 return new SuperConstructorInvocation( |
| 7161 keyword, period, constructorName, argumentList); |
| 7162 } |
| 7163 |
| 7164 /** |
| 7165 * Parse a switch statement. Return the switch statement that was parsed. |
| 7166 * |
| 7167 * switchStatement ::= |
| 7168 * 'switch' '(' expression ')' '{' switchCase* defaultCase? '}' |
| 7169 * |
| 7170 * switchCase ::= |
| 7171 * label* ('case' expression ':') statements |
| 7172 * |
| 7173 * defaultCase ::= |
| 7174 * label* 'default' ':' statements |
| 7175 */ |
| 7176 SwitchStatement _parseSwitchStatement() { |
| 7177 bool wasInSwitch = _inSwitch; |
| 7178 _inSwitch = true; |
| 7179 try { |
| 7180 HashSet<String> definedLabels = new HashSet<String>(); |
| 7181 Token keyword = _expectKeyword(Keyword.SWITCH); |
| 7182 Token leftParenthesis = _expect(TokenType.OPEN_PAREN); |
| 7183 Expression expression = parseExpression2(); |
| 7184 Token rightParenthesis = _expect(TokenType.CLOSE_PAREN); |
| 7185 Token leftBracket = _expect(TokenType.OPEN_CURLY_BRACKET); |
| 7186 Token defaultKeyword = null; |
| 7187 List<SwitchMember> members = new List<SwitchMember>(); |
| 7188 while (!_matches(TokenType.EOF) && |
| 7189 !_matches(TokenType.CLOSE_CURLY_BRACKET)) { |
| 7190 List<Label> labels = new List<Label>(); |
| 7191 while ( |
| 7192 _matchesIdentifier() && _tokenMatches(_peek(), TokenType.COLON)) { |
| 7193 SimpleIdentifier identifier = parseSimpleIdentifier(); |
| 7194 String label = identifier.token.lexeme; |
| 7195 if (definedLabels.contains(label)) { |
| 7196 _reportErrorForToken( |
| 7197 ParserErrorCode.DUPLICATE_LABEL_IN_SWITCH_STATEMENT, |
| 7198 identifier.token, [label]); |
| 7199 } else { |
| 7200 definedLabels.add(label); |
| 7201 } |
| 7202 Token colon = _expect(TokenType.COLON); |
| 7203 labels.add(new Label(identifier, colon)); |
| 7204 } |
| 7205 if (_matchesKeyword(Keyword.CASE)) { |
| 7206 Token caseKeyword = getAndAdvance(); |
| 7207 Expression caseExpression = parseExpression2(); |
| 7208 Token colon = _expect(TokenType.COLON); |
| 7209 members.add(new SwitchCase(labels, caseKeyword, caseExpression, colon, |
| 7210 _parseStatementList())); |
| 7211 if (defaultKeyword != null) { |
| 7212 _reportErrorForToken( |
| 7213 ParserErrorCode.SWITCH_HAS_CASE_AFTER_DEFAULT_CASE, |
| 7214 caseKeyword); |
| 7215 } |
| 7216 } else if (_matchesKeyword(Keyword.DEFAULT)) { |
| 7217 if (defaultKeyword != null) { |
| 7218 _reportErrorForToken( |
| 7219 ParserErrorCode.SWITCH_HAS_MULTIPLE_DEFAULT_CASES, _peek()); |
| 7220 } |
| 7221 defaultKeyword = getAndAdvance(); |
| 7222 Token colon = _expect(TokenType.COLON); |
| 7223 members.add(new SwitchDefault( |
| 7224 labels, defaultKeyword, colon, _parseStatementList())); |
| 7225 } else { |
| 7226 // We need to advance, otherwise we could end up in an infinite loop, |
| 7227 // but this could be a lot smarter about recovering from the error. |
| 7228 _reportErrorForCurrentToken(ParserErrorCode.EXPECTED_CASE_OR_DEFAULT); |
| 7229 while (!_matches(TokenType.EOF) && |
| 7230 !_matches(TokenType.CLOSE_CURLY_BRACKET) && |
| 7231 !_matchesKeyword(Keyword.CASE) && |
| 7232 !_matchesKeyword(Keyword.DEFAULT)) { |
| 7233 _advance(); |
| 7234 } |
| 7235 } |
| 7236 } |
| 7237 Token rightBracket = _expect(TokenType.CLOSE_CURLY_BRACKET); |
| 7238 return new SwitchStatement(keyword, leftParenthesis, expression, |
| 7239 rightParenthesis, leftBracket, members, rightBracket); |
| 7240 } finally { |
| 7241 _inSwitch = wasInSwitch; |
| 7242 } |
| 7243 } |
| 7244 |
| 7245 /** |
| 7246 * Parse a symbol literal. Return the symbol literal that was parsed. |
| 7247 * |
| 7248 * symbolLiteral ::= |
| 7249 * '#' identifier ('.' identifier)* |
| 7250 */ |
| 7251 SymbolLiteral _parseSymbolLiteral() { |
| 7252 Token poundSign = getAndAdvance(); |
| 7253 List<Token> components = new List<Token>(); |
| 7254 if (_matchesIdentifier()) { |
| 7255 components.add(getAndAdvance()); |
| 7256 while (_matches(TokenType.PERIOD)) { |
| 7257 _advance(); |
| 7258 if (_matchesIdentifier()) { |
| 7259 components.add(getAndAdvance()); |
| 7260 } else { |
| 7261 _reportErrorForCurrentToken(ParserErrorCode.MISSING_IDENTIFIER); |
| 7262 components.add(_createSyntheticToken(TokenType.IDENTIFIER)); |
| 7263 break; |
| 7264 } |
| 7265 } |
| 7266 } else if (_currentToken.isOperator) { |
| 7267 components.add(getAndAdvance()); |
| 7268 } else if (_tokenMatchesKeyword(_currentToken, Keyword.VOID)) { |
| 7269 components.add(getAndAdvance()); |
| 7270 } else { |
| 7271 _reportErrorForCurrentToken(ParserErrorCode.MISSING_IDENTIFIER); |
| 7272 components.add(_createSyntheticToken(TokenType.IDENTIFIER)); |
| 7273 } |
| 7274 return new SymbolLiteral(poundSign, components); |
| 7275 } |
| 7276 |
| 7277 /** |
| 7278 * Parse a throw expression. Return the throw expression that was parsed. |
| 7279 * |
| 7280 * throwExpression ::= |
| 7281 * 'throw' expression |
| 7282 */ |
| 7283 Expression _parseThrowExpression() { |
| 7284 Token keyword = _expectKeyword(Keyword.THROW); |
| 7285 if (_matches(TokenType.SEMICOLON) || _matches(TokenType.CLOSE_PAREN)) { |
| 7286 _reportErrorForToken( |
| 7287 ParserErrorCode.MISSING_EXPRESSION_IN_THROW, _currentToken); |
| 7288 return new ThrowExpression(keyword, _createSyntheticIdentifier()); |
| 7289 } |
| 7290 Expression expression = parseExpression2(); |
| 7291 return new ThrowExpression(keyword, expression); |
| 7292 } |
| 7293 |
| 7294 /** |
| 7295 * Parse a throw expression. Return the throw expression that was parsed. |
| 7296 * |
| 7297 * throwExpressionWithoutCascade ::= |
| 7298 * 'throw' expressionWithoutCascade |
| 7299 */ |
| 7300 Expression _parseThrowExpressionWithoutCascade() { |
| 7301 Token keyword = _expectKeyword(Keyword.THROW); |
| 7302 if (_matches(TokenType.SEMICOLON) || _matches(TokenType.CLOSE_PAREN)) { |
| 7303 _reportErrorForToken( |
| 7304 ParserErrorCode.MISSING_EXPRESSION_IN_THROW, _currentToken); |
| 7305 return new ThrowExpression(keyword, _createSyntheticIdentifier()); |
| 7306 } |
| 7307 Expression expression = parseExpressionWithoutCascade(); |
| 7308 return new ThrowExpression(keyword, expression); |
| 7309 } |
| 7310 |
| 7311 /** |
| 7312 * Parse a try statement. Return the try statement that was parsed. |
| 7313 * |
| 7314 * tryStatement ::= |
| 7315 * 'try' block (onPart+ finallyPart? | finallyPart) |
| 7316 * |
| 7317 * onPart ::= |
| 7318 * catchPart block |
| 7319 * | 'on' type catchPart? block |
| 7320 * |
| 7321 * catchPart ::= |
| 7322 * 'catch' '(' identifier (',' identifier)? ')' |
| 7323 * |
| 7324 * finallyPart ::= |
| 7325 * 'finally' block |
| 7326 */ |
| 7327 Statement _parseTryStatement() { |
| 7328 Token tryKeyword = _expectKeyword(Keyword.TRY); |
| 7329 Block body = parseBlock(); |
| 7330 List<CatchClause> catchClauses = new List<CatchClause>(); |
| 7331 Block finallyClause = null; |
| 7332 while (_matchesString(_ON) || _matchesKeyword(Keyword.CATCH)) { |
| 7333 Token onKeyword = null; |
| 7334 TypeName exceptionType = null; |
| 7335 if (_matchesString(_ON)) { |
| 7336 onKeyword = getAndAdvance(); |
| 7337 exceptionType = parseTypeName(); |
| 7338 } |
| 7339 Token catchKeyword = null; |
| 7340 Token leftParenthesis = null; |
| 7341 SimpleIdentifier exceptionParameter = null; |
| 7342 Token comma = null; |
| 7343 SimpleIdentifier stackTraceParameter = null; |
| 7344 Token rightParenthesis = null; |
| 7345 if (_matchesKeyword(Keyword.CATCH)) { |
| 7346 catchKeyword = getAndAdvance(); |
| 7347 leftParenthesis = _expect(TokenType.OPEN_PAREN); |
| 7348 exceptionParameter = parseSimpleIdentifier(); |
| 7349 if (_matches(TokenType.COMMA)) { |
| 7350 comma = getAndAdvance(); |
| 7351 stackTraceParameter = parseSimpleIdentifier(); |
| 7352 } |
| 7353 rightParenthesis = _expect(TokenType.CLOSE_PAREN); |
| 7354 } |
| 7355 Block catchBody = parseBlock(); |
| 7356 catchClauses.add(new CatchClause(onKeyword, exceptionType, catchKeyword, |
| 7357 leftParenthesis, exceptionParameter, comma, stackTraceParameter, |
| 7358 rightParenthesis, catchBody)); |
| 7359 } |
| 7360 Token finallyKeyword = null; |
| 7361 if (_matchesKeyword(Keyword.FINALLY)) { |
| 7362 finallyKeyword = getAndAdvance(); |
| 7363 finallyClause = parseBlock(); |
| 7364 } else { |
| 7365 if (catchClauses.isEmpty) { |
| 7366 _reportErrorForCurrentToken(ParserErrorCode.MISSING_CATCH_OR_FINALLY); |
| 7367 } |
| 7368 } |
| 7369 return new TryStatement( |
| 7370 tryKeyword, body, catchClauses, finallyKeyword, finallyClause); |
| 7371 } |
| 7372 |
| 7373 /** |
| 7374 * Parse a type alias. The [commentAndMetadata] is the metadata to be |
| 7375 * associated with the member. Return the type alias that was parsed. |
| 7376 * |
| 7377 * typeAlias ::= |
| 7378 * 'typedef' typeAliasBody |
| 7379 * |
| 7380 * typeAliasBody ::= |
| 7381 * classTypeAlias |
| 7382 * | functionTypeAlias |
| 7383 * |
| 7384 * classTypeAlias ::= |
| 7385 * identifier typeParameters? '=' 'abstract'? mixinApplication |
| 7386 * |
| 7387 * mixinApplication ::= |
| 7388 * qualified withClause implementsClause? ';' |
| 7389 * |
| 7390 * functionTypeAlias ::= |
| 7391 * functionPrefix typeParameterList? formalParameterList ';' |
| 7392 * |
| 7393 * functionPrefix ::= |
| 7394 * returnType? name |
| 7395 */ |
| 7396 TypeAlias _parseTypeAlias(CommentAndMetadata commentAndMetadata) { |
| 7397 Token keyword = _expectKeyword(Keyword.TYPEDEF); |
| 7398 if (_matchesIdentifier()) { |
| 7399 Token next = _peek(); |
| 7400 if (_tokenMatches(next, TokenType.LT)) { |
| 7401 next = _skipTypeParameterList(next); |
| 7402 if (next != null && _tokenMatches(next, TokenType.EQ)) { |
| 7403 TypeAlias typeAlias = |
| 7404 _parseClassTypeAlias(commentAndMetadata, null, keyword); |
| 7405 _reportErrorForToken( |
| 7406 ParserErrorCode.DEPRECATED_CLASS_TYPE_ALIAS, keyword); |
| 7407 return typeAlias; |
| 7408 } |
| 7409 } else if (_tokenMatches(next, TokenType.EQ)) { |
| 7410 TypeAlias typeAlias = |
| 7411 _parseClassTypeAlias(commentAndMetadata, null, keyword); |
| 7412 _reportErrorForToken( |
| 7413 ParserErrorCode.DEPRECATED_CLASS_TYPE_ALIAS, keyword); |
| 7414 return typeAlias; |
| 7415 } |
| 7416 } |
| 7417 return _parseFunctionTypeAlias(commentAndMetadata, keyword); |
| 7418 } |
| 7419 |
| 7420 /** |
| 7421 * Parse a unary expression. Return the unary expression that was parsed. |
| 7422 * |
| 7423 * unaryExpression ::= |
| 7424 * prefixOperator unaryExpression |
| 7425 * | awaitExpression |
| 7426 * | postfixExpression |
| 7427 * | unaryOperator 'super' |
| 7428 * | '-' 'super' |
| 7429 * | incrementOperator assignableExpression |
| 7430 */ |
| 7431 Expression _parseUnaryExpression() { |
| 7432 if (_matches(TokenType.MINUS) || |
| 7433 _matches(TokenType.BANG) || |
| 7434 _matches(TokenType.TILDE)) { |
| 7435 Token operator = getAndAdvance(); |
| 7436 if (_matchesKeyword(Keyword.SUPER)) { |
| 7437 if (_tokenMatches(_peek(), TokenType.OPEN_SQUARE_BRACKET) || |
| 7438 _tokenMatches(_peek(), TokenType.PERIOD)) { |
| 7439 // "prefixOperator unaryExpression" |
| 7440 // --> "prefixOperator postfixExpression" |
| 7441 // --> "prefixOperator primary selector*" |
| 7442 // --> "prefixOperator 'super' assignableSelector selector*" |
| 7443 return new PrefixExpression(operator, _parseUnaryExpression()); |
| 7444 } |
| 7445 return new PrefixExpression( |
| 7446 operator, new SuperExpression(getAndAdvance())); |
| 7447 } |
| 7448 return new PrefixExpression(operator, _parseUnaryExpression()); |
| 7449 } else if (_currentToken.type.isIncrementOperator) { |
| 7450 Token operator = getAndAdvance(); |
| 7451 if (_matchesKeyword(Keyword.SUPER)) { |
| 7452 if (_tokenMatches(_peek(), TokenType.OPEN_SQUARE_BRACKET) || |
| 7453 _tokenMatches(_peek(), TokenType.PERIOD)) { |
| 7454 // --> "prefixOperator 'super' assignableSelector selector*" |
| 7455 return new PrefixExpression(operator, _parseUnaryExpression()); |
| 7456 } |
| 7457 // |
| 7458 // Even though it is not valid to use an incrementing operator |
| 7459 // ('++' or '--') before 'super', we can (and therefore must) interpret |
| 7460 // "--super" as semantically equivalent to "-(-super)". Unfortunately, |
| 7461 // we cannot do the same for "++super" because "+super" is also not |
| 7462 // valid. |
| 7463 // |
| 7464 if (operator.type == TokenType.MINUS_MINUS) { |
| 7465 Token firstOperator = _createToken(operator, TokenType.MINUS); |
| 7466 Token secondOperator = |
| 7467 new Token(TokenType.MINUS, operator.offset + 1); |
| 7468 secondOperator.setNext(_currentToken); |
| 7469 firstOperator.setNext(secondOperator); |
| 7470 operator.previous.setNext(firstOperator); |
| 7471 return new PrefixExpression(firstOperator, new PrefixExpression( |
| 7472 secondOperator, new SuperExpression(getAndAdvance()))); |
| 7473 } else { |
| 7474 // Invalid operator before 'super' |
| 7475 _reportErrorForCurrentToken( |
| 7476 ParserErrorCode.INVALID_OPERATOR_FOR_SUPER, [operator.lexeme]); |
| 7477 return new PrefixExpression( |
| 7478 operator, new SuperExpression(getAndAdvance())); |
| 7479 } |
| 7480 } |
| 7481 return new PrefixExpression(operator, _parseAssignableExpression(false)); |
| 7482 } else if (_matches(TokenType.PLUS)) { |
| 7483 _reportErrorForCurrentToken(ParserErrorCode.MISSING_IDENTIFIER); |
| 7484 return _createSyntheticIdentifier(); |
| 7485 } else if (_inAsync && _matchesString(_AWAIT)) { |
| 7486 return _parseAwaitExpression(); |
| 7487 } |
| 7488 return _parsePostfixExpression(); |
| 7489 } |
| 7490 |
| 7491 /** |
| 7492 * Parse a string literal representing a URI. Return the string literal that |
| 7493 * was parsed. |
| 7494 */ |
| 7495 StringLiteral _parseUri() { |
| 7496 bool iskeywordAfterUri(Token token) => token.lexeme == Keyword.AS.syntax || |
| 7497 token.lexeme == _HIDE || |
| 7498 token.lexeme == _SHOW; |
| 7499 if (!_matches(TokenType.STRING) && |
| 7500 !_matches(TokenType.SEMICOLON) && |
| 7501 !iskeywordAfterUri(_currentToken)) { |
| 7502 // Attempt to recover in the case where the URI was not enclosed in |
| 7503 // quotes. |
| 7504 Token token = _currentToken; |
| 7505 while ((_tokenMatchesIdentifier(token) && !iskeywordAfterUri(token)) || |
| 7506 _tokenMatches(token, TokenType.COLON) || |
| 7507 _tokenMatches(token, TokenType.SLASH) || |
| 7508 _tokenMatches(token, TokenType.PERIOD) || |
| 7509 _tokenMatches(token, TokenType.PERIOD_PERIOD) || |
| 7510 _tokenMatches(token, TokenType.PERIOD_PERIOD_PERIOD) || |
| 7511 _tokenMatches(token, TokenType.INT) || |
| 7512 _tokenMatches(token, TokenType.DOUBLE)) { |
| 7513 token = token.next; |
| 7514 } |
| 7515 if (_tokenMatches(token, TokenType.SEMICOLON) || |
| 7516 iskeywordAfterUri(token)) { |
| 7517 Token endToken = token.previous; |
| 7518 token = _currentToken; |
| 7519 int endOffset = token.end; |
| 7520 StringBuffer buffer = new StringBuffer(); |
| 7521 buffer.write(token.lexeme); |
| 7522 while (token != endToken) { |
| 7523 token = token.next; |
| 7524 if (token.offset != endOffset || token.precedingComments != null) { |
| 7525 return parseStringLiteral(); |
| 7526 } |
| 7527 buffer.write(token.lexeme); |
| 7528 endOffset = token.end; |
| 7529 } |
| 7530 String value = buffer.toString(); |
| 7531 Token newToken = |
| 7532 new StringToken(TokenType.STRING, "'$value'", _currentToken.offset); |
| 7533 _reportErrorForToken( |
| 7534 ParserErrorCode.NON_STRING_LITERAL_AS_URI, newToken); |
| 7535 _currentToken = endToken.next; |
| 7536 return new SimpleStringLiteral(newToken, value); |
| 7537 } |
| 7538 } |
| 7539 return parseStringLiteral(); |
| 7540 } |
| 7541 |
| 7542 /** |
| 7543 * Parse a variable declaration. Return the variable declaration that was |
| 7544 * parsed. |
| 7545 * |
| 7546 * variableDeclaration ::= |
| 7547 * identifier ('=' expression)? |
| 7548 */ |
| 7549 VariableDeclaration _parseVariableDeclaration() { |
| 7550 // TODO(paulberry): prior to the fix for bug 23204, we permitted |
| 7551 // annotations before variable declarations (e.g. "String @deprecated s;"). |
| 7552 // Although such constructions are prohibited by the spec, we may want to |
| 7553 // consider handling them anyway to allow for better parser recovery in the |
| 7554 // event that the user erroneously tries to use them. However, as a |
| 7555 // counterargument, this would likely degrade parser recovery in the event |
| 7556 // of a construct like "class C { int @deprecated foo() {} }" (i.e. the |
| 7557 // user is in the middle of inserting "int bar;" prior to |
| 7558 // "@deprecated foo() {}"). |
| 7559 SimpleIdentifier name = parseSimpleIdentifier(); |
| 7560 Token equals = null; |
| 7561 Expression initializer = null; |
| 7562 if (_matches(TokenType.EQ)) { |
| 7563 equals = getAndAdvance(); |
| 7564 initializer = parseExpression2(); |
| 7565 } |
| 7566 return new VariableDeclaration(name, equals, initializer); |
| 7567 } |
| 7568 |
| 7569 /** |
| 7570 * Parse a variable declaration list. The [commentAndMetadata] is the metadata |
| 7571 * to be associated with the variable declaration list. Return the variable |
| 7572 * declaration list that was parsed. |
| 7573 * |
| 7574 * variableDeclarationList ::= |
| 7575 * finalConstVarOrType variableDeclaration (',' variableDeclaration)* |
| 7576 */ |
| 7577 VariableDeclarationList _parseVariableDeclarationListAfterMetadata( |
| 7578 CommentAndMetadata commentAndMetadata) { |
| 7579 FinalConstVarOrType holder = _parseFinalConstVarOrType(false); |
| 7580 return _parseVariableDeclarationListAfterType( |
| 7581 commentAndMetadata, holder.keyword, holder.type); |
| 7582 } |
| 7583 |
| 7584 /** |
| 7585 * Parse a variable declaration list. The [commentAndMetadata] is the metadata |
| 7586 * to be associated with the variable declaration list, or `null` if there is |
| 7587 * no attempt at parsing the comment and metadata. The [keyword] is the token |
| 7588 * representing the 'final', 'const' or 'var' keyword, or `null` if there is |
| 7589 * no keyword. The [type] is the type of the variables in the list. Return the |
| 7590 * variable declaration list that was parsed. |
| 7591 * |
| 7592 * variableDeclarationList ::= |
| 7593 * finalConstVarOrType variableDeclaration (',' variableDeclaration)* |
| 7594 */ |
| 7595 VariableDeclarationList _parseVariableDeclarationListAfterType( |
| 7596 CommentAndMetadata commentAndMetadata, Token keyword, TypeName type) { |
| 7597 if (type != null && |
| 7598 keyword != null && |
| 7599 _tokenMatchesKeyword(keyword, Keyword.VAR)) { |
| 7600 _reportErrorForToken(ParserErrorCode.VAR_AND_TYPE, keyword); |
| 7601 } |
| 7602 List<VariableDeclaration> variables = new List<VariableDeclaration>(); |
| 7603 variables.add(_parseVariableDeclaration()); |
| 7604 while (_matches(TokenType.COMMA)) { |
| 7605 _advance(); |
| 7606 variables.add(_parseVariableDeclaration()); |
| 7607 } |
| 7608 return new VariableDeclarationList( |
| 7609 commentAndMetadata != null ? commentAndMetadata.comment : null, |
| 7610 commentAndMetadata != null ? commentAndMetadata.metadata : null, |
| 7611 keyword, type, variables); |
| 7612 } |
| 7613 |
| 7614 /** |
| 7615 * Parse a variable declaration statement. The [commentAndMetadata] is the |
| 7616 * metadata to be associated with the variable declaration statement, or |
| 7617 * `null` if there is no attempt at parsing the comment and metadata. Return |
| 7618 * the variable declaration statement that was parsed. |
| 7619 * |
| 7620 * variableDeclarationStatement ::= |
| 7621 * variableDeclarationList ';' |
| 7622 */ |
| 7623 VariableDeclarationStatement _parseVariableDeclarationStatementAfterMetadata( |
| 7624 CommentAndMetadata commentAndMetadata) { |
| 7625 // Token startToken = currentToken; |
| 7626 VariableDeclarationList variableList = |
| 7627 _parseVariableDeclarationListAfterMetadata(commentAndMetadata); |
| 7628 // if (!matches(TokenType.SEMICOLON)) { |
| 7629 // if (matches(startToken, Keyword.VAR) && isTypedIdentifier(startToken
.getNext())) { |
| 7630 // // TODO(brianwilkerson) This appears to be of the form "var type v
ariable". We should do |
| 7631 // // a better job of recovering in this case. |
| 7632 // } |
| 7633 // } |
| 7634 Token semicolon = _expect(TokenType.SEMICOLON); |
| 7635 return new VariableDeclarationStatement(variableList, semicolon); |
| 7636 } |
| 7637 |
| 7638 /** |
| 7639 * Parse a variable declaration statement. The [commentAndMetadata] is the |
| 7640 * metadata to be associated with the variable declaration statement, or |
| 7641 * `null` if there is no attempt at parsing the comment and metadata. The |
| 7642 * [keyword] is the token representing the 'final', 'const' or 'var' keyword, |
| 7643 * or `null` if there is no keyword. The [type] is the type of the variables |
| 7644 * in the list. Return the variable declaration statement that was parsed. |
| 7645 * |
| 7646 * variableDeclarationStatement ::= |
| 7647 * variableDeclarationList ';' |
| 7648 */ |
| 7649 VariableDeclarationStatement _parseVariableDeclarationStatementAfterType( |
| 7650 CommentAndMetadata commentAndMetadata, Token keyword, TypeName type) { |
| 7651 VariableDeclarationList variableList = |
| 7652 _parseVariableDeclarationListAfterType( |
| 7653 commentAndMetadata, keyword, type); |
| 7654 Token semicolon = _expect(TokenType.SEMICOLON); |
| 7655 return new VariableDeclarationStatement(variableList, semicolon); |
| 7656 } |
| 7657 |
| 7658 /** |
| 7659 * Parse a while statement. Return the while statement that was parsed. |
| 7660 * |
| 7661 * whileStatement ::= |
| 7662 * 'while' '(' expression ')' statement |
| 7663 */ |
| 7664 Statement _parseWhileStatement() { |
| 7665 bool wasInLoop = _inLoop; |
| 7666 _inLoop = true; |
| 7667 try { |
| 7668 Token keyword = _expectKeyword(Keyword.WHILE); |
| 7669 Token leftParenthesis = _expect(TokenType.OPEN_PAREN); |
| 7670 Expression condition = parseExpression2(); |
| 7671 Token rightParenthesis = _expect(TokenType.CLOSE_PAREN); |
| 7672 Statement body = parseStatement2(); |
| 7673 return new WhileStatement( |
| 7674 keyword, leftParenthesis, condition, rightParenthesis, body); |
| 7675 } finally { |
| 7676 _inLoop = wasInLoop; |
| 7677 } |
| 7678 } |
| 7679 |
| 7680 /** |
| 7681 * Parse a yield statement. Return the yield statement that was parsed. |
| 7682 * |
| 7683 * yieldStatement ::= |
| 7684 * 'yield' '*'? expression ';' |
| 7685 */ |
| 7686 YieldStatement _parseYieldStatement() { |
| 7687 Token yieldToken = getAndAdvance(); |
| 7688 Token star = null; |
| 7689 if (_matches(TokenType.STAR)) { |
| 7690 star = getAndAdvance(); |
| 7691 } |
| 7692 Expression expression = parseExpression2(); |
| 7693 Token semicolon = _expect(TokenType.SEMICOLON); |
| 7694 return new YieldStatement(yieldToken, star, expression, semicolon); |
| 7695 } |
| 7696 |
| 7697 /** |
| 7698 * Return the token that is immediately after the current token. This is |
| 7699 * equivalent to [_peekAt](1). |
| 7700 */ |
| 7701 Token _peek() => _currentToken.next; |
| 7702 |
| 7703 /** |
| 7704 * Return the token that is the given [distance] after the current token, |
| 7705 * where the distance is the number of tokens to look ahead. A distance of `0` |
| 7706 * is the current token, `1` is the next token, etc. |
| 7707 */ |
| 7708 Token _peekAt(int distance) { |
| 7709 Token token = _currentToken; |
| 7710 for (int i = 0; i < distance; i++) { |
| 7711 token = token.next; |
| 7712 } |
| 7713 return token; |
| 7714 } |
| 7715 |
| 7716 /** |
| 7717 * Report the given [error]. |
| 7718 */ |
| 7719 void _reportError(AnalysisError error) { |
| 7720 if (_errorListenerLock != 0) { |
| 7721 return; |
| 7722 } |
| 7723 _errorListener.onError(error); |
| 7724 } |
| 7725 |
| 7726 /** |
| 7727 * Report an error with the given [errorCode] and [arguments] associated with |
| 7728 * the current token. |
| 7729 */ |
| 7730 void _reportErrorForCurrentToken(ParserErrorCode errorCode, |
| 7731 [List<Object> arguments]) { |
| 7732 _reportErrorForToken(errorCode, _currentToken, arguments); |
| 7733 } |
| 7734 |
| 7735 /** |
| 7736 * Report an error with the given [errorCode] and [arguments] associated with |
| 7737 * the given [node]. |
| 7738 */ |
| 7739 void _reportErrorForNode(ParserErrorCode errorCode, AstNode node, |
| 7740 [List<Object> arguments]) { |
| 7741 _reportError(new AnalysisError( |
| 7742 _source, node.offset, node.length, errorCode, arguments)); |
| 7743 } |
| 7744 |
| 7745 /** |
| 7746 * Report an error with the given [errorCode] and [arguments] associated with |
| 7747 * the given [token]. |
| 7748 */ |
| 7749 void _reportErrorForToken(ErrorCode errorCode, Token token, |
| 7750 [List<Object> arguments]) { |
| 7751 if (token.type == TokenType.EOF) { |
| 7752 token = token.previous; |
| 7753 } |
| 7754 _reportError(new AnalysisError(_source, token.offset, |
| 7755 math.max(token.length, 1), errorCode, arguments)); |
| 7756 } |
| 7757 |
| 7758 /** |
| 7759 * Skips a block with all containing blocks. |
| 7760 */ |
| 7761 void _skipBlock() { |
| 7762 Token endToken = (_currentToken as BeginToken).endToken; |
| 7763 if (endToken == null) { |
| 7764 endToken = _currentToken.next; |
| 7765 while (!identical(endToken, _currentToken)) { |
| 7766 _currentToken = endToken; |
| 7767 endToken = _currentToken.next; |
| 7768 } |
| 7769 _reportErrorForToken( |
| 7770 ParserErrorCode.EXPECTED_TOKEN, _currentToken.previous, ["}"]); |
| 7771 } else { |
| 7772 _currentToken = endToken.next; |
| 7773 } |
| 7774 } |
| 7775 |
| 7776 /** |
| 7777 * Parse the 'final', 'const', 'var' or type preceding a variable declaration, |
| 7778 * starting at the given token, without actually creating a type or changing |
| 7779 * the current token. Return the token following the type that was parsed, or |
| 7780 * `null` if the given token is not the first token in a valid type. The |
| 7781 * [startToken] is the token at which parsing is to begin. Return the token |
| 7782 * following the type that was parsed. |
| 7783 * |
| 7784 * finalConstVarOrType ::= |
| 7785 * | 'final' type? |
| 7786 * | 'const' type? |
| 7787 * | 'var' |
| 7788 * | type |
| 7789 */ |
| 7790 Token _skipFinalConstVarOrType(Token startToken) { |
| 7791 if (_tokenMatchesKeyword(startToken, Keyword.FINAL) || |
| 7792 _tokenMatchesKeyword(startToken, Keyword.CONST)) { |
| 7793 Token next = startToken.next; |
| 7794 if (_tokenMatchesIdentifier(next)) { |
| 7795 Token next2 = next.next; |
| 7796 // "Type parameter" or "Type<" or "prefix.Type" |
| 7797 if (_tokenMatchesIdentifier(next2) || |
| 7798 _tokenMatches(next2, TokenType.LT) || |
| 7799 _tokenMatches(next2, TokenType.PERIOD)) { |
| 7800 return _skipTypeName(next); |
| 7801 } |
| 7802 // "parameter" |
| 7803 return next; |
| 7804 } |
| 7805 } else if (_tokenMatchesKeyword(startToken, Keyword.VAR)) { |
| 7806 return startToken.next; |
| 7807 } else if (_tokenMatchesIdentifier(startToken)) { |
| 7808 Token next = startToken.next; |
| 7809 if (_tokenMatchesIdentifier(next) || |
| 7810 _tokenMatches(next, TokenType.LT) || |
| 7811 _tokenMatchesKeyword(next, Keyword.THIS) || |
| 7812 (_tokenMatches(next, TokenType.PERIOD) && |
| 7813 _tokenMatchesIdentifier(next.next) && |
| 7814 (_tokenMatchesIdentifier(next.next.next) || |
| 7815 _tokenMatches(next.next.next, TokenType.LT) || |
| 7816 _tokenMatchesKeyword(next.next.next, Keyword.THIS)))) { |
| 7817 return _skipReturnType(startToken); |
| 7818 } |
| 7819 } |
| 7820 return null; |
| 7821 } |
| 7822 |
| 7823 /** |
| 7824 * Parse a list of formal parameters, starting at the [startToken], without |
| 7825 * actually creating a formal parameter list or changing the current token. |
| 7826 * Return the token following the formal parameter list that was parsed, or |
| 7827 * `null` if the given token is not the first token in a valid list of formal |
| 7828 * parameter. |
| 7829 * |
| 7830 * Note that unlike other skip methods, this method uses a heuristic. In the |
| 7831 * worst case, the parameters could be prefixed by metadata, which would |
| 7832 * require us to be able to skip arbitrary expressions. Rather than duplicate |
| 7833 * the logic of most of the parse methods we simply look for something that is |
| 7834 * likely to be a list of parameters and then skip to returning the token |
| 7835 * after the closing parenthesis. |
| 7836 * |
| 7837 * This method must be kept in sync with [parseFormalParameterList]. |
| 7838 * |
| 7839 * formalParameterList ::= |
| 7840 * '(' ')' |
| 7841 * | '(' normalFormalParameters (',' optionalFormalParameters)? ')' |
| 7842 * | '(' optionalFormalParameters ')' |
| 7843 * |
| 7844 * normalFormalParameters ::= |
| 7845 * normalFormalParameter (',' normalFormalParameter)* |
| 7846 * |
| 7847 * optionalFormalParameters ::= |
| 7848 * optionalPositionalFormalParameters |
| 7849 * | namedFormalParameters |
| 7850 * |
| 7851 * optionalPositionalFormalParameters ::= |
| 7852 * '[' defaultFormalParameter (',' defaultFormalParameter)* ']' |
| 7853 * |
| 7854 * namedFormalParameters ::= |
| 7855 * '{' defaultNamedParameter (',' defaultNamedParameter)* '}' |
| 7856 */ |
| 7857 Token _skipFormalParameterList(Token startToken) { |
| 7858 if (!_tokenMatches(startToken, TokenType.OPEN_PAREN)) { |
| 7859 return null; |
| 7860 } |
| 7861 Token next = startToken.next; |
| 7862 if (_tokenMatches(next, TokenType.CLOSE_PAREN)) { |
| 7863 return next.next; |
| 7864 } |
| 7865 // |
| 7866 // Look to see whether the token after the open parenthesis is something |
| 7867 // that should only occur at the beginning of a parameter list. |
| 7868 // |
| 7869 if (next.matchesAny([ |
| 7870 TokenType.AT, |
| 7871 TokenType.OPEN_SQUARE_BRACKET, |
| 7872 TokenType.OPEN_CURLY_BRACKET |
| 7873 ]) || |
| 7874 _tokenMatchesKeyword(next, Keyword.VOID) || |
| 7875 (_tokenMatchesIdentifier(next) && |
| 7876 (next.next.matchesAny([TokenType.COMMA, TokenType.CLOSE_PAREN])))) { |
| 7877 return _skipPastMatchingToken(startToken); |
| 7878 } |
| 7879 // |
| 7880 // Look to see whether the first parameter is a function typed parameter |
| 7881 // without a return type. |
| 7882 // |
| 7883 if (_tokenMatchesIdentifier(next) && |
| 7884 _tokenMatches(next.next, TokenType.OPEN_PAREN)) { |
| 7885 Token afterParameters = _skipFormalParameterList(next.next); |
| 7886 if (afterParameters != null && |
| 7887 (afterParameters |
| 7888 .matchesAny([TokenType.COMMA, TokenType.CLOSE_PAREN]))) { |
| 7889 return _skipPastMatchingToken(startToken); |
| 7890 } |
| 7891 } |
| 7892 // |
| 7893 // Look to see whether the first parameter has a type or is a function typed |
| 7894 // parameter with a return type. |
| 7895 // |
| 7896 Token afterType = _skipFinalConstVarOrType(next); |
| 7897 if (afterType == null) { |
| 7898 return null; |
| 7899 } |
| 7900 if (_skipSimpleIdentifier(afterType) == null) { |
| 7901 return null; |
| 7902 } |
| 7903 return _skipPastMatchingToken(startToken); |
| 7904 } |
| 7905 |
| 7906 /** |
| 7907 * If the [startToken] is a begin token with an associated end token, then |
| 7908 * return the token following the end token. Otherwise, return `null`. |
| 7909 */ |
| 7910 Token _skipPastMatchingToken(Token startToken) { |
| 7911 if (startToken is! BeginToken) { |
| 7912 return null; |
| 7913 } |
| 7914 Token closeParen = (startToken as BeginToken).endToken; |
| 7915 if (closeParen == null) { |
| 7916 return null; |
| 7917 } |
| 7918 return closeParen.next; |
| 7919 } |
| 7920 |
| 7921 /** |
| 7922 * Parse a prefixed identifier, starting at the [startToken], without actually |
| 7923 * creating a prefixed identifier or changing the current token. Return the |
| 7924 * token following the prefixed identifier that was parsed, or `null` if the |
| 7925 * given token is not the first token in a valid prefixed identifier. |
| 7926 * |
| 7927 * This method must be kept in sync with [parsePrefixedIdentifier]. |
| 7928 * |
| 7929 * prefixedIdentifier ::= |
| 7930 * identifier ('.' identifier)? |
| 7931 */ |
| 7932 Token _skipPrefixedIdentifier(Token startToken) { |
| 7933 Token token = _skipSimpleIdentifier(startToken); |
| 7934 if (token == null) { |
| 7935 return null; |
| 7936 } else if (!_tokenMatches(token, TokenType.PERIOD)) { |
| 7937 return token; |
| 7938 } |
| 7939 token = token.next; |
| 7940 Token nextToken = _skipSimpleIdentifier(token); |
| 7941 if (nextToken != null) { |
| 7942 return nextToken; |
| 7943 } else if (_tokenMatches(token, TokenType.CLOSE_PAREN) || |
| 7944 _tokenMatches(token, TokenType.COMMA)) { |
| 7945 // If the `id.` is followed by something that cannot produce a valid |
| 7946 // structure then assume this is a prefixed identifier but missing the |
| 7947 // trailing identifier |
| 7948 return token; |
| 7949 } |
| 7950 return null; |
| 7951 } |
| 7952 |
| 7953 /** |
| 7954 * Parse a return type, starting at the [startToken], without actually |
| 7955 * creating a return type or changing the current token. Return the token |
| 7956 * following the return type that was parsed, or `null` if the given token is |
| 7957 * not the first token in a valid return type. |
| 7958 * |
| 7959 * This method must be kept in sync with [parseReturnType]. |
| 7960 * |
| 7961 * returnType ::= |
| 7962 * 'void' |
| 7963 * | type |
| 7964 */ |
| 7965 Token _skipReturnType(Token startToken) { |
| 7966 if (_tokenMatchesKeyword(startToken, Keyword.VOID)) { |
| 7967 return startToken.next; |
| 7968 } else { |
| 7969 return _skipTypeName(startToken); |
| 7970 } |
| 7971 } |
| 7972 |
| 7973 /** |
| 7974 * Parse a simple identifier, starting at the [startToken], without actually |
| 7975 * creating a simple identifier or changing the current token. Return the |
| 7976 * token following the simple identifier that was parsed, or `null` if the |
| 7977 * given token is not the first token in a valid simple identifier. |
| 7978 * |
| 7979 * This method must be kept in sync with [parseSimpleIdentifier]. |
| 7980 * |
| 7981 * identifier ::= |
| 7982 * IDENTIFIER |
| 7983 */ |
| 7984 Token _skipSimpleIdentifier(Token startToken) { |
| 7985 if (_tokenMatches(startToken, TokenType.IDENTIFIER) || |
| 7986 (_tokenMatches(startToken, TokenType.KEYWORD) && |
| 7987 (startToken as KeywordToken).keyword.isPseudoKeyword)) { |
| 7988 return startToken.next; |
| 7989 } |
| 7990 return null; |
| 7991 } |
| 7992 |
| 7993 /** |
| 7994 * Parse a string literal that contains interpolations, starting at the |
| 7995 * [startToken], without actually creating a string literal or changing the |
| 7996 * current token. Return the token following the string literal that was |
| 7997 * parsed, or `null` if the given token is not the first token in a valid |
| 7998 * string literal. |
| 7999 * |
| 8000 * This method must be kept in sync with [parseStringInterpolation]. |
| 8001 */ |
| 8002 Token _skipStringInterpolation(Token startToken) { |
| 8003 Token token = startToken; |
| 8004 TokenType type = token.type; |
| 8005 while (type == TokenType.STRING_INTERPOLATION_EXPRESSION || |
| 8006 type == TokenType.STRING_INTERPOLATION_IDENTIFIER) { |
| 8007 if (type == TokenType.STRING_INTERPOLATION_EXPRESSION) { |
| 8008 token = token.next; |
| 8009 type = token.type; |
| 8010 // |
| 8011 // Rather than verify that the following tokens represent a valid |
| 8012 // expression, we simply skip tokens until we reach the end of the |
| 8013 // interpolation, being careful to handle nested string literals. |
| 8014 // |
| 8015 int bracketNestingLevel = 1; |
| 8016 while (bracketNestingLevel > 0) { |
| 8017 if (type == TokenType.EOF) { |
| 8018 return null; |
| 8019 } else if (type == TokenType.OPEN_CURLY_BRACKET) { |
| 8020 bracketNestingLevel++; |
| 8021 } else if (type == TokenType.CLOSE_CURLY_BRACKET) { |
| 8022 bracketNestingLevel--; |
| 8023 } else if (type == TokenType.STRING) { |
| 8024 token = _skipStringLiteral(token); |
| 8025 if (token == null) { |
| 8026 return null; |
| 8027 } |
| 8028 } else { |
| 8029 token = token.next; |
| 8030 } |
| 8031 type = token.type; |
| 8032 } |
| 8033 token = token.next; |
| 8034 type = token.type; |
| 8035 } else { |
| 8036 token = token.next; |
| 8037 if (token.type != TokenType.IDENTIFIER) { |
| 8038 return null; |
| 8039 } |
| 8040 token = token.next; |
| 8041 } |
| 8042 type = token.type; |
| 8043 if (type == TokenType.STRING) { |
| 8044 token = token.next; |
| 8045 type = token.type; |
| 8046 } |
| 8047 } |
| 8048 return token; |
| 8049 } |
| 8050 |
| 8051 /** |
| 8052 * Parse a string literal, starting at the [startToken], without actually |
| 8053 * creating a string literal or changing the current token. Return the token |
| 8054 * following the string literal that was parsed, or `null` if the given token |
| 8055 * is not the first token in a valid string literal. |
| 8056 * |
| 8057 * This method must be kept in sync with [parseStringLiteral]. |
| 8058 * |
| 8059 * stringLiteral ::= |
| 8060 * MULTI_LINE_STRING+ |
| 8061 * | SINGLE_LINE_STRING+ |
| 8062 */ |
| 8063 Token _skipStringLiteral(Token startToken) { |
| 8064 Token token = startToken; |
| 8065 while (token != null && _tokenMatches(token, TokenType.STRING)) { |
| 8066 token = token.next; |
| 8067 TokenType type = token.type; |
| 8068 if (type == TokenType.STRING_INTERPOLATION_EXPRESSION || |
| 8069 type == TokenType.STRING_INTERPOLATION_IDENTIFIER) { |
| 8070 token = _skipStringInterpolation(token); |
| 8071 } |
| 8072 } |
| 8073 if (identical(token, startToken)) { |
| 8074 return null; |
| 8075 } |
| 8076 return token; |
| 8077 } |
| 8078 |
| 8079 /** |
| 8080 * Parse a list of type arguments, starting at the [startToken], without |
| 8081 * actually creating a type argument list or changing the current token. |
| 8082 * Return the token following the type argument list that was parsed, or |
| 8083 * `null` if the given token is not the first token in a valid type argument |
| 8084 * list. |
| 8085 * |
| 8086 * This method must be kept in sync with [parseTypeArgumentList]. |
| 8087 * |
| 8088 * typeArguments ::= |
| 8089 * '<' typeList '>' |
| 8090 * |
| 8091 * typeList ::= |
| 8092 * type (',' type)* |
| 8093 */ |
| 8094 Token _skipTypeArgumentList(Token startToken) { |
| 8095 Token token = startToken; |
| 8096 if (!_tokenMatches(token, TokenType.LT)) { |
| 8097 return null; |
| 8098 } |
| 8099 token = _skipTypeName(token.next); |
| 8100 if (token == null) { |
| 8101 // If the start token '<' is followed by '>' |
| 8102 // then assume this should be type argument list but is missing a type |
| 8103 token = startToken.next; |
| 8104 if (_tokenMatches(token, TokenType.GT)) { |
| 8105 return token.next; |
| 8106 } |
| 8107 return null; |
| 8108 } |
| 8109 while (_tokenMatches(token, TokenType.COMMA)) { |
| 8110 token = _skipTypeName(token.next); |
| 8111 if (token == null) { |
| 8112 return null; |
| 8113 } |
| 8114 } |
| 8115 if (token.type == TokenType.GT) { |
| 8116 return token.next; |
| 8117 } else if (token.type == TokenType.GT_GT) { |
| 8118 Token second = new Token(TokenType.GT, token.offset + 1); |
| 8119 second.setNextWithoutSettingPrevious(token.next); |
| 8120 return second; |
| 8121 } |
| 8122 return null; |
| 8123 } |
| 8124 |
| 8125 /** |
| 8126 * Parse a type name, starting at the [startToken], without actually creating |
| 8127 * a type name or changing the current token. Return the token following the |
| 8128 * type name that was parsed, or `null` if the given token is not the first |
| 8129 * token in a valid type name. |
| 8130 * |
| 8131 * This method must be kept in sync with [parseTypeName]. |
| 8132 * |
| 8133 * type ::= |
| 8134 * qualified typeArguments? |
| 8135 */ |
| 8136 Token _skipTypeName(Token startToken) { |
| 8137 Token token = _skipPrefixedIdentifier(startToken); |
| 8138 if (token == null) { |
| 8139 return null; |
| 8140 } |
| 8141 if (_tokenMatches(token, TokenType.LT)) { |
| 8142 token = _skipTypeArgumentList(token); |
| 8143 } |
| 8144 return token; |
| 8145 } |
| 8146 |
| 8147 /** |
| 8148 * Parse a list of type parameters, starting at the [startToken], without |
| 8149 * actually creating a type parameter list or changing the current token. |
| 8150 * Return the token following the type parameter list that was parsed, or |
| 8151 * `null` if the given token is not the first token in a valid type parameter |
| 8152 * list. |
| 8153 * |
| 8154 * This method must be kept in sync with [parseTypeParameterList]. |
| 8155 * |
| 8156 * typeParameterList ::= |
| 8157 * '<' typeParameter (',' typeParameter)* '>' |
| 8158 */ |
| 8159 Token _skipTypeParameterList(Token startToken) { |
| 8160 if (!_tokenMatches(startToken, TokenType.LT)) { |
| 8161 return null; |
| 8162 } |
| 8163 // |
| 8164 // We can't skip a type parameter because it can be preceeded by metadata, |
| 8165 // so we just assume that everything before the matching end token is valid. |
| 8166 // |
| 8167 int depth = 1; |
| 8168 Token next = startToken.next; |
| 8169 while (depth > 0) { |
| 8170 if (_tokenMatches(next, TokenType.EOF)) { |
| 8171 return null; |
| 8172 } else if (_tokenMatches(next, TokenType.LT)) { |
| 8173 depth++; |
| 8174 } else if (_tokenMatches(next, TokenType.GT)) { |
| 8175 depth--; |
| 8176 } else if (_tokenMatches(next, TokenType.GT_EQ)) { |
| 8177 if (depth == 1) { |
| 8178 Token fakeEquals = new Token(TokenType.EQ, next.offset + 2); |
| 8179 fakeEquals.setNextWithoutSettingPrevious(next.next); |
| 8180 return fakeEquals; |
| 8181 } |
| 8182 depth--; |
| 8183 } else if (_tokenMatches(next, TokenType.GT_GT)) { |
| 8184 depth -= 2; |
| 8185 } else if (_tokenMatches(next, TokenType.GT_GT_EQ)) { |
| 8186 if (depth < 2) { |
| 8187 return null; |
| 8188 } else if (depth == 2) { |
| 8189 Token fakeEquals = new Token(TokenType.EQ, next.offset + 2); |
| 8190 fakeEquals.setNextWithoutSettingPrevious(next.next); |
| 8191 return fakeEquals; |
| 8192 } |
| 8193 depth -= 2; |
| 8194 } |
| 8195 next = next.next; |
| 8196 } |
| 8197 return next; |
| 8198 } |
| 8199 |
| 8200 /** |
| 8201 * Return `true` if the given [token] has the given [type]. |
| 8202 */ |
| 8203 bool _tokenMatches(Token token, TokenType type) => token.type == type; |
| 8204 |
| 8205 /** |
| 8206 * Return `true` if the given [token] is a valid identifier. Valid identifiers |
| 8207 * include built-in identifiers (pseudo-keywords). |
| 8208 */ |
| 8209 bool _tokenMatchesIdentifier(Token token) => |
| 8210 _tokenMatches(token, TokenType.IDENTIFIER) || |
| 8211 (_tokenMatches(token, TokenType.KEYWORD) && |
| 8212 (token as KeywordToken).keyword.isPseudoKeyword); |
| 8213 |
| 8214 /** |
| 8215 * Return `true` if the given [token] matches the given [keyword]. |
| 8216 */ |
| 8217 bool _tokenMatchesKeyword(Token token, Keyword keyword) => |
| 8218 token.type == TokenType.KEYWORD && |
| 8219 (token as KeywordToken).keyword == keyword; |
| 8220 |
| 8221 /** |
| 8222 * Return `true` if the given [token] matches the given [identifier]. |
| 8223 */ |
| 8224 bool _tokenMatchesString(Token token, String identifier) => |
| 8225 token.type == TokenType.IDENTIFIER && token.lexeme == identifier; |
| 8226 |
| 8227 /** |
| 8228 * Translate the characters at the given [index] in the given [lexeme], |
| 8229 * appending the translated character to the given [buffer]. The index is |
| 8230 * assumed to be valid. |
| 8231 */ |
| 8232 int _translateCharacter(StringBuffer buffer, String lexeme, int index) { |
| 8233 int currentChar = lexeme.codeUnitAt(index); |
| 8234 if (currentChar != 0x5C) { |
| 8235 buffer.writeCharCode(currentChar); |
| 8236 return index + 1; |
| 8237 } |
| 8238 // |
| 8239 // We have found an escape sequence, so we parse the string to determine |
| 8240 // what kind of escape sequence and what character to add to the builder. |
| 8241 // |
| 8242 int length = lexeme.length; |
| 8243 int currentIndex = index + 1; |
| 8244 if (currentIndex >= length) { |
| 8245 // Illegal escape sequence: no char after escape. |
| 8246 // This cannot actually happen because it would require the escape |
| 8247 // character to be the last character in the string, but if it were it |
| 8248 // would escape the closing quote, leaving the string unclosed. |
| 8249 // reportError(ParserErrorCode.MISSING_CHAR_IN_ESCAPE_SEQUENCE); |
| 8250 return length; |
| 8251 } |
| 8252 currentChar = lexeme.codeUnitAt(currentIndex); |
| 8253 if (currentChar == 0x6E) { |
| 8254 buffer.writeCharCode(0xA); |
| 8255 // newline |
| 8256 } else if (currentChar == 0x72) { |
| 8257 buffer.writeCharCode(0xD); |
| 8258 // carriage return |
| 8259 } else if (currentChar == 0x66) { |
| 8260 buffer.writeCharCode(0xC); |
| 8261 // form feed |
| 8262 } else if (currentChar == 0x62) { |
| 8263 buffer.writeCharCode(0x8); |
| 8264 // backspace |
| 8265 } else if (currentChar == 0x74) { |
| 8266 buffer.writeCharCode(0x9); |
| 8267 // tab |
| 8268 } else if (currentChar == 0x76) { |
| 8269 buffer.writeCharCode(0xB); |
| 8270 // vertical tab |
| 8271 } else if (currentChar == 0x78) { |
| 8272 if (currentIndex + 2 >= length) { |
| 8273 // Illegal escape sequence: not enough hex digits |
| 8274 _reportErrorForCurrentToken(ParserErrorCode.INVALID_HEX_ESCAPE); |
| 8275 return length; |
| 8276 } |
| 8277 int firstDigit = lexeme.codeUnitAt(currentIndex + 1); |
| 8278 int secondDigit = lexeme.codeUnitAt(currentIndex + 2); |
| 8279 if (!_isHexDigit(firstDigit) || !_isHexDigit(secondDigit)) { |
| 8280 // Illegal escape sequence: invalid hex digit |
| 8281 _reportErrorForCurrentToken(ParserErrorCode.INVALID_HEX_ESCAPE); |
| 8282 } else { |
| 8283 int charCode = (Character.digit(firstDigit, 16) << 4) + |
| 8284 Character.digit(secondDigit, 16); |
| 8285 buffer.writeCharCode(charCode); |
| 8286 } |
| 8287 return currentIndex + 3; |
| 8288 } else if (currentChar == 0x75) { |
| 8289 currentIndex++; |
| 8290 if (currentIndex >= length) { |
| 8291 // Illegal escape sequence: not enough hex digits |
| 8292 _reportErrorForCurrentToken(ParserErrorCode.INVALID_UNICODE_ESCAPE); |
| 8293 return length; |
| 8294 } |
| 8295 currentChar = lexeme.codeUnitAt(currentIndex); |
| 8296 if (currentChar == 0x7B) { |
| 8297 currentIndex++; |
| 8298 if (currentIndex >= length) { |
| 8299 // Illegal escape sequence: incomplete escape |
| 8300 _reportErrorForCurrentToken(ParserErrorCode.INVALID_UNICODE_ESCAPE); |
| 8301 return length; |
| 8302 } |
| 8303 currentChar = lexeme.codeUnitAt(currentIndex); |
| 8304 int digitCount = 0; |
| 8305 int value = 0; |
| 8306 while (currentChar != 0x7D) { |
| 8307 if (!_isHexDigit(currentChar)) { |
| 8308 // Illegal escape sequence: invalid hex digit |
| 8309 _reportErrorForCurrentToken(ParserErrorCode.INVALID_UNICODE_ESCAPE); |
| 8310 currentIndex++; |
| 8311 while (currentIndex < length && |
| 8312 lexeme.codeUnitAt(currentIndex) != 0x7D) { |
| 8313 currentIndex++; |
| 8314 } |
| 8315 return currentIndex + 1; |
| 8316 } |
| 8317 digitCount++; |
| 8318 value = (value << 4) + Character.digit(currentChar, 16); |
| 8319 currentIndex++; |
| 8320 if (currentIndex >= length) { |
| 8321 // Illegal escape sequence: incomplete escape |
| 8322 _reportErrorForCurrentToken(ParserErrorCode.INVALID_UNICODE_ESCAPE); |
| 8323 return length; |
| 8324 } |
| 8325 currentChar = lexeme.codeUnitAt(currentIndex); |
| 8326 } |
| 8327 if (digitCount < 1 || digitCount > 6) { |
| 8328 // Illegal escape sequence: not enough or too many hex digits |
| 8329 _reportErrorForCurrentToken(ParserErrorCode.INVALID_UNICODE_ESCAPE); |
| 8330 } |
| 8331 _appendScalarValue(buffer, lexeme.substring(index, currentIndex + 1), |
| 8332 value, index, currentIndex); |
| 8333 return currentIndex + 1; |
| 8334 } else { |
| 8335 if (currentIndex + 3 >= length) { |
| 8336 // Illegal escape sequence: not enough hex digits |
| 8337 _reportErrorForCurrentToken(ParserErrorCode.INVALID_UNICODE_ESCAPE); |
| 8338 return length; |
| 8339 } |
| 8340 int firstDigit = currentChar; |
| 8341 int secondDigit = lexeme.codeUnitAt(currentIndex + 1); |
| 8342 int thirdDigit = lexeme.codeUnitAt(currentIndex + 2); |
| 8343 int fourthDigit = lexeme.codeUnitAt(currentIndex + 3); |
| 8344 if (!_isHexDigit(firstDigit) || |
| 8345 !_isHexDigit(secondDigit) || |
| 8346 !_isHexDigit(thirdDigit) || |
| 8347 !_isHexDigit(fourthDigit)) { |
| 8348 // Illegal escape sequence: invalid hex digits |
| 8349 _reportErrorForCurrentToken(ParserErrorCode.INVALID_UNICODE_ESCAPE); |
| 8350 } else { |
| 8351 _appendScalarValue( |
| 8352 buffer, |
| 8353 lexeme |
| 8354 .substring( |
| 8355 index, |
| 8356 currentIndex + 1), |
| 8357 (((((Character.digit(firstDigit, 16) << 4) + |
| 8358 Character.digit(secondDigit, 16)) << |
| 8359 4) + |
| 8360 Character.digit(thirdDigit, 16)) << |
| 8361 4) + |
| 8362 Character |
| 8363 .digit(fourthDigit, 16), |
| 8364 index, |
| 8365 currentIndex + |
| 8366 3); |
| 8367 } |
| 8368 return currentIndex + 4; |
| 8369 } |
| 8370 } else { |
| 8371 buffer.writeCharCode(currentChar); |
| 8372 } |
| 8373 return currentIndex + 1; |
| 8374 } |
| 8375 |
| 8376 /** |
| 8377 * Decrements the error reporting lock level. If level is more than `0`, then |
| 8378 * [reportError] wont report any error. |
| 8379 */ |
| 8380 void _unlockErrorListener() { |
| 8381 if (_errorListenerLock == 0) { |
| 8382 throw new IllegalStateException( |
| 8383 "Attempt to unlock not locked error listener."); |
| 8384 } |
| 8385 _errorListenerLock--; |
| 8386 } |
| 8387 |
| 8388 /** |
| 8389 * Validate that the given [parameterList] does not contain any field |
| 8390 * initializers. |
| 8391 */ |
| 8392 void _validateFormalParameterList(FormalParameterList parameterList) { |
| 8393 for (FormalParameter parameter in parameterList.parameters) { |
| 8394 if (parameter is FieldFormalParameter) { |
| 8395 _reportErrorForNode( |
| 8396 ParserErrorCode.FIELD_INITIALIZER_OUTSIDE_CONSTRUCTOR, |
| 8397 parameter.identifier); |
| 8398 } |
| 8399 } |
| 8400 } |
| 8401 |
| 8402 /** |
| 8403 * Validate that the given set of [modifiers] is appropriate for a class and |
| 8404 * return the 'abstract' keyword if there is one. |
| 8405 */ |
| 8406 Token _validateModifiersForClass(Modifiers modifiers) { |
| 8407 _validateModifiersForTopLevelDeclaration(modifiers); |
| 8408 if (modifiers.constKeyword != null) { |
| 8409 _reportErrorForToken(ParserErrorCode.CONST_CLASS, modifiers.constKeyword); |
| 8410 } |
| 8411 if (modifiers.externalKeyword != null) { |
| 8412 _reportErrorForToken( |
| 8413 ParserErrorCode.EXTERNAL_CLASS, modifiers.externalKeyword); |
| 8414 } |
| 8415 if (modifiers.finalKeyword != null) { |
| 8416 _reportErrorForToken(ParserErrorCode.FINAL_CLASS, modifiers.finalKeyword); |
| 8417 } |
| 8418 if (modifiers.varKeyword != null) { |
| 8419 _reportErrorForToken(ParserErrorCode.VAR_CLASS, modifiers.varKeyword); |
| 8420 } |
| 8421 return modifiers.abstractKeyword; |
| 8422 } |
| 8423 |
| 8424 /** |
| 8425 * Validate that the given set of [modifiers] is appropriate for a constructor |
| 8426 * and return the 'const' keyword if there is one. |
| 8427 */ |
| 8428 Token _validateModifiersForConstructor(Modifiers modifiers) { |
| 8429 if (modifiers.abstractKeyword != null) { |
| 8430 _reportErrorForToken( |
| 8431 ParserErrorCode.ABSTRACT_CLASS_MEMBER, modifiers.abstractKeyword); |
| 8432 } |
| 8433 if (modifiers.finalKeyword != null) { |
| 8434 _reportErrorForToken( |
| 8435 ParserErrorCode.FINAL_CONSTRUCTOR, modifiers.finalKeyword); |
| 8436 } |
| 8437 if (modifiers.staticKeyword != null) { |
| 8438 _reportErrorForToken( |
| 8439 ParserErrorCode.STATIC_CONSTRUCTOR, modifiers.staticKeyword); |
| 8440 } |
| 8441 if (modifiers.varKeyword != null) { |
| 8442 _reportErrorForToken( |
| 8443 ParserErrorCode.CONSTRUCTOR_WITH_RETURN_TYPE, modifiers.varKeyword); |
| 8444 } |
| 8445 Token externalKeyword = modifiers.externalKeyword; |
| 8446 Token constKeyword = modifiers.constKeyword; |
| 8447 Token factoryKeyword = modifiers.factoryKeyword; |
| 8448 if (externalKeyword != null && |
| 8449 constKeyword != null && |
| 8450 constKeyword.offset < externalKeyword.offset) { |
| 8451 _reportErrorForToken( |
| 8452 ParserErrorCode.EXTERNAL_AFTER_CONST, externalKeyword); |
| 8453 } |
| 8454 if (externalKeyword != null && |
| 8455 factoryKeyword != null && |
| 8456 factoryKeyword.offset < externalKeyword.offset) { |
| 8457 _reportErrorForToken( |
| 8458 ParserErrorCode.EXTERNAL_AFTER_FACTORY, externalKeyword); |
| 8459 } |
| 8460 return constKeyword; |
| 8461 } |
| 8462 |
| 8463 /** |
| 8464 * Validate that the given set of [modifiers] is appropriate for a class and |
| 8465 * return the 'abstract' keyword if there is one. |
| 8466 */ |
| 8467 void _validateModifiersForEnum(Modifiers modifiers) { |
| 8468 _validateModifiersForTopLevelDeclaration(modifiers); |
| 8469 if (modifiers.abstractKeyword != null) { |
| 8470 _reportErrorForToken( |
| 8471 ParserErrorCode.ABSTRACT_ENUM, modifiers.abstractKeyword); |
| 8472 } |
| 8473 if (modifiers.constKeyword != null) { |
| 8474 _reportErrorForToken(ParserErrorCode.CONST_ENUM, modifiers.constKeyword); |
| 8475 } |
| 8476 if (modifiers.externalKeyword != null) { |
| 8477 _reportErrorForToken( |
| 8478 ParserErrorCode.EXTERNAL_ENUM, modifiers.externalKeyword); |
| 8479 } |
| 8480 if (modifiers.finalKeyword != null) { |
| 8481 _reportErrorForToken(ParserErrorCode.FINAL_ENUM, modifiers.finalKeyword); |
| 8482 } |
| 8483 if (modifiers.varKeyword != null) { |
| 8484 _reportErrorForToken(ParserErrorCode.VAR_ENUM, modifiers.varKeyword); |
| 8485 } |
| 8486 } |
| 8487 |
| 8488 /** |
| 8489 * Validate that the given set of [modifiers] is appropriate for a field and |
| 8490 * return the 'final', 'const' or 'var' keyword if there is one. |
| 8491 */ |
| 8492 Token _validateModifiersForField(Modifiers modifiers) { |
| 8493 if (modifiers.abstractKeyword != null) { |
| 8494 _reportErrorForCurrentToken(ParserErrorCode.ABSTRACT_CLASS_MEMBER); |
| 8495 } |
| 8496 if (modifiers.externalKeyword != null) { |
| 8497 _reportErrorForToken( |
| 8498 ParserErrorCode.EXTERNAL_FIELD, modifiers.externalKeyword); |
| 8499 } |
| 8500 if (modifiers.factoryKeyword != null) { |
| 8501 _reportErrorForToken( |
| 8502 ParserErrorCode.NON_CONSTRUCTOR_FACTORY, modifiers.factoryKeyword); |
| 8503 } |
| 8504 Token staticKeyword = modifiers.staticKeyword; |
| 8505 Token constKeyword = modifiers.constKeyword; |
| 8506 Token finalKeyword = modifiers.finalKeyword; |
| 8507 Token varKeyword = modifiers.varKeyword; |
| 8508 if (constKeyword != null) { |
| 8509 if (finalKeyword != null) { |
| 8510 _reportErrorForToken(ParserErrorCode.CONST_AND_FINAL, finalKeyword); |
| 8511 } |
| 8512 if (varKeyword != null) { |
| 8513 _reportErrorForToken(ParserErrorCode.CONST_AND_VAR, varKeyword); |
| 8514 } |
| 8515 if (staticKeyword != null && constKeyword.offset < staticKeyword.offset) { |
| 8516 _reportErrorForToken(ParserErrorCode.STATIC_AFTER_CONST, staticKeyword); |
| 8517 } |
| 8518 } else if (finalKeyword != null) { |
| 8519 if (varKeyword != null) { |
| 8520 _reportErrorForToken(ParserErrorCode.FINAL_AND_VAR, varKeyword); |
| 8521 } |
| 8522 if (staticKeyword != null && finalKeyword.offset < staticKeyword.offset) { |
| 8523 _reportErrorForToken(ParserErrorCode.STATIC_AFTER_FINAL, staticKeyword); |
| 8524 } |
| 8525 } else if (varKeyword != null && |
| 8526 staticKeyword != null && |
| 8527 varKeyword.offset < staticKeyword.offset) { |
| 8528 _reportErrorForToken(ParserErrorCode.STATIC_AFTER_VAR, staticKeyword); |
| 8529 } |
| 8530 return Token.lexicallyFirst([constKeyword, finalKeyword, varKeyword]); |
| 8531 } |
| 8532 |
| 8533 /** |
| 8534 * Validate that the given set of [modifiers] is appropriate for a local |
| 8535 * function. |
| 8536 */ |
| 8537 void _validateModifiersForFunctionDeclarationStatement(Modifiers modifiers) { |
| 8538 if (modifiers.abstractKeyword != null || |
| 8539 modifiers.constKeyword != null || |
| 8540 modifiers.externalKeyword != null || |
| 8541 modifiers.factoryKeyword != null || |
| 8542 modifiers.finalKeyword != null || |
| 8543 modifiers.staticKeyword != null || |
| 8544 modifiers.varKeyword != null) { |
| 8545 _reportErrorForCurrentToken( |
| 8546 ParserErrorCode.LOCAL_FUNCTION_DECLARATION_MODIFIER); |
| 8547 } |
| 8548 } |
| 8549 |
| 8550 /** |
| 8551 * Validate that the given set of [modifiers] is appropriate for a getter, |
| 8552 * setter, or method. |
| 8553 */ |
| 8554 void _validateModifiersForGetterOrSetterOrMethod(Modifiers modifiers) { |
| 8555 if (modifiers.abstractKeyword != null) { |
| 8556 _reportErrorForCurrentToken(ParserErrorCode.ABSTRACT_CLASS_MEMBER); |
| 8557 } |
| 8558 if (modifiers.constKeyword != null) { |
| 8559 _reportErrorForToken( |
| 8560 ParserErrorCode.CONST_METHOD, modifiers.constKeyword); |
| 8561 } |
| 8562 if (modifiers.factoryKeyword != null) { |
| 8563 _reportErrorForToken( |
| 8564 ParserErrorCode.NON_CONSTRUCTOR_FACTORY, modifiers.factoryKeyword); |
| 8565 } |
| 8566 if (modifiers.finalKeyword != null) { |
| 8567 _reportErrorForToken( |
| 8568 ParserErrorCode.FINAL_METHOD, modifiers.finalKeyword); |
| 8569 } |
| 8570 if (modifiers.varKeyword != null) { |
| 8571 _reportErrorForToken( |
| 8572 ParserErrorCode.VAR_RETURN_TYPE, modifiers.varKeyword); |
| 8573 } |
| 8574 Token externalKeyword = modifiers.externalKeyword; |
| 8575 Token staticKeyword = modifiers.staticKeyword; |
| 8576 if (externalKeyword != null && |
| 8577 staticKeyword != null && |
| 8578 staticKeyword.offset < externalKeyword.offset) { |
| 8579 _reportErrorForToken( |
| 8580 ParserErrorCode.EXTERNAL_AFTER_STATIC, externalKeyword); |
| 8581 } |
| 8582 } |
| 8583 |
| 8584 /** |
| 8585 * Validate that the given set of [modifiers] is appropriate for a getter, |
| 8586 * setter, or method. |
| 8587 */ |
| 8588 void _validateModifiersForOperator(Modifiers modifiers) { |
| 8589 if (modifiers.abstractKeyword != null) { |
| 8590 _reportErrorForCurrentToken(ParserErrorCode.ABSTRACT_CLASS_MEMBER); |
| 8591 } |
| 8592 if (modifiers.constKeyword != null) { |
| 8593 _reportErrorForToken( |
| 8594 ParserErrorCode.CONST_METHOD, modifiers.constKeyword); |
| 8595 } |
| 8596 if (modifiers.factoryKeyword != null) { |
| 8597 _reportErrorForToken( |
| 8598 ParserErrorCode.NON_CONSTRUCTOR_FACTORY, modifiers.factoryKeyword); |
| 8599 } |
| 8600 if (modifiers.finalKeyword != null) { |
| 8601 _reportErrorForToken( |
| 8602 ParserErrorCode.FINAL_METHOD, modifiers.finalKeyword); |
| 8603 } |
| 8604 if (modifiers.staticKeyword != null) { |
| 8605 _reportErrorForToken( |
| 8606 ParserErrorCode.STATIC_OPERATOR, modifiers.staticKeyword); |
| 8607 } |
| 8608 if (modifiers.varKeyword != null) { |
| 8609 _reportErrorForToken( |
| 8610 ParserErrorCode.VAR_RETURN_TYPE, modifiers.varKeyword); |
| 8611 } |
| 8612 } |
| 8613 |
| 8614 /** |
| 8615 * Validate that the given set of [modifiers] is appropriate for a top-level |
| 8616 * declaration. |
| 8617 */ |
| 8618 void _validateModifiersForTopLevelDeclaration(Modifiers modifiers) { |
| 8619 if (modifiers.factoryKeyword != null) { |
| 8620 _reportErrorForToken(ParserErrorCode.FACTORY_TOP_LEVEL_DECLARATION, |
| 8621 modifiers.factoryKeyword); |
| 8622 } |
| 8623 if (modifiers.staticKeyword != null) { |
| 8624 _reportErrorForToken(ParserErrorCode.STATIC_TOP_LEVEL_DECLARATION, |
| 8625 modifiers.staticKeyword); |
| 8626 } |
| 8627 } |
| 8628 |
| 8629 /** |
| 8630 * Validate that the given set of [modifiers] is appropriate for a top-level |
| 8631 * function. |
| 8632 */ |
| 8633 void _validateModifiersForTopLevelFunction(Modifiers modifiers) { |
| 8634 _validateModifiersForTopLevelDeclaration(modifiers); |
| 8635 if (modifiers.abstractKeyword != null) { |
| 8636 _reportErrorForCurrentToken(ParserErrorCode.ABSTRACT_TOP_LEVEL_FUNCTION); |
| 8637 } |
| 8638 if (modifiers.constKeyword != null) { |
| 8639 _reportErrorForToken(ParserErrorCode.CONST_CLASS, modifiers.constKeyword); |
| 8640 } |
| 8641 if (modifiers.finalKeyword != null) { |
| 8642 _reportErrorForToken(ParserErrorCode.FINAL_CLASS, modifiers.finalKeyword); |
| 8643 } |
| 8644 if (modifiers.varKeyword != null) { |
| 8645 _reportErrorForToken( |
| 8646 ParserErrorCode.VAR_RETURN_TYPE, modifiers.varKeyword); |
| 8647 } |
| 8648 } |
| 8649 |
| 8650 /** |
| 8651 * Validate that the given set of [modifiers] is appropriate for a field and |
| 8652 * return the 'final', 'const' or 'var' keyword if there is one. |
| 8653 */ |
| 8654 Token _validateModifiersForTopLevelVariable(Modifiers modifiers) { |
| 8655 _validateModifiersForTopLevelDeclaration(modifiers); |
| 8656 if (modifiers.abstractKeyword != null) { |
| 8657 _reportErrorForCurrentToken(ParserErrorCode.ABSTRACT_TOP_LEVEL_VARIABLE); |
| 8658 } |
| 8659 if (modifiers.externalKeyword != null) { |
| 8660 _reportErrorForToken( |
| 8661 ParserErrorCode.EXTERNAL_FIELD, modifiers.externalKeyword); |
| 8662 } |
| 8663 Token constKeyword = modifiers.constKeyword; |
| 8664 Token finalKeyword = modifiers.finalKeyword; |
| 8665 Token varKeyword = modifiers.varKeyword; |
| 8666 if (constKeyword != null) { |
| 8667 if (finalKeyword != null) { |
| 8668 _reportErrorForToken(ParserErrorCode.CONST_AND_FINAL, finalKeyword); |
| 8669 } |
| 8670 if (varKeyword != null) { |
| 8671 _reportErrorForToken(ParserErrorCode.CONST_AND_VAR, varKeyword); |
| 8672 } |
| 8673 } else if (finalKeyword != null) { |
| 8674 if (varKeyword != null) { |
| 8675 _reportErrorForToken(ParserErrorCode.FINAL_AND_VAR, varKeyword); |
| 8676 } |
| 8677 } |
| 8678 return Token.lexicallyFirst([constKeyword, finalKeyword, varKeyword]); |
| 8679 } |
| 8680 |
| 8681 /** |
| 8682 * Validate that the given set of [modifiers] is appropriate for a class and |
| 8683 * return the 'abstract' keyword if there is one. |
| 8684 */ |
| 8685 void _validateModifiersForTypedef(Modifiers modifiers) { |
| 8686 _validateModifiersForTopLevelDeclaration(modifiers); |
| 8687 if (modifiers.abstractKeyword != null) { |
| 8688 _reportErrorForToken( |
| 8689 ParserErrorCode.ABSTRACT_TYPEDEF, modifiers.abstractKeyword); |
| 8690 } |
| 8691 if (modifiers.constKeyword != null) { |
| 8692 _reportErrorForToken( |
| 8693 ParserErrorCode.CONST_TYPEDEF, modifiers.constKeyword); |
| 8694 } |
| 8695 if (modifiers.externalKeyword != null) { |
| 8696 _reportErrorForToken( |
| 8697 ParserErrorCode.EXTERNAL_TYPEDEF, modifiers.externalKeyword); |
| 8698 } |
| 8699 if (modifiers.finalKeyword != null) { |
| 8700 _reportErrorForToken( |
| 8701 ParserErrorCode.FINAL_TYPEDEF, modifiers.finalKeyword); |
| 8702 } |
| 8703 if (modifiers.varKeyword != null) { |
| 8704 _reportErrorForToken(ParserErrorCode.VAR_TYPEDEF, modifiers.varKeyword); |
| 8705 } |
| 8706 } |
| 8707 } |
| 8708 /** |
| 8709 * A synthetic keyword token. |
| 8710 */ |
| 8711 class Parser_SyntheticKeywordToken extends KeywordToken { |
| 8712 /** |
| 8713 * Initialize a newly created token to represent the given [keyword] at the |
| 8714 * given [offset]. |
| 8715 */ |
| 8716 Parser_SyntheticKeywordToken(Keyword keyword, int offset) |
| 8717 : super(keyword, offset); |
| 8718 |
| 8719 @override |
| 8720 int get length => 0; |
| 8721 |
| 8722 @override |
| 8723 Token copy() => new Parser_SyntheticKeywordToken(keyword, offset); |
| 8724 } |
| 8725 |
| 8726 /** |
| 8727 * The error codes used for errors detected by the parser. The convention for |
| 8728 * this class is for the name of the error code to indicate the problem that |
| 8729 * caused the error to be generated and for the error message to explain what |
| 8730 * is wrong and, when appropriate, how the problem can be corrected. |
| 8731 */ |
| 8732 class ParserErrorCode extends ErrorCode { |
| 8733 static const ParserErrorCode ABSTRACT_CLASS_MEMBER = const ParserErrorCode( |
| 8734 'ABSTRACT_CLASS_MEMBER', |
| 8735 "Members of classes cannot be declared to be 'abstract'"); |
| 8736 |
| 8737 static const ParserErrorCode ABSTRACT_ENUM = const ParserErrorCode( |
| 8738 'ABSTRACT_ENUM', "Enums cannot be declared to be 'abstract'"); |
| 8739 |
| 8740 static const ParserErrorCode ABSTRACT_STATIC_METHOD = const ParserErrorCode( |
| 8741 'ABSTRACT_STATIC_METHOD', |
| 8742 "Static methods cannot be declared to be 'abstract'"); |
| 8743 |
| 8744 static const ParserErrorCode ABSTRACT_TOP_LEVEL_FUNCTION = |
| 8745 const ParserErrorCode('ABSTRACT_TOP_LEVEL_FUNCTION', |
| 8746 "Top-level functions cannot be declared to be 'abstract'"); |
| 8747 |
| 8748 static const ParserErrorCode ABSTRACT_TOP_LEVEL_VARIABLE = |
| 8749 const ParserErrorCode('ABSTRACT_TOP_LEVEL_VARIABLE', |
| 8750 "Top-level variables cannot be declared to be 'abstract'"); |
| 8751 |
| 8752 static const ParserErrorCode ABSTRACT_TYPEDEF = const ParserErrorCode( |
| 8753 'ABSTRACT_TYPEDEF', "Type aliases cannot be declared to be 'abstract'"); |
| 8754 |
| 8755 static const ParserErrorCode ANNOTATION_ON_ENUM_CONSTANT = |
| 8756 const ParserErrorCode('ANNOTATION_ON_ENUM_CONSTANT', |
| 8757 "Enum constants cannot have annotations"); |
| 8758 |
| 8759 static const ParserErrorCode ASSERT_DOES_NOT_TAKE_ASSIGNMENT = |
| 8760 const ParserErrorCode('ASSERT_DOES_NOT_TAKE_ASSIGNMENT', |
| 8761 "Assert cannot be called on an assignment"); |
| 8762 |
| 8763 static const ParserErrorCode ASSERT_DOES_NOT_TAKE_CASCADE = |
| 8764 const ParserErrorCode( |
| 8765 'ASSERT_DOES_NOT_TAKE_CASCADE', "Assert cannot be called on cascade"); |
| 8766 |
| 8767 static const ParserErrorCode ASSERT_DOES_NOT_TAKE_THROW = |
| 8768 const ParserErrorCode( |
| 8769 'ASSERT_DOES_NOT_TAKE_THROW', "Assert cannot be called on throws"); |
| 8770 |
| 8771 static const ParserErrorCode ASSERT_DOES_NOT_TAKE_RETHROW = |
| 8772 const ParserErrorCode('ASSERT_DOES_NOT_TAKE_RETHROW', |
| 8773 "Assert cannot be called on rethrows"); |
| 8774 |
| 8775 /** |
| 8776 * 16.32 Identifier Reference: It is a compile-time error if any of the |
| 8777 * identifiers async, await, or yield is used as an identifier in a function |
| 8778 * body marked with either async, async*, or sync*. |
| 8779 */ |
| 8780 static const ParserErrorCode ASYNC_KEYWORD_USED_AS_IDENTIFIER = |
| 8781 const ParserErrorCode('ASYNC_KEYWORD_USED_AS_IDENTIFIER', |
| 8782 "The keywords 'async', 'await', and 'yield' may not be used as identif
iers in an asynchronous or generator function."); |
| 8783 |
| 8784 static const ParserErrorCode BREAK_OUTSIDE_OF_LOOP = const ParserErrorCode( |
| 8785 'BREAK_OUTSIDE_OF_LOOP', |
| 8786 "A break statement cannot be used outside of a loop or switch statement"); |
| 8787 |
| 8788 static const ParserErrorCode CLASS_IN_CLASS = const ParserErrorCode( |
| 8789 'CLASS_IN_CLASS', "Classes cannot be declared inside other classes"); |
| 8790 |
| 8791 static const ParserErrorCode COLON_IN_PLACE_OF_IN = const ParserErrorCode( |
| 8792 'COLON_IN_PLACE_OF_IN', "For-in loops use 'in' rather than a colon"); |
| 8793 |
| 8794 static const ParserErrorCode CONST_AND_FINAL = const ParserErrorCode( |
| 8795 'CONST_AND_FINAL', |
| 8796 "Members cannot be declared to be both 'const' and 'final'"); |
| 8797 |
| 8798 static const ParserErrorCode CONST_AND_VAR = const ParserErrorCode( |
| 8799 'CONST_AND_VAR', |
| 8800 "Members cannot be declared to be both 'const' and 'var'"); |
| 8801 |
| 8802 static const ParserErrorCode CONST_CLASS = const ParserErrorCode( |
| 8803 'CONST_CLASS', "Classes cannot be declared to be 'const'"); |
| 8804 |
| 8805 static const ParserErrorCode CONST_CONSTRUCTOR_WITH_BODY = |
| 8806 const ParserErrorCode('CONST_CONSTRUCTOR_WITH_BODY', |
| 8807 "'const' constructors cannot have a body"); |
| 8808 |
| 8809 static const ParserErrorCode CONST_ENUM = const ParserErrorCode( |
| 8810 'CONST_ENUM', "Enums cannot be declared to be 'const'"); |
| 8811 |
| 8812 static const ParserErrorCode CONST_FACTORY = const ParserErrorCode( |
| 8813 'CONST_FACTORY', |
| 8814 "Only redirecting factory constructors can be declared to be 'const'"); |
| 8815 |
| 8816 static const ParserErrorCode CONST_METHOD = const ParserErrorCode( |
| 8817 'CONST_METHOD', |
| 8818 "Getters, setters and methods cannot be declared to be 'const'"); |
| 8819 |
| 8820 static const ParserErrorCode CONST_TYPEDEF = const ParserErrorCode( |
| 8821 'CONST_TYPEDEF', "Type aliases cannot be declared to be 'const'"); |
| 8822 |
| 8823 static const ParserErrorCode CONSTRUCTOR_WITH_RETURN_TYPE = |
| 8824 const ParserErrorCode('CONSTRUCTOR_WITH_RETURN_TYPE', |
| 8825 "Constructors cannot have a return type"); |
| 8826 |
| 8827 static const ParserErrorCode CONTINUE_OUTSIDE_OF_LOOP = const ParserErrorCode( |
| 8828 'CONTINUE_OUTSIDE_OF_LOOP', |
| 8829 "A continue statement cannot be used outside of a loop or switch statement
"); |
| 8830 |
| 8831 static const ParserErrorCode CONTINUE_WITHOUT_LABEL_IN_CASE = |
| 8832 const ParserErrorCode('CONTINUE_WITHOUT_LABEL_IN_CASE', |
| 8833 "A continue statement in a switch statement must have a label as a tar
get"); |
| 8834 |
| 8835 static const ParserErrorCode DEPRECATED_CLASS_TYPE_ALIAS = |
| 8836 const ParserErrorCode('DEPRECATED_CLASS_TYPE_ALIAS', |
| 8837 "The 'typedef' mixin application was replaced with 'class'"); |
| 8838 |
| 8839 static const ParserErrorCode DIRECTIVE_AFTER_DECLARATION = |
| 8840 const ParserErrorCode('DIRECTIVE_AFTER_DECLARATION', |
| 8841 "Directives must appear before any declarations"); |
| 8842 |
| 8843 static const ParserErrorCode DUPLICATE_LABEL_IN_SWITCH_STATEMENT = |
| 8844 const ParserErrorCode('DUPLICATE_LABEL_IN_SWITCH_STATEMENT', |
| 8845 "The label {0} was already used in this switch statement"); |
| 8846 |
| 8847 static const ParserErrorCode DUPLICATED_MODIFIER = const ParserErrorCode( |
| 8848 'DUPLICATED_MODIFIER', "The modifier '{0}' was already specified."); |
| 8849 |
| 8850 static const ParserErrorCode EMPTY_ENUM_BODY = const ParserErrorCode( |
| 8851 'EMPTY_ENUM_BODY', "An enum must declare at least one constant name"); |
| 8852 |
| 8853 static const ParserErrorCode ENUM_IN_CLASS = const ParserErrorCode( |
| 8854 'ENUM_IN_CLASS', "Enums cannot be declared inside classes"); |
| 8855 |
| 8856 static const ParserErrorCode EQUALITY_CANNOT_BE_EQUALITY_OPERAND = |
| 8857 const ParserErrorCode('EQUALITY_CANNOT_BE_EQUALITY_OPERAND', |
| 8858 "Equality expression cannot be operand of another equality expression.
"); |
| 8859 |
| 8860 static const ParserErrorCode EXPECTED_CASE_OR_DEFAULT = const ParserErrorCode( |
| 8861 'EXPECTED_CASE_OR_DEFAULT', "Expected 'case' or 'default'"); |
| 8862 |
| 8863 static const ParserErrorCode EXPECTED_CLASS_MEMBER = |
| 8864 const ParserErrorCode('EXPECTED_CLASS_MEMBER', "Expected a class member"); |
| 8865 |
| 8866 static const ParserErrorCode EXPECTED_EXECUTABLE = const ParserErrorCode( |
| 8867 'EXPECTED_EXECUTABLE', |
| 8868 "Expected a method, getter, setter or operator declaration"); |
| 8869 |
| 8870 static const ParserErrorCode EXPECTED_LIST_OR_MAP_LITERAL = |
| 8871 const ParserErrorCode( |
| 8872 'EXPECTED_LIST_OR_MAP_LITERAL', "Expected a list or map literal"); |
| 8873 |
| 8874 static const ParserErrorCode EXPECTED_STRING_LITERAL = const ParserErrorCode( |
| 8875 'EXPECTED_STRING_LITERAL', "Expected a string literal"); |
| 8876 |
| 8877 static const ParserErrorCode EXPECTED_TOKEN = |
| 8878 const ParserErrorCode('EXPECTED_TOKEN', "Expected to find '{0}'"); |
| 8879 |
| 8880 static const ParserErrorCode EXPECTED_TYPE_NAME = |
| 8881 const ParserErrorCode('EXPECTED_TYPE_NAME', "Expected a type name"); |
| 8882 |
| 8883 static const ParserErrorCode EXPORT_DIRECTIVE_AFTER_PART_DIRECTIVE = |
| 8884 const ParserErrorCode('EXPORT_DIRECTIVE_AFTER_PART_DIRECTIVE', |
| 8885 "Export directives must preceed part directives"); |
| 8886 |
| 8887 static const ParserErrorCode EXTERNAL_AFTER_CONST = const ParserErrorCode( |
| 8888 'EXTERNAL_AFTER_CONST', |
| 8889 "The modifier 'external' should be before the modifier 'const'"); |
| 8890 |
| 8891 static const ParserErrorCode EXTERNAL_AFTER_FACTORY = const ParserErrorCode( |
| 8892 'EXTERNAL_AFTER_FACTORY', |
| 8893 "The modifier 'external' should be before the modifier 'factory'"); |
| 8894 |
| 8895 static const ParserErrorCode EXTERNAL_AFTER_STATIC = const ParserErrorCode( |
| 8896 'EXTERNAL_AFTER_STATIC', |
| 8897 "The modifier 'external' should be before the modifier 'static'"); |
| 8898 |
| 8899 static const ParserErrorCode EXTERNAL_CLASS = const ParserErrorCode( |
| 8900 'EXTERNAL_CLASS', "Classes cannot be declared to be 'external'"); |
| 8901 |
| 8902 static const ParserErrorCode EXTERNAL_CONSTRUCTOR_WITH_BODY = |
| 8903 const ParserErrorCode('EXTERNAL_CONSTRUCTOR_WITH_BODY', |
| 8904 "External constructors cannot have a body"); |
| 8905 |
| 8906 static const ParserErrorCode EXTERNAL_ENUM = const ParserErrorCode( |
| 8907 'EXTERNAL_ENUM', "Enums cannot be declared to be 'external'"); |
| 8908 |
| 8909 static const ParserErrorCode EXTERNAL_FIELD = const ParserErrorCode( |
| 8910 'EXTERNAL_FIELD', "Fields cannot be declared to be 'external'"); |
| 8911 |
| 8912 static const ParserErrorCode EXTERNAL_GETTER_WITH_BODY = |
| 8913 const ParserErrorCode( |
| 8914 'EXTERNAL_GETTER_WITH_BODY', "External getters cannot have a body"); |
| 8915 |
| 8916 static const ParserErrorCode EXTERNAL_METHOD_WITH_BODY = |
| 8917 const ParserErrorCode( |
| 8918 'EXTERNAL_METHOD_WITH_BODY', "External methods cannot have a body"); |
| 8919 |
| 8920 static const ParserErrorCode EXTERNAL_OPERATOR_WITH_BODY = |
| 8921 const ParserErrorCode('EXTERNAL_OPERATOR_WITH_BODY', |
| 8922 "External operators cannot have a body"); |
| 8923 |
| 8924 static const ParserErrorCode EXTERNAL_SETTER_WITH_BODY = |
| 8925 const ParserErrorCode( |
| 8926 'EXTERNAL_SETTER_WITH_BODY', "External setters cannot have a body"); |
| 8927 |
| 8928 static const ParserErrorCode EXTERNAL_TYPEDEF = const ParserErrorCode( |
| 8929 'EXTERNAL_TYPEDEF', "Type aliases cannot be declared to be 'external'"); |
| 8930 |
| 8931 static const ParserErrorCode FACTORY_TOP_LEVEL_DECLARATION = |
| 8932 const ParserErrorCode('FACTORY_TOP_LEVEL_DECLARATION', |
| 8933 "Top-level declarations cannot be declared to be 'factory'"); |
| 8934 |
| 8935 static const ParserErrorCode FACTORY_WITH_INITIALIZERS = |
| 8936 const ParserErrorCode('FACTORY_WITH_INITIALIZERS', |
| 8937 "A 'factory' constructor cannot have initializers", |
| 8938 "Either remove the 'factory' keyword to make this a generative " |
| 8939 "constructor or remove the initializers."); |
| 8940 |
| 8941 static const ParserErrorCode FACTORY_WITHOUT_BODY = const ParserErrorCode( |
| 8942 'FACTORY_WITHOUT_BODY', |
| 8943 "A non-redirecting 'factory' constructor must have a body"); |
| 8944 |
| 8945 static const ParserErrorCode FIELD_INITIALIZER_OUTSIDE_CONSTRUCTOR = |
| 8946 const ParserErrorCode('FIELD_INITIALIZER_OUTSIDE_CONSTRUCTOR', |
| 8947 "Field initializers can only be used in a constructor"); |
| 8948 |
| 8949 static const ParserErrorCode FINAL_AND_VAR = const ParserErrorCode( |
| 8950 'FINAL_AND_VAR', |
| 8951 "Members cannot be declared to be both 'final' and 'var'"); |
| 8952 |
| 8953 static const ParserErrorCode FINAL_CLASS = const ParserErrorCode( |
| 8954 'FINAL_CLASS', "Classes cannot be declared to be 'final'"); |
| 8955 |
| 8956 static const ParserErrorCode FINAL_CONSTRUCTOR = const ParserErrorCode( |
| 8957 'FINAL_CONSTRUCTOR', "A constructor cannot be declared to be 'final'"); |
| 8958 |
| 8959 static const ParserErrorCode FINAL_ENUM = const ParserErrorCode( |
| 8960 'FINAL_ENUM', "Enums cannot be declared to be 'final'"); |
| 8961 |
| 8962 static const ParserErrorCode FINAL_METHOD = const ParserErrorCode( |
| 8963 'FINAL_METHOD', |
| 8964 "Getters, setters and methods cannot be declared to be 'final'"); |
| 8965 |
| 8966 static const ParserErrorCode FINAL_TYPEDEF = const ParserErrorCode( |
| 8967 'FINAL_TYPEDEF', "Type aliases cannot be declared to be 'final'"); |
| 8968 |
| 8969 static const ParserErrorCode FUNCTION_TYPED_PARAMETER_VAR = const ParserErrorC
ode( |
| 8970 'FUNCTION_TYPED_PARAMETER_VAR', |
| 8971 "Function typed parameters cannot specify 'const', 'final' or 'var' instea
d of return type"); |
| 8972 |
| 8973 static const ParserErrorCode GETTER_IN_FUNCTION = const ParserErrorCode( |
| 8974 'GETTER_IN_FUNCTION', |
| 8975 "Getters cannot be defined within methods or functions"); |
| 8976 |
| 8977 static const ParserErrorCode GETTER_WITH_PARAMETERS = const ParserErrorCode( |
| 8978 'GETTER_WITH_PARAMETERS', |
| 8979 "Getter should be declared without a parameter list"); |
| 8980 |
| 8981 static const ParserErrorCode ILLEGAL_ASSIGNMENT_TO_NON_ASSIGNABLE = |
| 8982 const ParserErrorCode('ILLEGAL_ASSIGNMENT_TO_NON_ASSIGNABLE', |
| 8983 "Illegal assignment to non-assignable expression"); |
| 8984 |
| 8985 static const ParserErrorCode IMPLEMENTS_BEFORE_EXTENDS = |
| 8986 const ParserErrorCode('IMPLEMENTS_BEFORE_EXTENDS', |
| 8987 "The extends clause must be before the implements clause"); |
| 8988 |
| 8989 static const ParserErrorCode IMPLEMENTS_BEFORE_WITH = const ParserErrorCode( |
| 8990 'IMPLEMENTS_BEFORE_WITH', |
| 8991 "The with clause must be before the implements clause"); |
| 8992 |
| 8993 static const ParserErrorCode IMPORT_DIRECTIVE_AFTER_PART_DIRECTIVE = |
| 8994 const ParserErrorCode('IMPORT_DIRECTIVE_AFTER_PART_DIRECTIVE', |
| 8995 "Import directives must preceed part directives"); |
| 8996 |
| 8997 static const ParserErrorCode INITIALIZED_VARIABLE_IN_FOR_EACH = |
| 8998 const ParserErrorCode('INITIALIZED_VARIABLE_IN_FOR_EACH', |
| 8999 "The loop variable in a for-each loop cannot be initialized"); |
| 9000 |
| 9001 static const ParserErrorCode INVALID_AWAIT_IN_FOR = const ParserErrorCode( |
| 9002 'INVALID_AWAIT_IN_FOR', |
| 9003 "The modifier 'await' is not allowed for a normal 'for' statement", |
| 9004 "Remove the keyword or use a for-each statement."); |
| 9005 |
| 9006 static const ParserErrorCode INVALID_CODE_POINT = const ParserErrorCode( |
| 9007 'INVALID_CODE_POINT', |
| 9008 "The escape sequence '{0}' is not a valid code point"); |
| 9009 |
| 9010 static const ParserErrorCode INVALID_COMMENT_REFERENCE = const ParserErrorCode
( |
| 9011 'INVALID_COMMENT_REFERENCE', |
| 9012 "Comment references should contain a possibly prefixed identifier and can
start with 'new', but should not contain anything else"); |
| 9013 |
| 9014 static const ParserErrorCode INVALID_HEX_ESCAPE = const ParserErrorCode( |
| 9015 'INVALID_HEX_ESCAPE', |
| 9016 "An escape sequence starting with '\\x' must be followed by 2 hexidecimal
digits"); |
| 9017 |
| 9018 static const ParserErrorCode INVALID_OPERATOR = const ParserErrorCode( |
| 9019 'INVALID_OPERATOR', "The string '{0}' is not a valid operator"); |
| 9020 |
| 9021 static const ParserErrorCode INVALID_OPERATOR_FOR_SUPER = |
| 9022 const ParserErrorCode('INVALID_OPERATOR_FOR_SUPER', |
| 9023 "The operator '{0}' cannot be used with 'super'"); |
| 9024 |
| 9025 static const ParserErrorCode INVALID_STAR_AFTER_ASYNC = const ParserErrorCode( |
| 9026 'INVALID_STAR_AFTER_ASYNC', |
| 9027 "The modifier 'async*' is not allowed for an expression function body", |
| 9028 "Convert the body to a block."); |
| 9029 |
| 9030 static const ParserErrorCode INVALID_SYNC = const ParserErrorCode( |
| 9031 'INVALID_SYNC', |
| 9032 "The modifier 'sync' is not allowed for an exrpression function body", |
| 9033 "Convert the body to a block."); |
| 9034 |
| 9035 static const ParserErrorCode INVALID_UNICODE_ESCAPE = const ParserErrorCode( |
| 9036 'INVALID_UNICODE_ESCAPE', |
| 9037 "An escape sequence starting with '\\u' must be followed by 4 hexidecimal
digits or from 1 to 6 digits between '{' and '}'"); |
| 9038 |
| 9039 static const ParserErrorCode LIBRARY_DIRECTIVE_NOT_FIRST = |
| 9040 const ParserErrorCode('LIBRARY_DIRECTIVE_NOT_FIRST', |
| 9041 "The library directive must appear before all other directives"); |
| 9042 |
| 9043 static const ParserErrorCode LOCAL_FUNCTION_DECLARATION_MODIFIER = |
| 9044 const ParserErrorCode('LOCAL_FUNCTION_DECLARATION_MODIFIER', |
| 9045 "Local function declarations cannot specify any modifier"); |
| 9046 |
| 9047 static const ParserErrorCode MISSING_ASSIGNABLE_SELECTOR = |
| 9048 const ParserErrorCode('MISSING_ASSIGNABLE_SELECTOR', |
| 9049 "Missing selector such as \".<identifier>\" or \"[0]\""); |
| 9050 |
| 9051 static const ParserErrorCode MISSING_ASSIGNMENT_IN_INITIALIZER = |
| 9052 const ParserErrorCode('MISSING_ASSIGNMENT_IN_INITIALIZER', |
| 9053 "Expected an assignment after the field name"); |
| 9054 |
| 9055 static const ParserErrorCode MISSING_CATCH_OR_FINALLY = const ParserErrorCode( |
| 9056 'MISSING_CATCH_OR_FINALLY', |
| 9057 "A try statement must have either a catch or finally clause"); |
| 9058 |
| 9059 static const ParserErrorCode MISSING_CLASS_BODY = const ParserErrorCode( |
| 9060 'MISSING_CLASS_BODY', |
| 9061 "A class definition must have a body, even if it is empty"); |
| 9062 |
| 9063 static const ParserErrorCode MISSING_CLOSING_PARENTHESIS = |
| 9064 const ParserErrorCode( |
| 9065 'MISSING_CLOSING_PARENTHESIS', "The closing parenthesis is missing"); |
| 9066 |
| 9067 static const ParserErrorCode MISSING_CONST_FINAL_VAR_OR_TYPE = |
| 9068 const ParserErrorCode('MISSING_CONST_FINAL_VAR_OR_TYPE', |
| 9069 "Variables must be declared using the keywords 'const', 'final', 'var'
or a type name"); |
| 9070 |
| 9071 static const ParserErrorCode MISSING_ENUM_BODY = const ParserErrorCode( |
| 9072 'MISSING_ENUM_BODY', |
| 9073 "An enum definition must have a body with at least one constant name"); |
| 9074 |
| 9075 static const ParserErrorCode MISSING_EXPRESSION_IN_INITIALIZER = |
| 9076 const ParserErrorCode('MISSING_EXPRESSION_IN_INITIALIZER', |
| 9077 "Expected an expression after the assignment operator"); |
| 9078 |
| 9079 static const ParserErrorCode MISSING_EXPRESSION_IN_THROW = |
| 9080 const ParserErrorCode('MISSING_EXPRESSION_IN_THROW', |
| 9081 "Throw expressions must compute the object to be thrown"); |
| 9082 |
| 9083 static const ParserErrorCode MISSING_FUNCTION_BODY = const ParserErrorCode( |
| 9084 'MISSING_FUNCTION_BODY', "A function body must be provided"); |
| 9085 |
| 9086 static const ParserErrorCode MISSING_FUNCTION_PARAMETERS = |
| 9087 const ParserErrorCode('MISSING_FUNCTION_PARAMETERS', |
| 9088 "Functions must have an explicit list of parameters"); |
| 9089 |
| 9090 static const ParserErrorCode MISSING_METHOD_PARAMETERS = |
| 9091 const ParserErrorCode('MISSING_METHOD_PARAMETERS', |
| 9092 "Methods must have an explicit list of parameters"); |
| 9093 |
| 9094 static const ParserErrorCode MISSING_GET = const ParserErrorCode( |
| 9095 'MISSING_GET', |
| 9096 "Getters must have the keyword 'get' before the getter name"); |
| 9097 |
| 9098 static const ParserErrorCode MISSING_IDENTIFIER = |
| 9099 const ParserErrorCode('MISSING_IDENTIFIER', "Expected an identifier"); |
| 9100 |
| 9101 static const ParserErrorCode MISSING_INITIALIZER = |
| 9102 const ParserErrorCode('MISSING_INITIALIZER', "Expected an initializer"); |
| 9103 |
| 9104 static const ParserErrorCode MISSING_KEYWORD_OPERATOR = const ParserErrorCode( |
| 9105 'MISSING_KEYWORD_OPERATOR', |
| 9106 "Operator declarations must be preceeded by the keyword 'operator'"); |
| 9107 |
| 9108 static const ParserErrorCode MISSING_NAME_IN_LIBRARY_DIRECTIVE = |
| 9109 const ParserErrorCode('MISSING_NAME_IN_LIBRARY_DIRECTIVE', |
| 9110 "Library directives must include a library name"); |
| 9111 |
| 9112 static const ParserErrorCode MISSING_NAME_IN_PART_OF_DIRECTIVE = |
| 9113 const ParserErrorCode('MISSING_NAME_IN_PART_OF_DIRECTIVE', |
| 9114 "Library directives must include a library name"); |
| 9115 |
| 9116 static const ParserErrorCode MISSING_PREFIX_IN_DEFERRED_IMPORT = |
| 9117 const ParserErrorCode('MISSING_PREFIX_IN_DEFERRED_IMPORT', |
| 9118 "Deferred imports must have a prefix"); |
| 9119 |
| 9120 static const ParserErrorCode MISSING_STAR_AFTER_SYNC = const ParserErrorCode( |
| 9121 'MISSING_STAR_AFTER_SYNC', |
| 9122 "The modifier 'sync' must be followed by a star ('*')", |
| 9123 "Remove the modifier or add a star."); |
| 9124 |
| 9125 static const ParserErrorCode MISSING_STATEMENT = |
| 9126 const ParserErrorCode('MISSING_STATEMENT', "Expected a statement"); |
| 9127 |
| 9128 static const ParserErrorCode MISSING_TERMINATOR_FOR_PARAMETER_GROUP = |
| 9129 const ParserErrorCode('MISSING_TERMINATOR_FOR_PARAMETER_GROUP', |
| 9130 "There is no '{0}' to close the parameter group"); |
| 9131 |
| 9132 static const ParserErrorCode MISSING_TYPEDEF_PARAMETERS = |
| 9133 const ParserErrorCode('MISSING_TYPEDEF_PARAMETERS', |
| 9134 "Type aliases for functions must have an explicit list of parameters")
; |
| 9135 |
| 9136 static const ParserErrorCode MISSING_VARIABLE_IN_FOR_EACH = const ParserErrorC
ode( |
| 9137 'MISSING_VARIABLE_IN_FOR_EACH', |
| 9138 "A loop variable must be declared in a for-each loop before the 'in', but
none were found"); |
| 9139 |
| 9140 static const ParserErrorCode MIXED_PARAMETER_GROUPS = const ParserErrorCode( |
| 9141 'MIXED_PARAMETER_GROUPS', |
| 9142 "Cannot have both positional and named parameters in a single parameter li
st"); |
| 9143 |
| 9144 static const ParserErrorCode MULTIPLE_EXTENDS_CLAUSES = const ParserErrorCode( |
| 9145 'MULTIPLE_EXTENDS_CLAUSES', |
| 9146 "Each class definition can have at most one extends clause"); |
| 9147 |
| 9148 static const ParserErrorCode MULTIPLE_IMPLEMENTS_CLAUSES = |
| 9149 const ParserErrorCode('MULTIPLE_IMPLEMENTS_CLAUSES', |
| 9150 "Each class definition can have at most one implements clause"); |
| 9151 |
| 9152 static const ParserErrorCode MULTIPLE_LIBRARY_DIRECTIVES = |
| 9153 const ParserErrorCode('MULTIPLE_LIBRARY_DIRECTIVES', |
| 9154 "Only one library directive may be declared in a file"); |
| 9155 |
| 9156 static const ParserErrorCode MULTIPLE_NAMED_PARAMETER_GROUPS = |
| 9157 const ParserErrorCode('MULTIPLE_NAMED_PARAMETER_GROUPS', |
| 9158 "Cannot have multiple groups of named parameters in a single parameter
list"); |
| 9159 |
| 9160 static const ParserErrorCode MULTIPLE_PART_OF_DIRECTIVES = |
| 9161 const ParserErrorCode('MULTIPLE_PART_OF_DIRECTIVES', |
| 9162 "Only one part-of directive may be declared in a file"); |
| 9163 |
| 9164 static const ParserErrorCode MULTIPLE_POSITIONAL_PARAMETER_GROUPS = |
| 9165 const ParserErrorCode('MULTIPLE_POSITIONAL_PARAMETER_GROUPS', |
| 9166 "Cannot have multiple groups of positional parameters in a single para
meter list"); |
| 9167 |
| 9168 static const ParserErrorCode MULTIPLE_VARIABLES_IN_FOR_EACH = |
| 9169 const ParserErrorCode('MULTIPLE_VARIABLES_IN_FOR_EACH', |
| 9170 "A single loop variable must be declared in a for-each loop before the
'in', but {0} were found"); |
| 9171 |
| 9172 static const ParserErrorCode MULTIPLE_WITH_CLAUSES = const ParserErrorCode( |
| 9173 'MULTIPLE_WITH_CLAUSES', |
| 9174 "Each class definition can have at most one with clause"); |
| 9175 |
| 9176 static const ParserErrorCode NAMED_FUNCTION_EXPRESSION = |
| 9177 const ParserErrorCode( |
| 9178 'NAMED_FUNCTION_EXPRESSION', "Function expressions cannot be named"); |
| 9179 |
| 9180 static const ParserErrorCode NAMED_PARAMETER_OUTSIDE_GROUP = |
| 9181 const ParserErrorCode('NAMED_PARAMETER_OUTSIDE_GROUP', |
| 9182 "Named parameters must be enclosed in curly braces ('{' and '}')"); |
| 9183 |
| 9184 static const ParserErrorCode NATIVE_CLAUSE_IN_NON_SDK_CODE = |
| 9185 const ParserErrorCode('NATIVE_CLAUSE_IN_NON_SDK_CODE', |
| 9186 "Native clause can only be used in the SDK and code that is loaded thr
ough native extensions"); |
| 9187 |
| 9188 static const ParserErrorCode NATIVE_FUNCTION_BODY_IN_NON_SDK_CODE = |
| 9189 const ParserErrorCode('NATIVE_FUNCTION_BODY_IN_NON_SDK_CODE', |
| 9190 "Native functions can only be declared in the SDK and code that is loa
ded through native extensions"); |
| 9191 |
| 9192 static const ParserErrorCode NON_CONSTRUCTOR_FACTORY = const ParserErrorCode( |
| 9193 'NON_CONSTRUCTOR_FACTORY', |
| 9194 "Only constructors can be declared to be a 'factory'"); |
| 9195 |
| 9196 static const ParserErrorCode NON_IDENTIFIER_LIBRARY_NAME = |
| 9197 const ParserErrorCode('NON_IDENTIFIER_LIBRARY_NAME', |
| 9198 "The name of a library must be an identifier"); |
| 9199 |
| 9200 static const ParserErrorCode NON_PART_OF_DIRECTIVE_IN_PART = |
| 9201 const ParserErrorCode('NON_PART_OF_DIRECTIVE_IN_PART', |
| 9202 "The part-of directive must be the only directive in a part"); |
| 9203 |
| 9204 static const ParserErrorCode NON_STRING_LITERAL_AS_URI = |
| 9205 const ParserErrorCode('NON_STRING_LITERAL_AS_URI', |
| 9206 "The URI must be a string literal", |
| 9207 "Enclose the URI in either single or double quotes."); |
| 9208 |
| 9209 static const ParserErrorCode NON_USER_DEFINABLE_OPERATOR = |
| 9210 const ParserErrorCode('NON_USER_DEFINABLE_OPERATOR', |
| 9211 "The operator '{0}' is not user definable"); |
| 9212 |
| 9213 static const ParserErrorCode NORMAL_BEFORE_OPTIONAL_PARAMETERS = |
| 9214 const ParserErrorCode('NORMAL_BEFORE_OPTIONAL_PARAMETERS', |
| 9215 "Normal parameters must occur before optional parameters"); |
| 9216 |
| 9217 static const ParserErrorCode POSITIONAL_AFTER_NAMED_ARGUMENT = |
| 9218 const ParserErrorCode('POSITIONAL_AFTER_NAMED_ARGUMENT', |
| 9219 "Positional arguments must occur before named arguments"); |
| 9220 |
| 9221 static const ParserErrorCode POSITIONAL_PARAMETER_OUTSIDE_GROUP = |
| 9222 const ParserErrorCode('POSITIONAL_PARAMETER_OUTSIDE_GROUP', |
| 9223 "Positional parameters must be enclosed in square brackets ('[' and ']
')"); |
| 9224 |
| 9225 static const ParserErrorCode REDIRECTION_IN_NON_FACTORY_CONSTRUCTOR = |
| 9226 const ParserErrorCode('REDIRECTION_IN_NON_FACTORY_CONSTRUCTOR', |
| 9227 "Only factory constructor can specify '=' redirection."); |
| 9228 |
| 9229 static const ParserErrorCode SETTER_IN_FUNCTION = const ParserErrorCode( |
| 9230 'SETTER_IN_FUNCTION', |
| 9231 "Setters cannot be defined within methods or functions"); |
| 9232 |
| 9233 static const ParserErrorCode STATIC_AFTER_CONST = const ParserErrorCode( |
| 9234 'STATIC_AFTER_CONST', |
| 9235 "The modifier 'static' should be before the modifier 'const'"); |
| 9236 |
| 9237 static const ParserErrorCode STATIC_AFTER_FINAL = const ParserErrorCode( |
| 9238 'STATIC_AFTER_FINAL', |
| 9239 "The modifier 'static' should be before the modifier 'final'"); |
| 9240 |
| 9241 static const ParserErrorCode STATIC_AFTER_VAR = const ParserErrorCode( |
| 9242 'STATIC_AFTER_VAR', |
| 9243 "The modifier 'static' should be before the modifier 'var'"); |
| 9244 |
| 9245 static const ParserErrorCode STATIC_CONSTRUCTOR = const ParserErrorCode( |
| 9246 'STATIC_CONSTRUCTOR', "Constructors cannot be static"); |
| 9247 |
| 9248 static const ParserErrorCode STATIC_GETTER_WITHOUT_BODY = |
| 9249 const ParserErrorCode( |
| 9250 'STATIC_GETTER_WITHOUT_BODY', "A 'static' getter must have a body"); |
| 9251 |
| 9252 static const ParserErrorCode STATIC_OPERATOR = |
| 9253 const ParserErrorCode('STATIC_OPERATOR', "Operators cannot be static"); |
| 9254 |
| 9255 static const ParserErrorCode STATIC_SETTER_WITHOUT_BODY = |
| 9256 const ParserErrorCode( |
| 9257 'STATIC_SETTER_WITHOUT_BODY', "A 'static' setter must have a body"); |
| 9258 |
| 9259 static const ParserErrorCode STATIC_TOP_LEVEL_DECLARATION = |
| 9260 const ParserErrorCode('STATIC_TOP_LEVEL_DECLARATION', |
| 9261 "Top-level declarations cannot be declared to be 'static'"); |
| 9262 |
| 9263 static const ParserErrorCode SWITCH_HAS_CASE_AFTER_DEFAULT_CASE = |
| 9264 const ParserErrorCode('SWITCH_HAS_CASE_AFTER_DEFAULT_CASE', |
| 9265 "The 'default' case should be the last case in a switch statement"); |
| 9266 |
| 9267 static const ParserErrorCode SWITCH_HAS_MULTIPLE_DEFAULT_CASES = |
| 9268 const ParserErrorCode('SWITCH_HAS_MULTIPLE_DEFAULT_CASES', |
| 9269 "The 'default' case can only be declared once"); |
| 9270 |
| 9271 static const ParserErrorCode TOP_LEVEL_OPERATOR = const ParserErrorCode( |
| 9272 'TOP_LEVEL_OPERATOR', "Operators must be declared within a class"); |
| 9273 |
| 9274 static const ParserErrorCode TYPEDEF_IN_CLASS = const ParserErrorCode( |
| 9275 'TYPEDEF_IN_CLASS', |
| 9276 "Function type aliases cannot be declared inside classes"); |
| 9277 |
| 9278 static const ParserErrorCode UNEXPECTED_TERMINATOR_FOR_PARAMETER_GROUP = |
| 9279 const ParserErrorCode('UNEXPECTED_TERMINATOR_FOR_PARAMETER_GROUP', |
| 9280 "There is no '{0}' to open a parameter group"); |
| 9281 |
| 9282 static const ParserErrorCode UNEXPECTED_TOKEN = |
| 9283 const ParserErrorCode('UNEXPECTED_TOKEN', "Unexpected token '{0}'"); |
| 9284 |
| 9285 static const ParserErrorCode WITH_BEFORE_EXTENDS = const ParserErrorCode( |
| 9286 'WITH_BEFORE_EXTENDS', |
| 9287 "The extends clause must be before the with clause"); |
| 9288 |
| 9289 static const ParserErrorCode WITH_WITHOUT_EXTENDS = const ParserErrorCode( |
| 9290 'WITH_WITHOUT_EXTENDS', |
| 9291 "The with clause cannot be used without an extends clause"); |
| 9292 |
| 9293 static const ParserErrorCode WRONG_SEPARATOR_FOR_NAMED_PARAMETER = |
| 9294 const ParserErrorCode('WRONG_SEPARATOR_FOR_NAMED_PARAMETER', |
| 9295 "The default value of a named parameter should be preceeded by ':'"); |
| 9296 |
| 9297 static const ParserErrorCode WRONG_SEPARATOR_FOR_POSITIONAL_PARAMETER = |
| 9298 const ParserErrorCode('WRONG_SEPARATOR_FOR_POSITIONAL_PARAMETER', |
| 9299 "The default value of a positional parameter should be preceeded by '=
'"); |
| 9300 |
| 9301 static const ParserErrorCode WRONG_TERMINATOR_FOR_PARAMETER_GROUP = |
| 9302 const ParserErrorCode('WRONG_TERMINATOR_FOR_PARAMETER_GROUP', |
| 9303 "Expected '{0}' to close parameter group"); |
| 9304 |
| 9305 static const ParserErrorCode VAR_AND_TYPE = const ParserErrorCode( |
| 9306 'VAR_AND_TYPE', |
| 9307 "Variables cannot be declared using both 'var' and a type name; remove the
'var'"); |
| 9308 |
| 9309 static const ParserErrorCode VAR_AS_TYPE_NAME = const ParserErrorCode( |
| 9310 'VAR_AS_TYPE_NAME', "The keyword 'var' cannot be used as a type name"); |
| 9311 |
| 9312 static const ParserErrorCode VAR_CLASS = const ParserErrorCode( |
| 9313 'VAR_CLASS', "Classes cannot be declared to be 'var'"); |
| 9314 |
| 9315 static const ParserErrorCode VAR_ENUM = |
| 9316 const ParserErrorCode('VAR_ENUM', "Enums cannot be declared to be 'var'"); |
| 9317 |
| 9318 static const ParserErrorCode VAR_RETURN_TYPE = const ParserErrorCode( |
| 9319 'VAR_RETURN_TYPE', "The return type cannot be 'var'"); |
| 9320 |
| 9321 static const ParserErrorCode VAR_TYPEDEF = const ParserErrorCode( |
| 9322 'VAR_TYPEDEF', "Type aliases cannot be declared to be 'var'"); |
| 9323 |
| 9324 static const ParserErrorCode VOID_PARAMETER = const ParserErrorCode( |
| 9325 'VOID_PARAMETER', "Parameters cannot have a type of 'void'"); |
| 9326 |
| 9327 static const ParserErrorCode VOID_VARIABLE = const ParserErrorCode( |
| 9328 'VOID_VARIABLE', "Variables cannot have a type of 'void'"); |
| 9329 |
| 9330 /** |
| 9331 * Initialize a newly created error code to have the given [name]. The message |
| 9332 * associated with the error will be created from the given [message] |
| 9333 * template. The correction associated with the error will be created from the |
| 9334 * given [correction] template. |
| 9335 */ |
| 9336 const ParserErrorCode(String name, String message, [String correction]) |
| 9337 : super(name, message, correction); |
| 9338 |
| 9339 @override |
| 9340 ErrorSeverity get errorSeverity => ErrorSeverity.ERROR; |
| 9341 |
| 9342 @override |
| 9343 ErrorType get type => ErrorType.SYNTACTIC_ERROR; |
| 9344 } |
| 9345 |
| 9346 /** |
| 9347 * An object that copies resolution information from one AST structure to |
| 9348 * another as long as the structures of the corresponding children of a pair of |
| 9349 * nodes are the same. |
| 9350 */ |
| 9351 class ResolutionCopier implements AstVisitor<bool> { |
| 9352 /** |
| 9353 * The AST node with which the node being visited is to be compared. This is |
| 9354 * only valid at the beginning of each visit method (until [isEqualNodes] is |
| 9355 * invoked). |
| 9356 */ |
| 9357 AstNode _toNode; |
| 9358 |
| 9359 @override |
| 9360 bool visitAdjacentStrings(AdjacentStrings node) { |
| 9361 AdjacentStrings toNode = this._toNode as AdjacentStrings; |
| 9362 return _isEqualNodeLists(node.strings, toNode.strings); |
| 9363 } |
| 9364 |
| 9365 @override |
| 9366 bool visitAnnotation(Annotation node) { |
| 9367 Annotation toNode = this._toNode as Annotation; |
| 9368 if (_and(_isEqualTokens(node.atSign, toNode.atSign), |
| 9369 _isEqualNodes(node.name, toNode.name), |
| 9370 _isEqualTokens(node.period, toNode.period), |
| 9371 _isEqualNodes(node.constructorName, toNode.constructorName), |
| 9372 _isEqualNodes(node.arguments, toNode.arguments))) { |
| 9373 toNode.element = node.element; |
| 9374 return true; |
| 9375 } |
| 9376 return false; |
| 9377 } |
| 9378 |
| 9379 @override |
| 9380 bool visitArgumentList(ArgumentList node) { |
| 9381 ArgumentList toNode = this._toNode as ArgumentList; |
| 9382 return _and(_isEqualTokens(node.leftParenthesis, toNode.leftParenthesis), |
| 9383 _isEqualNodeLists(node.arguments, toNode.arguments), |
| 9384 _isEqualTokens(node.rightParenthesis, toNode.rightParenthesis)); |
| 9385 } |
| 9386 |
| 9387 @override |
| 9388 bool visitAsExpression(AsExpression node) { |
| 9389 AsExpression toNode = this._toNode as AsExpression; |
| 9390 if (_and(_isEqualNodes(node.expression, toNode.expression), |
| 9391 _isEqualTokens(node.asOperator, toNode.asOperator), |
| 9392 _isEqualNodes(node.type, toNode.type))) { |
| 9393 toNode.propagatedType = node.propagatedType; |
| 9394 toNode.staticType = node.staticType; |
| 9395 return true; |
| 9396 } |
| 9397 return false; |
| 9398 } |
| 9399 |
| 9400 @override |
| 9401 bool visitAssertStatement(AssertStatement node) { |
| 9402 AssertStatement toNode = this._toNode as AssertStatement; |
| 9403 return _and(_isEqualTokens(node.assertKeyword, toNode.assertKeyword), |
| 9404 _isEqualTokens(node.leftParenthesis, toNode.leftParenthesis), |
| 9405 _isEqualNodes(node.condition, toNode.condition), |
| 9406 _isEqualTokens(node.rightParenthesis, toNode.rightParenthesis), |
| 9407 _isEqualTokens(node.semicolon, toNode.semicolon)); |
| 9408 } |
| 9409 |
| 9410 @override |
| 9411 bool visitAssignmentExpression(AssignmentExpression node) { |
| 9412 AssignmentExpression toNode = this._toNode as AssignmentExpression; |
| 9413 if (_and(_isEqualNodes(node.leftHandSide, toNode.leftHandSide), |
| 9414 _isEqualTokens(node.operator, toNode.operator), |
| 9415 _isEqualNodes(node.rightHandSide, toNode.rightHandSide))) { |
| 9416 toNode.propagatedElement = node.propagatedElement; |
| 9417 toNode.propagatedType = node.propagatedType; |
| 9418 toNode.staticElement = node.staticElement; |
| 9419 toNode.staticType = node.staticType; |
| 9420 return true; |
| 9421 } |
| 9422 return false; |
| 9423 } |
| 9424 |
| 9425 @override |
| 9426 bool visitAwaitExpression(AwaitExpression node) { |
| 9427 AwaitExpression toNode = this._toNode as AwaitExpression; |
| 9428 if (_and(_isEqualTokens(node.awaitKeyword, toNode.awaitKeyword), |
| 9429 _isEqualNodes(node.expression, toNode.expression))) { |
| 9430 toNode.propagatedType = node.propagatedType; |
| 9431 toNode.staticType = node.staticType; |
| 9432 return true; |
| 9433 } |
| 9434 return false; |
| 9435 } |
| 9436 |
| 9437 @override |
| 9438 bool visitBinaryExpression(BinaryExpression node) { |
| 9439 BinaryExpression toNode = this._toNode as BinaryExpression; |
| 9440 if (_and(_isEqualNodes(node.leftOperand, toNode.leftOperand), |
| 9441 _isEqualTokens(node.operator, toNode.operator), |
| 9442 _isEqualNodes(node.rightOperand, toNode.rightOperand))) { |
| 9443 toNode.propagatedElement = node.propagatedElement; |
| 9444 toNode.propagatedType = node.propagatedType; |
| 9445 toNode.staticElement = node.staticElement; |
| 9446 toNode.staticType = node.staticType; |
| 9447 return true; |
| 9448 } |
| 9449 return false; |
| 9450 } |
| 9451 |
| 9452 @override |
| 9453 bool visitBlock(Block node) { |
| 9454 Block toNode = this._toNode as Block; |
| 9455 return _and(_isEqualTokens(node.leftBracket, toNode.leftBracket), |
| 9456 _isEqualNodeLists(node.statements, toNode.statements), |
| 9457 _isEqualTokens(node.rightBracket, toNode.rightBracket)); |
| 9458 } |
| 9459 |
| 9460 @override |
| 9461 bool visitBlockFunctionBody(BlockFunctionBody node) { |
| 9462 BlockFunctionBody toNode = this._toNode as BlockFunctionBody; |
| 9463 return _isEqualNodes(node.block, toNode.block); |
| 9464 } |
| 9465 |
| 9466 @override |
| 9467 bool visitBooleanLiteral(BooleanLiteral node) { |
| 9468 BooleanLiteral toNode = this._toNode as BooleanLiteral; |
| 9469 if (_and(_isEqualTokens(node.literal, toNode.literal), |
| 9470 node.value == toNode.value)) { |
| 9471 toNode.propagatedType = node.propagatedType; |
| 9472 toNode.staticType = node.staticType; |
| 9473 return true; |
| 9474 } |
| 9475 return false; |
| 9476 } |
| 9477 |
| 9478 @override |
| 9479 bool visitBreakStatement(BreakStatement node) { |
| 9480 BreakStatement toNode = this._toNode as BreakStatement; |
| 9481 if (_and(_isEqualTokens(node.breakKeyword, toNode.breakKeyword), |
| 9482 _isEqualNodes(node.label, toNode.label), |
| 9483 _isEqualTokens(node.semicolon, toNode.semicolon))) { |
| 9484 // TODO(paulberry): map node.target to toNode.target. |
| 9485 return true; |
| 9486 } |
| 9487 return false; |
| 9488 } |
| 9489 |
| 9490 @override |
| 9491 bool visitCascadeExpression(CascadeExpression node) { |
| 9492 CascadeExpression toNode = this._toNode as CascadeExpression; |
| 9493 if (_and(_isEqualNodes(node.target, toNode.target), |
| 9494 _isEqualNodeLists(node.cascadeSections, toNode.cascadeSections))) { |
| 9495 toNode.propagatedType = node.propagatedType; |
| 9496 toNode.staticType = node.staticType; |
| 9497 return true; |
| 9498 } |
| 9499 return false; |
| 9500 } |
| 9501 |
| 9502 @override |
| 9503 bool visitCatchClause(CatchClause node) { |
| 9504 CatchClause toNode = this._toNode as CatchClause; |
| 9505 return _and(_isEqualTokens(node.onKeyword, toNode.onKeyword), |
| 9506 _isEqualNodes(node.exceptionType, toNode.exceptionType), |
| 9507 _isEqualTokens(node.catchKeyword, toNode.catchKeyword), |
| 9508 _isEqualTokens(node.leftParenthesis, toNode.leftParenthesis), |
| 9509 _isEqualNodes(node.exceptionParameter, toNode.exceptionParameter), |
| 9510 _isEqualTokens(node.comma, toNode.comma), |
| 9511 _isEqualNodes(node.stackTraceParameter, toNode.stackTraceParameter), |
| 9512 _isEqualTokens(node.rightParenthesis, toNode.rightParenthesis), |
| 9513 _isEqualNodes(node.body, toNode.body)); |
| 9514 } |
| 9515 |
| 9516 @override |
| 9517 bool visitClassDeclaration(ClassDeclaration node) { |
| 9518 ClassDeclaration toNode = this._toNode as ClassDeclaration; |
| 9519 return _and( |
| 9520 _isEqualNodes(node.documentationComment, toNode.documentationComment), |
| 9521 _isEqualNodeLists(node.metadata, toNode.metadata), |
| 9522 _isEqualTokens(node.abstractKeyword, toNode.abstractKeyword), |
| 9523 _isEqualTokens(node.classKeyword, toNode.classKeyword), |
| 9524 _isEqualNodes(node.name, toNode.name), |
| 9525 _isEqualNodes(node.typeParameters, toNode.typeParameters), |
| 9526 _isEqualNodes(node.extendsClause, toNode.extendsClause), |
| 9527 _isEqualNodes(node.withClause, toNode.withClause), |
| 9528 _isEqualNodes(node.implementsClause, toNode.implementsClause), |
| 9529 _isEqualTokens(node.leftBracket, toNode.leftBracket), |
| 9530 _isEqualNodeLists(node.members, toNode.members), |
| 9531 _isEqualTokens(node.rightBracket, toNode.rightBracket)); |
| 9532 } |
| 9533 |
| 9534 @override |
| 9535 bool visitClassTypeAlias(ClassTypeAlias node) { |
| 9536 ClassTypeAlias toNode = this._toNode as ClassTypeAlias; |
| 9537 return _and( |
| 9538 _isEqualNodes(node.documentationComment, toNode.documentationComment), |
| 9539 _isEqualNodeLists(node.metadata, toNode.metadata), |
| 9540 _isEqualTokens(node.typedefKeyword, toNode.typedefKeyword), |
| 9541 _isEqualNodes(node.name, toNode.name), |
| 9542 _isEqualNodes(node.typeParameters, toNode.typeParameters), |
| 9543 _isEqualTokens(node.equals, toNode.equals), |
| 9544 _isEqualTokens(node.abstractKeyword, toNode.abstractKeyword), |
| 9545 _isEqualNodes(node.superclass, toNode.superclass), |
| 9546 _isEqualNodes(node.withClause, toNode.withClause), |
| 9547 _isEqualNodes(node.implementsClause, toNode.implementsClause), |
| 9548 _isEqualTokens(node.semicolon, toNode.semicolon)); |
| 9549 } |
| 9550 |
| 9551 @override |
| 9552 bool visitComment(Comment node) { |
| 9553 Comment toNode = this._toNode as Comment; |
| 9554 return _isEqualNodeLists(node.references, toNode.references); |
| 9555 } |
| 9556 |
| 9557 @override |
| 9558 bool visitCommentReference(CommentReference node) { |
| 9559 CommentReference toNode = this._toNode as CommentReference; |
| 9560 return _and(_isEqualTokens(node.newKeyword, toNode.newKeyword), |
| 9561 _isEqualNodes(node.identifier, toNode.identifier)); |
| 9562 } |
| 9563 |
| 9564 @override |
| 9565 bool visitCompilationUnit(CompilationUnit node) { |
| 9566 CompilationUnit toNode = this._toNode as CompilationUnit; |
| 9567 if (_and(_isEqualTokens(node.beginToken, toNode.beginToken), |
| 9568 _isEqualNodes(node.scriptTag, toNode.scriptTag), |
| 9569 _isEqualNodeLists(node.directives, toNode.directives), |
| 9570 _isEqualNodeLists(node.declarations, toNode.declarations), |
| 9571 _isEqualTokens(node.endToken, toNode.endToken))) { |
| 9572 toNode.element = node.element; |
| 9573 return true; |
| 9574 } |
| 9575 return false; |
| 9576 } |
| 9577 |
| 9578 @override |
| 9579 bool visitConditionalExpression(ConditionalExpression node) { |
| 9580 ConditionalExpression toNode = this._toNode as ConditionalExpression; |
| 9581 if (_and(_isEqualNodes(node.condition, toNode.condition), |
| 9582 _isEqualTokens(node.question, toNode.question), |
| 9583 _isEqualNodes(node.thenExpression, toNode.thenExpression), |
| 9584 _isEqualTokens(node.colon, toNode.colon), |
| 9585 _isEqualNodes(node.elseExpression, toNode.elseExpression))) { |
| 9586 toNode.propagatedType = node.propagatedType; |
| 9587 toNode.staticType = node.staticType; |
| 9588 return true; |
| 9589 } |
| 9590 return false; |
| 9591 } |
| 9592 |
| 9593 @override |
| 9594 bool visitConstructorDeclaration(ConstructorDeclaration node) { |
| 9595 ConstructorDeclaration toNode = this._toNode as ConstructorDeclaration; |
| 9596 if (_and( |
| 9597 _isEqualNodes(node.documentationComment, toNode.documentationComment), |
| 9598 _isEqualNodeLists(node.metadata, toNode.metadata), |
| 9599 _isEqualTokens(node.externalKeyword, toNode.externalKeyword), |
| 9600 _isEqualTokens(node.constKeyword, toNode.constKeyword), |
| 9601 _isEqualTokens(node.factoryKeyword, toNode.factoryKeyword), |
| 9602 _isEqualNodes(node.returnType, toNode.returnType), |
| 9603 _isEqualTokens(node.period, toNode.period), |
| 9604 _isEqualNodes(node.name, toNode.name), |
| 9605 _isEqualNodes(node.parameters, toNode.parameters), |
| 9606 _isEqualTokens(node.separator, toNode.separator), |
| 9607 _isEqualNodeLists(node.initializers, toNode.initializers), |
| 9608 _isEqualNodes(node.redirectedConstructor, toNode.redirectedConstructor), |
| 9609 _isEqualNodes(node.body, toNode.body))) { |
| 9610 toNode.element = node.element; |
| 9611 return true; |
| 9612 } |
| 9613 return false; |
| 9614 } |
| 9615 |
| 9616 @override |
| 9617 bool visitConstructorFieldInitializer(ConstructorFieldInitializer node) { |
| 9618 ConstructorFieldInitializer toNode = |
| 9619 this._toNode as ConstructorFieldInitializer; |
| 9620 return _and(_isEqualTokens(node.thisKeyword, toNode.thisKeyword), |
| 9621 _isEqualTokens(node.period, toNode.period), |
| 9622 _isEqualNodes(node.fieldName, toNode.fieldName), |
| 9623 _isEqualTokens(node.equals, toNode.equals), |
| 9624 _isEqualNodes(node.expression, toNode.expression)); |
| 9625 } |
| 9626 |
| 9627 @override |
| 9628 bool visitConstructorName(ConstructorName node) { |
| 9629 ConstructorName toNode = this._toNode as ConstructorName; |
| 9630 if (_and(_isEqualNodes(node.type, toNode.type), |
| 9631 _isEqualTokens(node.period, toNode.period), |
| 9632 _isEqualNodes(node.name, toNode.name))) { |
| 9633 toNode.staticElement = node.staticElement; |
| 9634 return true; |
| 9635 } |
| 9636 return false; |
| 9637 } |
| 9638 |
| 9639 @override |
| 9640 bool visitContinueStatement(ContinueStatement node) { |
| 9641 ContinueStatement toNode = this._toNode as ContinueStatement; |
| 9642 if (_and(_isEqualTokens(node.continueKeyword, toNode.continueKeyword), |
| 9643 _isEqualNodes(node.label, toNode.label), |
| 9644 _isEqualTokens(node.semicolon, toNode.semicolon))) { |
| 9645 // TODO(paulberry): map node.target to toNode.target. |
| 9646 return true; |
| 9647 } |
| 9648 return false; |
| 9649 } |
| 9650 |
| 9651 @override |
| 9652 bool visitDeclaredIdentifier(DeclaredIdentifier node) { |
| 9653 DeclaredIdentifier toNode = this._toNode as DeclaredIdentifier; |
| 9654 return _and( |
| 9655 _isEqualNodes(node.documentationComment, toNode.documentationComment), |
| 9656 _isEqualNodeLists(node.metadata, toNode.metadata), |
| 9657 _isEqualTokens(node.keyword, toNode.keyword), |
| 9658 _isEqualNodes(node.type, toNode.type), |
| 9659 _isEqualNodes(node.identifier, toNode.identifier)); |
| 9660 } |
| 9661 |
| 9662 @override |
| 9663 bool visitDefaultFormalParameter(DefaultFormalParameter node) { |
| 9664 DefaultFormalParameter toNode = this._toNode as DefaultFormalParameter; |
| 9665 return _and(_isEqualNodes(node.parameter, toNode.parameter), |
| 9666 node.kind == toNode.kind, |
| 9667 _isEqualTokens(node.separator, toNode.separator), |
| 9668 _isEqualNodes(node.defaultValue, toNode.defaultValue)); |
| 9669 } |
| 9670 |
| 9671 @override |
| 9672 bool visitDoStatement(DoStatement node) { |
| 9673 DoStatement toNode = this._toNode as DoStatement; |
| 9674 return _and(_isEqualTokens(node.doKeyword, toNode.doKeyword), |
| 9675 _isEqualNodes(node.body, toNode.body), |
| 9676 _isEqualTokens(node.whileKeyword, toNode.whileKeyword), |
| 9677 _isEqualTokens(node.leftParenthesis, toNode.leftParenthesis), |
| 9678 _isEqualNodes(node.condition, toNode.condition), |
| 9679 _isEqualTokens(node.rightParenthesis, toNode.rightParenthesis), |
| 9680 _isEqualTokens(node.semicolon, toNode.semicolon)); |
| 9681 } |
| 9682 |
| 9683 @override |
| 9684 bool visitDoubleLiteral(DoubleLiteral node) { |
| 9685 DoubleLiteral toNode = this._toNode as DoubleLiteral; |
| 9686 if (_and(_isEqualTokens(node.literal, toNode.literal), |
| 9687 node.value == toNode.value)) { |
| 9688 toNode.propagatedType = node.propagatedType; |
| 9689 toNode.staticType = node.staticType; |
| 9690 return true; |
| 9691 } |
| 9692 return false; |
| 9693 } |
| 9694 |
| 9695 @override |
| 9696 bool visitEmptyFunctionBody(EmptyFunctionBody node) { |
| 9697 EmptyFunctionBody toNode = this._toNode as EmptyFunctionBody; |
| 9698 return _isEqualTokens(node.semicolon, toNode.semicolon); |
| 9699 } |
| 9700 |
| 9701 @override |
| 9702 bool visitEmptyStatement(EmptyStatement node) { |
| 9703 EmptyStatement toNode = this._toNode as EmptyStatement; |
| 9704 return _isEqualTokens(node.semicolon, toNode.semicolon); |
| 9705 } |
| 9706 |
| 9707 @override |
| 9708 bool visitEnumConstantDeclaration(EnumConstantDeclaration node) { |
| 9709 EnumConstantDeclaration toNode = this._toNode as EnumConstantDeclaration; |
| 9710 return _and( |
| 9711 _isEqualNodes(node.documentationComment, toNode.documentationComment), |
| 9712 _isEqualNodeLists(node.metadata, toNode.metadata), |
| 9713 _isEqualNodes(node.name, toNode.name)); |
| 9714 } |
| 9715 |
| 9716 @override |
| 9717 bool visitEnumDeclaration(EnumDeclaration node) { |
| 9718 EnumDeclaration toNode = this._toNode as EnumDeclaration; |
| 9719 return _and( |
| 9720 _isEqualNodes(node.documentationComment, toNode.documentationComment), |
| 9721 _isEqualNodeLists(node.metadata, toNode.metadata), |
| 9722 _isEqualTokens(node.enumKeyword, toNode.enumKeyword), |
| 9723 _isEqualNodes(node.name, toNode.name), |
| 9724 _isEqualTokens(node.leftBracket, toNode.leftBracket), |
| 9725 _isEqualNodeLists(node.constants, toNode.constants), |
| 9726 _isEqualTokens(node.rightBracket, toNode.rightBracket)); |
| 9727 } |
| 9728 |
| 9729 @override |
| 9730 bool visitExportDirective(ExportDirective node) { |
| 9731 ExportDirective toNode = this._toNode as ExportDirective; |
| 9732 if (_and( |
| 9733 _isEqualNodes(node.documentationComment, toNode.documentationComment), |
| 9734 _isEqualNodeLists(node.metadata, toNode.metadata), |
| 9735 _isEqualTokens(node.keyword, toNode.keyword), |
| 9736 _isEqualNodes(node.uri, toNode.uri), |
| 9737 _isEqualNodeLists(node.combinators, toNode.combinators), |
| 9738 _isEqualTokens(node.semicolon, toNode.semicolon))) { |
| 9739 toNode.element = node.element; |
| 9740 return true; |
| 9741 } |
| 9742 return false; |
| 9743 } |
| 9744 |
| 9745 @override |
| 9746 bool visitExpressionFunctionBody(ExpressionFunctionBody node) { |
| 9747 ExpressionFunctionBody toNode = this._toNode as ExpressionFunctionBody; |
| 9748 return _and( |
| 9749 _isEqualTokens(node.functionDefinition, toNode.functionDefinition), |
| 9750 _isEqualNodes(node.expression, toNode.expression), |
| 9751 _isEqualTokens(node.semicolon, toNode.semicolon)); |
| 9752 } |
| 9753 |
| 9754 @override |
| 9755 bool visitExpressionStatement(ExpressionStatement node) { |
| 9756 ExpressionStatement toNode = this._toNode as ExpressionStatement; |
| 9757 return _and(_isEqualNodes(node.expression, toNode.expression), |
| 9758 _isEqualTokens(node.semicolon, toNode.semicolon)); |
| 9759 } |
| 9760 |
| 9761 @override |
| 9762 bool visitExtendsClause(ExtendsClause node) { |
| 9763 ExtendsClause toNode = this._toNode as ExtendsClause; |
| 9764 return _and(_isEqualTokens(node.extendsKeyword, toNode.extendsKeyword), |
| 9765 _isEqualNodes(node.superclass, toNode.superclass)); |
| 9766 } |
| 9767 |
| 9768 @override |
| 9769 bool visitFieldDeclaration(FieldDeclaration node) { |
| 9770 FieldDeclaration toNode = this._toNode as FieldDeclaration; |
| 9771 return _and( |
| 9772 _isEqualNodes(node.documentationComment, toNode.documentationComment), |
| 9773 _isEqualNodeLists(node.metadata, toNode.metadata), |
| 9774 _isEqualTokens(node.staticKeyword, toNode.staticKeyword), |
| 9775 _isEqualNodes(node.fields, toNode.fields), |
| 9776 _isEqualTokens(node.semicolon, toNode.semicolon)); |
| 9777 } |
| 9778 |
| 9779 @override |
| 9780 bool visitFieldFormalParameter(FieldFormalParameter node) { |
| 9781 FieldFormalParameter toNode = this._toNode as FieldFormalParameter; |
| 9782 return _and( |
| 9783 _isEqualNodes(node.documentationComment, toNode.documentationComment), |
| 9784 _isEqualNodeLists(node.metadata, toNode.metadata), |
| 9785 _isEqualTokens(node.keyword, toNode.keyword), |
| 9786 _isEqualNodes(node.type, toNode.type), |
| 9787 _isEqualTokens(node.thisKeyword, toNode.thisKeyword), |
| 9788 _isEqualTokens(node.period, toNode.period), |
| 9789 _isEqualNodes(node.identifier, toNode.identifier)); |
| 9790 } |
| 9791 |
| 9792 @override |
| 9793 bool visitForEachStatement(ForEachStatement node) { |
| 9794 ForEachStatement toNode = this._toNode as ForEachStatement; |
| 9795 return _and(_isEqualTokens(node.forKeyword, toNode.forKeyword), |
| 9796 _isEqualTokens(node.leftParenthesis, toNode.leftParenthesis), |
| 9797 _isEqualNodes(node.loopVariable, toNode.loopVariable), |
| 9798 _isEqualTokens(node.inKeyword, toNode.inKeyword), |
| 9799 _isEqualNodes(node.iterable, toNode.iterable), |
| 9800 _isEqualTokens(node.rightParenthesis, toNode.rightParenthesis), |
| 9801 _isEqualNodes(node.body, toNode.body)); |
| 9802 } |
| 9803 |
| 9804 @override |
| 9805 bool visitFormalParameterList(FormalParameterList node) { |
| 9806 FormalParameterList toNode = this._toNode as FormalParameterList; |
| 9807 return _and(_isEqualTokens(node.leftParenthesis, toNode.leftParenthesis), |
| 9808 _isEqualNodeLists(node.parameters, toNode.parameters), |
| 9809 _isEqualTokens(node.leftDelimiter, toNode.leftDelimiter), |
| 9810 _isEqualTokens(node.rightDelimiter, toNode.rightDelimiter), |
| 9811 _isEqualTokens(node.rightParenthesis, toNode.rightParenthesis)); |
| 9812 } |
| 9813 |
| 9814 @override |
| 9815 bool visitForStatement(ForStatement node) { |
| 9816 ForStatement toNode = this._toNode as ForStatement; |
| 9817 return _and(_isEqualTokens(node.forKeyword, toNode.forKeyword), |
| 9818 _isEqualTokens(node.leftParenthesis, toNode.leftParenthesis), |
| 9819 _isEqualNodes(node.variables, toNode.variables), |
| 9820 _isEqualNodes(node.initialization, toNode.initialization), |
| 9821 _isEqualTokens(node.leftSeparator, toNode.leftSeparator), |
| 9822 _isEqualNodes(node.condition, toNode.condition), |
| 9823 _isEqualTokens(node.rightSeparator, toNode.rightSeparator), |
| 9824 _isEqualNodeLists(node.updaters, toNode.updaters), |
| 9825 _isEqualTokens(node.rightParenthesis, toNode.rightParenthesis), |
| 9826 _isEqualNodes(node.body, toNode.body)); |
| 9827 } |
| 9828 |
| 9829 @override |
| 9830 bool visitFunctionDeclaration(FunctionDeclaration node) { |
| 9831 FunctionDeclaration toNode = this._toNode as FunctionDeclaration; |
| 9832 return _and( |
| 9833 _isEqualNodes(node.documentationComment, toNode.documentationComment), |
| 9834 _isEqualNodeLists(node.metadata, toNode.metadata), |
| 9835 _isEqualTokens(node.externalKeyword, toNode.externalKeyword), |
| 9836 _isEqualNodes(node.returnType, toNode.returnType), |
| 9837 _isEqualTokens(node.propertyKeyword, toNode.propertyKeyword), |
| 9838 _isEqualNodes(node.name, toNode.name), |
| 9839 _isEqualNodes(node.functionExpression, toNode.functionExpression)); |
| 9840 } |
| 9841 |
| 9842 @override |
| 9843 bool visitFunctionDeclarationStatement(FunctionDeclarationStatement node) { |
| 9844 FunctionDeclarationStatement toNode = |
| 9845 this._toNode as FunctionDeclarationStatement; |
| 9846 return _isEqualNodes(node.functionDeclaration, toNode.functionDeclaration); |
| 9847 } |
| 9848 |
| 9849 @override |
| 9850 bool visitFunctionExpression(FunctionExpression node) { |
| 9851 FunctionExpression toNode = this._toNode as FunctionExpression; |
| 9852 if (_and(_isEqualNodes(node.parameters, toNode.parameters), |
| 9853 _isEqualNodes(node.body, toNode.body))) { |
| 9854 toNode.element = node.element; |
| 9855 toNode.propagatedType = node.propagatedType; |
| 9856 toNode.staticType = node.staticType; |
| 9857 return true; |
| 9858 } |
| 9859 return false; |
| 9860 } |
| 9861 |
| 9862 @override |
| 9863 bool visitFunctionExpressionInvocation(FunctionExpressionInvocation node) { |
| 9864 FunctionExpressionInvocation toNode = |
| 9865 this._toNode as FunctionExpressionInvocation; |
| 9866 if (_and(_isEqualNodes(node.function, toNode.function), |
| 9867 _isEqualNodes(node.argumentList, toNode.argumentList))) { |
| 9868 toNode.propagatedElement = node.propagatedElement; |
| 9869 toNode.propagatedType = node.propagatedType; |
| 9870 toNode.staticElement = node.staticElement; |
| 9871 toNode.staticType = node.staticType; |
| 9872 return true; |
| 9873 } |
| 9874 return false; |
| 9875 } |
| 9876 |
| 9877 @override |
| 9878 bool visitFunctionTypeAlias(FunctionTypeAlias node) { |
| 9879 FunctionTypeAlias toNode = this._toNode as FunctionTypeAlias; |
| 9880 return _and( |
| 9881 _isEqualNodes(node.documentationComment, toNode.documentationComment), |
| 9882 _isEqualNodeLists(node.metadata, toNode.metadata), |
| 9883 _isEqualTokens(node.typedefKeyword, toNode.typedefKeyword), |
| 9884 _isEqualNodes(node.returnType, toNode.returnType), |
| 9885 _isEqualNodes(node.name, toNode.name), |
| 9886 _isEqualNodes(node.typeParameters, toNode.typeParameters), |
| 9887 _isEqualNodes(node.parameters, toNode.parameters), |
| 9888 _isEqualTokens(node.semicolon, toNode.semicolon)); |
| 9889 } |
| 9890 |
| 9891 @override |
| 9892 bool visitFunctionTypedFormalParameter(FunctionTypedFormalParameter node) { |
| 9893 FunctionTypedFormalParameter toNode = |
| 9894 this._toNode as FunctionTypedFormalParameter; |
| 9895 return _and( |
| 9896 _isEqualNodes(node.documentationComment, toNode.documentationComment), |
| 9897 _isEqualNodeLists(node.metadata, toNode.metadata), |
| 9898 _isEqualNodes(node.returnType, toNode.returnType), |
| 9899 _isEqualNodes(node.identifier, toNode.identifier), |
| 9900 _isEqualNodes(node.parameters, toNode.parameters)); |
| 9901 } |
| 9902 |
| 9903 @override |
| 9904 bool visitHideCombinator(HideCombinator node) { |
| 9905 HideCombinator toNode = this._toNode as HideCombinator; |
| 9906 return _and(_isEqualTokens(node.keyword, toNode.keyword), |
| 9907 _isEqualNodeLists(node.hiddenNames, toNode.hiddenNames)); |
| 9908 } |
| 9909 |
| 9910 @override |
| 9911 bool visitIfStatement(IfStatement node) { |
| 9912 IfStatement toNode = this._toNode as IfStatement; |
| 9913 return _and(_isEqualTokens(node.ifKeyword, toNode.ifKeyword), |
| 9914 _isEqualTokens(node.leftParenthesis, toNode.leftParenthesis), |
| 9915 _isEqualNodes(node.condition, toNode.condition), |
| 9916 _isEqualTokens(node.rightParenthesis, toNode.rightParenthesis), |
| 9917 _isEqualNodes(node.thenStatement, toNode.thenStatement), |
| 9918 _isEqualTokens(node.elseKeyword, toNode.elseKeyword), |
| 9919 _isEqualNodes(node.elseStatement, toNode.elseStatement)); |
| 9920 } |
| 9921 |
| 9922 @override |
| 9923 bool visitImplementsClause(ImplementsClause node) { |
| 9924 ImplementsClause toNode = this._toNode as ImplementsClause; |
| 9925 return _and( |
| 9926 _isEqualTokens(node.implementsKeyword, toNode.implementsKeyword), |
| 9927 _isEqualNodeLists(node.interfaces, toNode.interfaces)); |
| 9928 } |
| 9929 |
| 9930 @override |
| 9931 bool visitImportDirective(ImportDirective node) { |
| 9932 ImportDirective toNode = this._toNode as ImportDirective; |
| 9933 if (_and( |
| 9934 _isEqualNodes(node.documentationComment, toNode.documentationComment), |
| 9935 _isEqualNodeLists(node.metadata, toNode.metadata), |
| 9936 _isEqualTokens(node.keyword, toNode.keyword), |
| 9937 _isEqualNodes(node.uri, toNode.uri), |
| 9938 _isEqualTokens(node.asKeyword, toNode.asKeyword), |
| 9939 _isEqualNodes(node.prefix, toNode.prefix), |
| 9940 _isEqualNodeLists(node.combinators, toNode.combinators), |
| 9941 _isEqualTokens(node.semicolon, toNode.semicolon))) { |
| 9942 toNode.element = node.element; |
| 9943 return true; |
| 9944 } |
| 9945 return false; |
| 9946 } |
| 9947 |
| 9948 @override |
| 9949 bool visitIndexExpression(IndexExpression node) { |
| 9950 IndexExpression toNode = this._toNode as IndexExpression; |
| 9951 if (_and(_isEqualNodes(node.target, toNode.target), |
| 9952 _isEqualTokens(node.leftBracket, toNode.leftBracket), |
| 9953 _isEqualNodes(node.index, toNode.index), |
| 9954 _isEqualTokens(node.rightBracket, toNode.rightBracket))) { |
| 9955 toNode.auxiliaryElements = node.auxiliaryElements; |
| 9956 toNode.propagatedElement = node.propagatedElement; |
| 9957 toNode.propagatedType = node.propagatedType; |
| 9958 toNode.staticElement = node.staticElement; |
| 9959 toNode.staticType = node.staticType; |
| 9960 return true; |
| 9961 } |
| 9962 return false; |
| 9963 } |
| 9964 |
| 9965 @override |
| 9966 bool visitInstanceCreationExpression(InstanceCreationExpression node) { |
| 9967 InstanceCreationExpression toNode = |
| 9968 this._toNode as InstanceCreationExpression; |
| 9969 if (_and(_isEqualTokens(node.keyword, toNode.keyword), |
| 9970 _isEqualNodes(node.constructorName, toNode.constructorName), |
| 9971 _isEqualNodes(node.argumentList, toNode.argumentList))) { |
| 9972 toNode.propagatedType = node.propagatedType; |
| 9973 toNode.staticElement = node.staticElement; |
| 9974 toNode.staticType = node.staticType; |
| 9975 return true; |
| 9976 } |
| 9977 return false; |
| 9978 } |
| 9979 |
| 9980 @override |
| 9981 bool visitIntegerLiteral(IntegerLiteral node) { |
| 9982 IntegerLiteral toNode = this._toNode as IntegerLiteral; |
| 9983 if (_and(_isEqualTokens(node.literal, toNode.literal), |
| 9984 node.value == toNode.value)) { |
| 9985 toNode.propagatedType = node.propagatedType; |
| 9986 toNode.staticType = node.staticType; |
| 9987 return true; |
| 9988 } |
| 9989 return false; |
| 9990 } |
| 9991 |
| 9992 @override |
| 9993 bool visitInterpolationExpression(InterpolationExpression node) { |
| 9994 InterpolationExpression toNode = this._toNode as InterpolationExpression; |
| 9995 return _and(_isEqualTokens(node.leftBracket, toNode.leftBracket), |
| 9996 _isEqualNodes(node.expression, toNode.expression), |
| 9997 _isEqualTokens(node.rightBracket, toNode.rightBracket)); |
| 9998 } |
| 9999 |
| 10000 @override |
| 10001 bool visitInterpolationString(InterpolationString node) { |
| 10002 InterpolationString toNode = this._toNode as InterpolationString; |
| 10003 return _and(_isEqualTokens(node.contents, toNode.contents), |
| 10004 node.value == toNode.value); |
| 10005 } |
| 10006 |
| 10007 @override |
| 10008 bool visitIsExpression(IsExpression node) { |
| 10009 IsExpression toNode = this._toNode as IsExpression; |
| 10010 if (_and(_isEqualNodes(node.expression, toNode.expression), |
| 10011 _isEqualTokens(node.isOperator, toNode.isOperator), |
| 10012 _isEqualTokens(node.notOperator, toNode.notOperator), |
| 10013 _isEqualNodes(node.type, toNode.type))) { |
| 10014 toNode.propagatedType = node.propagatedType; |
| 10015 toNode.staticType = node.staticType; |
| 10016 return true; |
| 10017 } |
| 10018 return false; |
| 10019 } |
| 10020 |
| 10021 @override |
| 10022 bool visitLabel(Label node) { |
| 10023 Label toNode = this._toNode as Label; |
| 10024 return _and(_isEqualNodes(node.label, toNode.label), |
| 10025 _isEqualTokens(node.colon, toNode.colon)); |
| 10026 } |
| 10027 |
| 10028 @override |
| 10029 bool visitLabeledStatement(LabeledStatement node) { |
| 10030 LabeledStatement toNode = this._toNode as LabeledStatement; |
| 10031 return _and(_isEqualNodeLists(node.labels, toNode.labels), |
| 10032 _isEqualNodes(node.statement, toNode.statement)); |
| 10033 } |
| 10034 |
| 10035 @override |
| 10036 bool visitLibraryDirective(LibraryDirective node) { |
| 10037 LibraryDirective toNode = this._toNode as LibraryDirective; |
| 10038 if (_and( |
| 10039 _isEqualNodes(node.documentationComment, toNode.documentationComment), |
| 10040 _isEqualNodeLists(node.metadata, toNode.metadata), |
| 10041 _isEqualTokens(node.libraryKeyword, toNode.libraryKeyword), |
| 10042 _isEqualNodes(node.name, toNode.name), |
| 10043 _isEqualTokens(node.semicolon, toNode.semicolon))) { |
| 10044 toNode.element = node.element; |
| 10045 return true; |
| 10046 } |
| 10047 return false; |
| 10048 } |
| 10049 |
| 10050 @override |
| 10051 bool visitLibraryIdentifier(LibraryIdentifier node) { |
| 10052 LibraryIdentifier toNode = this._toNode as LibraryIdentifier; |
| 10053 if (_isEqualNodeLists(node.components, toNode.components)) { |
| 10054 toNode.propagatedType = node.propagatedType; |
| 10055 toNode.staticType = node.staticType; |
| 10056 return true; |
| 10057 } |
| 10058 return false; |
| 10059 } |
| 10060 |
| 10061 @override |
| 10062 bool visitListLiteral(ListLiteral node) { |
| 10063 ListLiteral toNode = this._toNode as ListLiteral; |
| 10064 if (_and(_isEqualTokens(node.constKeyword, toNode.constKeyword), |
| 10065 _isEqualNodes(node.typeArguments, toNode.typeArguments), |
| 10066 _isEqualTokens(node.leftBracket, toNode.leftBracket), |
| 10067 _isEqualNodeLists(node.elements, toNode.elements), |
| 10068 _isEqualTokens(node.rightBracket, toNode.rightBracket))) { |
| 10069 toNode.propagatedType = node.propagatedType; |
| 10070 toNode.staticType = node.staticType; |
| 10071 return true; |
| 10072 } |
| 10073 return false; |
| 10074 } |
| 10075 |
| 10076 @override |
| 10077 bool visitMapLiteral(MapLiteral node) { |
| 10078 MapLiteral toNode = this._toNode as MapLiteral; |
| 10079 if (_and(_isEqualTokens(node.constKeyword, toNode.constKeyword), |
| 10080 _isEqualNodes(node.typeArguments, toNode.typeArguments), |
| 10081 _isEqualTokens(node.leftBracket, toNode.leftBracket), |
| 10082 _isEqualNodeLists(node.entries, toNode.entries), |
| 10083 _isEqualTokens(node.rightBracket, toNode.rightBracket))) { |
| 10084 toNode.propagatedType = node.propagatedType; |
| 10085 toNode.staticType = node.staticType; |
| 10086 return true; |
| 10087 } |
| 10088 return false; |
| 10089 } |
| 10090 |
| 10091 @override |
| 10092 bool visitMapLiteralEntry(MapLiteralEntry node) { |
| 10093 MapLiteralEntry toNode = this._toNode as MapLiteralEntry; |
| 10094 return _and(_isEqualNodes(node.key, toNode.key), |
| 10095 _isEqualTokens(node.separator, toNode.separator), |
| 10096 _isEqualNodes(node.value, toNode.value)); |
| 10097 } |
| 10098 |
| 10099 @override |
| 10100 bool visitMethodDeclaration(MethodDeclaration node) { |
| 10101 MethodDeclaration toNode = this._toNode as MethodDeclaration; |
| 10102 return _and( |
| 10103 _isEqualNodes(node.documentationComment, toNode.documentationComment), |
| 10104 _isEqualNodeLists(node.metadata, toNode.metadata), |
| 10105 _isEqualTokens(node.externalKeyword, toNode.externalKeyword), |
| 10106 _isEqualTokens(node.modifierKeyword, toNode.modifierKeyword), |
| 10107 _isEqualNodes(node.returnType, toNode.returnType), |
| 10108 _isEqualTokens(node.propertyKeyword, toNode.propertyKeyword), |
| 10109 _isEqualTokens(node.propertyKeyword, toNode.propertyKeyword), |
| 10110 _isEqualNodes(node.name, toNode.name), |
| 10111 _isEqualNodes(node.parameters, toNode.parameters), |
| 10112 _isEqualNodes(node.body, toNode.body)); |
| 10113 } |
| 10114 |
| 10115 @override |
| 10116 bool visitMethodInvocation(MethodInvocation node) { |
| 10117 MethodInvocation toNode = this._toNode as MethodInvocation; |
| 10118 if (_and(_isEqualNodes(node.target, toNode.target), |
| 10119 _isEqualTokens(node.operator, toNode.operator), |
| 10120 _isEqualNodes(node.methodName, toNode.methodName), |
| 10121 _isEqualNodes(node.argumentList, toNode.argumentList))) { |
| 10122 toNode.propagatedType = node.propagatedType; |
| 10123 toNode.staticType = node.staticType; |
| 10124 return true; |
| 10125 } |
| 10126 return false; |
| 10127 } |
| 10128 |
| 10129 @override |
| 10130 bool visitNamedExpression(NamedExpression node) { |
| 10131 NamedExpression toNode = this._toNode as NamedExpression; |
| 10132 if (_and(_isEqualNodes(node.name, toNode.name), |
| 10133 _isEqualNodes(node.expression, toNode.expression))) { |
| 10134 toNode.propagatedType = node.propagatedType; |
| 10135 toNode.staticType = node.staticType; |
| 10136 return true; |
| 10137 } |
| 10138 return false; |
| 10139 } |
| 10140 |
| 10141 @override |
| 10142 bool visitNativeClause(NativeClause node) { |
| 10143 NativeClause toNode = this._toNode as NativeClause; |
| 10144 return _and(_isEqualTokens(node.nativeKeyword, toNode.nativeKeyword), |
| 10145 _isEqualNodes(node.name, toNode.name)); |
| 10146 } |
| 10147 |
| 10148 @override |
| 10149 bool visitNativeFunctionBody(NativeFunctionBody node) { |
| 10150 NativeFunctionBody toNode = this._toNode as NativeFunctionBody; |
| 10151 return _and(_isEqualTokens(node.nativeKeyword, toNode.nativeKeyword), |
| 10152 _isEqualNodes(node.stringLiteral, toNode.stringLiteral), |
| 10153 _isEqualTokens(node.semicolon, toNode.semicolon)); |
| 10154 } |
| 10155 |
| 10156 @override |
| 10157 bool visitNullLiteral(NullLiteral node) { |
| 10158 NullLiteral toNode = this._toNode as NullLiteral; |
| 10159 if (_isEqualTokens(node.literal, toNode.literal)) { |
| 10160 toNode.propagatedType = node.propagatedType; |
| 10161 toNode.staticType = node.staticType; |
| 10162 return true; |
| 10163 } |
| 10164 return false; |
| 10165 } |
| 10166 |
| 10167 @override |
| 10168 bool visitParenthesizedExpression(ParenthesizedExpression node) { |
| 10169 ParenthesizedExpression toNode = this._toNode as ParenthesizedExpression; |
| 10170 if (_and(_isEqualTokens(node.leftParenthesis, toNode.leftParenthesis), |
| 10171 _isEqualNodes(node.expression, toNode.expression), |
| 10172 _isEqualTokens(node.rightParenthesis, toNode.rightParenthesis))) { |
| 10173 toNode.propagatedType = node.propagatedType; |
| 10174 toNode.staticType = node.staticType; |
| 10175 return true; |
| 10176 } |
| 10177 return false; |
| 10178 } |
| 10179 |
| 10180 @override |
| 10181 bool visitPartDirective(PartDirective node) { |
| 10182 PartDirective toNode = this._toNode as PartDirective; |
| 10183 if (_and( |
| 10184 _isEqualNodes(node.documentationComment, toNode.documentationComment), |
| 10185 _isEqualNodeLists(node.metadata, toNode.metadata), |
| 10186 _isEqualTokens(node.partKeyword, toNode.partKeyword), |
| 10187 _isEqualNodes(node.uri, toNode.uri), |
| 10188 _isEqualTokens(node.semicolon, toNode.semicolon))) { |
| 10189 toNode.element = node.element; |
| 10190 return true; |
| 10191 } |
| 10192 return false; |
| 10193 } |
| 10194 |
| 10195 @override |
| 10196 bool visitPartOfDirective(PartOfDirective node) { |
| 10197 PartOfDirective toNode = this._toNode as PartOfDirective; |
| 10198 if (_and( |
| 10199 _isEqualNodes(node.documentationComment, toNode.documentationComment), |
| 10200 _isEqualNodeLists(node.metadata, toNode.metadata), |
| 10201 _isEqualTokens(node.partKeyword, toNode.partKeyword), |
| 10202 _isEqualTokens(node.ofKeyword, toNode.ofKeyword), |
| 10203 _isEqualNodes(node.libraryName, toNode.libraryName), |
| 10204 _isEqualTokens(node.semicolon, toNode.semicolon))) { |
| 10205 toNode.element = node.element; |
| 10206 return true; |
| 10207 } |
| 10208 return false; |
| 10209 } |
| 10210 |
| 10211 @override |
| 10212 bool visitPostfixExpression(PostfixExpression node) { |
| 10213 PostfixExpression toNode = this._toNode as PostfixExpression; |
| 10214 if (_and(_isEqualNodes(node.operand, toNode.operand), |
| 10215 _isEqualTokens(node.operator, toNode.operator))) { |
| 10216 toNode.propagatedElement = node.propagatedElement; |
| 10217 toNode.propagatedType = node.propagatedType; |
| 10218 toNode.staticElement = node.staticElement; |
| 10219 toNode.staticType = node.staticType; |
| 10220 return true; |
| 10221 } |
| 10222 return false; |
| 10223 } |
| 10224 |
| 10225 @override |
| 10226 bool visitPrefixedIdentifier(PrefixedIdentifier node) { |
| 10227 PrefixedIdentifier toNode = this._toNode as PrefixedIdentifier; |
| 10228 if (_and(_isEqualNodes(node.prefix, toNode.prefix), |
| 10229 _isEqualTokens(node.period, toNode.period), |
| 10230 _isEqualNodes(node.identifier, toNode.identifier))) { |
| 10231 toNode.propagatedType = node.propagatedType; |
| 10232 toNode.staticType = node.staticType; |
| 10233 return true; |
| 10234 } |
| 10235 return false; |
| 10236 } |
| 10237 |
| 10238 @override |
| 10239 bool visitPrefixExpression(PrefixExpression node) { |
| 10240 PrefixExpression toNode = this._toNode as PrefixExpression; |
| 10241 if (_and(_isEqualTokens(node.operator, toNode.operator), |
| 10242 _isEqualNodes(node.operand, toNode.operand))) { |
| 10243 toNode.propagatedElement = node.propagatedElement; |
| 10244 toNode.propagatedType = node.propagatedType; |
| 10245 toNode.staticElement = node.staticElement; |
| 10246 toNode.staticType = node.staticType; |
| 10247 return true; |
| 10248 } |
| 10249 return false; |
| 10250 } |
| 10251 |
| 10252 @override |
| 10253 bool visitPropertyAccess(PropertyAccess node) { |
| 10254 PropertyAccess toNode = this._toNode as PropertyAccess; |
| 10255 if (_and(_isEqualNodes(node.target, toNode.target), |
| 10256 _isEqualTokens(node.operator, toNode.operator), |
| 10257 _isEqualNodes(node.propertyName, toNode.propertyName))) { |
| 10258 toNode.propagatedType = node.propagatedType; |
| 10259 toNode.staticType = node.staticType; |
| 10260 return true; |
| 10261 } |
| 10262 return false; |
| 10263 } |
| 10264 |
| 10265 @override |
| 10266 bool visitRedirectingConstructorInvocation( |
| 10267 RedirectingConstructorInvocation node) { |
| 10268 RedirectingConstructorInvocation toNode = |
| 10269 this._toNode as RedirectingConstructorInvocation; |
| 10270 if (_and(_isEqualTokens(node.thisKeyword, toNode.thisKeyword), |
| 10271 _isEqualTokens(node.period, toNode.period), |
| 10272 _isEqualNodes(node.constructorName, toNode.constructorName), |
| 10273 _isEqualNodes(node.argumentList, toNode.argumentList))) { |
| 10274 toNode.staticElement = node.staticElement; |
| 10275 return true; |
| 10276 } |
| 10277 return false; |
| 10278 } |
| 10279 |
| 10280 @override |
| 10281 bool visitRethrowExpression(RethrowExpression node) { |
| 10282 RethrowExpression toNode = this._toNode as RethrowExpression; |
| 10283 if (_isEqualTokens(node.rethrowKeyword, toNode.rethrowKeyword)) { |
| 10284 toNode.propagatedType = node.propagatedType; |
| 10285 toNode.staticType = node.staticType; |
| 10286 return true; |
| 10287 } |
| 10288 return false; |
| 10289 } |
| 10290 |
| 10291 @override |
| 10292 bool visitReturnStatement(ReturnStatement node) { |
| 10293 ReturnStatement toNode = this._toNode as ReturnStatement; |
| 10294 return _and(_isEqualTokens(node.returnKeyword, toNode.returnKeyword), |
| 10295 _isEqualNodes(node.expression, toNode.expression), |
| 10296 _isEqualTokens(node.semicolon, toNode.semicolon)); |
| 10297 } |
| 10298 |
| 10299 @override |
| 10300 bool visitScriptTag(ScriptTag node) { |
| 10301 ScriptTag toNode = this._toNode as ScriptTag; |
| 10302 return _isEqualTokens(node.scriptTag, toNode.scriptTag); |
| 10303 } |
| 10304 |
| 10305 @override |
| 10306 bool visitShowCombinator(ShowCombinator node) { |
| 10307 ShowCombinator toNode = this._toNode as ShowCombinator; |
| 10308 return _and(_isEqualTokens(node.keyword, toNode.keyword), |
| 10309 _isEqualNodeLists(node.shownNames, toNode.shownNames)); |
| 10310 } |
| 10311 |
| 10312 @override |
| 10313 bool visitSimpleFormalParameter(SimpleFormalParameter node) { |
| 10314 SimpleFormalParameter toNode = this._toNode as SimpleFormalParameter; |
| 10315 return _and( |
| 10316 _isEqualNodes(node.documentationComment, toNode.documentationComment), |
| 10317 _isEqualNodeLists(node.metadata, toNode.metadata), |
| 10318 _isEqualTokens(node.keyword, toNode.keyword), |
| 10319 _isEqualNodes(node.type, toNode.type), |
| 10320 _isEqualNodes(node.identifier, toNode.identifier)); |
| 10321 } |
| 10322 |
| 10323 @override |
| 10324 bool visitSimpleIdentifier(SimpleIdentifier node) { |
| 10325 SimpleIdentifier toNode = this._toNode as SimpleIdentifier; |
| 10326 if (_isEqualTokens(node.token, toNode.token)) { |
| 10327 toNode.staticElement = node.staticElement; |
| 10328 toNode.staticType = node.staticType; |
| 10329 toNode.propagatedElement = node.propagatedElement; |
| 10330 toNode.propagatedType = node.propagatedType; |
| 10331 toNode.auxiliaryElements = node.auxiliaryElements; |
| 10332 return true; |
| 10333 } |
| 10334 return false; |
| 10335 } |
| 10336 |
| 10337 @override |
| 10338 bool visitSimpleStringLiteral(SimpleStringLiteral node) { |
| 10339 SimpleStringLiteral toNode = this._toNode as SimpleStringLiteral; |
| 10340 if (_and(_isEqualTokens(node.literal, toNode.literal), |
| 10341 node.value == toNode.value)) { |
| 10342 toNode.propagatedType = node.propagatedType; |
| 10343 toNode.staticType = node.staticType; |
| 10344 return true; |
| 10345 } |
| 10346 return false; |
| 10347 } |
| 10348 |
| 10349 @override |
| 10350 bool visitStringInterpolation(StringInterpolation node) { |
| 10351 StringInterpolation toNode = this._toNode as StringInterpolation; |
| 10352 if (_isEqualNodeLists(node.elements, toNode.elements)) { |
| 10353 toNode.propagatedType = node.propagatedType; |
| 10354 toNode.staticType = node.staticType; |
| 10355 return true; |
| 10356 } |
| 10357 return false; |
| 10358 } |
| 10359 |
| 10360 @override |
| 10361 bool visitSuperConstructorInvocation(SuperConstructorInvocation node) { |
| 10362 SuperConstructorInvocation toNode = |
| 10363 this._toNode as SuperConstructorInvocation; |
| 10364 if (_and(_isEqualTokens(node.superKeyword, toNode.superKeyword), |
| 10365 _isEqualTokens(node.period, toNode.period), |
| 10366 _isEqualNodes(node.constructorName, toNode.constructorName), |
| 10367 _isEqualNodes(node.argumentList, toNode.argumentList))) { |
| 10368 toNode.staticElement = node.staticElement; |
| 10369 return true; |
| 10370 } |
| 10371 return false; |
| 10372 } |
| 10373 |
| 10374 @override |
| 10375 bool visitSuperExpression(SuperExpression node) { |
| 10376 SuperExpression toNode = this._toNode as SuperExpression; |
| 10377 if (_isEqualTokens(node.superKeyword, toNode.superKeyword)) { |
| 10378 toNode.propagatedType = node.propagatedType; |
| 10379 toNode.staticType = node.staticType; |
| 10380 return true; |
| 10381 } |
| 10382 return false; |
| 10383 } |
| 10384 |
| 10385 @override |
| 10386 bool visitSwitchCase(SwitchCase node) { |
| 10387 SwitchCase toNode = this._toNode as SwitchCase; |
| 10388 return _and(_isEqualNodeLists(node.labels, toNode.labels), |
| 10389 _isEqualTokens(node.keyword, toNode.keyword), |
| 10390 _isEqualNodes(node.expression, toNode.expression), |
| 10391 _isEqualTokens(node.colon, toNode.colon), |
| 10392 _isEqualNodeLists(node.statements, toNode.statements)); |
| 10393 } |
| 10394 |
| 10395 @override |
| 10396 bool visitSwitchDefault(SwitchDefault node) { |
| 10397 SwitchDefault toNode = this._toNode as SwitchDefault; |
| 10398 return _and(_isEqualNodeLists(node.labels, toNode.labels), |
| 10399 _isEqualTokens(node.keyword, toNode.keyword), |
| 10400 _isEqualTokens(node.colon, toNode.colon), |
| 10401 _isEqualNodeLists(node.statements, toNode.statements)); |
| 10402 } |
| 10403 |
| 10404 @override |
| 10405 bool visitSwitchStatement(SwitchStatement node) { |
| 10406 SwitchStatement toNode = this._toNode as SwitchStatement; |
| 10407 return _and(_isEqualTokens(node.switchKeyword, toNode.switchKeyword), |
| 10408 _isEqualTokens(node.leftParenthesis, toNode.leftParenthesis), |
| 10409 _isEqualNodes(node.expression, toNode.expression), |
| 10410 _isEqualTokens(node.rightParenthesis, toNode.rightParenthesis), |
| 10411 _isEqualTokens(node.leftBracket, toNode.leftBracket), |
| 10412 _isEqualNodeLists(node.members, toNode.members), |
| 10413 _isEqualTokens(node.rightBracket, toNode.rightBracket)); |
| 10414 } |
| 10415 |
| 10416 @override |
| 10417 bool visitSymbolLiteral(SymbolLiteral node) { |
| 10418 SymbolLiteral toNode = this._toNode as SymbolLiteral; |
| 10419 if (_and(_isEqualTokens(node.poundSign, toNode.poundSign), |
| 10420 _isEqualTokenLists(node.components, toNode.components))) { |
| 10421 toNode.propagatedType = node.propagatedType; |
| 10422 toNode.staticType = node.staticType; |
| 10423 return true; |
| 10424 } |
| 10425 return false; |
| 10426 } |
| 10427 |
| 10428 @override |
| 10429 bool visitThisExpression(ThisExpression node) { |
| 10430 ThisExpression toNode = this._toNode as ThisExpression; |
| 10431 if (_isEqualTokens(node.thisKeyword, toNode.thisKeyword)) { |
| 10432 toNode.propagatedType = node.propagatedType; |
| 10433 toNode.staticType = node.staticType; |
| 10434 return true; |
| 10435 } |
| 10436 return false; |
| 10437 } |
| 10438 |
| 10439 @override |
| 10440 bool visitThrowExpression(ThrowExpression node) { |
| 10441 ThrowExpression toNode = this._toNode as ThrowExpression; |
| 10442 if (_and(_isEqualTokens(node.throwKeyword, toNode.throwKeyword), |
| 10443 _isEqualNodes(node.expression, toNode.expression))) { |
| 10444 toNode.propagatedType = node.propagatedType; |
| 10445 toNode.staticType = node.staticType; |
| 10446 return true; |
| 10447 } |
| 10448 return false; |
| 10449 } |
| 10450 |
| 10451 @override |
| 10452 bool visitTopLevelVariableDeclaration(TopLevelVariableDeclaration node) { |
| 10453 TopLevelVariableDeclaration toNode = |
| 10454 this._toNode as TopLevelVariableDeclaration; |
| 10455 return _and( |
| 10456 _isEqualNodes(node.documentationComment, toNode.documentationComment), |
| 10457 _isEqualNodeLists(node.metadata, toNode.metadata), |
| 10458 _isEqualNodes(node.variables, toNode.variables), |
| 10459 _isEqualTokens(node.semicolon, toNode.semicolon)); |
| 10460 } |
| 10461 |
| 10462 @override |
| 10463 bool visitTryStatement(TryStatement node) { |
| 10464 TryStatement toNode = this._toNode as TryStatement; |
| 10465 return _and(_isEqualTokens(node.tryKeyword, toNode.tryKeyword), |
| 10466 _isEqualNodes(node.body, toNode.body), |
| 10467 _isEqualNodeLists(node.catchClauses, toNode.catchClauses), |
| 10468 _isEqualTokens(node.finallyKeyword, toNode.finallyKeyword), |
| 10469 _isEqualNodes(node.finallyBlock, toNode.finallyBlock)); |
| 10470 } |
| 10471 |
| 10472 @override |
| 10473 bool visitTypeArgumentList(TypeArgumentList node) { |
| 10474 TypeArgumentList toNode = this._toNode as TypeArgumentList; |
| 10475 return _and(_isEqualTokens(node.leftBracket, toNode.leftBracket), |
| 10476 _isEqualNodeLists(node.arguments, toNode.arguments), |
| 10477 _isEqualTokens(node.rightBracket, toNode.rightBracket)); |
| 10478 } |
| 10479 |
| 10480 @override |
| 10481 bool visitTypeName(TypeName node) { |
| 10482 TypeName toNode = this._toNode as TypeName; |
| 10483 if (_and(_isEqualNodes(node.name, toNode.name), |
| 10484 _isEqualNodes(node.typeArguments, toNode.typeArguments))) { |
| 10485 toNode.type = node.type; |
| 10486 return true; |
| 10487 } |
| 10488 return false; |
| 10489 } |
| 10490 |
| 10491 @override |
| 10492 bool visitTypeParameter(TypeParameter node) { |
| 10493 TypeParameter toNode = this._toNode as TypeParameter; |
| 10494 return _and( |
| 10495 _isEqualNodes(node.documentationComment, toNode.documentationComment), |
| 10496 _isEqualNodeLists(node.metadata, toNode.metadata), |
| 10497 _isEqualNodes(node.name, toNode.name), |
| 10498 _isEqualTokens(node.extendsKeyword, toNode.extendsKeyword), |
| 10499 _isEqualNodes(node.bound, toNode.bound)); |
| 10500 } |
| 10501 |
| 10502 @override |
| 10503 bool visitTypeParameterList(TypeParameterList node) { |
| 10504 TypeParameterList toNode = this._toNode as TypeParameterList; |
| 10505 return _and(_isEqualTokens(node.leftBracket, toNode.leftBracket), |
| 10506 _isEqualNodeLists(node.typeParameters, toNode.typeParameters), |
| 10507 _isEqualTokens(node.rightBracket, toNode.rightBracket)); |
| 10508 } |
| 10509 |
| 10510 @override |
| 10511 bool visitVariableDeclaration(VariableDeclaration node) { |
| 10512 VariableDeclaration toNode = this._toNode as VariableDeclaration; |
| 10513 return _and( |
| 10514 _isEqualNodes(node.documentationComment, toNode.documentationComment), |
| 10515 _isEqualNodeLists(node.metadata, toNode.metadata), |
| 10516 _isEqualNodes(node.name, toNode.name), |
| 10517 _isEqualTokens(node.equals, toNode.equals), |
| 10518 _isEqualNodes(node.initializer, toNode.initializer)); |
| 10519 } |
| 10520 |
| 10521 @override |
| 10522 bool visitVariableDeclarationList(VariableDeclarationList node) { |
| 10523 VariableDeclarationList toNode = this._toNode as VariableDeclarationList; |
| 10524 return _and( |
| 10525 _isEqualNodes(node.documentationComment, toNode.documentationComment), |
| 10526 _isEqualNodeLists(node.metadata, toNode.metadata), |
| 10527 _isEqualTokens(node.keyword, toNode.keyword), |
| 10528 _isEqualNodes(node.type, toNode.type), |
| 10529 _isEqualNodeLists(node.variables, toNode.variables)); |
| 10530 } |
| 10531 |
| 10532 @override |
| 10533 bool visitVariableDeclarationStatement(VariableDeclarationStatement node) { |
| 10534 VariableDeclarationStatement toNode = |
| 10535 this._toNode as VariableDeclarationStatement; |
| 10536 return _and(_isEqualNodes(node.variables, toNode.variables), |
| 10537 _isEqualTokens(node.semicolon, toNode.semicolon)); |
| 10538 } |
| 10539 |
| 10540 @override |
| 10541 bool visitWhileStatement(WhileStatement node) { |
| 10542 WhileStatement toNode = this._toNode as WhileStatement; |
| 10543 return _and(_isEqualTokens(node.whileKeyword, toNode.whileKeyword), |
| 10544 _isEqualTokens(node.leftParenthesis, toNode.leftParenthesis), |
| 10545 _isEqualNodes(node.condition, toNode.condition), |
| 10546 _isEqualTokens(node.rightParenthesis, toNode.rightParenthesis), |
| 10547 _isEqualNodes(node.body, toNode.body)); |
| 10548 } |
| 10549 |
| 10550 @override |
| 10551 bool visitWithClause(WithClause node) { |
| 10552 WithClause toNode = this._toNode as WithClause; |
| 10553 return _and(_isEqualTokens(node.withKeyword, toNode.withKeyword), |
| 10554 _isEqualNodeLists(node.mixinTypes, toNode.mixinTypes)); |
| 10555 } |
| 10556 |
| 10557 @override |
| 10558 bool visitYieldStatement(YieldStatement node) { |
| 10559 YieldStatement toNode = this._toNode as YieldStatement; |
| 10560 return _and(_isEqualTokens(node.yieldKeyword, toNode.yieldKeyword), |
| 10561 _isEqualNodes(node.expression, toNode.expression), |
| 10562 _isEqualTokens(node.semicolon, toNode.semicolon)); |
| 10563 } |
| 10564 |
| 10565 /** |
| 10566 * Return `true` if all of the parameters are `true`. |
| 10567 */ |
| 10568 bool _and(bool b1, bool b2, [bool b3 = true, bool b4 = true, bool b5 = true, |
| 10569 bool b6 = true, bool b7 = true, bool b8 = true, bool b9 = true, |
| 10570 bool b10 = true, bool b11 = true, bool b12 = true, bool b13 = true]) { |
| 10571 // TODO(brianwilkerson) Inline this method. |
| 10572 return b1 && |
| 10573 b2 && |
| 10574 b3 && |
| 10575 b4 && |
| 10576 b5 && |
| 10577 b6 && |
| 10578 b7 && |
| 10579 b8 && |
| 10580 b9 && |
| 10581 b10 && |
| 10582 b11 && |
| 10583 b12 && |
| 10584 b13; |
| 10585 } |
| 10586 |
| 10587 /** |
| 10588 * Return `true` if the [first] and [second] lists of AST nodes have the same |
| 10589 * size and corresponding elements are equal. |
| 10590 */ |
| 10591 bool _isEqualNodeLists(NodeList first, NodeList second) { |
| 10592 if (first == null) { |
| 10593 return second == null; |
| 10594 } else if (second == null) { |
| 10595 return false; |
| 10596 } |
| 10597 int size = first.length; |
| 10598 if (second.length != size) { |
| 10599 return false; |
| 10600 } |
| 10601 bool equal = true; |
| 10602 for (int i = 0; i < size; i++) { |
| 10603 if (!_isEqualNodes(first[i], second[i])) { |
| 10604 equal = false; |
| 10605 } |
| 10606 } |
| 10607 return equal; |
| 10608 } |
| 10609 |
| 10610 /** |
| 10611 * Return `true` if the [fromNode] and [toNode] have the same structure. As a |
| 10612 * side-effect, if the nodes do have the same structure, any resolution data |
| 10613 * from the first node will be copied to the second node. |
| 10614 */ |
| 10615 bool _isEqualNodes(AstNode fromNode, AstNode toNode) { |
| 10616 if (fromNode == null) { |
| 10617 return toNode == null; |
| 10618 } else if (toNode == null) { |
| 10619 return false; |
| 10620 } else if (fromNode.runtimeType == toNode.runtimeType) { |
| 10621 this._toNode = toNode; |
| 10622 return fromNode.accept(this); |
| 10623 } |
| 10624 // |
| 10625 // Check for a simple transformation caused by entering a period. |
| 10626 // |
| 10627 if (toNode is PrefixedIdentifier) { |
| 10628 SimpleIdentifier prefix = toNode.prefix; |
| 10629 if (fromNode.runtimeType == prefix.runtimeType) { |
| 10630 this._toNode = prefix; |
| 10631 return fromNode.accept(this); |
| 10632 } |
| 10633 } else if (toNode is PropertyAccess) { |
| 10634 Expression target = toNode.target; |
| 10635 if (fromNode.runtimeType == target.runtimeType) { |
| 10636 this._toNode = target; |
| 10637 return fromNode.accept(this); |
| 10638 } |
| 10639 } |
| 10640 return false; |
| 10641 } |
| 10642 |
| 10643 /** |
| 10644 * Return `true` if the [first] and [second] arrays of tokens have the same |
| 10645 * length and corresponding elements are equal. |
| 10646 */ |
| 10647 bool _isEqualTokenLists(List<Token> first, List<Token> second) { |
| 10648 int length = first.length; |
| 10649 if (second.length != length) { |
| 10650 return false; |
| 10651 } |
| 10652 for (int i = 0; i < length; i++) { |
| 10653 if (!_isEqualTokens(first[i], second[i])) { |
| 10654 return false; |
| 10655 } |
| 10656 } |
| 10657 return true; |
| 10658 } |
| 10659 |
| 10660 /** |
| 10661 * Return `true` if the [first] and [second] tokens have the same structure. |
| 10662 */ |
| 10663 bool _isEqualTokens(Token first, Token second) { |
| 10664 if (first == null) { |
| 10665 return second == null; |
| 10666 } else if (second == null) { |
| 10667 return false; |
| 10668 } |
| 10669 return first.lexeme == second.lexeme; |
| 10670 } |
| 10671 |
| 10672 /** |
| 10673 * Copy resolution data from the [fromNode] to the [toNode]. |
| 10674 */ |
| 10675 static void copyResolutionData(AstNode fromNode, AstNode toNode) { |
| 10676 ResolutionCopier copier = new ResolutionCopier(); |
| 10677 copier._isEqualNodes(fromNode, toNode); |
| 10678 } |
| 10679 } |
OLD | NEW |