| OLD | NEW |
| 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 library engine.parser; | 5 library analyzer.src.generated.parser; |
| 6 | 6 |
| 7 import 'dart:collection'; | 7 import 'dart:collection'; |
| 8 import "dart:math" as math; | 8 import "dart:math" as math; |
| 9 | 9 |
| 10 import 'ast.dart'; | 10 import 'package:analyzer/dart/ast/ast.dart'; |
| 11 import 'engine.dart' show AnalysisEngine, AnalysisOptionsImpl; | 11 import 'package:analyzer/dart/ast/token.dart'; |
| 12 import 'error.dart'; | 12 import 'package:analyzer/error/error.dart'; |
| 13 import 'java_core.dart'; | 13 import 'package:analyzer/error/listener.dart'; |
| 14 import 'java_engine.dart'; | 14 import 'package:analyzer/src/dart/ast/ast.dart'; |
| 15 import 'scanner.dart'; | 15 import 'package:analyzer/src/dart/ast/token.dart'; |
| 16 import 'source.dart'; | 16 import 'package:analyzer/src/dart/error/syntactic_errors.dart'; |
| 17 import 'utilities_collection.dart' show TokenMap; | 17 import 'package:analyzer/src/dart/scanner/reader.dart'; |
| 18 import 'utilities_dart.dart'; | 18 import 'package:analyzer/src/dart/scanner/scanner.dart'; |
| 19 import 'package:analyzer/src/error/codes.dart'; |
| 20 import 'package:analyzer/src/generated/engine.dart' show AnalysisEngine; |
| 21 import 'package:analyzer/src/generated/java_core.dart'; |
| 22 import 'package:analyzer/src/generated/java_engine.dart'; |
| 23 import 'package:analyzer/src/generated/source.dart'; |
| 24 import 'package:analyzer/src/generated/utilities_dart.dart'; |
| 19 | 25 |
| 20 Map<String, MethodTrampoline> methodTable_Parser = <String, MethodTrampoline>{ | 26 export 'package:analyzer/src/dart/ast/utilities.dart' show ResolutionCopier; |
| 21 'parseCompilationUnit_1': new MethodTrampoline( | 27 export 'package:analyzer/src/dart/error/syntactic_errors.dart'; |
| 22 1, (Parser target, arg0) => target.parseCompilationUnit(arg0)), | |
| 23 'parseDirectives_1': new MethodTrampoline( | |
| 24 1, (Parser target, arg0) => target.parseDirectives(arg0)), | |
| 25 'parseExpression_1': new MethodTrampoline( | |
| 26 1, (Parser target, arg0) => target.parseExpression(arg0)), | |
| 27 'parseStatement_1': new MethodTrampoline( | |
| 28 1, (Parser target, arg0) => target.parseStatement(arg0)), | |
| 29 'parseStatements_1': new MethodTrampoline( | |
| 30 1, (Parser target, arg0) => target.parseStatements(arg0)), | |
| 31 'parseAnnotation_0': | |
| 32 new MethodTrampoline(0, (Parser target) => target.parseAnnotation()), | |
| 33 'parseArgument_0': | |
| 34 new MethodTrampoline(0, (Parser target) => target.parseArgument()), | |
| 35 'parseArgumentList_0': | |
| 36 new MethodTrampoline(0, (Parser target) => target.parseArgumentList()), | |
| 37 'parseBitwiseOrExpression_0': new MethodTrampoline( | |
| 38 0, (Parser target) => target.parseBitwiseOrExpression()), | |
| 39 'parseBlock_0': | |
| 40 new MethodTrampoline(0, (Parser target) => target.parseBlock()), | |
| 41 'parseClassMember_1': new MethodTrampoline( | |
| 42 1, (Parser target, arg0) => target.parseClassMember(arg0)), | |
| 43 'parseCompilationUnit_0': new MethodTrampoline( | |
| 44 0, (Parser target) => target.parseCompilationUnit2()), | |
| 45 'parseConditionalExpression_0': new MethodTrampoline( | |
| 46 0, (Parser target) => target.parseConditionalExpression()), | |
| 47 'parseConstructorName_0': | |
| 48 new MethodTrampoline(0, (Parser target) => target.parseConstructorName()), | |
| 49 'parseExpression_0': | |
| 50 new MethodTrampoline(0, (Parser target) => target.parseExpression2()), | |
| 51 'parseExpressionWithoutCascade_0': new MethodTrampoline( | |
| 52 0, (Parser target) => target.parseExpressionWithoutCascade()), | |
| 53 'parseExtendsClause_0': | |
| 54 new MethodTrampoline(0, (Parser target) => target.parseExtendsClause()), | |
| 55 'parseFormalParameterList_0': new MethodTrampoline( | |
| 56 0, (Parser target) => target.parseFormalParameterList()), | |
| 57 'parseFunctionExpression_0': new MethodTrampoline( | |
| 58 0, (Parser target) => target.parseFunctionExpression()), | |
| 59 'parseImplementsClause_0': new MethodTrampoline( | |
| 60 0, (Parser target) => target.parseImplementsClause()), | |
| 61 'parseLabel_0': | |
| 62 new MethodTrampoline(0, (Parser target) => target.parseLabel()), | |
| 63 'parseLibraryIdentifier_0': new MethodTrampoline( | |
| 64 0, (Parser target) => target.parseLibraryIdentifier()), | |
| 65 'parseLogicalOrExpression_0': new MethodTrampoline( | |
| 66 0, (Parser target) => target.parseLogicalOrExpression()), | |
| 67 'parseMapLiteralEntry_0': | |
| 68 new MethodTrampoline(0, (Parser target) => target.parseMapLiteralEntry()), | |
| 69 'parseNormalFormalParameter_0': new MethodTrampoline( | |
| 70 0, (Parser target) => target.parseNormalFormalParameter()), | |
| 71 'parsePrefixedIdentifier_0': new MethodTrampoline( | |
| 72 0, (Parser target) => target.parsePrefixedIdentifier()), | |
| 73 'parseReturnType_0': | |
| 74 new MethodTrampoline(0, (Parser target) => target.parseReturnType()), | |
| 75 'parseSimpleIdentifier_0': new MethodTrampoline( | |
| 76 0, (Parser target) => target.parseSimpleIdentifier()), | |
| 77 'parseStatement_0': | |
| 78 new MethodTrampoline(0, (Parser target) => target.parseStatement2()), | |
| 79 'parseStringLiteral_0': | |
| 80 new MethodTrampoline(0, (Parser target) => target.parseStringLiteral()), | |
| 81 'parseTypeArgumentList_0': new MethodTrampoline( | |
| 82 0, (Parser target) => target.parseTypeArgumentList()), | |
| 83 'parseTypeName_0': | |
| 84 new MethodTrampoline(0, (Parser target) => target.parseTypeName()), | |
| 85 'parseTypeParameter_0': | |
| 86 new MethodTrampoline(0, (Parser target) => target.parseTypeParameter()), | |
| 87 'parseTypeParameterList_0': new MethodTrampoline( | |
| 88 0, (Parser target) => target.parseTypeParameterList()), | |
| 89 'parseWithClause_0': | |
| 90 new MethodTrampoline(0, (Parser target) => target.parseWithClause()), | |
| 91 'advance_0': new MethodTrampoline(0, (Parser target) => target._advance()), | |
| 92 'appendScalarValue_5': new MethodTrampoline( | |
| 93 5, | |
| 94 (Parser target, arg0, arg1, arg2, arg3, arg4) => | |
| 95 target._appendScalarValue(arg0, arg1, arg2, arg3, arg4)), | |
| 96 'computeStringValue_3': new MethodTrampoline( | |
| 97 3, | |
| 98 (Parser target, arg0, arg1, arg2) => | |
| 99 target._computeStringValue(arg0, arg1, arg2)), | |
| 100 'convertToFunctionDeclaration_1': new MethodTrampoline( | |
| 101 1, (Parser target, arg0) => target._convertToFunctionDeclaration(arg0)), | |
| 102 'couldBeStartOfCompilationUnitMember_0': new MethodTrampoline( | |
| 103 0, (Parser target) => target._couldBeStartOfCompilationUnitMember()), | |
| 104 'createSyntheticIdentifier_0': new MethodTrampoline( | |
| 105 0, (Parser target) => target._createSyntheticIdentifier()), | |
| 106 'createSyntheticKeyword_1': new MethodTrampoline( | |
| 107 1, (Parser target, arg0) => target._createSyntheticKeyword(arg0)), | |
| 108 'createSyntheticStringLiteral_0': new MethodTrampoline( | |
| 109 0, (Parser target) => target._createSyntheticStringLiteral()), | |
| 110 'createSyntheticToken_1': new MethodTrampoline( | |
| 111 1, (Parser target, arg0) => target._createSyntheticToken(arg0)), | |
| 112 'ensureAssignable_1': new MethodTrampoline( | |
| 113 1, (Parser target, arg0) => target._ensureAssignable(arg0)), | |
| 114 'expect_1': | |
| 115 new MethodTrampoline(1, (Parser target, arg0) => target._expect(arg0)), | |
| 116 'expectGt_0': new MethodTrampoline(0, (Parser target) => target._expectGt()), | |
| 117 'expectKeyword_1': new MethodTrampoline( | |
| 118 1, (Parser target, arg0) => target._expectKeyword(arg0)), | |
| 119 'expectSemicolon_0': | |
| 120 new MethodTrampoline(0, (Parser target) => target._expectSemicolon()), | |
| 121 'findRange_2': new MethodTrampoline( | |
| 122 2, (Parser target, arg0, arg1) => target._findRange(arg0, arg1)), | |
| 123 'getCodeBlockRanges_1': new MethodTrampoline( | |
| 124 1, (Parser target, arg0) => target._getCodeBlockRanges(arg0)), | |
| 125 'getEndToken_1': new MethodTrampoline( | |
| 126 1, (Parser target, arg0) => target._getEndToken(arg0)), | |
| 127 'injectToken_1': new MethodTrampoline( | |
| 128 1, (Parser target, arg0) => target._injectToken(arg0)), | |
| 129 'isFunctionDeclaration_0': new MethodTrampoline( | |
| 130 0, (Parser target) => target._isFunctionDeclaration()), | |
| 131 'isFunctionExpression_1': new MethodTrampoline( | |
| 132 1, (Parser target, arg0) => target._isFunctionExpression(arg0)), | |
| 133 'isHexDigit_1': new MethodTrampoline( | |
| 134 1, (Parser target, arg0) => target._isHexDigit(arg0)), | |
| 135 'isInitializedVariableDeclaration_0': new MethodTrampoline( | |
| 136 0, (Parser target) => target._isInitializedVariableDeclaration()), | |
| 137 'isLinkText_2': new MethodTrampoline( | |
| 138 2, (Parser target, arg0, arg1) => target._isLinkText(arg0, arg1)), | |
| 139 'isOperator_1': new MethodTrampoline( | |
| 140 1, (Parser target, arg0) => target._isOperator(arg0)), | |
| 141 'isSwitchMember_0': | |
| 142 new MethodTrampoline(0, (Parser target) => target._isSwitchMember()), | |
| 143 'isTypedIdentifier_1': new MethodTrampoline( | |
| 144 1, (Parser target, arg0) => target._isTypedIdentifier(arg0)), | |
| 145 'lockErrorListener_0': | |
| 146 new MethodTrampoline(0, (Parser target) => target._lockErrorListener()), | |
| 147 'matches_1': | |
| 148 new MethodTrampoline(1, (Parser target, arg0) => target._matches(arg0)), | |
| 149 'matchesGt_0': | |
| 150 new MethodTrampoline(0, (Parser target) => target._matchesGt()), | |
| 151 'matchesIdentifier_0': | |
| 152 new MethodTrampoline(0, (Parser target) => target._matchesIdentifier()), | |
| 153 'matchesKeyword_1': new MethodTrampoline( | |
| 154 1, (Parser target, arg0) => target._matchesKeyword(arg0)), | |
| 155 'matchesString_1': new MethodTrampoline( | |
| 156 1, (Parser target, arg0) => target._matchesString(arg0)), | |
| 157 'optional_1': | |
| 158 new MethodTrampoline(1, (Parser target, arg0) => target._optional(arg0)), | |
| 159 'parseAdditiveExpression_0': new MethodTrampoline( | |
| 160 0, (Parser target) => target._parseAdditiveExpression()), | |
| 161 'parseAssertStatement_0': new MethodTrampoline( | |
| 162 0, (Parser target) => target._parseAssertStatement()), | |
| 163 'parseAssignableExpression_1': new MethodTrampoline( | |
| 164 1, (Parser target, arg0) => target._parseAssignableExpression(arg0)), | |
| 165 'parseAssignableSelector_2': new MethodTrampoline( | |
| 166 2, | |
| 167 (Parser target, arg0, arg1) => | |
| 168 target._parseAssignableSelector(arg0, arg1)), | |
| 169 'parseAwaitExpression_0': new MethodTrampoline( | |
| 170 0, (Parser target) => target._parseAwaitExpression()), | |
| 171 'parseBitwiseAndExpression_0': new MethodTrampoline( | |
| 172 0, (Parser target) => target._parseBitwiseAndExpression()), | |
| 173 'parseBitwiseXorExpression_0': new MethodTrampoline( | |
| 174 0, (Parser target) => target._parseBitwiseXorExpression()), | |
| 175 'parseBreakStatement_0': | |
| 176 new MethodTrampoline(0, (Parser target) => target._parseBreakStatement()), | |
| 177 'parseCascadeSection_0': | |
| 178 new MethodTrampoline(0, (Parser target) => target._parseCascadeSection()), | |
| 179 'parseClassDeclaration_2': new MethodTrampoline(2, | |
| 180 (Parser target, arg0, arg1) => target._parseClassDeclaration(arg0, arg1)), | |
| 181 'parseClassMembers_2': new MethodTrampoline( | |
| 182 2, (Parser target, arg0, arg1) => target._parseClassMembers(arg0, arg1)), | |
| 183 'parseClassTypeAlias_3': new MethodTrampoline( | |
| 184 3, | |
| 185 (Parser target, arg0, arg1, arg2) => | |
| 186 target._parseClassTypeAlias(arg0, arg1, arg2)), | |
| 187 'parseCombinator_0': | |
| 188 new MethodTrampoline(0, (Parser target) => target.parseCombinator()), | |
| 189 'parseCombinators_0': | |
| 190 new MethodTrampoline(0, (Parser target) => target._parseCombinators()), | |
| 191 'parseCommentAndMetadata_0': new MethodTrampoline( | |
| 192 0, (Parser target) => target._parseCommentAndMetadata()), | |
| 193 'parseCommentReference_2': new MethodTrampoline(2, | |
| 194 (Parser target, arg0, arg1) => target._parseCommentReference(arg0, arg1)), | |
| 195 'parseCommentReferences_1': new MethodTrampoline( | |
| 196 1, (Parser target, arg0) => target._parseCommentReferences(arg0)), | |
| 197 'parseCompilationUnitMember_1': new MethodTrampoline( | |
| 198 1, (Parser target, arg0) => target._parseCompilationUnitMember(arg0)), | |
| 199 'parseConstExpression_0': new MethodTrampoline( | |
| 200 0, (Parser target) => target._parseConstExpression()), | |
| 201 'parseConstructor_8': new MethodTrampoline( | |
| 202 8, | |
| 203 (Parser target, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7) => target | |
| 204 ._parseConstructor(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7)), | |
| 205 'parseConstructorFieldInitializer_0': new MethodTrampoline( | |
| 206 0, (Parser target) => target._parseConstructorFieldInitializer()), | |
| 207 'parseContinueStatement_0': new MethodTrampoline( | |
| 208 0, (Parser target) => target._parseContinueStatement()), | |
| 209 'parseDirective_1': new MethodTrampoline( | |
| 210 1, (Parser target, arg0) => target._parseDirective(arg0)), | |
| 211 'parseDirectives_0': | |
| 212 new MethodTrampoline(0, (Parser target) => target._parseDirectives()), | |
| 213 'parseDocumentationComment_0': new MethodTrampoline( | |
| 214 0, (Parser target) => target._parseDocumentationComment()), | |
| 215 'parseDoStatement_0': | |
| 216 new MethodTrampoline(0, (Parser target) => target._parseDoStatement()), | |
| 217 'parseEmptyStatement_0': | |
| 218 new MethodTrampoline(0, (Parser target) => target._parseEmptyStatement()), | |
| 219 'parseEnumConstantDeclaration_0': new MethodTrampoline( | |
| 220 0, (Parser target) => target._parseEnumConstantDeclaration()), | |
| 221 'parseEnumDeclaration_1': new MethodTrampoline( | |
| 222 1, (Parser target, arg0) => target._parseEnumDeclaration(arg0)), | |
| 223 'parseEqualityExpression_0': new MethodTrampoline( | |
| 224 0, (Parser target) => target._parseEqualityExpression()), | |
| 225 'parseExportDirective_1': new MethodTrampoline( | |
| 226 1, (Parser target, arg0) => target._parseExportDirective(arg0)), | |
| 227 'parseExpressionList_0': | |
| 228 new MethodTrampoline(0, (Parser target) => target._parseExpressionList()), | |
| 229 'parseFinalConstVarOrType_1': new MethodTrampoline( | |
| 230 1, (Parser target, arg0) => target._parseFinalConstVarOrType(arg0)), | |
| 231 'parseFormalParameter_1': new MethodTrampoline( | |
| 232 1, (Parser target, arg0) => target._parseFormalParameter(arg0)), | |
| 233 'parseForStatement_0': | |
| 234 new MethodTrampoline(0, (Parser target) => target._parseForStatement()), | |
| 235 'parseFunctionBody_3': new MethodTrampoline( | |
| 236 3, | |
| 237 (Parser target, arg0, arg1, arg2) => | |
| 238 target._parseFunctionBody(arg0, arg1, arg2)), | |
| 239 'parseFunctionDeclaration_3': new MethodTrampoline( | |
| 240 3, | |
| 241 (Parser target, arg0, arg1, arg2) => | |
| 242 target._parseFunctionDeclaration(arg0, arg1, arg2)), | |
| 243 'parseFunctionDeclarationStatement_0': new MethodTrampoline( | |
| 244 0, (Parser target) => target._parseFunctionDeclarationStatement()), | |
| 245 'parseFunctionDeclarationStatementAfterReturnType_2': new MethodTrampoline( | |
| 246 2, | |
| 247 (Parser target, arg0, arg1) => | |
| 248 target._parseFunctionDeclarationStatementAfterReturnType(arg0, arg1)), | |
| 249 'parseFunctionTypeAlias_2': new MethodTrampoline( | |
| 250 2, | |
| 251 (Parser target, arg0, arg1) => | |
| 252 target._parseFunctionTypeAlias(arg0, arg1)), | |
| 253 'parseGetter_4': new MethodTrampoline( | |
| 254 4, | |
| 255 (Parser target, arg0, arg1, arg2, arg3) => | |
| 256 target._parseGetter(arg0, arg1, arg2, arg3)), | |
| 257 'parseIdentifierList_0': | |
| 258 new MethodTrampoline(0, (Parser target) => target._parseIdentifierList()), | |
| 259 'parseIfStatement_0': | |
| 260 new MethodTrampoline(0, (Parser target) => target._parseIfStatement()), | |
| 261 'parseImportDirective_1': new MethodTrampoline( | |
| 262 1, (Parser target, arg0) => target._parseImportDirective(arg0)), | |
| 263 'parseInitializedIdentifierList_4': new MethodTrampoline( | |
| 264 4, | |
| 265 (Parser target, arg0, arg1, arg2, arg3) => | |
| 266 target._parseInitializedIdentifierList(arg0, arg1, arg2, arg3)), | |
| 267 'parseInstanceCreationExpression_1': new MethodTrampoline(1, | |
| 268 (Parser target, arg0) => target._parseInstanceCreationExpression(arg0)), | |
| 269 'parseLibraryDirective_1': new MethodTrampoline( | |
| 270 1, (Parser target, arg0) => target._parseLibraryDirective(arg0)), | |
| 271 'parseLibraryName_2': new MethodTrampoline( | |
| 272 2, (Parser target, arg0, arg1) => target._parseLibraryName(arg0, arg1)), | |
| 273 'parseListLiteral_2': new MethodTrampoline( | |
| 274 2, (Parser target, arg0, arg1) => target._parseListLiteral(arg0, arg1)), | |
| 275 'parseListOrMapLiteral_1': new MethodTrampoline( | |
| 276 1, (Parser target, arg0) => target._parseListOrMapLiteral(arg0)), | |
| 277 'parseLogicalAndExpression_0': new MethodTrampoline( | |
| 278 0, (Parser target) => target._parseLogicalAndExpression()), | |
| 279 'parseMapLiteral_2': new MethodTrampoline( | |
| 280 2, (Parser target, arg0, arg1) => target._parseMapLiteral(arg0, arg1)), | |
| 281 'parseMethodDeclarationAfterParameters_7': new MethodTrampoline( | |
| 282 7, | |
| 283 (Parser target, arg0, arg1, arg2, arg3, arg4, arg5, arg6) => | |
| 284 target._parseMethodDeclarationAfterParameters( | |
| 285 arg0, arg1, arg2, arg3, arg4, arg5, arg6)), | |
| 286 'parseMethodDeclarationAfterReturnType_4': new MethodTrampoline( | |
| 287 4, | |
| 288 (Parser target, arg0, arg1, arg2, arg3) => target | |
| 289 ._parseMethodDeclarationAfterReturnType(arg0, arg1, arg2, arg3)), | |
| 290 'parseModifiers_0': | |
| 291 new MethodTrampoline(0, (Parser target) => target._parseModifiers()), | |
| 292 'parseMultiplicativeExpression_0': new MethodTrampoline( | |
| 293 0, (Parser target) => target._parseMultiplicativeExpression()), | |
| 294 'parseNativeClause_0': | |
| 295 new MethodTrampoline(0, (Parser target) => target._parseNativeClause()), | |
| 296 'parseNewExpression_0': | |
| 297 new MethodTrampoline(0, (Parser target) => target._parseNewExpression()), | |
| 298 'parseNonLabeledStatement_0': new MethodTrampoline( | |
| 299 0, (Parser target) => target._parseNonLabeledStatement()), | |
| 300 'parseOperator_3': new MethodTrampoline( | |
| 301 3, | |
| 302 (Parser target, arg0, arg1, arg2) => | |
| 303 target._parseOperator(arg0, arg1, arg2)), | |
| 304 'parseOptionalReturnType_0': new MethodTrampoline( | |
| 305 0, (Parser target) => target._parseOptionalReturnType()), | |
| 306 'parsePartDirective_1': new MethodTrampoline( | |
| 307 1, (Parser target, arg0) => target._parsePartDirective(arg0)), | |
| 308 'parsePostfixExpression_0': new MethodTrampoline( | |
| 309 0, (Parser target) => target._parsePostfixExpression()), | |
| 310 'parsePrimaryExpression_0': new MethodTrampoline( | |
| 311 0, (Parser target) => target._parsePrimaryExpression()), | |
| 312 'parseRedirectingConstructorInvocation_0': new MethodTrampoline( | |
| 313 0, (Parser target) => target._parseRedirectingConstructorInvocation()), | |
| 314 'parseRelationalExpression_0': new MethodTrampoline( | |
| 315 0, (Parser target) => target._parseRelationalExpression()), | |
| 316 'parseRethrowExpression_0': new MethodTrampoline( | |
| 317 0, (Parser target) => target._parseRethrowExpression()), | |
| 318 'parseReturnStatement_0': new MethodTrampoline( | |
| 319 0, (Parser target) => target._parseReturnStatement()), | |
| 320 'parseSetter_4': new MethodTrampoline( | |
| 321 4, | |
| 322 (Parser target, arg0, arg1, arg2, arg3) => | |
| 323 target._parseSetter(arg0, arg1, arg2, arg3)), | |
| 324 'parseShiftExpression_0': new MethodTrampoline( | |
| 325 0, (Parser target) => target._parseShiftExpression()), | |
| 326 'parseStatementList_0': | |
| 327 new MethodTrampoline(0, (Parser target) => target._parseStatementList()), | |
| 328 'parseStringInterpolation_1': new MethodTrampoline( | |
| 329 1, (Parser target, arg0) => target._parseStringInterpolation(arg0)), | |
| 330 'parseSuperConstructorInvocation_0': new MethodTrampoline( | |
| 331 0, (Parser target) => target._parseSuperConstructorInvocation()), | |
| 332 'parseSwitchStatement_0': new MethodTrampoline( | |
| 333 0, (Parser target) => target._parseSwitchStatement()), | |
| 334 'parseSymbolLiteral_0': | |
| 335 new MethodTrampoline(0, (Parser target) => target._parseSymbolLiteral()), | |
| 336 'parseThrowExpression_0': new MethodTrampoline( | |
| 337 0, (Parser target) => target._parseThrowExpression()), | |
| 338 'parseThrowExpressionWithoutCascade_0': new MethodTrampoline( | |
| 339 0, (Parser target) => target._parseThrowExpressionWithoutCascade()), | |
| 340 'parseTryStatement_0': | |
| 341 new MethodTrampoline(0, (Parser target) => target._parseTryStatement()), | |
| 342 'parseTypeAlias_1': new MethodTrampoline( | |
| 343 1, (Parser target, arg0) => target._parseTypeAlias(arg0)), | |
| 344 'parseUnaryExpression_0': new MethodTrampoline( | |
| 345 0, (Parser target) => target._parseUnaryExpression()), | |
| 346 'parseVariableDeclaration_0': new MethodTrampoline( | |
| 347 0, (Parser target) => target._parseVariableDeclaration()), | |
| 348 'parseVariableDeclarationListAfterMetadata_1': new MethodTrampoline( | |
| 349 1, | |
| 350 (Parser target, arg0) => | |
| 351 target._parseVariableDeclarationListAfterMetadata(arg0)), | |
| 352 'parseVariableDeclarationListAfterType_3': new MethodTrampoline( | |
| 353 3, | |
| 354 (Parser target, arg0, arg1, arg2) => | |
| 355 target._parseVariableDeclarationListAfterType(arg0, arg1, arg2)), | |
| 356 'parseVariableDeclarationStatementAfterMetadata_1': new MethodTrampoline( | |
| 357 1, | |
| 358 (Parser target, arg0) => | |
| 359 target._parseVariableDeclarationStatementAfterMetadata(arg0)), | |
| 360 'parseVariableDeclarationStatementAfterType_3': new MethodTrampoline( | |
| 361 3, | |
| 362 (Parser target, arg0, arg1, arg2) => | |
| 363 target._parseVariableDeclarationStatementAfterType(arg0, arg1, arg2)), | |
| 364 'parseWhileStatement_0': | |
| 365 new MethodTrampoline(0, (Parser target) => target._parseWhileStatement()), | |
| 366 'parseYieldStatement_0': | |
| 367 new MethodTrampoline(0, (Parser target) => target._parseYieldStatement()), | |
| 368 'peek_0': new MethodTrampoline(0, (Parser target) => target._peek()), | |
| 369 'peekAt_1': | |
| 370 new MethodTrampoline(1, (Parser target, arg0) => target._peekAt(arg0)), | |
| 371 'reportError_1': new MethodTrampoline( | |
| 372 1, (Parser target, arg0) => target._reportError(arg0)), | |
| 373 'reportErrorForCurrentToken_2': new MethodTrampoline( | |
| 374 2, | |
| 375 (Parser target, arg0, arg1) => | |
| 376 target._reportErrorForCurrentToken(arg0, arg1)), | |
| 377 'reportErrorForNode_3': new MethodTrampoline( | |
| 378 3, | |
| 379 (Parser target, arg0, arg1, arg2) => | |
| 380 target._reportErrorForNode(arg0, arg1, arg2)), | |
| 381 'reportErrorForToken_3': new MethodTrampoline( | |
| 382 3, | |
| 383 (Parser target, arg0, arg1, arg2) => | |
| 384 target._reportErrorForToken(arg0, arg1, arg2)), | |
| 385 'skipBlock_0': | |
| 386 new MethodTrampoline(0, (Parser target) => target._skipBlock()), | |
| 387 'skipFinalConstVarOrType_1': new MethodTrampoline( | |
| 388 1, (Parser target, arg0) => target._skipFinalConstVarOrType(arg0)), | |
| 389 'skipFormalParameterList_1': new MethodTrampoline( | |
| 390 1, (Parser target, arg0) => target._skipFormalParameterList(arg0)), | |
| 391 'skipPastMatchingToken_1': new MethodTrampoline( | |
| 392 1, (Parser target, arg0) => target._skipPastMatchingToken(arg0)), | |
| 393 'skipPrefixedIdentifier_1': new MethodTrampoline( | |
| 394 1, (Parser target, arg0) => target._skipPrefixedIdentifier(arg0)), | |
| 395 'skipReturnType_1': new MethodTrampoline( | |
| 396 1, (Parser target, arg0) => target._skipReturnType(arg0)), | |
| 397 'skipSimpleIdentifier_1': new MethodTrampoline( | |
| 398 1, (Parser target, arg0) => target._skipSimpleIdentifier(arg0)), | |
| 399 'skipStringInterpolation_1': new MethodTrampoline( | |
| 400 1, (Parser target, arg0) => target._skipStringInterpolation(arg0)), | |
| 401 'skipStringLiteral_1': new MethodTrampoline( | |
| 402 1, (Parser target, arg0) => target._skipStringLiteral(arg0)), | |
| 403 'skipTypeArgumentList_1': new MethodTrampoline( | |
| 404 1, (Parser target, arg0) => target._skipTypeArgumentList(arg0)), | |
| 405 'skipTypeName_1': new MethodTrampoline( | |
| 406 1, (Parser target, arg0) => target._skipTypeName(arg0)), | |
| 407 'skipTypeParameterList_1': new MethodTrampoline( | |
| 408 1, (Parser target, arg0) => target._skipTypeParameterList(arg0)), | |
| 409 'tokenMatches_2': new MethodTrampoline( | |
| 410 2, (Parser target, arg0, arg1) => target._tokenMatches(arg0, arg1)), | |
| 411 'tokenMatchesIdentifier_1': new MethodTrampoline( | |
| 412 1, (Parser target, arg0) => target._tokenMatchesIdentifier(arg0)), | |
| 413 'tokenMatchesKeyword_2': new MethodTrampoline(2, | |
| 414 (Parser target, arg0, arg1) => target._tokenMatchesKeyword(arg0, arg1)), | |
| 415 'tokenMatchesString_2': new MethodTrampoline( | |
| 416 2, (Parser target, arg0, arg1) => target._tokenMatchesString(arg0, arg1)), | |
| 417 'translateCharacter_3': new MethodTrampoline( | |
| 418 3, | |
| 419 (Parser target, arg0, arg1, arg2) => | |
| 420 target._translateCharacter(arg0, arg1, arg2)), | |
| 421 'unlockErrorListener_0': | |
| 422 new MethodTrampoline(0, (Parser target) => target._unlockErrorListener()), | |
| 423 'validateFormalParameterList_1': new MethodTrampoline( | |
| 424 1, (Parser target, arg0) => target._validateFormalParameterList(arg0)), | |
| 425 'validateModifiersForClass_1': new MethodTrampoline( | |
| 426 1, (Parser target, arg0) => target._validateModifiersForClass(arg0)), | |
| 427 'validateModifiersForConstructor_1': new MethodTrampoline(1, | |
| 428 (Parser target, arg0) => target._validateModifiersForConstructor(arg0)), | |
| 429 'validateModifiersForEnum_1': new MethodTrampoline( | |
| 430 1, (Parser target, arg0) => target._validateModifiersForEnum(arg0)), | |
| 431 'validateModifiersForField_1': new MethodTrampoline( | |
| 432 1, (Parser target, arg0) => target._validateModifiersForField(arg0)), | |
| 433 'validateModifiersForFunctionDeclarationStatement_1': new MethodTrampoline( | |
| 434 1, | |
| 435 (Parser target, arg0) => | |
| 436 target._validateModifiersForFunctionDeclarationStatement(arg0)), | |
| 437 'validateModifiersForGetterOrSetterOrMethod_1': new MethodTrampoline( | |
| 438 1, | |
| 439 (Parser target, arg0) => | |
| 440 target._validateModifiersForGetterOrSetterOrMethod(arg0)), | |
| 441 'validateModifiersForOperator_1': new MethodTrampoline( | |
| 442 1, (Parser target, arg0) => target._validateModifiersForOperator(arg0)), | |
| 443 'validateModifiersForTopLevelDeclaration_1': new MethodTrampoline( | |
| 444 1, | |
| 445 (Parser target, arg0) => | |
| 446 target._validateModifiersForTopLevelDeclaration(arg0)), | |
| 447 'validateModifiersForTopLevelFunction_1': new MethodTrampoline( | |
| 448 1, | |
| 449 (Parser target, arg0) => | |
| 450 target._validateModifiersForTopLevelFunction(arg0)), | |
| 451 'validateModifiersForTopLevelVariable_1': new MethodTrampoline( | |
| 452 1, | |
| 453 (Parser target, arg0) => | |
| 454 target._validateModifiersForTopLevelVariable(arg0)), | |
| 455 'validateModifiersForTypedef_1': new MethodTrampoline( | |
| 456 1, (Parser target, arg0) => target._validateModifiersForTypedef(arg0)), | |
| 457 }; | |
| 458 | |
| 459 Object invokeParserMethodImpl( | |
| 460 Parser parser, String methodName, List<Object> objects, Token tokenStream) { | |
| 461 parser.currentToken = tokenStream; | |
| 462 MethodTrampoline method = | |
| 463 methodTable_Parser['${methodName}_${objects.length}']; | |
| 464 if (method == null) { | |
| 465 throw new IllegalArgumentException('There is no method named $methodName'); | |
| 466 } | |
| 467 return method.invoke(parser, objects); | |
| 468 } | |
| 469 | 28 |
| 470 /** | 29 /** |
| 471 * A simple data-holder for a method that needs to return multiple values. | 30 * A simple data-holder for a method that needs to return multiple values. |
| 472 */ | 31 */ |
| 473 class CommentAndMetadata { | 32 class CommentAndMetadata { |
| 474 /** | 33 /** |
| 475 * The documentation comment that was parsed, or `null` if none was given. | 34 * The documentation comment that was parsed, or `null` if none was given. |
| 476 */ | 35 */ |
| 477 final Comment comment; | 36 final Comment comment; |
| 478 | 37 |
| 479 /** | 38 /** |
| 480 * The metadata that was parsed. | 39 * The metadata that was parsed, or `null` if none was given. |
| 481 */ | 40 */ |
| 482 final List<Annotation> metadata; | 41 final List<Annotation> metadata; |
| 483 | 42 |
| 484 /** | 43 /** |
| 485 * Initialize a newly created holder with the given [comment] and [metadata]. | 44 * Initialize a newly created holder with the given [comment] and [metadata]. |
| 486 */ | 45 */ |
| 487 CommentAndMetadata(this.comment, this.metadata); | 46 CommentAndMetadata(this.comment, this.metadata); |
| 47 |
| 48 /** |
| 49 * Return `true` if some metadata was parsed. |
| 50 */ |
| 51 bool get hasMetadata => metadata != null && metadata.isNotEmpty; |
| 488 } | 52 } |
| 489 | 53 |
| 490 /** | 54 /** |
| 491 * A simple data-holder for a method that needs to return multiple values. | 55 * A simple data-holder for a method that needs to return multiple values. |
| 492 */ | 56 */ |
| 493 class FinalConstVarOrType { | 57 class FinalConstVarOrType { |
| 494 /** | 58 /** |
| 495 * The 'final', 'const' or 'var' keyword, or `null` if none was given. | 59 * The 'final', 'const' or 'var' keyword, or `null` if none was given. |
| 496 */ | 60 */ |
| 497 final Token keyword; | 61 final Token keyword; |
| 498 | 62 |
| 499 /** | 63 /** |
| 500 * The type, of `null` if no type was specified. | 64 * The type, of `null` if no type was specified. |
| 501 */ | 65 */ |
| 502 final TypeName type; | 66 final TypeName type; |
| 503 | 67 |
| 504 /** | 68 /** |
| 505 * Initialize a newly created holder with the given [keyword] and [type]. | 69 * Initialize a newly created holder with the given [keyword] and [type]. |
| 506 */ | 70 */ |
| 507 FinalConstVarOrType(this.keyword, this.type); | 71 FinalConstVarOrType(this.keyword, this.type); |
| 508 } | 72 } |
| 509 | 73 |
| 510 /** | 74 /** |
| 511 * A dispatcher that will invoke the right parse method when re-parsing a | |
| 512 * specified child of the visited node. All of the methods in this class assume | |
| 513 * that the parser is positioned to parse the replacement for the node. All of | |
| 514 * the methods will throw an [IncrementalParseException] if the node could not | |
| 515 * be parsed for some reason. | |
| 516 */ | |
| 517 class IncrementalParseDispatcher implements AstVisitor<AstNode> { | |
| 518 /** | |
| 519 * The parser used to parse the replacement for the node. | |
| 520 */ | |
| 521 final Parser _parser; | |
| 522 | |
| 523 /** | |
| 524 * The node that is to be replaced. | |
| 525 */ | |
| 526 final AstNode _oldNode; | |
| 527 | |
| 528 /** | |
| 529 * Initialize a newly created dispatcher to parse a single node that will | |
| 530 * use the [_parser] to replace the [_oldNode]. | |
| 531 */ | |
| 532 IncrementalParseDispatcher(this._parser, this._oldNode); | |
| 533 | |
| 534 @override | |
| 535 AstNode visitAdjacentStrings(AdjacentStrings node) { | |
| 536 if (node.strings.contains(_oldNode)) { | |
| 537 return _parser.parseStringLiteral(); | |
| 538 } | |
| 539 return _notAChild(node); | |
| 540 } | |
| 541 | |
| 542 @override | |
| 543 AstNode visitAnnotation(Annotation node) { | |
| 544 if (identical(_oldNode, node.name)) { | |
| 545 throw new InsufficientContextException(); | |
| 546 } else if (identical(_oldNode, node.constructorName)) { | |
| 547 throw new InsufficientContextException(); | |
| 548 } else if (identical(_oldNode, node.arguments)) { | |
| 549 return _parser.parseArgumentList(); | |
| 550 } | |
| 551 return _notAChild(node); | |
| 552 } | |
| 553 | |
| 554 @override | |
| 555 AstNode visitArgumentList(ArgumentList node) { | |
| 556 if (node.arguments.contains(_oldNode)) { | |
| 557 return _parser.parseArgument(); | |
| 558 } | |
| 559 return _notAChild(node); | |
| 560 } | |
| 561 | |
| 562 @override | |
| 563 AstNode visitAsExpression(AsExpression node) { | |
| 564 if (identical(_oldNode, node.expression)) { | |
| 565 return _parser.parseBitwiseOrExpression(); | |
| 566 } else if (identical(_oldNode, node.type)) { | |
| 567 return _parser.parseTypeName(); | |
| 568 } | |
| 569 return _notAChild(node); | |
| 570 } | |
| 571 | |
| 572 @override | |
| 573 AstNode visitAssertStatement(AssertStatement node) { | |
| 574 if (identical(_oldNode, node.condition)) { | |
| 575 return _parser.parseExpression2(); | |
| 576 } | |
| 577 return _notAChild(node); | |
| 578 } | |
| 579 | |
| 580 @override | |
| 581 AstNode visitAssignmentExpression(AssignmentExpression node) { | |
| 582 if (identical(_oldNode, node.leftHandSide)) { | |
| 583 // TODO(brianwilkerson) If the assignment is part of a cascade section, | |
| 584 // then we don't have a single parse method that will work. | |
| 585 // Otherwise, we can parse a conditional expression, but need to ensure | |
| 586 // that the resulting expression is assignable. | |
| 587 // return parser.parseConditionalExpression(); | |
| 588 throw new InsufficientContextException(); | |
| 589 } else if (identical(_oldNode, node.rightHandSide)) { | |
| 590 if (_isCascadeAllowedInAssignment(node)) { | |
| 591 return _parser.parseExpression2(); | |
| 592 } | |
| 593 return _parser.parseExpressionWithoutCascade(); | |
| 594 } | |
| 595 return _notAChild(node); | |
| 596 } | |
| 597 | |
| 598 @override | |
| 599 AstNode visitAwaitExpression(AwaitExpression node) { | |
| 600 if (identical(_oldNode, node.expression)) { | |
| 601 // TODO(brianwilkerson) Depending on precedence, | |
| 602 // this might not be sufficient. | |
| 603 return _parser.parseExpression2(); | |
| 604 } | |
| 605 return _notAChild(node); | |
| 606 } | |
| 607 | |
| 608 @override | |
| 609 AstNode visitBinaryExpression(BinaryExpression node) { | |
| 610 if (identical(_oldNode, node.leftOperand)) { | |
| 611 throw new InsufficientContextException(); | |
| 612 } else if (identical(_oldNode, node.rightOperand)) { | |
| 613 throw new InsufficientContextException(); | |
| 614 } | |
| 615 return _notAChild(node); | |
| 616 } | |
| 617 | |
| 618 @override | |
| 619 AstNode visitBlock(Block node) { | |
| 620 if (node.statements.contains(_oldNode)) { | |
| 621 return _parser.parseStatement2(); | |
| 622 } | |
| 623 return _notAChild(node); | |
| 624 } | |
| 625 | |
| 626 @override | |
| 627 AstNode visitBlockFunctionBody(BlockFunctionBody node) { | |
| 628 if (identical(_oldNode, node.block)) { | |
| 629 return _parser.parseBlock(); | |
| 630 } | |
| 631 return _notAChild(node); | |
| 632 } | |
| 633 | |
| 634 @override | |
| 635 AstNode visitBooleanLiteral(BooleanLiteral node) => _notAChild(node); | |
| 636 | |
| 637 @override | |
| 638 AstNode visitBreakStatement(BreakStatement node) { | |
| 639 if (identical(_oldNode, node.label)) { | |
| 640 return _parser.parseSimpleIdentifier(); | |
| 641 } | |
| 642 return _notAChild(node); | |
| 643 } | |
| 644 | |
| 645 @override | |
| 646 AstNode visitCascadeExpression(CascadeExpression node) { | |
| 647 if (identical(_oldNode, node.target)) { | |
| 648 return _parser.parseConditionalExpression(); | |
| 649 } else if (node.cascadeSections.contains(_oldNode)) { | |
| 650 throw new InsufficientContextException(); | |
| 651 } | |
| 652 return _notAChild(node); | |
| 653 } | |
| 654 | |
| 655 @override | |
| 656 AstNode visitCatchClause(CatchClause node) { | |
| 657 if (identical(_oldNode, node.exceptionType)) { | |
| 658 return _parser.parseTypeName(); | |
| 659 } else if (identical(_oldNode, node.exceptionParameter)) { | |
| 660 return _parser.parseSimpleIdentifier(); | |
| 661 } else if (identical(_oldNode, node.stackTraceParameter)) { | |
| 662 return _parser.parseSimpleIdentifier(); | |
| 663 } else if (identical(_oldNode, node.body)) { | |
| 664 return _parser.parseBlock(); | |
| 665 } | |
| 666 return _notAChild(node); | |
| 667 } | |
| 668 | |
| 669 @override | |
| 670 AstNode visitClassDeclaration(ClassDeclaration node) { | |
| 671 if (identical(_oldNode, node.documentationComment)) { | |
| 672 throw new InsufficientContextException(); | |
| 673 } else if (node.metadata.contains(_oldNode)) { | |
| 674 return _parser.parseAnnotation(); | |
| 675 } else if (identical(_oldNode, node.name)) { | |
| 676 // Changing the class name changes whether a member is interpreted as a | |
| 677 // constructor or not, so we'll just have to re-parse the entire class. | |
| 678 throw new InsufficientContextException(); | |
| 679 } else if (identical(_oldNode, node.typeParameters)) { | |
| 680 return _parser.parseTypeParameterList(); | |
| 681 } else if (identical(_oldNode, node.extendsClause)) { | |
| 682 return _parser.parseExtendsClause(); | |
| 683 } else if (identical(_oldNode, node.withClause)) { | |
| 684 return _parser.parseWithClause(); | |
| 685 } else if (identical(_oldNode, node.implementsClause)) { | |
| 686 return _parser.parseImplementsClause(); | |
| 687 } else if (node.members.contains(_oldNode)) { | |
| 688 ClassMember member = _parser.parseClassMember(node.name.name); | |
| 689 if (member == null) { | |
| 690 throw new InsufficientContextException(); | |
| 691 } | |
| 692 return member; | |
| 693 } | |
| 694 return _notAChild(node); | |
| 695 } | |
| 696 | |
| 697 @override | |
| 698 AstNode visitClassTypeAlias(ClassTypeAlias node) { | |
| 699 if (identical(_oldNode, node.documentationComment)) { | |
| 700 throw new InsufficientContextException(); | |
| 701 } else if (node.metadata.contains(_oldNode)) { | |
| 702 return _parser.parseAnnotation(); | |
| 703 } else if (identical(_oldNode, node.name)) { | |
| 704 return _parser.parseSimpleIdentifier(); | |
| 705 } else if (identical(_oldNode, node.typeParameters)) { | |
| 706 return _parser.parseTypeParameterList(); | |
| 707 } else if (identical(_oldNode, node.superclass)) { | |
| 708 return _parser.parseTypeName(); | |
| 709 } else if (identical(_oldNode, node.withClause)) { | |
| 710 return _parser.parseWithClause(); | |
| 711 } else if (identical(_oldNode, node.implementsClause)) { | |
| 712 return _parser.parseImplementsClause(); | |
| 713 } | |
| 714 return _notAChild(node); | |
| 715 } | |
| 716 | |
| 717 @override | |
| 718 AstNode visitComment(Comment node) { | |
| 719 throw new InsufficientContextException(); | |
| 720 } | |
| 721 | |
| 722 @override | |
| 723 AstNode visitCommentReference(CommentReference node) { | |
| 724 if (identical(_oldNode, node.identifier)) { | |
| 725 return _parser.parsePrefixedIdentifier(); | |
| 726 } | |
| 727 return _notAChild(node); | |
| 728 } | |
| 729 | |
| 730 @override | |
| 731 AstNode visitCompilationUnit(CompilationUnit node) { | |
| 732 throw new InsufficientContextException(); | |
| 733 } | |
| 734 | |
| 735 @override | |
| 736 AstNode visitConditionalExpression(ConditionalExpression node) { | |
| 737 if (identical(_oldNode, node.condition)) { | |
| 738 return _parser.parseIfNullExpression(); | |
| 739 } else if (identical(_oldNode, node.thenExpression)) { | |
| 740 return _parser.parseExpressionWithoutCascade(); | |
| 741 } else if (identical(_oldNode, node.elseExpression)) { | |
| 742 return _parser.parseExpressionWithoutCascade(); | |
| 743 } | |
| 744 return _notAChild(node); | |
| 745 } | |
| 746 | |
| 747 @override | |
| 748 AstNode visitConstructorDeclaration(ConstructorDeclaration node) { | |
| 749 if (identical(_oldNode, node.documentationComment)) { | |
| 750 throw new InsufficientContextException(); | |
| 751 } else if (node.metadata.contains(_oldNode)) { | |
| 752 return _parser.parseAnnotation(); | |
| 753 } else if (identical(_oldNode, node.returnType)) { | |
| 754 throw new InsufficientContextException(); | |
| 755 } else if (identical(_oldNode, node.name)) { | |
| 756 throw new InsufficientContextException(); | |
| 757 } else if (identical(_oldNode, node.parameters)) { | |
| 758 return _parser.parseFormalParameterList(); | |
| 759 } else if (identical(_oldNode, node.redirectedConstructor)) { | |
| 760 throw new InsufficientContextException(); | |
| 761 } else if (node.initializers.contains(_oldNode)) { | |
| 762 throw new InsufficientContextException(); | |
| 763 } else if (identical(_oldNode, node.body)) { | |
| 764 throw new InsufficientContextException(); | |
| 765 } | |
| 766 return _notAChild(node); | |
| 767 } | |
| 768 | |
| 769 @override | |
| 770 AstNode visitConstructorFieldInitializer(ConstructorFieldInitializer node) { | |
| 771 if (identical(_oldNode, node.fieldName)) { | |
| 772 return _parser.parseSimpleIdentifier(); | |
| 773 } else if (identical(_oldNode, node.expression)) { | |
| 774 throw new InsufficientContextException(); | |
| 775 } | |
| 776 return _notAChild(node); | |
| 777 } | |
| 778 | |
| 779 @override | |
| 780 AstNode visitConstructorName(ConstructorName node) { | |
| 781 if (identical(_oldNode, node.type)) { | |
| 782 return _parser.parseTypeName(); | |
| 783 } else if (identical(_oldNode, node.name)) { | |
| 784 return _parser.parseSimpleIdentifier(); | |
| 785 } | |
| 786 return _notAChild(node); | |
| 787 } | |
| 788 | |
| 789 @override | |
| 790 AstNode visitContinueStatement(ContinueStatement node) { | |
| 791 if (identical(_oldNode, node.label)) { | |
| 792 return _parser.parseSimpleIdentifier(); | |
| 793 } | |
| 794 return _notAChild(node); | |
| 795 } | |
| 796 | |
| 797 @override | |
| 798 AstNode visitDeclaredIdentifier(DeclaredIdentifier node) { | |
| 799 if (identical(_oldNode, node.documentationComment)) { | |
| 800 throw new InsufficientContextException(); | |
| 801 } else if (node.metadata.contains(_oldNode)) { | |
| 802 return _parser.parseAnnotation(); | |
| 803 } else if (identical(_oldNode, node.type)) { | |
| 804 throw new InsufficientContextException(); | |
| 805 } else if (identical(_oldNode, node.identifier)) { | |
| 806 return _parser.parseSimpleIdentifier(); | |
| 807 } | |
| 808 return _notAChild(node); | |
| 809 } | |
| 810 | |
| 811 @override | |
| 812 AstNode visitDefaultFormalParameter(DefaultFormalParameter node) { | |
| 813 if (identical(_oldNode, node.parameter)) { | |
| 814 return _parser.parseNormalFormalParameter(); | |
| 815 } else if (identical(_oldNode, node.defaultValue)) { | |
| 816 return _parser.parseExpression2(); | |
| 817 } | |
| 818 return _notAChild(node); | |
| 819 } | |
| 820 | |
| 821 @override | |
| 822 AstNode visitDoStatement(DoStatement node) { | |
| 823 if (identical(_oldNode, node.body)) { | |
| 824 return _parser.parseStatement2(); | |
| 825 } else if (identical(_oldNode, node.condition)) { | |
| 826 return _parser.parseExpression2(); | |
| 827 } | |
| 828 return _notAChild(node); | |
| 829 } | |
| 830 | |
| 831 @override | |
| 832 AstNode visitDoubleLiteral(DoubleLiteral node) => _notAChild(node); | |
| 833 | |
| 834 @override | |
| 835 AstNode visitEmptyFunctionBody(EmptyFunctionBody node) => _notAChild(node); | |
| 836 | |
| 837 @override | |
| 838 AstNode visitEmptyStatement(EmptyStatement node) => _notAChild(node); | |
| 839 | |
| 840 @override | |
| 841 AstNode visitEnumConstantDeclaration(EnumConstantDeclaration node) { | |
| 842 if (identical(_oldNode, node.documentationComment)) { | |
| 843 throw new InsufficientContextException(); | |
| 844 } else if (node.metadata.contains(_oldNode)) { | |
| 845 return _parser.parseAnnotation(); | |
| 846 } else if (identical(_oldNode, node.name)) { | |
| 847 return _parser.parseSimpleIdentifier(); | |
| 848 } | |
| 849 return _notAChild(node); | |
| 850 } | |
| 851 | |
| 852 @override | |
| 853 AstNode visitEnumDeclaration(EnumDeclaration node) { | |
| 854 if (identical(_oldNode, node.documentationComment)) { | |
| 855 throw new InsufficientContextException(); | |
| 856 } else if (node.metadata.contains(_oldNode)) { | |
| 857 return _parser.parseAnnotation(); | |
| 858 } else if (identical(_oldNode, node.name)) { | |
| 859 return _parser.parseSimpleIdentifier(); | |
| 860 } else if (node.constants.contains(_oldNode)) { | |
| 861 throw new InsufficientContextException(); | |
| 862 } | |
| 863 return _notAChild(node); | |
| 864 } | |
| 865 | |
| 866 @override | |
| 867 AstNode visitExportDirective(ExportDirective node) { | |
| 868 if (identical(_oldNode, node.documentationComment)) { | |
| 869 throw new InsufficientContextException(); | |
| 870 } else if (node.metadata.contains(_oldNode)) { | |
| 871 return _parser.parseAnnotation(); | |
| 872 } else if (identical(_oldNode, node.uri)) { | |
| 873 return _parser.parseStringLiteral(); | |
| 874 } else if (node.combinators.contains(_oldNode)) { | |
| 875 throw new IncrementalParseException(); | |
| 876 //return parser.parseCombinator(); | |
| 877 } | |
| 878 return _notAChild(node); | |
| 879 } | |
| 880 | |
| 881 @override | |
| 882 AstNode visitExpressionFunctionBody(ExpressionFunctionBody node) { | |
| 883 if (identical(_oldNode, node.expression)) { | |
| 884 return _parser.parseExpression2(); | |
| 885 } | |
| 886 return _notAChild(node); | |
| 887 } | |
| 888 | |
| 889 @override | |
| 890 AstNode visitExpressionStatement(ExpressionStatement node) { | |
| 891 if (identical(_oldNode, node.expression)) { | |
| 892 return _parser.parseExpression2(); | |
| 893 } | |
| 894 return _notAChild(node); | |
| 895 } | |
| 896 | |
| 897 @override | |
| 898 AstNode visitExtendsClause(ExtendsClause node) { | |
| 899 if (identical(_oldNode, node.superclass)) { | |
| 900 return _parser.parseTypeName(); | |
| 901 } | |
| 902 return _notAChild(node); | |
| 903 } | |
| 904 | |
| 905 @override | |
| 906 AstNode visitFieldDeclaration(FieldDeclaration node) { | |
| 907 if (identical(_oldNode, node.documentationComment)) { | |
| 908 throw new InsufficientContextException(); | |
| 909 } else if (node.metadata.contains(_oldNode)) { | |
| 910 return _parser.parseAnnotation(); | |
| 911 } else if (identical(_oldNode, node.fields)) { | |
| 912 throw new InsufficientContextException(); | |
| 913 } | |
| 914 return _notAChild(node); | |
| 915 } | |
| 916 | |
| 917 @override | |
| 918 AstNode visitFieldFormalParameter(FieldFormalParameter node) { | |
| 919 if (identical(_oldNode, node.documentationComment)) { | |
| 920 throw new InsufficientContextException(); | |
| 921 } else if (node.metadata.contains(_oldNode)) { | |
| 922 return _parser.parseAnnotation(); | |
| 923 } else if (identical(_oldNode, node.type)) { | |
| 924 return _parser.parseTypeName(); | |
| 925 } else if (identical(_oldNode, node.identifier)) { | |
| 926 return _parser.parseSimpleIdentifier(); | |
| 927 } else if (identical(_oldNode, node.parameters)) { | |
| 928 return _parser.parseFormalParameterList(); | |
| 929 } | |
| 930 return _notAChild(node); | |
| 931 } | |
| 932 | |
| 933 @override | |
| 934 AstNode visitForEachStatement(ForEachStatement node) { | |
| 935 if (identical(_oldNode, node.loopVariable)) { | |
| 936 throw new InsufficientContextException(); | |
| 937 //return parser.parseDeclaredIdentifier(); | |
| 938 } else if (identical(_oldNode, node.identifier)) { | |
| 939 return _parser.parseSimpleIdentifier(); | |
| 940 } else if (identical(_oldNode, node.body)) { | |
| 941 return _parser.parseStatement2(); | |
| 942 } | |
| 943 return _notAChild(node); | |
| 944 } | |
| 945 | |
| 946 @override | |
| 947 AstNode visitFormalParameterList(FormalParameterList node) { | |
| 948 // We don't know which kind of parameter to parse. | |
| 949 throw new InsufficientContextException(); | |
| 950 } | |
| 951 | |
| 952 @override | |
| 953 AstNode visitForStatement(ForStatement node) { | |
| 954 if (identical(_oldNode, node.variables)) { | |
| 955 throw new InsufficientContextException(); | |
| 956 } else if (identical(_oldNode, node.initialization)) { | |
| 957 throw new InsufficientContextException(); | |
| 958 } else if (identical(_oldNode, node.condition)) { | |
| 959 return _parser.parseExpression2(); | |
| 960 } else if (node.updaters.contains(_oldNode)) { | |
| 961 return _parser.parseExpression2(); | |
| 962 } else if (identical(_oldNode, node.body)) { | |
| 963 return _parser.parseStatement2(); | |
| 964 } | |
| 965 return _notAChild(node); | |
| 966 } | |
| 967 | |
| 968 @override | |
| 969 AstNode visitFunctionDeclaration(FunctionDeclaration node) { | |
| 970 if (identical(_oldNode, node.documentationComment)) { | |
| 971 throw new InsufficientContextException(); | |
| 972 } else if (node.metadata.contains(_oldNode)) { | |
| 973 return _parser.parseAnnotation(); | |
| 974 } else if (identical(_oldNode, node.returnType)) { | |
| 975 return _parser.parseReturnType(); | |
| 976 } else if (identical(_oldNode, node.name)) { | |
| 977 return _parser.parseSimpleIdentifier(); | |
| 978 } else if (identical(_oldNode, node.functionExpression)) { | |
| 979 throw new InsufficientContextException(); | |
| 980 } | |
| 981 return _notAChild(node); | |
| 982 } | |
| 983 | |
| 984 @override | |
| 985 AstNode visitFunctionDeclarationStatement(FunctionDeclarationStatement node) { | |
| 986 if (identical(_oldNode, node.functionDeclaration)) { | |
| 987 throw new InsufficientContextException(); | |
| 988 } | |
| 989 return _notAChild(node); | |
| 990 } | |
| 991 | |
| 992 @override | |
| 993 AstNode visitFunctionExpression(FunctionExpression node) { | |
| 994 if (identical(_oldNode, node.parameters)) { | |
| 995 return _parser.parseFormalParameterList(); | |
| 996 } else if (identical(_oldNode, node.body)) { | |
| 997 throw new InsufficientContextException(); | |
| 998 } | |
| 999 return _notAChild(node); | |
| 1000 } | |
| 1001 | |
| 1002 @override | |
| 1003 AstNode visitFunctionExpressionInvocation(FunctionExpressionInvocation node) { | |
| 1004 if (identical(_oldNode, node.function)) { | |
| 1005 throw new InsufficientContextException(); | |
| 1006 } else if (identical(_oldNode, node.argumentList)) { | |
| 1007 return _parser.parseArgumentList(); | |
| 1008 } | |
| 1009 return _notAChild(node); | |
| 1010 } | |
| 1011 | |
| 1012 @override | |
| 1013 AstNode visitFunctionTypeAlias(FunctionTypeAlias node) { | |
| 1014 if (identical(_oldNode, node.documentationComment)) { | |
| 1015 throw new InsufficientContextException(); | |
| 1016 } else if (node.metadata.contains(_oldNode)) { | |
| 1017 return _parser.parseAnnotation(); | |
| 1018 } else if (identical(_oldNode, node.returnType)) { | |
| 1019 return _parser.parseReturnType(); | |
| 1020 } else if (identical(_oldNode, node.name)) { | |
| 1021 return _parser.parseSimpleIdentifier(); | |
| 1022 } else if (identical(_oldNode, node.typeParameters)) { | |
| 1023 return _parser.parseTypeParameterList(); | |
| 1024 } else if (identical(_oldNode, node.parameters)) { | |
| 1025 return _parser.parseFormalParameterList(); | |
| 1026 } | |
| 1027 return _notAChild(node); | |
| 1028 } | |
| 1029 | |
| 1030 @override | |
| 1031 AstNode visitFunctionTypedFormalParameter(FunctionTypedFormalParameter node) { | |
| 1032 if (identical(_oldNode, node.documentationComment)) { | |
| 1033 throw new InsufficientContextException(); | |
| 1034 } else if (node.metadata.contains(_oldNode)) { | |
| 1035 return _parser.parseAnnotation(); | |
| 1036 } else if (identical(_oldNode, node.returnType)) { | |
| 1037 return _parser.parseReturnType(); | |
| 1038 } else if (identical(_oldNode, node.identifier)) { | |
| 1039 return _parser.parseSimpleIdentifier(); | |
| 1040 } else if (identical(_oldNode, node.parameters)) { | |
| 1041 return _parser.parseFormalParameterList(); | |
| 1042 } | |
| 1043 return _notAChild(node); | |
| 1044 } | |
| 1045 | |
| 1046 @override | |
| 1047 AstNode visitHideCombinator(HideCombinator node) { | |
| 1048 if (node.hiddenNames.contains(_oldNode)) { | |
| 1049 return _parser.parseSimpleIdentifier(); | |
| 1050 } | |
| 1051 return _notAChild(node); | |
| 1052 } | |
| 1053 | |
| 1054 @override | |
| 1055 AstNode visitIfStatement(IfStatement node) { | |
| 1056 if (identical(_oldNode, node.condition)) { | |
| 1057 return _parser.parseExpression2(); | |
| 1058 } else if (identical(_oldNode, node.thenStatement)) { | |
| 1059 return _parser.parseStatement2(); | |
| 1060 } else if (identical(_oldNode, node.elseStatement)) { | |
| 1061 return _parser.parseStatement2(); | |
| 1062 } | |
| 1063 return _notAChild(node); | |
| 1064 } | |
| 1065 | |
| 1066 @override | |
| 1067 AstNode visitImplementsClause(ImplementsClause node) { | |
| 1068 if (node.interfaces.contains(node)) { | |
| 1069 return _parser.parseTypeName(); | |
| 1070 } | |
| 1071 return _notAChild(node); | |
| 1072 } | |
| 1073 | |
| 1074 @override | |
| 1075 AstNode visitImportDirective(ImportDirective node) { | |
| 1076 if (identical(_oldNode, node.documentationComment)) { | |
| 1077 throw new InsufficientContextException(); | |
| 1078 } else if (node.metadata.contains(_oldNode)) { | |
| 1079 return _parser.parseAnnotation(); | |
| 1080 } else if (identical(_oldNode, node.uri)) { | |
| 1081 return _parser.parseStringLiteral(); | |
| 1082 } else if (identical(_oldNode, node.prefix)) { | |
| 1083 return _parser.parseSimpleIdentifier(); | |
| 1084 } else if (node.combinators.contains(_oldNode)) { | |
| 1085 return _parser.parseCombinator(); | |
| 1086 } | |
| 1087 return _notAChild(node); | |
| 1088 } | |
| 1089 | |
| 1090 @override | |
| 1091 AstNode visitIndexExpression(IndexExpression node) { | |
| 1092 if (identical(_oldNode, node.target)) { | |
| 1093 throw new InsufficientContextException(); | |
| 1094 } else if (identical(_oldNode, node.index)) { | |
| 1095 return _parser.parseExpression2(); | |
| 1096 } | |
| 1097 return _notAChild(node); | |
| 1098 } | |
| 1099 | |
| 1100 @override | |
| 1101 AstNode visitInstanceCreationExpression(InstanceCreationExpression node) { | |
| 1102 if (identical(_oldNode, node.constructorName)) { | |
| 1103 return _parser.parseConstructorName(); | |
| 1104 } else if (identical(_oldNode, node.argumentList)) { | |
| 1105 return _parser.parseArgumentList(); | |
| 1106 } | |
| 1107 return _notAChild(node); | |
| 1108 } | |
| 1109 | |
| 1110 @override | |
| 1111 AstNode visitIntegerLiteral(IntegerLiteral node) => _notAChild(node); | |
| 1112 | |
| 1113 @override | |
| 1114 AstNode visitInterpolationExpression(InterpolationExpression node) { | |
| 1115 if (identical(_oldNode, node.expression)) { | |
| 1116 if (node.leftBracket == null) { | |
| 1117 throw new InsufficientContextException(); | |
| 1118 //return parser.parseThisOrSimpleIdentifier(); | |
| 1119 } | |
| 1120 return _parser.parseExpression2(); | |
| 1121 } | |
| 1122 return _notAChild(node); | |
| 1123 } | |
| 1124 | |
| 1125 @override | |
| 1126 AstNode visitInterpolationString(InterpolationString node) { | |
| 1127 throw new InsufficientContextException(); | |
| 1128 } | |
| 1129 | |
| 1130 @override | |
| 1131 AstNode visitIsExpression(IsExpression node) { | |
| 1132 if (identical(_oldNode, node.expression)) { | |
| 1133 return _parser.parseBitwiseOrExpression(); | |
| 1134 } else if (identical(_oldNode, node.type)) { | |
| 1135 return _parser.parseTypeName(); | |
| 1136 } | |
| 1137 return _notAChild(node); | |
| 1138 } | |
| 1139 | |
| 1140 @override | |
| 1141 AstNode visitLabel(Label node) { | |
| 1142 if (identical(_oldNode, node.label)) { | |
| 1143 return _parser.parseSimpleIdentifier(); | |
| 1144 } | |
| 1145 return _notAChild(node); | |
| 1146 } | |
| 1147 | |
| 1148 @override | |
| 1149 AstNode visitLabeledStatement(LabeledStatement node) { | |
| 1150 if (node.labels.contains(_oldNode)) { | |
| 1151 return _parser.parseLabel(); | |
| 1152 } else if (identical(_oldNode, node.statement)) { | |
| 1153 return _parser.parseStatement2(); | |
| 1154 } | |
| 1155 return _notAChild(node); | |
| 1156 } | |
| 1157 | |
| 1158 @override | |
| 1159 AstNode visitLibraryDirective(LibraryDirective node) { | |
| 1160 if (identical(_oldNode, node.documentationComment)) { | |
| 1161 throw new InsufficientContextException(); | |
| 1162 } else if (node.metadata.contains(_oldNode)) { | |
| 1163 return _parser.parseAnnotation(); | |
| 1164 } else if (identical(_oldNode, node.name)) { | |
| 1165 return _parser.parseLibraryIdentifier(); | |
| 1166 } | |
| 1167 return _notAChild(node); | |
| 1168 } | |
| 1169 | |
| 1170 @override | |
| 1171 AstNode visitLibraryIdentifier(LibraryIdentifier node) { | |
| 1172 if (node.components.contains(_oldNode)) { | |
| 1173 return _parser.parseSimpleIdentifier(); | |
| 1174 } | |
| 1175 return _notAChild(node); | |
| 1176 } | |
| 1177 | |
| 1178 @override | |
| 1179 AstNode visitListLiteral(ListLiteral node) { | |
| 1180 if (identical(_oldNode, node.typeArguments)) { | |
| 1181 return _parser.parseTypeArgumentList(); | |
| 1182 } else if (node.elements.contains(_oldNode)) { | |
| 1183 return _parser.parseExpression2(); | |
| 1184 } | |
| 1185 return _notAChild(node); | |
| 1186 } | |
| 1187 | |
| 1188 @override | |
| 1189 AstNode visitMapLiteral(MapLiteral node) { | |
| 1190 if (identical(_oldNode, node.typeArguments)) { | |
| 1191 return _parser.parseTypeArgumentList(); | |
| 1192 } else if (node.entries.contains(_oldNode)) { | |
| 1193 return _parser.parseMapLiteralEntry(); | |
| 1194 } | |
| 1195 return _notAChild(node); | |
| 1196 } | |
| 1197 | |
| 1198 @override | |
| 1199 AstNode visitMapLiteralEntry(MapLiteralEntry node) { | |
| 1200 if (identical(_oldNode, node.key)) { | |
| 1201 return _parser.parseExpression2(); | |
| 1202 } else if (identical(_oldNode, node.value)) { | |
| 1203 return _parser.parseExpression2(); | |
| 1204 } | |
| 1205 return _notAChild(node); | |
| 1206 } | |
| 1207 | |
| 1208 @override | |
| 1209 AstNode visitMethodDeclaration(MethodDeclaration node) { | |
| 1210 if (identical(_oldNode, node.documentationComment)) { | |
| 1211 throw new InsufficientContextException(); | |
| 1212 } else if (node.metadata.contains(_oldNode)) { | |
| 1213 return _parser.parseAnnotation(); | |
| 1214 } else if (identical(_oldNode, node.returnType)) { | |
| 1215 throw new InsufficientContextException(); | |
| 1216 //return parser.parseTypeName(); | |
| 1217 //return parser.parseReturnType(); | |
| 1218 } else if (identical(_oldNode, node.name)) { | |
| 1219 if (node.operatorKeyword != null) { | |
| 1220 throw new InsufficientContextException(); | |
| 1221 } | |
| 1222 return _parser.parseSimpleIdentifier(); | |
| 1223 } else if (identical(_oldNode, node.body)) { | |
| 1224 //return parser.parseFunctionBody(); | |
| 1225 throw new InsufficientContextException(); | |
| 1226 } else if (identical(_oldNode, node.parameters)) { | |
| 1227 // TODO(paulberry): if we want errors to be correct, we'll need to also | |
| 1228 // call _validateFormalParameterList, and sometimes | |
| 1229 // _validateModifiersForGetterOrSetterOrMethod. | |
| 1230 return _parser.parseFormalParameterList(); | |
| 1231 } | |
| 1232 return _notAChild(node); | |
| 1233 } | |
| 1234 | |
| 1235 @override | |
| 1236 AstNode visitMethodInvocation(MethodInvocation node) { | |
| 1237 if (identical(_oldNode, node.target)) { | |
| 1238 throw new IncrementalParseException(); | |
| 1239 } else if (identical(_oldNode, node.methodName)) { | |
| 1240 return _parser.parseSimpleIdentifier(); | |
| 1241 } else if (identical(_oldNode, node.argumentList)) { | |
| 1242 return _parser.parseArgumentList(); | |
| 1243 } | |
| 1244 return _notAChild(node); | |
| 1245 } | |
| 1246 | |
| 1247 @override | |
| 1248 AstNode visitNamedExpression(NamedExpression node) { | |
| 1249 if (identical(_oldNode, node.name)) { | |
| 1250 return _parser.parseLabel(); | |
| 1251 } else if (identical(_oldNode, node.expression)) { | |
| 1252 return _parser.parseExpression2(); | |
| 1253 } | |
| 1254 return _notAChild(node); | |
| 1255 } | |
| 1256 | |
| 1257 @override | |
| 1258 AstNode visitNativeClause(NativeClause node) { | |
| 1259 if (identical(_oldNode, node.name)) { | |
| 1260 return _parser.parseStringLiteral(); | |
| 1261 } | |
| 1262 return _notAChild(node); | |
| 1263 } | |
| 1264 | |
| 1265 @override | |
| 1266 AstNode visitNativeFunctionBody(NativeFunctionBody node) { | |
| 1267 if (identical(_oldNode, node.stringLiteral)) { | |
| 1268 return _parser.parseStringLiteral(); | |
| 1269 } | |
| 1270 return _notAChild(node); | |
| 1271 } | |
| 1272 | |
| 1273 @override | |
| 1274 AstNode visitNullLiteral(NullLiteral node) => _notAChild(node); | |
| 1275 | |
| 1276 @override | |
| 1277 AstNode visitParenthesizedExpression(ParenthesizedExpression node) { | |
| 1278 if (identical(_oldNode, node.expression)) { | |
| 1279 return _parser.parseExpression2(); | |
| 1280 } | |
| 1281 return _notAChild(node); | |
| 1282 } | |
| 1283 | |
| 1284 @override | |
| 1285 AstNode visitPartDirective(PartDirective node) { | |
| 1286 if (identical(_oldNode, node.documentationComment)) { | |
| 1287 throw new InsufficientContextException(); | |
| 1288 } else if (node.metadata.contains(_oldNode)) { | |
| 1289 return _parser.parseAnnotation(); | |
| 1290 } else if (identical(_oldNode, node.uri)) { | |
| 1291 return _parser.parseStringLiteral(); | |
| 1292 } | |
| 1293 return _notAChild(node); | |
| 1294 } | |
| 1295 | |
| 1296 @override | |
| 1297 AstNode visitPartOfDirective(PartOfDirective node) { | |
| 1298 if (identical(_oldNode, node.documentationComment)) { | |
| 1299 throw new InsufficientContextException(); | |
| 1300 } else if (node.metadata.contains(_oldNode)) { | |
| 1301 return _parser.parseAnnotation(); | |
| 1302 } else if (identical(_oldNode, node.libraryName)) { | |
| 1303 return _parser.parseLibraryIdentifier(); | |
| 1304 } | |
| 1305 return _notAChild(node); | |
| 1306 } | |
| 1307 | |
| 1308 @override | |
| 1309 AstNode visitPostfixExpression(PostfixExpression node) { | |
| 1310 if (identical(_oldNode, node.operand)) { | |
| 1311 throw new InsufficientContextException(); | |
| 1312 } | |
| 1313 return _notAChild(node); | |
| 1314 } | |
| 1315 | |
| 1316 @override | |
| 1317 AstNode visitPrefixedIdentifier(PrefixedIdentifier node) { | |
| 1318 if (identical(_oldNode, node.prefix)) { | |
| 1319 return _parser.parseSimpleIdentifier(); | |
| 1320 } else if (identical(_oldNode, node.identifier)) { | |
| 1321 return _parser.parseSimpleIdentifier(); | |
| 1322 } | |
| 1323 return _notAChild(node); | |
| 1324 } | |
| 1325 | |
| 1326 @override | |
| 1327 AstNode visitPrefixExpression(PrefixExpression node) { | |
| 1328 if (identical(_oldNode, node.operand)) { | |
| 1329 throw new InsufficientContextException(); | |
| 1330 } | |
| 1331 return _notAChild(node); | |
| 1332 } | |
| 1333 | |
| 1334 @override | |
| 1335 AstNode visitPropertyAccess(PropertyAccess node) { | |
| 1336 if (identical(_oldNode, node.target)) { | |
| 1337 throw new InsufficientContextException(); | |
| 1338 } else if (identical(_oldNode, node.propertyName)) { | |
| 1339 return _parser.parseSimpleIdentifier(); | |
| 1340 } | |
| 1341 return _notAChild(node); | |
| 1342 } | |
| 1343 | |
| 1344 @override | |
| 1345 AstNode visitRedirectingConstructorInvocation( | |
| 1346 RedirectingConstructorInvocation node) { | |
| 1347 if (identical(_oldNode, node.constructorName)) { | |
| 1348 return _parser.parseSimpleIdentifier(); | |
| 1349 } else if (identical(_oldNode, node.argumentList)) { | |
| 1350 return _parser.parseArgumentList(); | |
| 1351 } | |
| 1352 return _notAChild(node); | |
| 1353 } | |
| 1354 | |
| 1355 @override | |
| 1356 AstNode visitRethrowExpression(RethrowExpression node) => _notAChild(node); | |
| 1357 | |
| 1358 @override | |
| 1359 AstNode visitReturnStatement(ReturnStatement node) { | |
| 1360 if (identical(_oldNode, node.expression)) { | |
| 1361 return _parser.parseExpression2(); | |
| 1362 } | |
| 1363 return _notAChild(node); | |
| 1364 } | |
| 1365 | |
| 1366 @override | |
| 1367 AstNode visitScriptTag(ScriptTag node) => _notAChild(node); | |
| 1368 | |
| 1369 @override | |
| 1370 AstNode visitShowCombinator(ShowCombinator node) { | |
| 1371 if (node.shownNames.contains(_oldNode)) { | |
| 1372 return _parser.parseSimpleIdentifier(); | |
| 1373 } | |
| 1374 return _notAChild(node); | |
| 1375 } | |
| 1376 | |
| 1377 @override | |
| 1378 AstNode visitSimpleFormalParameter(SimpleFormalParameter node) { | |
| 1379 if (identical(_oldNode, node.documentationComment)) { | |
| 1380 throw new InsufficientContextException(); | |
| 1381 } else if (node.metadata.contains(_oldNode)) { | |
| 1382 return _parser.parseAnnotation(); | |
| 1383 } else if (identical(_oldNode, node.type)) { | |
| 1384 throw new InsufficientContextException(); | |
| 1385 } else if (identical(_oldNode, node.identifier)) { | |
| 1386 throw new InsufficientContextException(); | |
| 1387 } | |
| 1388 return _notAChild(node); | |
| 1389 } | |
| 1390 | |
| 1391 @override | |
| 1392 AstNode visitSimpleIdentifier(SimpleIdentifier node) => _notAChild(node); | |
| 1393 | |
| 1394 @override | |
| 1395 AstNode visitSimpleStringLiteral(SimpleStringLiteral node) => | |
| 1396 _notAChild(node); | |
| 1397 | |
| 1398 @override | |
| 1399 AstNode visitStringInterpolation(StringInterpolation node) { | |
| 1400 if (node.elements.contains(_oldNode)) { | |
| 1401 throw new InsufficientContextException(); | |
| 1402 } | |
| 1403 return _notAChild(node); | |
| 1404 } | |
| 1405 | |
| 1406 @override | |
| 1407 AstNode visitSuperConstructorInvocation(SuperConstructorInvocation node) { | |
| 1408 if (identical(_oldNode, node.constructorName)) { | |
| 1409 return _parser.parseSimpleIdentifier(); | |
| 1410 } else if (identical(_oldNode, node.argumentList)) { | |
| 1411 return _parser.parseArgumentList(); | |
| 1412 } | |
| 1413 return _notAChild(node); | |
| 1414 } | |
| 1415 | |
| 1416 @override | |
| 1417 AstNode visitSuperExpression(SuperExpression node) => _notAChild(node); | |
| 1418 | |
| 1419 @override | |
| 1420 AstNode visitSwitchCase(SwitchCase node) { | |
| 1421 if (node.labels.contains(_oldNode)) { | |
| 1422 return _parser.parseLabel(); | |
| 1423 } else if (identical(_oldNode, node.expression)) { | |
| 1424 return _parser.parseExpression2(); | |
| 1425 } else if (node.statements.contains(_oldNode)) { | |
| 1426 return _parser.parseStatement2(); | |
| 1427 } | |
| 1428 return _notAChild(node); | |
| 1429 } | |
| 1430 | |
| 1431 @override | |
| 1432 AstNode visitSwitchDefault(SwitchDefault node) { | |
| 1433 if (node.labels.contains(_oldNode)) { | |
| 1434 return _parser.parseLabel(); | |
| 1435 } else if (node.statements.contains(_oldNode)) { | |
| 1436 return _parser.parseStatement2(); | |
| 1437 } | |
| 1438 return _notAChild(node); | |
| 1439 } | |
| 1440 | |
| 1441 @override | |
| 1442 AstNode visitSwitchStatement(SwitchStatement node) { | |
| 1443 if (identical(_oldNode, node.expression)) { | |
| 1444 return _parser.parseExpression2(); | |
| 1445 } else if (node.members.contains(_oldNode)) { | |
| 1446 throw new InsufficientContextException(); | |
| 1447 } | |
| 1448 return _notAChild(node); | |
| 1449 } | |
| 1450 | |
| 1451 @override | |
| 1452 AstNode visitSymbolLiteral(SymbolLiteral node) => _notAChild(node); | |
| 1453 | |
| 1454 @override | |
| 1455 AstNode visitThisExpression(ThisExpression node) => _notAChild(node); | |
| 1456 | |
| 1457 @override | |
| 1458 AstNode visitThrowExpression(ThrowExpression node) { | |
| 1459 if (identical(_oldNode, node.expression)) { | |
| 1460 if (_isCascadeAllowedInThrow(node)) { | |
| 1461 return _parser.parseExpression2(); | |
| 1462 } | |
| 1463 return _parser.parseExpressionWithoutCascade(); | |
| 1464 } | |
| 1465 return _notAChild(node); | |
| 1466 } | |
| 1467 | |
| 1468 @override | |
| 1469 AstNode visitTopLevelVariableDeclaration(TopLevelVariableDeclaration node) { | |
| 1470 if (identical(_oldNode, node.documentationComment)) { | |
| 1471 throw new InsufficientContextException(); | |
| 1472 } else if (node.metadata.contains(_oldNode)) { | |
| 1473 return _parser.parseAnnotation(); | |
| 1474 } else if (identical(_oldNode, node.variables)) { | |
| 1475 throw new InsufficientContextException(); | |
| 1476 } | |
| 1477 return _notAChild(node); | |
| 1478 } | |
| 1479 | |
| 1480 @override | |
| 1481 AstNode visitTryStatement(TryStatement node) { | |
| 1482 if (identical(_oldNode, node.body)) { | |
| 1483 return _parser.parseBlock(); | |
| 1484 } else if (node.catchClauses.contains(_oldNode)) { | |
| 1485 throw new InsufficientContextException(); | |
| 1486 } else if (identical(_oldNode, node.finallyBlock)) { | |
| 1487 throw new InsufficientContextException(); | |
| 1488 } | |
| 1489 return _notAChild(node); | |
| 1490 } | |
| 1491 | |
| 1492 @override | |
| 1493 AstNode visitTypeArgumentList(TypeArgumentList node) { | |
| 1494 if (node.arguments.contains(_oldNode)) { | |
| 1495 return _parser.parseTypeName(); | |
| 1496 } | |
| 1497 return _notAChild(node); | |
| 1498 } | |
| 1499 | |
| 1500 @override | |
| 1501 AstNode visitTypeName(TypeName node) { | |
| 1502 if (identical(_oldNode, node.name)) { | |
| 1503 return _parser.parsePrefixedIdentifier(); | |
| 1504 } else if (identical(_oldNode, node.typeArguments)) { | |
| 1505 return _parser.parseTypeArgumentList(); | |
| 1506 } | |
| 1507 return _notAChild(node); | |
| 1508 } | |
| 1509 | |
| 1510 @override | |
| 1511 AstNode visitTypeParameter(TypeParameter node) { | |
| 1512 if (identical(_oldNode, node.documentationComment)) { | |
| 1513 throw new InsufficientContextException(); | |
| 1514 } else if (node.metadata.contains(_oldNode)) { | |
| 1515 return _parser.parseAnnotation(); | |
| 1516 } else if (identical(_oldNode, node.name)) { | |
| 1517 return _parser.parseSimpleIdentifier(); | |
| 1518 } else if (identical(_oldNode, node.bound)) { | |
| 1519 return _parser.parseTypeName(); | |
| 1520 } | |
| 1521 return _notAChild(node); | |
| 1522 } | |
| 1523 | |
| 1524 @override | |
| 1525 AstNode visitTypeParameterList(TypeParameterList node) { | |
| 1526 if (node.typeParameters.contains(node)) { | |
| 1527 return _parser.parseTypeParameter(); | |
| 1528 } | |
| 1529 return _notAChild(node); | |
| 1530 } | |
| 1531 | |
| 1532 @override | |
| 1533 AstNode visitVariableDeclaration(VariableDeclaration node) { | |
| 1534 if (identical(_oldNode, node.documentationComment)) { | |
| 1535 throw new InsufficientContextException(); | |
| 1536 } else if (node.metadata.contains(_oldNode)) { | |
| 1537 return _parser.parseAnnotation(); | |
| 1538 } else if (identical(_oldNode, node.name)) { | |
| 1539 throw new InsufficientContextException(); | |
| 1540 } else if (identical(_oldNode, node.initializer)) { | |
| 1541 throw new InsufficientContextException(); | |
| 1542 } | |
| 1543 return _notAChild(node); | |
| 1544 } | |
| 1545 | |
| 1546 @override | |
| 1547 AstNode visitVariableDeclarationList(VariableDeclarationList node) { | |
| 1548 if (identical(_oldNode, node.documentationComment)) { | |
| 1549 throw new InsufficientContextException(); | |
| 1550 } else if (node.metadata.contains(_oldNode)) { | |
| 1551 return _parser.parseAnnotation(); | |
| 1552 } else if (identical(_oldNode, node.type)) { | |
| 1553 // There is not enough context to know whether we should reparse the type | |
| 1554 // using parseReturnType() (which allows 'void') or parseTypeName() | |
| 1555 // (which doesn't). Note that even though the language disallows | |
| 1556 // variables of type 'void', the parser sometimes accepts them in the | |
| 1557 // course of error recovery (e.g. "class C { void v; }" | |
| 1558 throw new InsufficientContextException(); | |
| 1559 } else if (node.variables.contains(_oldNode)) { | |
| 1560 throw new InsufficientContextException(); | |
| 1561 } | |
| 1562 return _notAChild(node); | |
| 1563 } | |
| 1564 | |
| 1565 @override | |
| 1566 AstNode visitVariableDeclarationStatement(VariableDeclarationStatement node) { | |
| 1567 if (identical(_oldNode, node.variables)) { | |
| 1568 throw new InsufficientContextException(); | |
| 1569 } | |
| 1570 return _notAChild(node); | |
| 1571 } | |
| 1572 | |
| 1573 @override | |
| 1574 AstNode visitWhileStatement(WhileStatement node) { | |
| 1575 if (identical(_oldNode, node.condition)) { | |
| 1576 return _parser.parseExpression2(); | |
| 1577 } else if (identical(_oldNode, node.body)) { | |
| 1578 return _parser.parseStatement2(); | |
| 1579 } | |
| 1580 return _notAChild(node); | |
| 1581 } | |
| 1582 | |
| 1583 @override | |
| 1584 AstNode visitWithClause(WithClause node) { | |
| 1585 if (node.mixinTypes.contains(node)) { | |
| 1586 return _parser.parseTypeName(); | |
| 1587 } | |
| 1588 return _notAChild(node); | |
| 1589 } | |
| 1590 | |
| 1591 @override | |
| 1592 AstNode visitYieldStatement(YieldStatement node) { | |
| 1593 if (identical(_oldNode, node.expression)) { | |
| 1594 return _parser.parseExpression2(); | |
| 1595 } | |
| 1596 return _notAChild(node); | |
| 1597 } | |
| 1598 | |
| 1599 /** | |
| 1600 * Return `true` if the given assignment [expression] can have a cascade | |
| 1601 * expression on the right-hand side. | |
| 1602 */ | |
| 1603 bool _isCascadeAllowedInAssignment(AssignmentExpression expression) { | |
| 1604 // TODO(brianwilkerson) Implement this method. | |
| 1605 throw new InsufficientContextException(); | |
| 1606 } | |
| 1607 | |
| 1608 /** | |
| 1609 * Return `true` if the given throw [expression] can have a cascade | |
| 1610 * expression. | |
| 1611 */ | |
| 1612 bool _isCascadeAllowedInThrow(ThrowExpression expression) { | |
| 1613 // TODO(brianwilkerson) Implement this method. | |
| 1614 throw new InsufficientContextException(); | |
| 1615 } | |
| 1616 | |
| 1617 /** | |
| 1618 * Throw an exception indicating that the visited [node] was not the parent of | |
| 1619 * the node to be replaced. | |
| 1620 */ | |
| 1621 AstNode _notAChild(AstNode node) { | |
| 1622 throw new IncrementalParseException.con1( | |
| 1623 "Internal error: the visited node (a ${node.runtimeType}) was not the pa
rent of the node to be replaced (a ${_oldNode.runtimeType})"); | |
| 1624 } | |
| 1625 } | |
| 1626 | |
| 1627 /** | |
| 1628 * An exception that occurred while attempting to parse a replacement for a | |
| 1629 * specified node in an existing AST structure. | |
| 1630 */ | |
| 1631 class IncrementalParseException extends RuntimeException { | |
| 1632 /** | |
| 1633 * Initialize a newly created exception to have no message and to be its own | |
| 1634 * cause. | |
| 1635 */ | |
| 1636 IncrementalParseException() : super(); | |
| 1637 | |
| 1638 /** | |
| 1639 * Initialize a newly created exception to have the given [message] and to be | |
| 1640 * its own cause. | |
| 1641 */ | |
| 1642 IncrementalParseException.con1(String message) : super(message: message); | |
| 1643 | |
| 1644 /** | |
| 1645 * Initialize a newly created exception to have no message and to have the | |
| 1646 * given [cause]. | |
| 1647 */ | |
| 1648 IncrementalParseException.con2(Exception cause) : super(cause: cause); | |
| 1649 } | |
| 1650 | |
| 1651 /** | |
| 1652 * An object used to re-parse a single AST structure within a larger AST | |
| 1653 * structure. | |
| 1654 */ | |
| 1655 class IncrementalParser { | |
| 1656 /** | |
| 1657 * The source being parsed. | |
| 1658 */ | |
| 1659 final Source _source; | |
| 1660 | |
| 1661 /** | |
| 1662 * A map from old tokens to new tokens used during the cloning process. | |
| 1663 */ | |
| 1664 final TokenMap _tokenMap; | |
| 1665 | |
| 1666 /** | |
| 1667 * The error listener that will be informed of any errors that are found | |
| 1668 * during the parse. | |
| 1669 */ | |
| 1670 final AnalysisErrorListener _errorListener; | |
| 1671 | |
| 1672 /** | |
| 1673 * The node in the AST structure that contains the revised content. | |
| 1674 */ | |
| 1675 AstNode _updatedNode; | |
| 1676 | |
| 1677 /** | |
| 1678 * Initialize a newly created incremental parser to parse a portion of the | |
| 1679 * content of the given [_source]. The [_tokenMap] is a map from old tokens to | |
| 1680 * new tokens that is used during the cloning process. The [_errorListener] | |
| 1681 * will be informed of any errors that are found during the parse. | |
| 1682 */ | |
| 1683 IncrementalParser(this._source, this._tokenMap, this._errorListener); | |
| 1684 | |
| 1685 /** | |
| 1686 * Return the node in the AST structure that contains the revised content. | |
| 1687 */ | |
| 1688 AstNode get updatedNode => _updatedNode; | |
| 1689 | |
| 1690 /** | |
| 1691 * Given a range of tokens that were re-scanned, re-parse the minimum number | |
| 1692 * of tokens to produce a consistent AST structure. The range is represented | |
| 1693 * by the first and last tokens in the range. | |
| 1694 * | |
| 1695 * More specifically, the [leftToken] is the token in the new token stream | |
| 1696 * immediately to the left of the range of tokens that were inserted and the | |
| 1697 * [rightToken] is the token in the new token stream immediately to the right | |
| 1698 * of the range of tokens that were inserted. The [originalStart] and | |
| 1699 * [originalEnd] are the offsets in the original source of the first and last | |
| 1700 * characters that were modified. | |
| 1701 * | |
| 1702 * The tokens are assumed to be contained in the same token stream. | |
| 1703 */ | |
| 1704 AstNode reparse(AstNode originalStructure, Token leftToken, Token rightToken, | |
| 1705 int originalStart, int originalEnd) { | |
| 1706 AstNode oldNode = null; | |
| 1707 AstNode newNode = null; | |
| 1708 // | |
| 1709 // Find the first token that needs to be re-parsed. | |
| 1710 // | |
| 1711 Token firstToken = leftToken.next; | |
| 1712 if (identical(firstToken, rightToken)) { | |
| 1713 // If there are no new tokens, then we need to include at least one copied | |
| 1714 // node in the range. | |
| 1715 firstToken = leftToken; | |
| 1716 } | |
| 1717 // | |
| 1718 // Find the smallest AST node that encompasses the range of re-scanned | |
| 1719 // tokens. | |
| 1720 // | |
| 1721 if (originalEnd < originalStart) { | |
| 1722 oldNode = new NodeLocator(originalStart).searchWithin(originalStructure); | |
| 1723 } else { | |
| 1724 oldNode = new NodeLocator(originalStart, originalEnd) | |
| 1725 .searchWithin(originalStructure); | |
| 1726 } | |
| 1727 // | |
| 1728 // Find the token at which parsing is to begin. | |
| 1729 // | |
| 1730 int originalOffset = oldNode.offset; | |
| 1731 Token parseToken = _findTokenAt(firstToken, originalOffset); | |
| 1732 if (parseToken == null) { | |
| 1733 return null; | |
| 1734 } | |
| 1735 // | |
| 1736 // Parse the appropriate AST structure starting at the appropriate place. | |
| 1737 // | |
| 1738 Parser parser = new Parser(_source, _errorListener); | |
| 1739 parser.currentToken = parseToken; | |
| 1740 while (newNode == null) { | |
| 1741 AstNode parent = oldNode.parent; | |
| 1742 if (parent == null) { | |
| 1743 parseToken = _findFirstToken(parseToken); | |
| 1744 parser.currentToken = parseToken; | |
| 1745 return parser.parseCompilationUnit2(); | |
| 1746 } | |
| 1747 bool advanceToParent = false; | |
| 1748 try { | |
| 1749 IncrementalParseDispatcher dispatcher = | |
| 1750 new IncrementalParseDispatcher(parser, oldNode); | |
| 1751 IncrementalParseStateBuilder contextBuilder = | |
| 1752 new IncrementalParseStateBuilder(parser); | |
| 1753 contextBuilder.buildState(oldNode); | |
| 1754 newNode = parent.accept(dispatcher); | |
| 1755 // | |
| 1756 // Validate that the new node can replace the old node. | |
| 1757 // | |
| 1758 Token mappedToken = _tokenMap.get(oldNode.endToken.next); | |
| 1759 if (mappedToken == null || | |
| 1760 newNode == null || | |
| 1761 mappedToken.offset != newNode.endToken.next.offset || | |
| 1762 newNode.offset != oldNode.offset) { | |
| 1763 advanceToParent = true; | |
| 1764 } | |
| 1765 } on InsufficientContextException { | |
| 1766 advanceToParent = true; | |
| 1767 } catch (exception) { | |
| 1768 return null; | |
| 1769 } | |
| 1770 if (advanceToParent) { | |
| 1771 newNode = null; | |
| 1772 oldNode = parent; | |
| 1773 originalOffset = oldNode.offset; | |
| 1774 parseToken = _findTokenAt(parseToken, originalOffset); | |
| 1775 parser.currentToken = parseToken; | |
| 1776 } | |
| 1777 } | |
| 1778 _updatedNode = newNode; | |
| 1779 // | |
| 1780 // Replace the old node with the new node in a copy of the original AST | |
| 1781 // structure. | |
| 1782 // | |
| 1783 if (identical(oldNode, originalStructure)) { | |
| 1784 // We ended up re-parsing the whole structure, so there's no need for a | |
| 1785 // copy. | |
| 1786 ResolutionCopier.copyResolutionData(oldNode, newNode); | |
| 1787 return newNode; | |
| 1788 } | |
| 1789 ResolutionCopier.copyResolutionData(oldNode, newNode); | |
| 1790 IncrementalAstCloner cloner = | |
| 1791 new IncrementalAstCloner(oldNode, newNode, _tokenMap); | |
| 1792 return originalStructure.accept(cloner) as AstNode; | |
| 1793 } | |
| 1794 | |
| 1795 /** | |
| 1796 * Return the first (non-EOF) token in the token stream containing the | |
| 1797 * [firstToken]. | |
| 1798 */ | |
| 1799 Token _findFirstToken(Token firstToken) { | |
| 1800 while (firstToken.type != TokenType.EOF) { | |
| 1801 firstToken = firstToken.previous; | |
| 1802 } | |
| 1803 return firstToken.next; | |
| 1804 } | |
| 1805 | |
| 1806 /** | |
| 1807 * Find the token at or before the [firstToken] with the given [offset], or | |
| 1808 * `null` if there is no such token. | |
| 1809 */ | |
| 1810 Token _findTokenAt(Token firstToken, int offset) { | |
| 1811 while (firstToken.offset > offset && firstToken.type != TokenType.EOF) { | |
| 1812 firstToken = firstToken.previous; | |
| 1813 } | |
| 1814 return firstToken; | |
| 1815 } | |
| 1816 } | |
| 1817 | |
| 1818 /** | |
| 1819 * A visitor capable of inferring the correct parser state for incremental | |
| 1820 * parsing. This visitor visits each parent/child relationship in the chain of | |
| 1821 * ancestors of the node to be replaced (starting with the root of the parse | |
| 1822 * tree), updating the parser to the correct state for parsing the child of the | |
| 1823 * given parent. Once it has visited all of these relationships, the parser | |
| 1824 * will be in the correct state for reparsing the node to be replaced. | |
| 1825 */ | |
| 1826 class IncrementalParseStateBuilder extends SimpleAstVisitor { | |
| 1827 // TODO(paulberry): add support for other pieces of parser state (_inAsync, | |
| 1828 // _inGenerator, _inLoop, and _inSwitch). Note that _inLoop and _inSwitch | |
| 1829 // only affect error message generation. | |
| 1830 | |
| 1831 /** | |
| 1832 * The parser whose state should be built. | |
| 1833 */ | |
| 1834 final Parser _parser; | |
| 1835 | |
| 1836 /** | |
| 1837 * The child node in the parent/child relationship currently being visited. | |
| 1838 * (The corresponding parent is the node passed to the visit...() function.) | |
| 1839 */ | |
| 1840 AstNode _childNode; | |
| 1841 | |
| 1842 /** | |
| 1843 * Create an IncrementalParseStateBuilder which will build the correct state | |
| 1844 * for [_parser]. | |
| 1845 */ | |
| 1846 IncrementalParseStateBuilder(this._parser); | |
| 1847 | |
| 1848 /** | |
| 1849 * Build the correct parser state for parsing a replacement for [node]. | |
| 1850 */ | |
| 1851 void buildState(AstNode node) { | |
| 1852 List<AstNode> ancestors = <AstNode>[]; | |
| 1853 while (node != null) { | |
| 1854 ancestors.add(node); | |
| 1855 node = node.parent; | |
| 1856 } | |
| 1857 _parser._inInitializer = false; | |
| 1858 for (int i = ancestors.length - 2; i >= 0; i--) { | |
| 1859 _childNode = ancestors[i]; | |
| 1860 ancestors[i + 1].accept(this); | |
| 1861 } | |
| 1862 } | |
| 1863 | |
| 1864 @override | |
| 1865 void visitArgumentList(ArgumentList node) { | |
| 1866 _parser._inInitializer = false; | |
| 1867 } | |
| 1868 | |
| 1869 @override | |
| 1870 void visitConstructorFieldInitializer(ConstructorFieldInitializer node) { | |
| 1871 if (identical(_childNode, node.expression)) { | |
| 1872 _parser._inInitializer = true; | |
| 1873 } | |
| 1874 } | |
| 1875 | |
| 1876 @override | |
| 1877 void visitIndexExpression(IndexExpression node) { | |
| 1878 if (identical(_childNode, node.index)) { | |
| 1879 _parser._inInitializer = false; | |
| 1880 } | |
| 1881 } | |
| 1882 | |
| 1883 @override | |
| 1884 void visitInterpolationExpression(InterpolationExpression node) { | |
| 1885 if (identical(_childNode, node.expression)) { | |
| 1886 _parser._inInitializer = false; | |
| 1887 } | |
| 1888 } | |
| 1889 | |
| 1890 @override | |
| 1891 void visitListLiteral(ListLiteral node) { | |
| 1892 if (node.elements.contains(_childNode)) { | |
| 1893 _parser._inInitializer = false; | |
| 1894 } | |
| 1895 } | |
| 1896 | |
| 1897 @override | |
| 1898 void visitMapLiteral(MapLiteral node) { | |
| 1899 if (node.entries.contains(_childNode)) { | |
| 1900 _parser._inInitializer = false; | |
| 1901 } | |
| 1902 } | |
| 1903 | |
| 1904 @override | |
| 1905 void visitParenthesizedExpression(ParenthesizedExpression node) { | |
| 1906 if (identical(_childNode, node.expression)) { | |
| 1907 _parser._inInitializer = false; | |
| 1908 } | |
| 1909 } | |
| 1910 } | |
| 1911 | |
| 1912 /** | |
| 1913 * An exception indicating that an AST node cannot be re-parsed because there is | |
| 1914 * not enough context to know how to re-parse the node. Clients can attempt to | |
| 1915 * re-parse the parent of the node. | |
| 1916 */ | |
| 1917 class InsufficientContextException extends IncrementalParseException { | |
| 1918 /** | |
| 1919 * Initialize a newly created exception to have no message and to be its own | |
| 1920 * cause. | |
| 1921 */ | |
| 1922 InsufficientContextException() : super(); | |
| 1923 | |
| 1924 /** | |
| 1925 * Initialize a newly created exception to have the given [message] and to be | |
| 1926 * its own cause. | |
| 1927 */ | |
| 1928 InsufficientContextException.con1(String message) : super.con1(message); | |
| 1929 | |
| 1930 /** | |
| 1931 * Initialize a newly created exception to have no message and to have the | |
| 1932 * given [cause]. | |
| 1933 */ | |
| 1934 InsufficientContextException.con2(Exception cause) : super.con2(cause); | |
| 1935 } | |
| 1936 | |
| 1937 /** | |
| 1938 * Wrapper around [Function] which should be called with "target" and | |
| 1939 * "arguments". | |
| 1940 */ | |
| 1941 class MethodTrampoline { | |
| 1942 int parameterCount; | |
| 1943 Function trampoline; | |
| 1944 MethodTrampoline(this.parameterCount, this.trampoline); | |
| 1945 Object invoke(target, List arguments) { | |
| 1946 if (arguments.length != parameterCount) { | |
| 1947 throw new IllegalArgumentException( | |
| 1948 "${arguments.length} != $parameterCount"); | |
| 1949 } | |
| 1950 switch (parameterCount) { | |
| 1951 case 0: | |
| 1952 return trampoline(target); | |
| 1953 case 1: | |
| 1954 return trampoline(target, arguments[0]); | |
| 1955 case 2: | |
| 1956 return trampoline(target, arguments[0], arguments[1]); | |
| 1957 case 3: | |
| 1958 return trampoline(target, arguments[0], arguments[1], arguments[2]); | |
| 1959 case 4: | |
| 1960 return trampoline( | |
| 1961 target, arguments[0], arguments[1], arguments[2], arguments[3]); | |
| 1962 default: | |
| 1963 throw new IllegalArgumentException("Not implemented for > 4 arguments"); | |
| 1964 } | |
| 1965 } | |
| 1966 } | |
| 1967 | |
| 1968 /** | |
| 1969 * A simple data-holder for a method that needs to return multiple values. | 75 * A simple data-holder for a method that needs to return multiple values. |
| 1970 */ | 76 */ |
| 1971 class Modifiers { | 77 class Modifiers { |
| 1972 /** | 78 /** |
| 1973 * The token representing the keyword 'abstract', or `null` if the keyword was | 79 * The token representing the keyword 'abstract', or `null` if the keyword was |
| 1974 * not found. | 80 * not found. |
| 1975 */ | 81 */ |
| 1976 Token abstractKeyword; | 82 Token abstractKeyword; |
| 1977 | 83 |
| 1978 /** | 84 /** |
| (...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2068 */ | 174 */ |
| 2069 final Source _source; | 175 final Source _source; |
| 2070 | 176 |
| 2071 /** | 177 /** |
| 2072 * The error listener that will be informed of any errors that are found | 178 * The error listener that will be informed of any errors that are found |
| 2073 * during the parse. | 179 * during the parse. |
| 2074 */ | 180 */ |
| 2075 final AnalysisErrorListener _errorListener; | 181 final AnalysisErrorListener _errorListener; |
| 2076 | 182 |
| 2077 /** | 183 /** |
| 2078 * An [errorListener] lock, if more than `0`, then errors are not reported. | 184 * An [_errorListener] lock, if more than `0`, then errors are not reported. |
| 2079 */ | 185 */ |
| 2080 int _errorListenerLock = 0; | 186 int _errorListenerLock = 0; |
| 2081 | 187 |
| 2082 /** | 188 /** |
| 189 * A flag indicating whether the parser is to parse asserts in the initializer |
| 190 * list of a constructor. |
| 191 */ |
| 192 bool _enableAssertInitializer = false; |
| 193 |
| 194 /** |
| 195 * A flag indicating whether the parser is to parse the non-nullable modifier |
| 196 * in type names. |
| 197 */ |
| 198 bool _enableNnbd = false; |
| 199 |
| 200 /** |
| 2083 * A flag indicating whether parser is to parse function bodies. | 201 * A flag indicating whether parser is to parse function bodies. |
| 2084 */ | 202 */ |
| 2085 bool _parseFunctionBodies = true; | 203 bool _parseFunctionBodies = true; |
| 2086 | 204 |
| 2087 /** | 205 /** |
| 2088 * The next token to be parsed. | 206 * The next token to be parsed. |
| 2089 */ | 207 */ |
| 2090 Token _currentToken; | 208 Token _currentToken; |
| 2091 | 209 |
| 2092 /** | 210 /** |
| 2093 * A flag indicating whether the parser is currently in a function body marked | 211 * A flag indicating whether the parser is currently in a function body marked |
| 2094 * as being 'async'. | 212 * as being 'async'. |
| 2095 */ | 213 */ |
| 2096 bool _inAsync = false; | 214 bool _inAsync = false; |
| 2097 | 215 |
| 2098 /** | 216 /** |
| 2099 * A flag indicating whether the parser is currently in a function body marked | 217 * A flag indicating whether the parser is currently in a function body marked |
| 2100 * as being 'async'. | 218 * (by a star) as being a generator. |
| 2101 */ | 219 */ |
| 2102 bool _inGenerator = false; | 220 bool _inGenerator = false; |
| 2103 | 221 |
| 2104 /** | 222 /** |
| 2105 * A flag indicating whether the parser is currently in the body of a loop. | 223 * A flag indicating whether the parser is currently in the body of a loop. |
| 2106 */ | 224 */ |
| 2107 bool _inLoop = false; | 225 bool _inLoop = false; |
| 2108 | 226 |
| 2109 /** | 227 /** |
| 2110 * A flag indicating whether the parser is currently in a switch statement. | 228 * A flag indicating whether the parser is currently in a switch statement. |
| 2111 */ | 229 */ |
| 2112 bool _inSwitch = false; | 230 bool _inSwitch = false; |
| 2113 | 231 |
| 2114 /** | 232 /** |
| 2115 * A flag indicating whether the parser is currently in a constructor field | 233 * A flag indicating whether the parser is currently in a constructor field |
| 2116 * initializer, with no intervening parens, braces, or brackets. | 234 * initializer, with no intervening parentheses, braces, or brackets. |
| 2117 */ | 235 */ |
| 2118 bool _inInitializer = false; | 236 bool _inInitializer = false; |
| 2119 | 237 |
| 2120 /** | 238 /** |
| 2121 * A flag indicating whether the parser is to parse generic method syntax. | 239 * A flag indicating whether the parser is to parse generic method syntax. |
| 2122 */ | 240 */ |
| 2123 bool parseGenericMethods = false; | 241 bool parseGenericMethods = false; |
| 2124 | 242 |
| 2125 /** | 243 /** |
| 2126 * Initialize a newly created parser to parse the content of the given | 244 * A flag indicating whether to parse generic method comments, of the form |
| 2127 * [_source] and to report any errors that are found to the given | 245 * `/*=T*/` and `/*<T>*/`. |
| 2128 * [_errorListener]. | 246 */ |
| 247 bool parseGenericMethodComments = false; |
| 248 |
| 249 /** |
| 250 * Initialize a newly created parser to parse tokens in the given [_source] |
| 251 * and to report any errors that are found to the given [_errorListener]. |
| 2129 */ | 252 */ |
| 2130 Parser(this._source, this._errorListener); | 253 Parser(this._source, this._errorListener); |
| 2131 | 254 |
| 2132 void set currentToken(Token currentToken) { | 255 /** |
| 2133 this._currentToken = currentToken; | 256 * Return the current token. |
| 257 */ |
| 258 Token get currentToken => _currentToken; |
| 259 |
| 260 /** |
| 261 * Set the token with which the parse is to begin to the given [token]. |
| 262 */ |
| 263 void set currentToken(Token token) { |
| 264 this._currentToken = token; |
| 265 } |
| 266 |
| 267 /** |
| 268 * Return `true` if the parser is to parse asserts in the initializer list of |
| 269 * a constructor. |
| 270 */ |
| 271 bool get enableAssertInitializer => _enableAssertInitializer; |
| 272 |
| 273 /** |
| 274 * Set whether the parser is to parse asserts in the initializer list of a |
| 275 * constructor to match the given [enable] flag. |
| 276 */ |
| 277 void set enableAssertInitializer(bool enable) { |
| 278 _enableAssertInitializer = enable; |
| 279 } |
| 280 |
| 281 /** |
| 282 * Return `true` if the parser is to parse the non-nullable modifier in type |
| 283 * names. |
| 284 */ |
| 285 bool get enableNnbd => _enableNnbd; |
| 286 |
| 287 /** |
| 288 * Set whether the parser is to parse the non-nullable modifier in type names |
| 289 * to match the given [enable] flag. |
| 290 */ |
| 291 void set enableNnbd(bool enable) { |
| 292 _enableNnbd = enable; |
| 2134 } | 293 } |
| 2135 | 294 |
| 2136 /** | 295 /** |
| 2137 * Return `true` if the current token is the first token of a return type that | 296 * Return `true` if the current token is the first token of a return type that |
| 2138 * is followed by an identifier, possibly followed by a list of type | 297 * is followed by an identifier, possibly followed by a list of type |
| 2139 * parameters, followed by a left-parenthesis. This is used by | 298 * parameters, followed by a left-parenthesis. This is used by |
| 2140 * [_parseTypeAlias] to determine whether or not to parse a return type. | 299 * [parseTypeAlias] to determine whether or not to parse a return type. |
| 2141 */ | 300 */ |
| 301 @deprecated |
| 2142 bool get hasReturnTypeInTypeAlias { | 302 bool get hasReturnTypeInTypeAlias { |
| 2143 Token next = _skipReturnType(_currentToken); | 303 Token next = skipReturnType(_currentToken); |
| 2144 if (next == null) { | 304 if (next == null) { |
| 2145 return false; | 305 return false; |
| 2146 } | 306 } |
| 2147 return _tokenMatchesIdentifier(next); | 307 return _tokenMatchesIdentifier(next); |
| 2148 } | 308 } |
| 2149 | 309 |
| 2150 /** | 310 /** |
| 2151 * Set whether the parser is to parse the async support. | 311 * Set whether the parser is to parse the async support. |
| 312 * |
| 313 * Support for removing the 'async' library has been removed. |
| 2152 */ | 314 */ |
| 2153 @deprecated | 315 @deprecated |
| 2154 void set parseAsync(bool parseAsync) { | 316 void set parseAsync(bool parseAsync) {} |
| 2155 // Async support cannot be disabled | 317 |
| 2156 } | |
| 2157 | |
| 2158 /** | |
| 2159 * Set whether the parser is to parse deferred libraries. | |
| 2160 */ | |
| 2161 @deprecated | 318 @deprecated |
| 2162 void set parseDeferredLibraries(bool parseDeferredLibraries) { | 319 bool get parseConditionalDirectives => true; |
| 2163 // Deferred libraries support cannot be disabled | 320 |
| 2164 } | |
| 2165 | |
| 2166 /** | |
| 2167 * Set whether the parser is to parse enum declarations. | |
| 2168 */ | |
| 2169 @deprecated | 321 @deprecated |
| 2170 void set parseEnum(bool parseEnum) { | 322 void set parseConditionalDirectives(bool value) {} |
| 2171 // Enum support cannot be disabled | |
| 2172 } | |
| 2173 | 323 |
| 2174 /** | 324 /** |
| 2175 * Set whether parser is to parse function bodies. | 325 * Set whether parser is to parse function bodies. |
| 2176 */ | 326 */ |
| 2177 void set parseFunctionBodies(bool parseFunctionBodies) { | 327 void set parseFunctionBodies(bool parseFunctionBodies) { |
| 2178 this._parseFunctionBodies = parseFunctionBodies; | 328 this._parseFunctionBodies = parseFunctionBodies; |
| 2179 } | 329 } |
| 2180 | 330 |
| 2181 /** | 331 /** |
| 2182 * Advance to the next token in the token stream, making it the new current | |
| 2183 * token and return the token that was current before this method was invoked. | |
| 2184 */ | |
| 2185 Token getAndAdvance() { | |
| 2186 Token token = _currentToken; | |
| 2187 _advance(); | |
| 2188 return token; | |
| 2189 } | |
| 2190 | |
| 2191 /** | |
| 2192 * Parse an annotation. Return the annotation that was parsed. | |
| 2193 * | |
| 2194 * annotation ::= | |
| 2195 * '@' qualified ('.' identifier)? arguments? | |
| 2196 * | |
| 2197 */ | |
| 2198 Annotation parseAnnotation() { | |
| 2199 Token atSign = _expect(TokenType.AT); | |
| 2200 Identifier name = parsePrefixedIdentifier(); | |
| 2201 Token period = null; | |
| 2202 SimpleIdentifier constructorName = null; | |
| 2203 if (_matches(TokenType.PERIOD)) { | |
| 2204 period = getAndAdvance(); | |
| 2205 constructorName = parseSimpleIdentifier(); | |
| 2206 } | |
| 2207 ArgumentList arguments = null; | |
| 2208 if (_matches(TokenType.OPEN_PAREN)) { | |
| 2209 arguments = parseArgumentList(); | |
| 2210 } | |
| 2211 return new Annotation(atSign, name, period, constructorName, arguments); | |
| 2212 } | |
| 2213 | |
| 2214 /** | |
| 2215 * Parse an argument. Return the argument that was parsed. | |
| 2216 * | |
| 2217 * argument ::= | |
| 2218 * namedArgument | |
| 2219 * | expression | |
| 2220 * | |
| 2221 * namedArgument ::= | |
| 2222 * label expression | |
| 2223 */ | |
| 2224 Expression parseArgument() { | |
| 2225 // | |
| 2226 // Both namedArgument and expression can start with an identifier, but only | |
| 2227 // namedArgument can have an identifier followed by a colon. | |
| 2228 // | |
| 2229 if (_matchesIdentifier() && _tokenMatches(_peek(), TokenType.COLON)) { | |
| 2230 return new NamedExpression(parseLabel(), parseExpression2()); | |
| 2231 } else { | |
| 2232 return parseExpression2(); | |
| 2233 } | |
| 2234 } | |
| 2235 | |
| 2236 /** | |
| 2237 * Parse a list of arguments. Return the argument list that was parsed. | |
| 2238 * | |
| 2239 * arguments ::= | |
| 2240 * '(' argumentList? ')' | |
| 2241 * | |
| 2242 * argumentList ::= | |
| 2243 * namedArgument (',' namedArgument)* | |
| 2244 * | expressionList (',' namedArgument)* | |
| 2245 */ | |
| 2246 ArgumentList parseArgumentList() { | |
| 2247 Token leftParenthesis = _expect(TokenType.OPEN_PAREN); | |
| 2248 List<Expression> arguments = new List<Expression>(); | |
| 2249 if (_matches(TokenType.CLOSE_PAREN)) { | |
| 2250 return new ArgumentList(leftParenthesis, arguments, getAndAdvance()); | |
| 2251 } | |
| 2252 // | |
| 2253 // Even though unnamed arguments must all appear before any named arguments, | |
| 2254 // we allow them to appear in any order so that we can recover faster. | |
| 2255 // | |
| 2256 bool wasInInitializer = _inInitializer; | |
| 2257 _inInitializer = false; | |
| 2258 try { | |
| 2259 Expression argument = parseArgument(); | |
| 2260 arguments.add(argument); | |
| 2261 bool foundNamedArgument = argument is NamedExpression; | |
| 2262 bool generatedError = false; | |
| 2263 while (_optional(TokenType.COMMA)) { | |
| 2264 argument = parseArgument(); | |
| 2265 arguments.add(argument); | |
| 2266 if (foundNamedArgument) { | |
| 2267 bool blankArgument = | |
| 2268 argument is SimpleIdentifier && argument.name.isEmpty; | |
| 2269 if (!generatedError && | |
| 2270 !(argument is NamedExpression && !blankArgument)) { | |
| 2271 // Report the error, once, but allow the arguments to be in any | |
| 2272 // order in the AST. | |
| 2273 _reportErrorForCurrentToken( | |
| 2274 ParserErrorCode.POSITIONAL_AFTER_NAMED_ARGUMENT); | |
| 2275 generatedError = true; | |
| 2276 } | |
| 2277 } else if (argument is NamedExpression) { | |
| 2278 foundNamedArgument = true; | |
| 2279 } | |
| 2280 } | |
| 2281 // TODO(brianwilkerson) Recovery: Look at the left parenthesis to see | |
| 2282 // whether there is a matching right parenthesis. If there is, then we're | |
| 2283 // more likely missing a comma and should go back to parsing arguments. | |
| 2284 Token rightParenthesis = _expect(TokenType.CLOSE_PAREN); | |
| 2285 return new ArgumentList(leftParenthesis, arguments, rightParenthesis); | |
| 2286 } finally { | |
| 2287 _inInitializer = wasInInitializer; | |
| 2288 } | |
| 2289 } | |
| 2290 | |
| 2291 /** | |
| 2292 * Parse a bitwise or expression. Return the bitwise or expression that was | |
| 2293 * parsed. | |
| 2294 * | |
| 2295 * bitwiseOrExpression ::= | |
| 2296 * bitwiseXorExpression ('|' bitwiseXorExpression)* | |
| 2297 * | 'super' ('|' bitwiseXorExpression)+ | |
| 2298 */ | |
| 2299 Expression parseBitwiseOrExpression() { | |
| 2300 Expression expression; | |
| 2301 if (_matchesKeyword(Keyword.SUPER) && | |
| 2302 _tokenMatches(_peek(), TokenType.BAR)) { | |
| 2303 expression = new SuperExpression(getAndAdvance()); | |
| 2304 } else { | |
| 2305 expression = _parseBitwiseXorExpression(); | |
| 2306 } | |
| 2307 while (_matches(TokenType.BAR)) { | |
| 2308 Token operator = getAndAdvance(); | |
| 2309 expression = new BinaryExpression( | |
| 2310 expression, operator, _parseBitwiseXorExpression()); | |
| 2311 } | |
| 2312 return expression; | |
| 2313 } | |
| 2314 | |
| 2315 /** | |
| 2316 * Parse a block. Return the block that was parsed. | |
| 2317 * | |
| 2318 * block ::= | |
| 2319 * '{' statements '}' | |
| 2320 */ | |
| 2321 Block parseBlock() { | |
| 2322 Token leftBracket = _expect(TokenType.OPEN_CURLY_BRACKET); | |
| 2323 List<Statement> statements = new List<Statement>(); | |
| 2324 Token statementStart = _currentToken; | |
| 2325 while ( | |
| 2326 !_matches(TokenType.EOF) && !_matches(TokenType.CLOSE_CURLY_BRACKET)) { | |
| 2327 Statement statement = parseStatement2(); | |
| 2328 if (statement != null) { | |
| 2329 statements.add(statement); | |
| 2330 } | |
| 2331 if (identical(_currentToken, statementStart)) { | |
| 2332 // Ensure that we are making progress and report an error if we're not. | |
| 2333 _reportErrorForToken(ParserErrorCode.UNEXPECTED_TOKEN, _currentToken, | |
| 2334 [_currentToken.lexeme]); | |
| 2335 _advance(); | |
| 2336 } | |
| 2337 statementStart = _currentToken; | |
| 2338 } | |
| 2339 Token rightBracket = _expect(TokenType.CLOSE_CURLY_BRACKET); | |
| 2340 return new Block(leftBracket, statements, rightBracket); | |
| 2341 } | |
| 2342 | |
| 2343 /** | |
| 2344 * Parse a class member. The [className] is the name of the class containing | |
| 2345 * the member being parsed. Return the class member that was parsed, or `null` | |
| 2346 * if what was found was not a valid class member. | |
| 2347 * | |
| 2348 * classMemberDefinition ::= | |
| 2349 * declaration ';' | |
| 2350 * | methodSignature functionBody | |
| 2351 */ | |
| 2352 ClassMember parseClassMember(String className) { | |
| 2353 CommentAndMetadata commentAndMetadata = _parseCommentAndMetadata(); | |
| 2354 Modifiers modifiers = _parseModifiers(); | |
| 2355 if (_matchesKeyword(Keyword.VOID)) { | |
| 2356 TypeName returnType = parseReturnType(); | |
| 2357 if (_matchesKeyword(Keyword.GET) && _tokenMatchesIdentifier(_peek())) { | |
| 2358 _validateModifiersForGetterOrSetterOrMethod(modifiers); | |
| 2359 return _parseGetter(commentAndMetadata, modifiers.externalKeyword, | |
| 2360 modifiers.staticKeyword, returnType); | |
| 2361 } else if (_matchesKeyword(Keyword.SET) && | |
| 2362 _tokenMatchesIdentifier(_peek())) { | |
| 2363 _validateModifiersForGetterOrSetterOrMethod(modifiers); | |
| 2364 return _parseSetter(commentAndMetadata, modifiers.externalKeyword, | |
| 2365 modifiers.staticKeyword, returnType); | |
| 2366 } else if (_matchesKeyword(Keyword.OPERATOR) && _isOperator(_peek())) { | |
| 2367 _validateModifiersForOperator(modifiers); | |
| 2368 return _parseOperator( | |
| 2369 commentAndMetadata, modifiers.externalKeyword, returnType); | |
| 2370 } else if (_matchesIdentifier() && | |
| 2371 _peek().matchesAny([ | |
| 2372 TokenType.OPEN_PAREN, | |
| 2373 TokenType.OPEN_CURLY_BRACKET, | |
| 2374 TokenType.FUNCTION, | |
| 2375 TokenType.LT | |
| 2376 ])) { | |
| 2377 _validateModifiersForGetterOrSetterOrMethod(modifiers); | |
| 2378 return _parseMethodDeclarationAfterReturnType(commentAndMetadata, | |
| 2379 modifiers.externalKeyword, modifiers.staticKeyword, returnType); | |
| 2380 } else { | |
| 2381 // | |
| 2382 // We have found an error of some kind. Try to recover. | |
| 2383 // | |
| 2384 if (_matchesIdentifier()) { | |
| 2385 if (_peek().matchesAny( | |
| 2386 [TokenType.EQ, TokenType.COMMA, TokenType.SEMICOLON])) { | |
| 2387 // | |
| 2388 // We appear to have a variable declaration with a type of "void". | |
| 2389 // | |
| 2390 _reportErrorForNode(ParserErrorCode.VOID_VARIABLE, returnType); | |
| 2391 return _parseInitializedIdentifierList( | |
| 2392 commentAndMetadata, | |
| 2393 modifiers.staticKeyword, | |
| 2394 _validateModifiersForField(modifiers), | |
| 2395 returnType); | |
| 2396 } | |
| 2397 } | |
| 2398 if (_isOperator(_currentToken)) { | |
| 2399 // | |
| 2400 // We appear to have found an operator declaration without the | |
| 2401 // 'operator' keyword. | |
| 2402 // | |
| 2403 _validateModifiersForOperator(modifiers); | |
| 2404 return _parseOperator( | |
| 2405 commentAndMetadata, modifiers.externalKeyword, returnType); | |
| 2406 } | |
| 2407 _reportErrorForToken( | |
| 2408 ParserErrorCode.EXPECTED_EXECUTABLE, _currentToken); | |
| 2409 return null; | |
| 2410 } | |
| 2411 } else if (_matchesKeyword(Keyword.GET) && | |
| 2412 _tokenMatchesIdentifier(_peek())) { | |
| 2413 _validateModifiersForGetterOrSetterOrMethod(modifiers); | |
| 2414 return _parseGetter(commentAndMetadata, modifiers.externalKeyword, | |
| 2415 modifiers.staticKeyword, null); | |
| 2416 } else if (_matchesKeyword(Keyword.SET) && | |
| 2417 _tokenMatchesIdentifier(_peek())) { | |
| 2418 _validateModifiersForGetterOrSetterOrMethod(modifiers); | |
| 2419 return _parseSetter(commentAndMetadata, modifiers.externalKeyword, | |
| 2420 modifiers.staticKeyword, null); | |
| 2421 } else if (_matchesKeyword(Keyword.OPERATOR) && _isOperator(_peek())) { | |
| 2422 _validateModifiersForOperator(modifiers); | |
| 2423 return _parseOperator( | |
| 2424 commentAndMetadata, modifiers.externalKeyword, null); | |
| 2425 } else if (!_matchesIdentifier()) { | |
| 2426 // | |
| 2427 // Recover from an error. | |
| 2428 // | |
| 2429 if (_matchesKeyword(Keyword.CLASS)) { | |
| 2430 _reportErrorForCurrentToken(ParserErrorCode.CLASS_IN_CLASS); | |
| 2431 // TODO(brianwilkerson) We don't currently have any way to capture the | |
| 2432 // class that was parsed. | |
| 2433 _parseClassDeclaration(commentAndMetadata, null); | |
| 2434 return null; | |
| 2435 } else if (_matchesKeyword(Keyword.ABSTRACT) && | |
| 2436 _tokenMatchesKeyword(_peek(), Keyword.CLASS)) { | |
| 2437 _reportErrorForToken(ParserErrorCode.CLASS_IN_CLASS, _peek()); | |
| 2438 // TODO(brianwilkerson) We don't currently have any way to capture the | |
| 2439 // class that was parsed. | |
| 2440 _parseClassDeclaration(commentAndMetadata, getAndAdvance()); | |
| 2441 return null; | |
| 2442 } else if (_matchesKeyword(Keyword.ENUM)) { | |
| 2443 _reportErrorForToken(ParserErrorCode.ENUM_IN_CLASS, _peek()); | |
| 2444 // TODO(brianwilkerson) We don't currently have any way to capture the | |
| 2445 // enum that was parsed. | |
| 2446 _parseEnumDeclaration(commentAndMetadata); | |
| 2447 return null; | |
| 2448 } else if (_isOperator(_currentToken)) { | |
| 2449 // | |
| 2450 // We appear to have found an operator declaration without the | |
| 2451 // 'operator' keyword. | |
| 2452 // | |
| 2453 _validateModifiersForOperator(modifiers); | |
| 2454 return _parseOperator( | |
| 2455 commentAndMetadata, modifiers.externalKeyword, null); | |
| 2456 } | |
| 2457 Token keyword = modifiers.varKeyword; | |
| 2458 if (keyword == null) { | |
| 2459 keyword = modifiers.finalKeyword; | |
| 2460 } | |
| 2461 if (keyword == null) { | |
| 2462 keyword = modifiers.constKeyword; | |
| 2463 } | |
| 2464 if (keyword != null) { | |
| 2465 // | |
| 2466 // We appear to have found an incomplete field declaration. | |
| 2467 // | |
| 2468 _reportErrorForCurrentToken(ParserErrorCode.MISSING_IDENTIFIER); | |
| 2469 List<VariableDeclaration> variables = new List<VariableDeclaration>(); | |
| 2470 variables.add( | |
| 2471 new VariableDeclaration(_createSyntheticIdentifier(), null, null)); | |
| 2472 return new FieldDeclaration( | |
| 2473 commentAndMetadata.comment, | |
| 2474 commentAndMetadata.metadata, | |
| 2475 null, | |
| 2476 new VariableDeclarationList(null, null, keyword, null, variables), | |
| 2477 _expectSemicolon()); | |
| 2478 } | |
| 2479 _reportErrorForToken( | |
| 2480 ParserErrorCode.EXPECTED_CLASS_MEMBER, _currentToken); | |
| 2481 if (commentAndMetadata.comment != null || | |
| 2482 !commentAndMetadata.metadata.isEmpty) { | |
| 2483 // | |
| 2484 // We appear to have found an incomplete declaration at the end of the | |
| 2485 // class. At this point it consists of a metadata, which we don't want | |
| 2486 // to loose, so we'll treat it as a method declaration with a missing | |
| 2487 // name, parameters and empty body. | |
| 2488 // | |
| 2489 return new MethodDeclaration( | |
| 2490 commentAndMetadata.comment, | |
| 2491 commentAndMetadata.metadata, | |
| 2492 null, | |
| 2493 null, | |
| 2494 null, | |
| 2495 null, | |
| 2496 null, | |
| 2497 _createSyntheticIdentifier(), | |
| 2498 null, | |
| 2499 new FormalParameterList( | |
| 2500 null, new List<FormalParameter>(), null, null, null), | |
| 2501 new EmptyFunctionBody(_createSyntheticToken(TokenType.SEMICOLON))); | |
| 2502 } | |
| 2503 return null; | |
| 2504 } else if (_tokenMatches(_peek(), TokenType.PERIOD) && | |
| 2505 _tokenMatchesIdentifier(_peekAt(2)) && | |
| 2506 _tokenMatches(_peekAt(3), TokenType.OPEN_PAREN)) { | |
| 2507 return _parseConstructor( | |
| 2508 commentAndMetadata, | |
| 2509 modifiers.externalKeyword, | |
| 2510 _validateModifiersForConstructor(modifiers), | |
| 2511 modifiers.factoryKeyword, | |
| 2512 parseSimpleIdentifier(), | |
| 2513 getAndAdvance(), | |
| 2514 parseSimpleIdentifier(), | |
| 2515 parseFormalParameterList()); | |
| 2516 } else if (_tokenMatches(_peek(), TokenType.OPEN_PAREN)) { | |
| 2517 SimpleIdentifier methodName = parseSimpleIdentifier(); | |
| 2518 FormalParameterList parameters = parseFormalParameterList(); | |
| 2519 if (_matches(TokenType.COLON) || | |
| 2520 modifiers.factoryKeyword != null || | |
| 2521 methodName.name == className) { | |
| 2522 return _parseConstructor( | |
| 2523 commentAndMetadata, | |
| 2524 modifiers.externalKeyword, | |
| 2525 _validateModifiersForConstructor(modifiers), | |
| 2526 modifiers.factoryKeyword, | |
| 2527 methodName, | |
| 2528 null, | |
| 2529 null, | |
| 2530 parameters); | |
| 2531 } | |
| 2532 _validateModifiersForGetterOrSetterOrMethod(modifiers); | |
| 2533 _validateFormalParameterList(parameters); | |
| 2534 return _parseMethodDeclarationAfterParameters( | |
| 2535 commentAndMetadata, | |
| 2536 modifiers.externalKeyword, | |
| 2537 modifiers.staticKeyword, | |
| 2538 null, | |
| 2539 methodName, | |
| 2540 null, | |
| 2541 parameters); | |
| 2542 } else if (_peek() | |
| 2543 .matchesAny([TokenType.EQ, TokenType.COMMA, TokenType.SEMICOLON])) { | |
| 2544 if (modifiers.constKeyword == null && | |
| 2545 modifiers.finalKeyword == null && | |
| 2546 modifiers.varKeyword == null) { | |
| 2547 _reportErrorForCurrentToken( | |
| 2548 ParserErrorCode.MISSING_CONST_FINAL_VAR_OR_TYPE); | |
| 2549 } | |
| 2550 return _parseInitializedIdentifierList(commentAndMetadata, | |
| 2551 modifiers.staticKeyword, _validateModifiersForField(modifiers), null); | |
| 2552 } else if (_matchesKeyword(Keyword.TYPEDEF)) { | |
| 2553 _reportErrorForCurrentToken(ParserErrorCode.TYPEDEF_IN_CLASS); | |
| 2554 // TODO(brianwilkerson) We don't currently have any way to capture the | |
| 2555 // function type alias that was parsed. | |
| 2556 _parseFunctionTypeAlias(commentAndMetadata, getAndAdvance()); | |
| 2557 return null; | |
| 2558 } else if (parseGenericMethods) { | |
| 2559 Token token = _skipTypeParameterList(_peek()); | |
| 2560 if (token != null && _tokenMatches(token, TokenType.OPEN_PAREN)) { | |
| 2561 return _parseMethodDeclarationAfterReturnType(commentAndMetadata, | |
| 2562 modifiers.externalKeyword, modifiers.staticKeyword, null); | |
| 2563 } | |
| 2564 } | |
| 2565 TypeName type = parseTypeName(); | |
| 2566 if (_matchesKeyword(Keyword.GET) && _tokenMatchesIdentifier(_peek())) { | |
| 2567 _validateModifiersForGetterOrSetterOrMethod(modifiers); | |
| 2568 return _parseGetter(commentAndMetadata, modifiers.externalKeyword, | |
| 2569 modifiers.staticKeyword, type); | |
| 2570 } else if (_matchesKeyword(Keyword.SET) && | |
| 2571 _tokenMatchesIdentifier(_peek())) { | |
| 2572 _validateModifiersForGetterOrSetterOrMethod(modifiers); | |
| 2573 return _parseSetter(commentAndMetadata, modifiers.externalKeyword, | |
| 2574 modifiers.staticKeyword, type); | |
| 2575 } else if (_matchesKeyword(Keyword.OPERATOR) && _isOperator(_peek())) { | |
| 2576 _validateModifiersForOperator(modifiers); | |
| 2577 return _parseOperator( | |
| 2578 commentAndMetadata, modifiers.externalKeyword, type); | |
| 2579 } else if (!_matchesIdentifier()) { | |
| 2580 if (_matches(TokenType.CLOSE_CURLY_BRACKET)) { | |
| 2581 // | |
| 2582 // We appear to have found an incomplete declaration at the end of the | |
| 2583 // class. At this point it consists of a type name, so we'll treat it as | |
| 2584 // a field declaration with a missing field name and semicolon. | |
| 2585 // | |
| 2586 return _parseInitializedIdentifierList( | |
| 2587 commentAndMetadata, | |
| 2588 modifiers.staticKeyword, | |
| 2589 _validateModifiersForField(modifiers), | |
| 2590 type); | |
| 2591 } | |
| 2592 if (_isOperator(_currentToken)) { | |
| 2593 // | |
| 2594 // We appear to have found an operator declaration without the | |
| 2595 // 'operator' keyword. | |
| 2596 // | |
| 2597 _validateModifiersForOperator(modifiers); | |
| 2598 return _parseOperator( | |
| 2599 commentAndMetadata, modifiers.externalKeyword, type); | |
| 2600 } | |
| 2601 // | |
| 2602 // We appear to have found an incomplete declaration before another | |
| 2603 // declaration. At this point it consists of a type name, so we'll treat | |
| 2604 // it as a field declaration with a missing field name and semicolon. | |
| 2605 // | |
| 2606 _reportErrorForToken( | |
| 2607 ParserErrorCode.EXPECTED_CLASS_MEMBER, _currentToken); | |
| 2608 try { | |
| 2609 _lockErrorListener(); | |
| 2610 return _parseInitializedIdentifierList( | |
| 2611 commentAndMetadata, | |
| 2612 modifiers.staticKeyword, | |
| 2613 _validateModifiersForField(modifiers), | |
| 2614 type); | |
| 2615 } finally { | |
| 2616 _unlockErrorListener(); | |
| 2617 } | |
| 2618 } else if (_tokenMatches(_peek(), TokenType.OPEN_PAREN)) { | |
| 2619 SimpleIdentifier methodName = parseSimpleIdentifier(); | |
| 2620 FormalParameterList parameters = parseFormalParameterList(); | |
| 2621 if (methodName.name == className) { | |
| 2622 _reportErrorForNode(ParserErrorCode.CONSTRUCTOR_WITH_RETURN_TYPE, type); | |
| 2623 return _parseConstructor( | |
| 2624 commentAndMetadata, | |
| 2625 modifiers.externalKeyword, | |
| 2626 _validateModifiersForConstructor(modifiers), | |
| 2627 modifiers.factoryKeyword, | |
| 2628 methodName, | |
| 2629 null, | |
| 2630 null, | |
| 2631 parameters); | |
| 2632 } | |
| 2633 _validateModifiersForGetterOrSetterOrMethod(modifiers); | |
| 2634 _validateFormalParameterList(parameters); | |
| 2635 return _parseMethodDeclarationAfterParameters( | |
| 2636 commentAndMetadata, | |
| 2637 modifiers.externalKeyword, | |
| 2638 modifiers.staticKeyword, | |
| 2639 type, | |
| 2640 methodName, | |
| 2641 null, | |
| 2642 parameters); | |
| 2643 } else if (parseGenericMethods && _tokenMatches(_peek(), TokenType.LT)) { | |
| 2644 return _parseMethodDeclarationAfterReturnType(commentAndMetadata, | |
| 2645 modifiers.externalKeyword, modifiers.staticKeyword, type); | |
| 2646 } else if (_tokenMatches(_peek(), TokenType.OPEN_CURLY_BRACKET)) { | |
| 2647 // We have found "TypeName identifier {", and are guessing that this is a | |
| 2648 // getter without the keyword 'get'. | |
| 2649 _validateModifiersForGetterOrSetterOrMethod(modifiers); | |
| 2650 _reportErrorForCurrentToken(ParserErrorCode.MISSING_GET); | |
| 2651 _currentToken = _injectToken( | |
| 2652 new Parser_SyntheticKeywordToken(Keyword.GET, _currentToken.offset)); | |
| 2653 return _parseGetter(commentAndMetadata, modifiers.externalKeyword, | |
| 2654 modifiers.staticKeyword, type); | |
| 2655 } | |
| 2656 return _parseInitializedIdentifierList(commentAndMetadata, | |
| 2657 modifiers.staticKeyword, _validateModifiersForField(modifiers), type); | |
| 2658 } | |
| 2659 | |
| 2660 /** | |
| 2661 * Parse a single combinator. Return the combinator that was parsed, or `null` | |
| 2662 * if no combinator is found. | |
| 2663 * | |
| 2664 * combinator ::= | |
| 2665 * 'show' identifier (',' identifier)* | |
| 2666 * | 'hide' identifier (',' identifier)* | |
| 2667 */ | |
| 2668 Combinator parseCombinator() { | |
| 2669 if (_matchesString(_SHOW) || _matchesString(_HIDE)) { | |
| 2670 Token keyword = getAndAdvance(); | |
| 2671 List<SimpleIdentifier> names = _parseIdentifierList(); | |
| 2672 if (keyword.lexeme == _SHOW) { | |
| 2673 return new ShowCombinator(keyword, names); | |
| 2674 } else { | |
| 2675 return new HideCombinator(keyword, names); | |
| 2676 } | |
| 2677 } | |
| 2678 return null; | |
| 2679 } | |
| 2680 | |
| 2681 /** | |
| 2682 * Parse a compilation unit, starting with the given [token]. Return the | |
| 2683 * compilation unit that was parsed. | |
| 2684 */ | |
| 2685 CompilationUnit parseCompilationUnit(Token token) { | |
| 2686 _currentToken = token; | |
| 2687 return parseCompilationUnit2(); | |
| 2688 } | |
| 2689 | |
| 2690 /** | |
| 2691 * Parse a compilation unit. Return the compilation unit that was parsed. | |
| 2692 * | |
| 2693 * Specified: | |
| 2694 * | |
| 2695 * compilationUnit ::= | |
| 2696 * scriptTag? directive* topLevelDeclaration* | |
| 2697 * | |
| 2698 * Actual: | |
| 2699 * | |
| 2700 * compilationUnit ::= | |
| 2701 * scriptTag? topLevelElement* | |
| 2702 * | |
| 2703 * topLevelElement ::= | |
| 2704 * directive | |
| 2705 * | topLevelDeclaration | |
| 2706 */ | |
| 2707 CompilationUnit parseCompilationUnit2() { | |
| 2708 Token firstToken = _currentToken; | |
| 2709 ScriptTag scriptTag = null; | |
| 2710 if (_matches(TokenType.SCRIPT_TAG)) { | |
| 2711 scriptTag = new ScriptTag(getAndAdvance()); | |
| 2712 } | |
| 2713 // | |
| 2714 // Even though all directives must appear before declarations and must occur | |
| 2715 // in a given order, we allow directives and declarations to occur in any | |
| 2716 // order so that we can recover better. | |
| 2717 // | |
| 2718 bool libraryDirectiveFound = false; | |
| 2719 bool partOfDirectiveFound = false; | |
| 2720 bool partDirectiveFound = false; | |
| 2721 bool directiveFoundAfterDeclaration = false; | |
| 2722 List<Directive> directives = new List<Directive>(); | |
| 2723 List<CompilationUnitMember> declarations = | |
| 2724 new List<CompilationUnitMember>(); | |
| 2725 Token memberStart = _currentToken; | |
| 2726 while (!_matches(TokenType.EOF)) { | |
| 2727 CommentAndMetadata commentAndMetadata = _parseCommentAndMetadata(); | |
| 2728 if ((_matchesKeyword(Keyword.IMPORT) || | |
| 2729 _matchesKeyword(Keyword.EXPORT) || | |
| 2730 _matchesKeyword(Keyword.LIBRARY) || | |
| 2731 _matchesKeyword(Keyword.PART)) && | |
| 2732 !_tokenMatches(_peek(), TokenType.PERIOD) && | |
| 2733 !_tokenMatches(_peek(), TokenType.LT) && | |
| 2734 !_tokenMatches(_peek(), TokenType.OPEN_PAREN)) { | |
| 2735 Directive directive = _parseDirective(commentAndMetadata); | |
| 2736 if (declarations.length > 0 && !directiveFoundAfterDeclaration) { | |
| 2737 _reportErrorForToken(ParserErrorCode.DIRECTIVE_AFTER_DECLARATION, | |
| 2738 directive.beginToken); | |
| 2739 directiveFoundAfterDeclaration = true; | |
| 2740 } | |
| 2741 if (directive is LibraryDirective) { | |
| 2742 if (libraryDirectiveFound) { | |
| 2743 _reportErrorForCurrentToken( | |
| 2744 ParserErrorCode.MULTIPLE_LIBRARY_DIRECTIVES); | |
| 2745 } else { | |
| 2746 if (directives.length > 0) { | |
| 2747 _reportErrorForToken(ParserErrorCode.LIBRARY_DIRECTIVE_NOT_FIRST, | |
| 2748 directive.libraryKeyword); | |
| 2749 } | |
| 2750 libraryDirectiveFound = true; | |
| 2751 } | |
| 2752 } else if (directive is PartDirective) { | |
| 2753 partDirectiveFound = true; | |
| 2754 } else if (partDirectiveFound) { | |
| 2755 if (directive is ExportDirective) { | |
| 2756 _reportErrorForToken( | |
| 2757 ParserErrorCode.EXPORT_DIRECTIVE_AFTER_PART_DIRECTIVE, | |
| 2758 directive.keyword); | |
| 2759 } else if (directive is ImportDirective) { | |
| 2760 _reportErrorForToken( | |
| 2761 ParserErrorCode.IMPORT_DIRECTIVE_AFTER_PART_DIRECTIVE, | |
| 2762 directive.keyword); | |
| 2763 } | |
| 2764 } | |
| 2765 if (directive is PartOfDirective) { | |
| 2766 if (partOfDirectiveFound) { | |
| 2767 _reportErrorForCurrentToken( | |
| 2768 ParserErrorCode.MULTIPLE_PART_OF_DIRECTIVES); | |
| 2769 } else { | |
| 2770 int directiveCount = directives.length; | |
| 2771 for (int i = 0; i < directiveCount; i++) { | |
| 2772 _reportErrorForToken( | |
| 2773 ParserErrorCode.NON_PART_OF_DIRECTIVE_IN_PART, | |
| 2774 directives[i].keyword); | |
| 2775 } | |
| 2776 partOfDirectiveFound = true; | |
| 2777 } | |
| 2778 } else { | |
| 2779 if (partOfDirectiveFound) { | |
| 2780 _reportErrorForToken(ParserErrorCode.NON_PART_OF_DIRECTIVE_IN_PART, | |
| 2781 directive.keyword); | |
| 2782 } | |
| 2783 } | |
| 2784 directives.add(directive); | |
| 2785 } else if (_matches(TokenType.SEMICOLON)) { | |
| 2786 _reportErrorForToken(ParserErrorCode.UNEXPECTED_TOKEN, _currentToken, | |
| 2787 [_currentToken.lexeme]); | |
| 2788 _advance(); | |
| 2789 } else { | |
| 2790 CompilationUnitMember member = | |
| 2791 _parseCompilationUnitMember(commentAndMetadata); | |
| 2792 if (member != null) { | |
| 2793 declarations.add(member); | |
| 2794 } | |
| 2795 } | |
| 2796 if (identical(_currentToken, memberStart)) { | |
| 2797 _reportErrorForToken(ParserErrorCode.UNEXPECTED_TOKEN, _currentToken, | |
| 2798 [_currentToken.lexeme]); | |
| 2799 _advance(); | |
| 2800 while (!_matches(TokenType.EOF) && | |
| 2801 !_couldBeStartOfCompilationUnitMember()) { | |
| 2802 _advance(); | |
| 2803 } | |
| 2804 } | |
| 2805 memberStart = _currentToken; | |
| 2806 } | |
| 2807 return new CompilationUnit( | |
| 2808 firstToken, scriptTag, directives, declarations, _currentToken); | |
| 2809 } | |
| 2810 | |
| 2811 /** | |
| 2812 * Parse a conditional expression. Return the conditional expression that was | |
| 2813 * parsed. | |
| 2814 * | |
| 2815 * conditionalExpression ::= | |
| 2816 * ifNullExpression ('?' expressionWithoutCascade ':' expressionWithou
tCascade)? | |
| 2817 */ | |
| 2818 Expression parseConditionalExpression() { | |
| 2819 Expression condition = parseIfNullExpression(); | |
| 2820 if (!_matches(TokenType.QUESTION)) { | |
| 2821 return condition; | |
| 2822 } | |
| 2823 Token question = getAndAdvance(); | |
| 2824 Expression thenExpression = parseExpressionWithoutCascade(); | |
| 2825 Token colon = _expect(TokenType.COLON); | |
| 2826 Expression elseExpression = parseExpressionWithoutCascade(); | |
| 2827 return new ConditionalExpression( | |
| 2828 condition, question, thenExpression, colon, elseExpression); | |
| 2829 } | |
| 2830 | |
| 2831 /** | |
| 2832 * Parse the name of a constructor. Return the constructor name that was | |
| 2833 * parsed. | |
| 2834 * | |
| 2835 * constructorName: | |
| 2836 * type ('.' identifier)? | |
| 2837 */ | |
| 2838 ConstructorName parseConstructorName() { | |
| 2839 TypeName type = parseTypeName(); | |
| 2840 Token period = null; | |
| 2841 SimpleIdentifier name = null; | |
| 2842 if (_matches(TokenType.PERIOD)) { | |
| 2843 period = getAndAdvance(); | |
| 2844 name = parseSimpleIdentifier(); | |
| 2845 } | |
| 2846 return new ConstructorName(type, period, name); | |
| 2847 } | |
| 2848 | |
| 2849 /** | |
| 2850 * Parse the script tag and directives in a compilation unit, starting with | |
| 2851 * the given [token], until the first non-directive is encountered. The | |
| 2852 * remainder of the compilation unit will not be parsed. Specifically, if | |
| 2853 * there are directives later in the file, they will not be parsed. Return the | |
| 2854 * compilation unit that was parsed. | |
| 2855 */ | |
| 2856 CompilationUnit parseDirectives(Token token) { | |
| 2857 _currentToken = token; | |
| 2858 return _parseDirectives(); | |
| 2859 } | |
| 2860 | |
| 2861 /** | |
| 2862 * Parse an expression, starting with the given [token]. Return the expression | |
| 2863 * that was parsed, or `null` if the tokens do not represent a recognizable | |
| 2864 * expression. | |
| 2865 */ | |
| 2866 Expression parseExpression(Token token) { | |
| 2867 _currentToken = token; | |
| 2868 return parseExpression2(); | |
| 2869 } | |
| 2870 | |
| 2871 /** | |
| 2872 * Parse an expression that might contain a cascade. Return the expression | |
| 2873 * that was parsed. | |
| 2874 * | |
| 2875 * expression ::= | |
| 2876 * assignableExpression assignmentOperator expression | |
| 2877 * | conditionalExpression cascadeSection* | |
| 2878 * | throwExpression | |
| 2879 */ | |
| 2880 Expression parseExpression2() { | |
| 2881 if (_matchesKeyword(Keyword.THROW)) { | |
| 2882 return _parseThrowExpression(); | |
| 2883 } else if (_matchesKeyword(Keyword.RETHROW)) { | |
| 2884 // TODO(brianwilkerson) Rethrow is a statement again. | |
| 2885 return _parseRethrowExpression(); | |
| 2886 } | |
| 2887 // | |
| 2888 // assignableExpression is a subset of conditionalExpression, so we can | |
| 2889 // parse a conditional expression and then determine whether it is followed | |
| 2890 // by an assignmentOperator, checking for conformance to the restricted | |
| 2891 // grammar after making that determination. | |
| 2892 // | |
| 2893 Expression expression = parseConditionalExpression(); | |
| 2894 TokenType tokenType = _currentToken.type; | |
| 2895 if (tokenType == TokenType.PERIOD_PERIOD) { | |
| 2896 List<Expression> cascadeSections = new List<Expression>(); | |
| 2897 while (tokenType == TokenType.PERIOD_PERIOD) { | |
| 2898 Expression section = _parseCascadeSection(); | |
| 2899 if (section != null) { | |
| 2900 cascadeSections.add(section); | |
| 2901 } | |
| 2902 tokenType = _currentToken.type; | |
| 2903 } | |
| 2904 return new CascadeExpression(expression, cascadeSections); | |
| 2905 } else if (tokenType.isAssignmentOperator) { | |
| 2906 Token operator = getAndAdvance(); | |
| 2907 _ensureAssignable(expression); | |
| 2908 return new AssignmentExpression(expression, operator, parseExpression2()); | |
| 2909 } | |
| 2910 return expression; | |
| 2911 } | |
| 2912 | |
| 2913 /** | |
| 2914 * Parse an expression that does not contain any cascades. Return the | |
| 2915 * expression that was parsed. | |
| 2916 * | |
| 2917 * expressionWithoutCascade ::= | |
| 2918 * assignableExpression assignmentOperator expressionWithoutCascade | |
| 2919 * | conditionalExpression | |
| 2920 * | throwExpressionWithoutCascade | |
| 2921 */ | |
| 2922 Expression parseExpressionWithoutCascade() { | |
| 2923 if (_matchesKeyword(Keyword.THROW)) { | |
| 2924 return _parseThrowExpressionWithoutCascade(); | |
| 2925 } else if (_matchesKeyword(Keyword.RETHROW)) { | |
| 2926 return _parseRethrowExpression(); | |
| 2927 } | |
| 2928 // | |
| 2929 // assignableExpression is a subset of conditionalExpression, so we can | |
| 2930 // parse a conditional expression and then determine whether it is followed | |
| 2931 // by an assignmentOperator, checking for conformance to the restricted | |
| 2932 // grammar after making that determination. | |
| 2933 // | |
| 2934 Expression expression = parseConditionalExpression(); | |
| 2935 if (_currentToken.type.isAssignmentOperator) { | |
| 2936 Token operator = getAndAdvance(); | |
| 2937 _ensureAssignable(expression); | |
| 2938 expression = new AssignmentExpression( | |
| 2939 expression, operator, parseExpressionWithoutCascade()); | |
| 2940 } | |
| 2941 return expression; | |
| 2942 } | |
| 2943 | |
| 2944 /** | |
| 2945 * Parse a class extends clause. Return the class extends clause that was | |
| 2946 * parsed. | |
| 2947 * | |
| 2948 * classExtendsClause ::= | |
| 2949 * 'extends' type | |
| 2950 */ | |
| 2951 ExtendsClause parseExtendsClause() { | |
| 2952 Token keyword = _expectKeyword(Keyword.EXTENDS); | |
| 2953 TypeName superclass = parseTypeName(); | |
| 2954 return new ExtendsClause(keyword, superclass); | |
| 2955 } | |
| 2956 | |
| 2957 /** | |
| 2958 * Parse a list of formal parameters. Return the formal parameters that were | |
| 2959 * parsed. | |
| 2960 * | |
| 2961 * formalParameterList ::= | |
| 2962 * '(' ')' | |
| 2963 * | '(' normalFormalParameters (',' optionalFormalParameters)? ')' | |
| 2964 * | '(' optionalFormalParameters ')' | |
| 2965 * | |
| 2966 * normalFormalParameters ::= | |
| 2967 * normalFormalParameter (',' normalFormalParameter)* | |
| 2968 * | |
| 2969 * optionalFormalParameters ::= | |
| 2970 * optionalPositionalFormalParameters | |
| 2971 * | namedFormalParameters | |
| 2972 * | |
| 2973 * optionalPositionalFormalParameters ::= | |
| 2974 * '[' defaultFormalParameter (',' defaultFormalParameter)* ']' | |
| 2975 * | |
| 2976 * namedFormalParameters ::= | |
| 2977 * '{' defaultNamedParameter (',' defaultNamedParameter)* '}' | |
| 2978 */ | |
| 2979 FormalParameterList parseFormalParameterList() { | |
| 2980 Token leftParenthesis = _expect(TokenType.OPEN_PAREN); | |
| 2981 if (_matches(TokenType.CLOSE_PAREN)) { | |
| 2982 return new FormalParameterList( | |
| 2983 leftParenthesis, null, null, null, getAndAdvance()); | |
| 2984 } | |
| 2985 // | |
| 2986 // Even though it is invalid to have default parameters outside of brackets, | |
| 2987 // required parameters inside of brackets, or multiple groups of default and | |
| 2988 // named parameters, we allow all of these cases so that we can recover | |
| 2989 // better. | |
| 2990 // | |
| 2991 List<FormalParameter> parameters = new List<FormalParameter>(); | |
| 2992 List<FormalParameter> normalParameters = new List<FormalParameter>(); | |
| 2993 List<FormalParameter> positionalParameters = new List<FormalParameter>(); | |
| 2994 List<FormalParameter> namedParameters = new List<FormalParameter>(); | |
| 2995 List<FormalParameter> currentParameters = normalParameters; | |
| 2996 Token leftSquareBracket = null; | |
| 2997 Token rightSquareBracket = null; | |
| 2998 Token leftCurlyBracket = null; | |
| 2999 Token rightCurlyBracket = null; | |
| 3000 ParameterKind kind = ParameterKind.REQUIRED; | |
| 3001 bool firstParameter = true; | |
| 3002 bool reportedMuliplePositionalGroups = false; | |
| 3003 bool reportedMulipleNamedGroups = false; | |
| 3004 bool reportedMixedGroups = false; | |
| 3005 bool wasOptionalParameter = false; | |
| 3006 Token initialToken = null; | |
| 3007 do { | |
| 3008 if (firstParameter) { | |
| 3009 firstParameter = false; | |
| 3010 } else if (!_optional(TokenType.COMMA)) { | |
| 3011 // TODO(brianwilkerson) The token is wrong, we need to recover from this | |
| 3012 // case. | |
| 3013 if (_getEndToken(leftParenthesis) != null) { | |
| 3014 _reportErrorForCurrentToken( | |
| 3015 ParserErrorCode.EXPECTED_TOKEN, [TokenType.COMMA.lexeme]); | |
| 3016 } else { | |
| 3017 _reportErrorForToken(ParserErrorCode.MISSING_CLOSING_PARENTHESIS, | |
| 3018 _currentToken.previous); | |
| 3019 break; | |
| 3020 } | |
| 3021 } | |
| 3022 initialToken = _currentToken; | |
| 3023 // | |
| 3024 // Handle the beginning of parameter groups. | |
| 3025 // | |
| 3026 if (_matches(TokenType.OPEN_SQUARE_BRACKET)) { | |
| 3027 wasOptionalParameter = true; | |
| 3028 if (leftSquareBracket != null && !reportedMuliplePositionalGroups) { | |
| 3029 _reportErrorForCurrentToken( | |
| 3030 ParserErrorCode.MULTIPLE_POSITIONAL_PARAMETER_GROUPS); | |
| 3031 reportedMuliplePositionalGroups = true; | |
| 3032 } | |
| 3033 if (leftCurlyBracket != null && !reportedMixedGroups) { | |
| 3034 _reportErrorForCurrentToken(ParserErrorCode.MIXED_PARAMETER_GROUPS); | |
| 3035 reportedMixedGroups = true; | |
| 3036 } | |
| 3037 leftSquareBracket = getAndAdvance(); | |
| 3038 currentParameters = positionalParameters; | |
| 3039 kind = ParameterKind.POSITIONAL; | |
| 3040 } else if (_matches(TokenType.OPEN_CURLY_BRACKET)) { | |
| 3041 wasOptionalParameter = true; | |
| 3042 if (leftCurlyBracket != null && !reportedMulipleNamedGroups) { | |
| 3043 _reportErrorForCurrentToken( | |
| 3044 ParserErrorCode.MULTIPLE_NAMED_PARAMETER_GROUPS); | |
| 3045 reportedMulipleNamedGroups = true; | |
| 3046 } | |
| 3047 if (leftSquareBracket != null && !reportedMixedGroups) { | |
| 3048 _reportErrorForCurrentToken(ParserErrorCode.MIXED_PARAMETER_GROUPS); | |
| 3049 reportedMixedGroups = true; | |
| 3050 } | |
| 3051 leftCurlyBracket = getAndAdvance(); | |
| 3052 currentParameters = namedParameters; | |
| 3053 kind = ParameterKind.NAMED; | |
| 3054 } | |
| 3055 // | |
| 3056 // Parse and record the parameter. | |
| 3057 // | |
| 3058 FormalParameter parameter = _parseFormalParameter(kind); | |
| 3059 parameters.add(parameter); | |
| 3060 currentParameters.add(parameter); | |
| 3061 if (kind == ParameterKind.REQUIRED && wasOptionalParameter) { | |
| 3062 _reportErrorForNode( | |
| 3063 ParserErrorCode.NORMAL_BEFORE_OPTIONAL_PARAMETERS, parameter); | |
| 3064 } | |
| 3065 // | |
| 3066 // Handle the end of parameter groups. | |
| 3067 // | |
| 3068 // TODO(brianwilkerson) Improve the detection and reporting of missing and | |
| 3069 // mismatched delimiters. | |
| 3070 if (_matches(TokenType.CLOSE_SQUARE_BRACKET)) { | |
| 3071 rightSquareBracket = getAndAdvance(); | |
| 3072 currentParameters = normalParameters; | |
| 3073 if (leftSquareBracket == null) { | |
| 3074 if (leftCurlyBracket != null) { | |
| 3075 _reportErrorForCurrentToken( | |
| 3076 ParserErrorCode.WRONG_TERMINATOR_FOR_PARAMETER_GROUP, ["}"]); | |
| 3077 rightCurlyBracket = rightSquareBracket; | |
| 3078 rightSquareBracket = null; | |
| 3079 } else { | |
| 3080 _reportErrorForCurrentToken( | |
| 3081 ParserErrorCode.UNEXPECTED_TERMINATOR_FOR_PARAMETER_GROUP, | |
| 3082 ["["]); | |
| 3083 } | |
| 3084 } | |
| 3085 kind = ParameterKind.REQUIRED; | |
| 3086 } else if (_matches(TokenType.CLOSE_CURLY_BRACKET)) { | |
| 3087 rightCurlyBracket = getAndAdvance(); | |
| 3088 currentParameters = normalParameters; | |
| 3089 if (leftCurlyBracket == null) { | |
| 3090 if (leftSquareBracket != null) { | |
| 3091 _reportErrorForCurrentToken( | |
| 3092 ParserErrorCode.WRONG_TERMINATOR_FOR_PARAMETER_GROUP, ["]"]); | |
| 3093 rightSquareBracket = rightCurlyBracket; | |
| 3094 rightCurlyBracket = null; | |
| 3095 } else { | |
| 3096 _reportErrorForCurrentToken( | |
| 3097 ParserErrorCode.UNEXPECTED_TERMINATOR_FOR_PARAMETER_GROUP, | |
| 3098 ["{"]); | |
| 3099 } | |
| 3100 } | |
| 3101 kind = ParameterKind.REQUIRED; | |
| 3102 } | |
| 3103 } while (!_matches(TokenType.CLOSE_PAREN) && | |
| 3104 !identical(initialToken, _currentToken)); | |
| 3105 Token rightParenthesis = _expect(TokenType.CLOSE_PAREN); | |
| 3106 // | |
| 3107 // Check that the groups were closed correctly. | |
| 3108 // | |
| 3109 if (leftSquareBracket != null && rightSquareBracket == null) { | |
| 3110 _reportErrorForCurrentToken( | |
| 3111 ParserErrorCode.MISSING_TERMINATOR_FOR_PARAMETER_GROUP, ["]"]); | |
| 3112 } | |
| 3113 if (leftCurlyBracket != null && rightCurlyBracket == null) { | |
| 3114 _reportErrorForCurrentToken( | |
| 3115 ParserErrorCode.MISSING_TERMINATOR_FOR_PARAMETER_GROUP, ["}"]); | |
| 3116 } | |
| 3117 // | |
| 3118 // Build the parameter list. | |
| 3119 // | |
| 3120 if (leftSquareBracket == null) { | |
| 3121 leftSquareBracket = leftCurlyBracket; | |
| 3122 } | |
| 3123 if (rightSquareBracket == null) { | |
| 3124 rightSquareBracket = rightCurlyBracket; | |
| 3125 } | |
| 3126 return new FormalParameterList(leftParenthesis, parameters, | |
| 3127 leftSquareBracket, rightSquareBracket, rightParenthesis); | |
| 3128 } | |
| 3129 | |
| 3130 /** | |
| 3131 * Parse a function expression. Return the function expression that was | |
| 3132 * parsed. | |
| 3133 * | |
| 3134 * functionExpression ::= | |
| 3135 * typeParameters? formalParameterList functionExpressionBody | |
| 3136 */ | |
| 3137 FunctionExpression parseFunctionExpression() { | |
| 3138 TypeParameterList typeParameters = null; | |
| 3139 if (parseGenericMethods && _matches(TokenType.LT)) { | |
| 3140 typeParameters = parseTypeParameterList(); | |
| 3141 } | |
| 3142 FormalParameterList parameters = parseFormalParameterList(); | |
| 3143 _validateFormalParameterList(parameters); | |
| 3144 FunctionBody body = | |
| 3145 _parseFunctionBody(false, ParserErrorCode.MISSING_FUNCTION_BODY, true); | |
| 3146 return new FunctionExpression(typeParameters, parameters, body); | |
| 3147 } | |
| 3148 | |
| 3149 /** | |
| 3150 * Parse an if-null expression. Return the if-null expression that was | |
| 3151 * parsed. | |
| 3152 * | |
| 3153 * ifNullExpression ::= logicalOrExpression ('??' logicalOrExpression)* | |
| 3154 */ | |
| 3155 Expression parseIfNullExpression() { | |
| 3156 Expression expression = parseLogicalOrExpression(); | |
| 3157 while (_matches(TokenType.QUESTION_QUESTION)) { | |
| 3158 Token operator = getAndAdvance(); | |
| 3159 expression = new BinaryExpression( | |
| 3160 expression, operator, parseLogicalOrExpression()); | |
| 3161 } | |
| 3162 return expression; | |
| 3163 } | |
| 3164 | |
| 3165 /** | |
| 3166 * Parse an implements clause. Return the implements clause that was parsed. | |
| 3167 * | |
| 3168 * implementsClause ::= | |
| 3169 * 'implements' type (',' type)* | |
| 3170 */ | |
| 3171 ImplementsClause parseImplementsClause() { | |
| 3172 Token keyword = _expectKeyword(Keyword.IMPLEMENTS); | |
| 3173 List<TypeName> interfaces = new List<TypeName>(); | |
| 3174 interfaces.add(parseTypeName()); | |
| 3175 while (_optional(TokenType.COMMA)) { | |
| 3176 interfaces.add(parseTypeName()); | |
| 3177 } | |
| 3178 return new ImplementsClause(keyword, interfaces); | |
| 3179 } | |
| 3180 | |
| 3181 /** | |
| 3182 * Parse a label. Return the label that was parsed. | |
| 3183 * | |
| 3184 * label ::= | |
| 3185 * identifier ':' | |
| 3186 */ | |
| 3187 Label parseLabel() { | |
| 3188 SimpleIdentifier label = parseSimpleIdentifier(); | |
| 3189 Token colon = _expect(TokenType.COLON); | |
| 3190 return new Label(label, colon); | |
| 3191 } | |
| 3192 | |
| 3193 /** | |
| 3194 * Parse a library identifier. Return the library identifier that was parsed. | |
| 3195 * | |
| 3196 * libraryIdentifier ::= | |
| 3197 * identifier ('.' identifier)* | |
| 3198 */ | |
| 3199 LibraryIdentifier parseLibraryIdentifier() { | |
| 3200 List<SimpleIdentifier> components = new List<SimpleIdentifier>(); | |
| 3201 components.add(parseSimpleIdentifier()); | |
| 3202 while (_matches(TokenType.PERIOD)) { | |
| 3203 _advance(); | |
| 3204 components.add(parseSimpleIdentifier()); | |
| 3205 } | |
| 3206 return new LibraryIdentifier(components); | |
| 3207 } | |
| 3208 | |
| 3209 /** | |
| 3210 * Parse a logical or expression. Return the logical or expression that was | |
| 3211 * parsed. | |
| 3212 * | |
| 3213 * logicalOrExpression ::= | |
| 3214 * logicalAndExpression ('||' logicalAndExpression)* | |
| 3215 */ | |
| 3216 Expression parseLogicalOrExpression() { | |
| 3217 Expression expression = _parseLogicalAndExpression(); | |
| 3218 while (_matches(TokenType.BAR_BAR)) { | |
| 3219 Token operator = getAndAdvance(); | |
| 3220 expression = new BinaryExpression( | |
| 3221 expression, operator, _parseLogicalAndExpression()); | |
| 3222 } | |
| 3223 return expression; | |
| 3224 } | |
| 3225 | |
| 3226 /** | |
| 3227 * Parse a map literal entry. Return the map literal entry that was parsed. | |
| 3228 * | |
| 3229 * mapLiteralEntry ::= | |
| 3230 * expression ':' expression | |
| 3231 */ | |
| 3232 MapLiteralEntry parseMapLiteralEntry() { | |
| 3233 Expression key = parseExpression2(); | |
| 3234 Token separator = _expect(TokenType.COLON); | |
| 3235 Expression value = parseExpression2(); | |
| 3236 return new MapLiteralEntry(key, separator, value); | |
| 3237 } | |
| 3238 | |
| 3239 /** | |
| 3240 * Parse a normal formal parameter. Return the normal formal parameter that | |
| 3241 * was parsed. | |
| 3242 * | |
| 3243 * normalFormalParameter ::= | |
| 3244 * functionSignature | |
| 3245 * | fieldFormalParameter | |
| 3246 * | simpleFormalParameter | |
| 3247 * | |
| 3248 * functionSignature: | |
| 3249 * metadata returnType? identifier typeParameters? formalParameterList | |
| 3250 * | |
| 3251 * fieldFormalParameter ::= | |
| 3252 * metadata finalConstVarOrType? 'this' '.' identifier | |
| 3253 * | |
| 3254 * simpleFormalParameter ::= | |
| 3255 * declaredIdentifier | |
| 3256 * | metadata identifier | |
| 3257 */ | |
| 3258 NormalFormalParameter parseNormalFormalParameter() { | |
| 3259 CommentAndMetadata commentAndMetadata = _parseCommentAndMetadata(); | |
| 3260 FinalConstVarOrType holder = _parseFinalConstVarOrType(true); | |
| 3261 Token thisKeyword = null; | |
| 3262 Token period = null; | |
| 3263 if (_matchesKeyword(Keyword.THIS)) { | |
| 3264 thisKeyword = getAndAdvance(); | |
| 3265 period = _expect(TokenType.PERIOD); | |
| 3266 } | |
| 3267 SimpleIdentifier identifier = parseSimpleIdentifier(); | |
| 3268 TypeParameterList typeParameters = null; | |
| 3269 if (parseGenericMethods && _matches(TokenType.LT)) { | |
| 3270 typeParameters = parseTypeParameterList(); | |
| 3271 } | |
| 3272 if (_matches(TokenType.OPEN_PAREN)) { | |
| 3273 FormalParameterList parameters = parseFormalParameterList(); | |
| 3274 if (thisKeyword == null) { | |
| 3275 if (holder.keyword != null) { | |
| 3276 _reportErrorForToken( | |
| 3277 ParserErrorCode.FUNCTION_TYPED_PARAMETER_VAR, holder.keyword); | |
| 3278 } | |
| 3279 return new FunctionTypedFormalParameter( | |
| 3280 commentAndMetadata.comment, | |
| 3281 commentAndMetadata.metadata, | |
| 3282 holder.type, | |
| 3283 identifier, | |
| 3284 typeParameters, | |
| 3285 parameters); | |
| 3286 } else { | |
| 3287 return new FieldFormalParameter( | |
| 3288 commentAndMetadata.comment, | |
| 3289 commentAndMetadata.metadata, | |
| 3290 holder.keyword, | |
| 3291 holder.type, | |
| 3292 thisKeyword, | |
| 3293 period, | |
| 3294 identifier, | |
| 3295 typeParameters, | |
| 3296 parameters); | |
| 3297 } | |
| 3298 } else if (typeParameters != null) { | |
| 3299 // TODO(brianwilkerson) Report an error. It looks like a function-typed | |
| 3300 // parameter with no parameter list. | |
| 3301 //_reportErrorForToken(ParserErrorCode.MISSING_PARAMETERS, typeParameters.
endToken); | |
| 3302 } | |
| 3303 TypeName type = holder.type; | |
| 3304 if (type != null) { | |
| 3305 if (_tokenMatchesKeyword(type.name.beginToken, Keyword.VOID)) { | |
| 3306 _reportErrorForToken( | |
| 3307 ParserErrorCode.VOID_PARAMETER, type.name.beginToken); | |
| 3308 } else if (holder.keyword != null && | |
| 3309 _tokenMatchesKeyword(holder.keyword, Keyword.VAR)) { | |
| 3310 _reportErrorForToken(ParserErrorCode.VAR_AND_TYPE, holder.keyword); | |
| 3311 } | |
| 3312 } | |
| 3313 if (thisKeyword != null) { | |
| 3314 // TODO(brianwilkerson) If there are type parameters but no parameters, | |
| 3315 // should we create a synthetic empty parameter list here so we can | |
| 3316 // capture the type parameters? | |
| 3317 return new FieldFormalParameter( | |
| 3318 commentAndMetadata.comment, | |
| 3319 commentAndMetadata.metadata, | |
| 3320 holder.keyword, | |
| 3321 holder.type, | |
| 3322 thisKeyword, | |
| 3323 period, | |
| 3324 identifier, | |
| 3325 null, | |
| 3326 null); | |
| 3327 } | |
| 3328 return new SimpleFormalParameter(commentAndMetadata.comment, | |
| 3329 commentAndMetadata.metadata, holder.keyword, holder.type, identifier); | |
| 3330 } | |
| 3331 | |
| 3332 /** | |
| 3333 * Parse a prefixed identifier. Return the prefixed identifier that was | |
| 3334 * parsed. | |
| 3335 * | |
| 3336 * prefixedIdentifier ::= | |
| 3337 * identifier ('.' identifier)? | |
| 3338 */ | |
| 3339 Identifier parsePrefixedIdentifier() { | |
| 3340 SimpleIdentifier qualifier = parseSimpleIdentifier(); | |
| 3341 if (!_matches(TokenType.PERIOD)) { | |
| 3342 return qualifier; | |
| 3343 } | |
| 3344 Token period = getAndAdvance(); | |
| 3345 SimpleIdentifier qualified = parseSimpleIdentifier(); | |
| 3346 return new PrefixedIdentifier(qualifier, period, qualified); | |
| 3347 } | |
| 3348 | |
| 3349 /** | |
| 3350 * Parse a return type. Return the return type that was parsed. | |
| 3351 * | |
| 3352 * returnType ::= | |
| 3353 * 'void' | |
| 3354 * | type | |
| 3355 */ | |
| 3356 TypeName parseReturnType() { | |
| 3357 if (_matchesKeyword(Keyword.VOID)) { | |
| 3358 return new TypeName(new SimpleIdentifier(getAndAdvance()), null); | |
| 3359 } else { | |
| 3360 return parseTypeName(); | |
| 3361 } | |
| 3362 } | |
| 3363 | |
| 3364 /** | |
| 3365 * Parse a simple identifier. Return the simple identifier that was parsed. | |
| 3366 * | |
| 3367 * identifier ::= | |
| 3368 * IDENTIFIER | |
| 3369 */ | |
| 3370 SimpleIdentifier parseSimpleIdentifier() { | |
| 3371 if (_matchesIdentifier()) { | |
| 3372 String lexeme = _currentToken.lexeme; | |
| 3373 if ((_inAsync || _inGenerator) && | |
| 3374 (lexeme == 'async' || lexeme == 'await' || lexeme == 'yield')) { | |
| 3375 _reportErrorForCurrentToken( | |
| 3376 ParserErrorCode.ASYNC_KEYWORD_USED_AS_IDENTIFIER); | |
| 3377 } | |
| 3378 return new SimpleIdentifier(getAndAdvance()); | |
| 3379 } | |
| 3380 _reportErrorForCurrentToken(ParserErrorCode.MISSING_IDENTIFIER); | |
| 3381 return _createSyntheticIdentifier(); | |
| 3382 } | |
| 3383 | |
| 3384 /** | |
| 3385 * Parse a statement, starting with the given [token]. Return the statement | |
| 3386 * that was parsed, or `null` if the tokens do not represent a recognizable | |
| 3387 * statement. | |
| 3388 */ | |
| 3389 Statement parseStatement(Token token) { | |
| 3390 _currentToken = token; | |
| 3391 return parseStatement2(); | |
| 3392 } | |
| 3393 | |
| 3394 /** | |
| 3395 * Parse a statement. Return the statement that was parsed. | |
| 3396 * | |
| 3397 * statement ::= | |
| 3398 * label* nonLabeledStatement | |
| 3399 */ | |
| 3400 Statement parseStatement2() { | |
| 3401 List<Label> labels = new List<Label>(); | |
| 3402 while (_matchesIdentifier() && _tokenMatches(_peek(), TokenType.COLON)) { | |
| 3403 labels.add(parseLabel()); | |
| 3404 } | |
| 3405 Statement statement = _parseNonLabeledStatement(); | |
| 3406 if (labels.isEmpty) { | |
| 3407 return statement; | |
| 3408 } | |
| 3409 return new LabeledStatement(labels, statement); | |
| 3410 } | |
| 3411 | |
| 3412 /** | |
| 3413 * Parse a sequence of statements, starting with the given [token]. Return the | |
| 3414 * statements that were parsed, or `null` if the tokens do not represent a | |
| 3415 * recognizable sequence of statements. | |
| 3416 */ | |
| 3417 List<Statement> parseStatements(Token token) { | |
| 3418 _currentToken = token; | |
| 3419 return _parseStatementList(); | |
| 3420 } | |
| 3421 | |
| 3422 /** | |
| 3423 * Parse a string literal. Return the string literal that was parsed. | |
| 3424 * | |
| 3425 * stringLiteral ::= | |
| 3426 * MULTI_LINE_STRING+ | |
| 3427 * | SINGLE_LINE_STRING+ | |
| 3428 */ | |
| 3429 StringLiteral parseStringLiteral() { | |
| 3430 List<StringLiteral> strings = new List<StringLiteral>(); | |
| 3431 while (_matches(TokenType.STRING)) { | |
| 3432 Token string = getAndAdvance(); | |
| 3433 if (_matches(TokenType.STRING_INTERPOLATION_EXPRESSION) || | |
| 3434 _matches(TokenType.STRING_INTERPOLATION_IDENTIFIER)) { | |
| 3435 strings.add(_parseStringInterpolation(string)); | |
| 3436 } else { | |
| 3437 strings.add(new SimpleStringLiteral( | |
| 3438 string, _computeStringValue(string.lexeme, true, true))); | |
| 3439 } | |
| 3440 } | |
| 3441 if (strings.length < 1) { | |
| 3442 _reportErrorForCurrentToken(ParserErrorCode.EXPECTED_STRING_LITERAL); | |
| 3443 return _createSyntheticStringLiteral(); | |
| 3444 } else if (strings.length == 1) { | |
| 3445 return strings[0]; | |
| 3446 } else { | |
| 3447 return new AdjacentStrings(strings); | |
| 3448 } | |
| 3449 } | |
| 3450 | |
| 3451 /** | |
| 3452 * Parse a list of type arguments. Return the type argument list that was | |
| 3453 * parsed. | |
| 3454 * | |
| 3455 * typeArguments ::= | |
| 3456 * '<' typeList '>' | |
| 3457 * | |
| 3458 * typeList ::= | |
| 3459 * type (',' type)* | |
| 3460 */ | |
| 3461 TypeArgumentList parseTypeArgumentList() { | |
| 3462 Token leftBracket = _expect(TokenType.LT); | |
| 3463 List<TypeName> arguments = new List<TypeName>(); | |
| 3464 arguments.add(parseTypeName()); | |
| 3465 while (_optional(TokenType.COMMA)) { | |
| 3466 arguments.add(parseTypeName()); | |
| 3467 } | |
| 3468 Token rightBracket = _expectGt(); | |
| 3469 return new TypeArgumentList(leftBracket, arguments, rightBracket); | |
| 3470 } | |
| 3471 | |
| 3472 /** | |
| 3473 * Parse a type name. Return the type name that was parsed. | |
| 3474 * | |
| 3475 * type ::= | |
| 3476 * qualified typeArguments? | |
| 3477 */ | |
| 3478 TypeName parseTypeName() { | |
| 3479 Identifier typeName; | |
| 3480 if (_matchesKeyword(Keyword.VAR)) { | |
| 3481 _reportErrorForCurrentToken(ParserErrorCode.VAR_AS_TYPE_NAME); | |
| 3482 typeName = new SimpleIdentifier(getAndAdvance()); | |
| 3483 } else if (_matchesIdentifier()) { | |
| 3484 typeName = parsePrefixedIdentifier(); | |
| 3485 } else { | |
| 3486 typeName = _createSyntheticIdentifier(); | |
| 3487 _reportErrorForCurrentToken(ParserErrorCode.EXPECTED_TYPE_NAME); | |
| 3488 } | |
| 3489 TypeArgumentList typeArguments = null; | |
| 3490 if (_matches(TokenType.LT)) { | |
| 3491 typeArguments = parseTypeArgumentList(); | |
| 3492 } | |
| 3493 return new TypeName(typeName, typeArguments); | |
| 3494 } | |
| 3495 | |
| 3496 /** | |
| 3497 * Parse a type parameter. Return the type parameter that was parsed. | |
| 3498 * | |
| 3499 * typeParameter ::= | |
| 3500 * metadata name ('extends' bound)? | |
| 3501 */ | |
| 3502 TypeParameter parseTypeParameter() { | |
| 3503 CommentAndMetadata commentAndMetadata = _parseCommentAndMetadata(); | |
| 3504 SimpleIdentifier name = parseSimpleIdentifier(); | |
| 3505 if (_matchesKeyword(Keyword.EXTENDS)) { | |
| 3506 Token keyword = getAndAdvance(); | |
| 3507 TypeName bound = parseTypeName(); | |
| 3508 return new TypeParameter(commentAndMetadata.comment, | |
| 3509 commentAndMetadata.metadata, name, keyword, bound); | |
| 3510 } | |
| 3511 return new TypeParameter(commentAndMetadata.comment, | |
| 3512 commentAndMetadata.metadata, name, null, null); | |
| 3513 } | |
| 3514 | |
| 3515 /** | |
| 3516 * Parse a list of type parameters. Return the list of type parameters that | |
| 3517 * were parsed. | |
| 3518 * | |
| 3519 * typeParameterList ::= | |
| 3520 * '<' typeParameter (',' typeParameter)* '>' | |
| 3521 */ | |
| 3522 TypeParameterList parseTypeParameterList() { | |
| 3523 Token leftBracket = _expect(TokenType.LT); | |
| 3524 List<TypeParameter> typeParameters = new List<TypeParameter>(); | |
| 3525 typeParameters.add(parseTypeParameter()); | |
| 3526 while (_optional(TokenType.COMMA)) { | |
| 3527 typeParameters.add(parseTypeParameter()); | |
| 3528 } | |
| 3529 Token rightBracket = _expectGt(); | |
| 3530 return new TypeParameterList(leftBracket, typeParameters, rightBracket); | |
| 3531 } | |
| 3532 | |
| 3533 /** | |
| 3534 * Parse a with clause. Return the with clause that was parsed. | |
| 3535 * | |
| 3536 * withClause ::= | |
| 3537 * 'with' typeName (',' typeName)* | |
| 3538 */ | |
| 3539 WithClause parseWithClause() { | |
| 3540 Token with2 = _expectKeyword(Keyword.WITH); | |
| 3541 List<TypeName> types = new List<TypeName>(); | |
| 3542 types.add(parseTypeName()); | |
| 3543 while (_optional(TokenType.COMMA)) { | |
| 3544 types.add(parseTypeName()); | |
| 3545 } | |
| 3546 return new WithClause(with2, types); | |
| 3547 } | |
| 3548 | |
| 3549 /** | |
| 3550 * Advance to the next token in the token stream. | |
| 3551 */ | |
| 3552 void _advance() { | |
| 3553 _currentToken = _currentToken.next; | |
| 3554 } | |
| 3555 | |
| 3556 /** | |
| 3557 * Append the character equivalent of the given [scalarValue] to the given | |
| 3558 * [builder]. Use the [startIndex] and [endIndex] to report an error, and | |
| 3559 * don't append anything to the builder, if the scalar value is invalid. The | |
| 3560 * [escapeSequence] is the escape sequence that was parsed to produce the | |
| 3561 * scalar value (used for error reporting). | |
| 3562 */ | |
| 3563 void _appendScalarValue(StringBuffer buffer, String escapeSequence, | |
| 3564 int scalarValue, int startIndex, int endIndex) { | |
| 3565 if (scalarValue < 0 || | |
| 3566 scalarValue > Character.MAX_CODE_POINT || | |
| 3567 (scalarValue >= 0xD800 && scalarValue <= 0xDFFF)) { | |
| 3568 _reportErrorForCurrentToken( | |
| 3569 ParserErrorCode.INVALID_CODE_POINT, [escapeSequence]); | |
| 3570 return; | |
| 3571 } | |
| 3572 if (scalarValue < Character.MAX_VALUE) { | |
| 3573 buffer.writeCharCode(scalarValue); | |
| 3574 } else { | |
| 3575 buffer.write(Character.toChars(scalarValue)); | |
| 3576 } | |
| 3577 } | |
| 3578 | |
| 3579 /** | |
| 3580 * Return the content of a string with the given literal representation. The | 332 * Return the content of a string with the given literal representation. The |
| 3581 * [lexeme] is the literal representation of the string. The flag [isFirst] is | 333 * [lexeme] is the literal representation of the string. The flag [isFirst] is |
| 3582 * `true` if this is the first token in a string literal. The flag [isLast] is | 334 * `true` if this is the first token in a string literal. The flag [isLast] is |
| 3583 * `true` if this is the last token in a string literal. | 335 * `true` if this is the last token in a string literal. |
| 3584 */ | 336 */ |
| 3585 String _computeStringValue(String lexeme, bool isFirst, bool isLast) { | 337 String computeStringValue(String lexeme, bool isFirst, bool isLast) { |
| 3586 StringLexemeHelper helper = new StringLexemeHelper(lexeme, isFirst, isLast); | 338 StringLexemeHelper helper = new StringLexemeHelper(lexeme, isFirst, isLast); |
| 3587 int start = helper.start; | 339 int start = helper.start; |
| 3588 int end = helper.end; | 340 int end = helper.end; |
| 3589 bool stringEndsAfterStart = end >= start; | 341 bool stringEndsAfterStart = end >= start; |
| 3590 assert(stringEndsAfterStart); | 342 assert(stringEndsAfterStart); |
| 3591 if (!stringEndsAfterStart) { | 343 if (!stringEndsAfterStart) { |
| 3592 AnalysisEngine.instance.logger.logError( | 344 AnalysisEngine.instance.logger.logError( |
| 3593 "Internal error: computeStringValue($lexeme, $isFirst, $isLast)"); | 345 "Internal error: computeStringValue($lexeme, $isFirst, $isLast)"); |
| 3594 return ""; | 346 return ""; |
| 3595 } | 347 } |
| 3596 if (helper.isRaw) { | 348 if (helper.isRaw) { |
| 3597 return lexeme.substring(start, end); | 349 return lexeme.substring(start, end); |
| 3598 } | 350 } |
| 3599 StringBuffer buffer = new StringBuffer(); | 351 StringBuffer buffer = new StringBuffer(); |
| 3600 int index = start; | 352 int index = start; |
| 3601 while (index < end) { | 353 while (index < end) { |
| 3602 index = _translateCharacter(buffer, lexeme, index); | 354 index = _translateCharacter(buffer, lexeme, index); |
| 3603 } | 355 } |
| 3604 return buffer.toString(); | 356 return buffer.toString(); |
| 3605 } | 357 } |
| 3606 | 358 |
| 3607 /** | 359 /** |
| 3608 * Convert the given [method] declaration into the nearest valid top-level | |
| 3609 * function declaration (that is, the function declaration that most closely | |
| 3610 * captures the components of the given method declaration). | |
| 3611 */ | |
| 3612 FunctionDeclaration _convertToFunctionDeclaration(MethodDeclaration method) => | |
| 3613 new FunctionDeclaration( | |
| 3614 method.documentationComment, | |
| 3615 method.metadata, | |
| 3616 method.externalKeyword, | |
| 3617 method.returnType, | |
| 3618 method.propertyKeyword, | |
| 3619 method.name, | |
| 3620 new FunctionExpression( | |
| 3621 method.typeParameters, method.parameters, method.body)); | |
| 3622 | |
| 3623 /** | |
| 3624 * Return `true` if the current token could be the start of a compilation unit | |
| 3625 * member. This method is used for recovery purposes to decide when to stop | |
| 3626 * skipping tokens after finding an error while parsing a compilation unit | |
| 3627 * member. | |
| 3628 */ | |
| 3629 bool _couldBeStartOfCompilationUnitMember() { | |
| 3630 if ((_matchesKeyword(Keyword.IMPORT) || | |
| 3631 _matchesKeyword(Keyword.EXPORT) || | |
| 3632 _matchesKeyword(Keyword.LIBRARY) || | |
| 3633 _matchesKeyword(Keyword.PART)) && | |
| 3634 !_tokenMatches(_peek(), TokenType.PERIOD) && | |
| 3635 !_tokenMatches(_peek(), TokenType.LT)) { | |
| 3636 // This looks like the start of a directive | |
| 3637 return true; | |
| 3638 } else if (_matchesKeyword(Keyword.CLASS)) { | |
| 3639 // This looks like the start of a class definition | |
| 3640 return true; | |
| 3641 } else if (_matchesKeyword(Keyword.TYPEDEF) && | |
| 3642 !_tokenMatches(_peek(), TokenType.PERIOD) && | |
| 3643 !_tokenMatches(_peek(), TokenType.LT)) { | |
| 3644 // This looks like the start of a typedef | |
| 3645 return true; | |
| 3646 } else if (_matchesKeyword(Keyword.VOID) || | |
| 3647 ((_matchesKeyword(Keyword.GET) || _matchesKeyword(Keyword.SET)) && | |
| 3648 _tokenMatchesIdentifier(_peek())) || | |
| 3649 (_matchesKeyword(Keyword.OPERATOR) && _isOperator(_peek()))) { | |
| 3650 // This looks like the start of a function | |
| 3651 return true; | |
| 3652 } else if (_matchesIdentifier()) { | |
| 3653 if (_tokenMatches(_peek(), TokenType.OPEN_PAREN)) { | |
| 3654 // This looks like the start of a function | |
| 3655 return true; | |
| 3656 } | |
| 3657 Token token = _skipReturnType(_currentToken); | |
| 3658 if (token == null) { | |
| 3659 return false; | |
| 3660 } | |
| 3661 if (_matchesKeyword(Keyword.GET) || | |
| 3662 _matchesKeyword(Keyword.SET) || | |
| 3663 (_matchesKeyword(Keyword.OPERATOR) && _isOperator(_peek())) || | |
| 3664 _matchesIdentifier()) { | |
| 3665 return true; | |
| 3666 } | |
| 3667 } | |
| 3668 return false; | |
| 3669 } | |
| 3670 | |
| 3671 /** | |
| 3672 * Return a synthetic identifier. | 360 * Return a synthetic identifier. |
| 3673 */ | 361 */ |
| 3674 SimpleIdentifier _createSyntheticIdentifier() { | 362 SimpleIdentifier createSyntheticIdentifier({bool isDeclaration: false}) { |
| 3675 Token syntheticToken; | 363 Token syntheticToken; |
| 3676 if (_currentToken.type == TokenType.KEYWORD) { | 364 if (_currentToken.type == TokenType.KEYWORD) { |
| 3677 // Consider current keyword token as an identifier. | 365 // Consider current keyword token as an identifier. |
| 3678 // It is not always true, e.g. "^is T" where "^" is place the place for | 366 // It is not always true, e.g. "^is T" where "^" is place the place for |
| 3679 // synthetic identifier. By creating SyntheticStringToken we can | 367 // synthetic identifier. By creating SyntheticStringToken we can |
| 3680 // distinguish a real identifier from synthetic. In the code completion | 368 // distinguish a real identifier from synthetic. In the code completion |
| 3681 // behavior will depend on a cursor position - before or on "is". | 369 // behavior will depend on a cursor position - before or on "is". |
| 3682 syntheticToken = _injectToken(new SyntheticStringToken( | 370 syntheticToken = _injectToken(new SyntheticStringToken( |
| 3683 TokenType.IDENTIFIER, _currentToken.lexeme, _currentToken.offset)); | 371 TokenType.IDENTIFIER, _currentToken.lexeme, _currentToken.offset)); |
| 3684 } else { | 372 } else { |
| 3685 syntheticToken = _createSyntheticToken(TokenType.IDENTIFIER); | 373 syntheticToken = _createSyntheticToken(TokenType.IDENTIFIER); |
| 3686 } | 374 } |
| 3687 return new SimpleIdentifier(syntheticToken); | 375 return new SimpleIdentifier(syntheticToken, isDeclaration: isDeclaration); |
| 3688 } | 376 } |
| 3689 | |
| 3690 /** | |
| 3691 * Return a synthetic token representing the given [keyword]. | |
| 3692 */ | |
| 3693 Token _createSyntheticKeyword(Keyword keyword) => _injectToken( | |
| 3694 new Parser_SyntheticKeywordToken(keyword, _currentToken.offset)); | |
| 3695 | 377 |
| 3696 /** | 378 /** |
| 3697 * Return a synthetic string literal. | 379 * Return a synthetic string literal. |
| 3698 */ | 380 */ |
| 3699 SimpleStringLiteral _createSyntheticStringLiteral() => | 381 SimpleStringLiteral createSyntheticStringLiteral() => |
| 3700 new SimpleStringLiteral(_createSyntheticToken(TokenType.STRING), ""); | 382 new SimpleStringLiteral(_createSyntheticToken(TokenType.STRING), ""); |
| 3701 | 383 |
| 3702 /** | 384 /** |
| 3703 * Return a synthetic token with the given [type]. | 385 * Advance to the next token in the token stream, making it the new current |
| 3704 */ | 386 * token and return the token that was current before this method was invoked. |
| 3705 Token _createSyntheticToken(TokenType type) => | 387 */ |
| 3706 _injectToken(new StringToken(type, "", _currentToken.offset)); | 388 Token getAndAdvance() { |
| 3707 | 389 Token token = _currentToken; |
| 3708 /** | 390 _currentToken = _currentToken.next; |
| 3709 * Create and return a new token with the given [type]. The token will replace | |
| 3710 * the first portion of the given [token], so it will have the same offset and | |
| 3711 * will have any comments that might have preceeded the token. | |
| 3712 */ | |
| 3713 Token _createToken(Token token, TokenType type, {bool isBegin: false}) { | |
| 3714 CommentToken comments = token.precedingComments; | |
| 3715 if (comments == null) { | |
| 3716 if (isBegin) { | |
| 3717 return new BeginToken(type, token.offset); | |
| 3718 } | |
| 3719 return new Token(type, token.offset); | |
| 3720 } else if (isBegin) { | |
| 3721 return new BeginTokenWithComment(type, token.offset, comments); | |
| 3722 } | |
| 3723 return new TokenWithComment(type, token.offset, comments); | |
| 3724 } | |
| 3725 | |
| 3726 /** | |
| 3727 * Check that the given [expression] is assignable and report an error if it | |
| 3728 * isn't. | |
| 3729 * | |
| 3730 * assignableExpression ::= | |
| 3731 * primary (arguments* assignableSelector)+ | |
| 3732 * | 'super' unconditionalAssignableSelector | |
| 3733 * | identifier | |
| 3734 * | |
| 3735 * unconditionalAssignableSelector ::= | |
| 3736 * '[' expression ']' | |
| 3737 * | '.' identifier | |
| 3738 * | |
| 3739 * assignableSelector ::= | |
| 3740 * unconditionalAssignableSelector | |
| 3741 * | '?.' identifier | |
| 3742 */ | |
| 3743 void _ensureAssignable(Expression expression) { | |
| 3744 if (expression != null && !expression.isAssignable) { | |
| 3745 _reportErrorForCurrentToken( | |
| 3746 ParserErrorCode.ILLEGAL_ASSIGNMENT_TO_NON_ASSIGNABLE); | |
| 3747 } | |
| 3748 } | |
| 3749 | |
| 3750 /** | |
| 3751 * If the current token has the expected type, return it after advancing to | |
| 3752 * the next token. Otherwise report an error and return the current token | |
| 3753 * without advancing. | |
| 3754 * | |
| 3755 * Note that the method [_expectGt] should be used if the argument to this | |
| 3756 * method would be [TokenType.GT]. | |
| 3757 * | |
| 3758 * The [type] is the type of token that is expected. | |
| 3759 */ | |
| 3760 Token _expect(TokenType type) { | |
| 3761 if (_matches(type)) { | |
| 3762 return getAndAdvance(); | |
| 3763 } | |
| 3764 // Remove uses of this method in favor of matches? | |
| 3765 // Pass in the error code to use to report the error? | |
| 3766 if (type == TokenType.SEMICOLON) { | |
| 3767 if (_tokenMatches(_currentToken.next, TokenType.SEMICOLON)) { | |
| 3768 _reportErrorForCurrentToken( | |
| 3769 ParserErrorCode.UNEXPECTED_TOKEN, [_currentToken.lexeme]); | |
| 3770 _advance(); | |
| 3771 return getAndAdvance(); | |
| 3772 } | |
| 3773 _reportErrorForToken(ParserErrorCode.EXPECTED_TOKEN, | |
| 3774 _currentToken.previous, [type.lexeme]); | |
| 3775 } else { | |
| 3776 _reportErrorForCurrentToken( | |
| 3777 ParserErrorCode.EXPECTED_TOKEN, [type.lexeme]); | |
| 3778 } | |
| 3779 return _currentToken; | |
| 3780 } | |
| 3781 | |
| 3782 /** | |
| 3783 * If the current token has the type [TokenType.GT], return it after advancing | |
| 3784 * to the next token. Otherwise report an error and return the current token | |
| 3785 * without advancing. | |
| 3786 */ | |
| 3787 Token _expectGt() { | |
| 3788 if (_matchesGt()) { | |
| 3789 return getAndAdvance(); | |
| 3790 } | |
| 3791 _reportErrorForCurrentToken( | |
| 3792 ParserErrorCode.EXPECTED_TOKEN, [TokenType.GT.lexeme]); | |
| 3793 return _currentToken; | |
| 3794 } | |
| 3795 | |
| 3796 /** | |
| 3797 * If the current token is a keyword matching the given [keyword], return it | |
| 3798 * after advancing to the next token. Otherwise report an error and return the | |
| 3799 * current token without advancing. | |
| 3800 */ | |
| 3801 Token _expectKeyword(Keyword keyword) { | |
| 3802 if (_matchesKeyword(keyword)) { | |
| 3803 return getAndAdvance(); | |
| 3804 } | |
| 3805 // Remove uses of this method in favor of matches? | |
| 3806 // Pass in the error code to use to report the error? | |
| 3807 _reportErrorForCurrentToken( | |
| 3808 ParserErrorCode.EXPECTED_TOKEN, [keyword.syntax]); | |
| 3809 return _currentToken; | |
| 3810 } | |
| 3811 | |
| 3812 /** | |
| 3813 * If the current token is a semicolon, return it after advancing to the next | |
| 3814 * token. Otherwise report an error and create a synthetic semicolon. | |
| 3815 */ | |
| 3816 Token _expectSemicolon() { | |
| 3817 // TODO(scheglov) consider pushing this behavior into [_expect] | |
| 3818 if (_matches(TokenType.SEMICOLON)) { | |
| 3819 return getAndAdvance(); | |
| 3820 } else { | |
| 3821 _reportErrorForToken( | |
| 3822 ParserErrorCode.EXPECTED_TOKEN, _currentToken.previous, [";"]); | |
| 3823 return _createSyntheticToken(TokenType.SEMICOLON); | |
| 3824 } | |
| 3825 } | |
| 3826 | |
| 3827 /** | |
| 3828 * Search the given list of [ranges] for a range that contains the given | |
| 3829 * [index]. Return the range that was found, or `null` if none of the ranges | |
| 3830 * contain the index. | |
| 3831 */ | |
| 3832 List<int> _findRange(List<List<int>> ranges, int index) { | |
| 3833 int rangeCount = ranges.length; | |
| 3834 for (int i = 0; i < rangeCount; i++) { | |
| 3835 List<int> range = ranges[i]; | |
| 3836 if (range[0] <= index && index <= range[1]) { | |
| 3837 return range; | |
| 3838 } else if (index < range[0]) { | |
| 3839 return null; | |
| 3840 } | |
| 3841 } | |
| 3842 return null; | |
| 3843 } | |
| 3844 | |
| 3845 /** | |
| 3846 * Return a list of the ranges of characters in the given [comment] that | |
| 3847 * should be treated as code blocks. | |
| 3848 */ | |
| 3849 List<List<int>> _getCodeBlockRanges(String comment) { | |
| 3850 List<List<int>> ranges = new List<List<int>>(); | |
| 3851 int length = comment.length; | |
| 3852 if (length < 3) { | |
| 3853 return ranges; | |
| 3854 } | |
| 3855 int index = 0; | |
| 3856 int firstChar = comment.codeUnitAt(0); | |
| 3857 if (firstChar == 0x2F) { | |
| 3858 int secondChar = comment.codeUnitAt(1); | |
| 3859 int thirdChar = comment.codeUnitAt(2); | |
| 3860 if ((secondChar == 0x2A && thirdChar == 0x2A) || | |
| 3861 (secondChar == 0x2F && thirdChar == 0x2F)) { | |
| 3862 index = 3; | |
| 3863 } | |
| 3864 } | |
| 3865 while (index < length) { | |
| 3866 int currentChar = comment.codeUnitAt(index); | |
| 3867 if (currentChar == 0xD || currentChar == 0xA) { | |
| 3868 index = index + 1; | |
| 3869 while (index < length && | |
| 3870 Character.isWhitespace(comment.codeUnitAt(index))) { | |
| 3871 index = index + 1; | |
| 3872 } | |
| 3873 if (StringUtilities.startsWith6( | |
| 3874 comment, index, 0x2A, 0x20, 0x20, 0x20, 0x20, 0x20)) { | |
| 3875 int end = index + 6; | |
| 3876 while (end < length && | |
| 3877 comment.codeUnitAt(end) != 0xD && | |
| 3878 comment.codeUnitAt(end) != 0xA) { | |
| 3879 end = end + 1; | |
| 3880 } | |
| 3881 ranges.add(<int>[index, end]); | |
| 3882 index = end; | |
| 3883 } | |
| 3884 } else if (index + 1 < length && | |
| 3885 currentChar == 0x5B && | |
| 3886 comment.codeUnitAt(index + 1) == 0x3A) { | |
| 3887 int end = StringUtilities.indexOf2(comment, index + 2, 0x3A, 0x5D); | |
| 3888 if (end < 0) { | |
| 3889 end = length; | |
| 3890 } | |
| 3891 ranges.add(<int>[index, end]); | |
| 3892 index = end + 1; | |
| 3893 } else { | |
| 3894 index = index + 1; | |
| 3895 } | |
| 3896 } | |
| 3897 return ranges; | |
| 3898 } | |
| 3899 | |
| 3900 /** | |
| 3901 * Return the end token associated with the given [beginToken], or `null` if | |
| 3902 * either the given token is not a begin token or it does not have an end | |
| 3903 * token associated with it. | |
| 3904 */ | |
| 3905 Token _getEndToken(Token beginToken) { | |
| 3906 if (beginToken is BeginToken) { | |
| 3907 return beginToken.endToken; | |
| 3908 } | |
| 3909 return null; | |
| 3910 } | |
| 3911 | |
| 3912 /** | |
| 3913 * Inject the given [token] into the token stream immediately before the | |
| 3914 * current token. | |
| 3915 */ | |
| 3916 Token _injectToken(Token token) { | |
| 3917 Token previous = _currentToken.previous; | |
| 3918 token.setNext(_currentToken); | |
| 3919 previous.setNext(token); | |
| 3920 return token; | 391 return token; |
| 3921 } | 392 } |
| 3922 | 393 |
| 3923 /** | 394 /** |
| 3924 * Return `true` if the current token appears to be the beginning of a | 395 * Return `true` if the current token appears to be the beginning of a |
| 3925 * function declaration. | 396 * function declaration. |
| 3926 */ | 397 */ |
| 3927 bool _isFunctionDeclaration() { | 398 bool isFunctionDeclaration() { |
| 3928 if (_matchesKeyword(Keyword.VOID)) { | 399 Keyword keyword = _currentToken.keyword; |
| 400 if (keyword == Keyword.VOID) { |
| 3929 return true; | 401 return true; |
| 3930 } | 402 } |
| 3931 Token afterReturnType = _skipTypeName(_currentToken); | 403 Token afterReturnType = skipTypeName(_currentToken); |
| 3932 if (afterReturnType == null) { | 404 if (afterReturnType == null) { |
| 3933 // There was no return type, but it is optional, so go back to where we | 405 // There was no return type, but it is optional, so go back to where we |
| 3934 // started. | 406 // started. |
| 3935 afterReturnType = _currentToken; | 407 afterReturnType = _currentToken; |
| 3936 } | 408 } |
| 3937 Token afterIdentifier = _skipSimpleIdentifier(afterReturnType); | 409 Token afterIdentifier = skipSimpleIdentifier(afterReturnType); |
| 3938 if (afterIdentifier == null) { | 410 if (afterIdentifier == null) { |
| 3939 // It's possible that we parsed the function name as if it were a type | 411 // It's possible that we parsed the function name as if it were a type |
| 3940 // name, so see whether it makes sense if we assume that there is no type. | 412 // name, so see whether it makes sense if we assume that there is no type. |
| 3941 afterIdentifier = _skipSimpleIdentifier(_currentToken); | 413 afterIdentifier = skipSimpleIdentifier(_currentToken); |
| 3942 } | 414 } |
| 3943 if (afterIdentifier == null) { | 415 if (afterIdentifier == null) { |
| 3944 return false; | 416 return false; |
| 3945 } | 417 } |
| 3946 if (_isFunctionExpression(afterIdentifier)) { | 418 if (isFunctionExpression(afterIdentifier)) { |
| 3947 return true; | 419 return true; |
| 3948 } | 420 } |
| 3949 // It's possible that we have found a getter. While this isn't valid at this | 421 // It's possible that we have found a getter. While this isn't valid at this |
| 3950 // point we test for it in order to recover better. | 422 // point we test for it in order to recover better. |
| 3951 if (_matchesKeyword(Keyword.GET)) { | 423 if (keyword == Keyword.GET) { |
| 3952 Token afterName = _skipSimpleIdentifier(_currentToken.next); | 424 Token afterName = skipSimpleIdentifier(_currentToken.next); |
| 3953 if (afterName == null) { | 425 if (afterName == null) { |
| 3954 return false; | 426 return false; |
| 3955 } | 427 } |
| 3956 return _tokenMatches(afterName, TokenType.FUNCTION) || | 428 TokenType type = afterName.type; |
| 3957 _tokenMatches(afterName, TokenType.OPEN_CURLY_BRACKET); | 429 return type == TokenType.FUNCTION || type == TokenType.OPEN_CURLY_BRACKET; |
| 3958 } else if (_tokenMatchesKeyword(afterReturnType, Keyword.GET)) { | 430 } else if (_tokenMatchesKeyword(afterReturnType, Keyword.GET)) { |
| 3959 Token afterName = _skipSimpleIdentifier(afterReturnType.next); | 431 Token afterName = skipSimpleIdentifier(afterReturnType.next); |
| 3960 if (afterName == null) { | 432 if (afterName == null) { |
| 3961 return false; | 433 return false; |
| 3962 } | 434 } |
| 3963 return _tokenMatches(afterName, TokenType.FUNCTION) || | 435 TokenType type = afterName.type; |
| 3964 _tokenMatches(afterName, TokenType.OPEN_CURLY_BRACKET); | 436 return type == TokenType.FUNCTION || type == TokenType.OPEN_CURLY_BRACKET; |
| 3965 } | 437 } |
| 3966 return false; | 438 return false; |
| 3967 } | 439 } |
| 3968 | 440 |
| 3969 /** | 441 /** |
| 3970 * Return `true` if the given [token] appears to be the beginning of a | 442 * Return `true` if the given [token] appears to be the beginning of a |
| 3971 * function expression. | 443 * function expression. |
| 3972 */ | 444 */ |
| 3973 bool _isFunctionExpression(Token token) { | 445 bool isFunctionExpression(Token token) { |
| 3974 // Function expressions aren't allowed in initializer lists. | 446 // Function expressions aren't allowed in initializer lists. |
| 3975 if (_inInitializer) { | 447 if (_inInitializer) { |
| 3976 return false; | 448 return false; |
| 3977 } | 449 } |
| 3978 Token afterTypeParameters = _skipTypeParameterList(token); | 450 Token afterTypeParameters = _skipTypeParameterList(token); |
| 3979 if (afterTypeParameters == null) { | 451 if (afterTypeParameters == null) { |
| 3980 afterTypeParameters = token; | 452 afterTypeParameters = token; |
| 3981 } | 453 } |
| 3982 Token afterParameters = _skipFormalParameterList(afterTypeParameters); | 454 Token afterParameters = _skipFormalParameterList(afterTypeParameters); |
| 3983 if (afterParameters == null) { | 455 if (afterParameters == null) { |
| 3984 return false; | 456 return false; |
| 3985 } | 457 } |
| 3986 if (afterParameters | 458 if (afterParameters.matchesAny( |
| 3987 .matchesAny([TokenType.OPEN_CURLY_BRACKET, TokenType.FUNCTION])) { | 459 const <TokenType>[TokenType.OPEN_CURLY_BRACKET, TokenType.FUNCTION])) { |
| 3988 return true; | 460 return true; |
| 3989 } | 461 } |
| 3990 String lexeme = afterParameters.lexeme; | 462 String lexeme = afterParameters.lexeme; |
| 3991 return lexeme == ASYNC || lexeme == SYNC; | 463 return lexeme == ASYNC || lexeme == SYNC; |
| 3992 } | 464 } |
| 3993 | 465 |
| 3994 /** | 466 /** |
| 3995 * Return `true` if the given [character] is a valid hexadecimal digit. | |
| 3996 */ | |
| 3997 bool _isHexDigit(int character) => (0x30 <= character && character <= 0x39) || | |
| 3998 (0x41 <= character && character <= 0x46) || | |
| 3999 (0x61 <= character && character <= 0x66); | |
| 4000 | |
| 4001 /** | |
| 4002 * Return `true` if the current token is the first token in an initialized | 467 * Return `true` if the current token is the first token in an initialized |
| 4003 * variable declaration rather than an expression. This method assumes that we | 468 * variable declaration rather than an expression. This method assumes that we |
| 4004 * have already skipped past any metadata that might be associated with the | 469 * have already skipped past any metadata that might be associated with the |
| 4005 * declaration. | 470 * declaration. |
| 4006 * | 471 * |
| 4007 * initializedVariableDeclaration ::= | 472 * initializedVariableDeclaration ::= |
| 4008 * declaredIdentifier ('=' expression)? (',' initializedIdentifier)* | 473 * declaredIdentifier ('=' expression)? (',' initializedIdentifier)* |
| 4009 * | 474 * |
| 4010 * declaredIdentifier ::= | 475 * declaredIdentifier ::= |
| 4011 * metadata finalConstVarOrType identifier | 476 * metadata finalConstVarOrType identifier |
| 4012 * | 477 * |
| 4013 * finalConstVarOrType ::= | 478 * finalConstVarOrType ::= |
| 4014 * 'final' type? | 479 * 'final' type? |
| 4015 * | 'const' type? | 480 * | 'const' type? |
| 4016 * | 'var' | 481 * | 'var' |
| 4017 * | type | 482 * | type |
| 4018 * | 483 * |
| 4019 * type ::= | 484 * type ::= |
| 4020 * qualified typeArguments? | 485 * qualified typeArguments? |
| 4021 * | 486 * |
| 4022 * initializedIdentifier ::= | 487 * initializedIdentifier ::= |
| 4023 * identifier ('=' expression)? | 488 * identifier ('=' expression)? |
| 4024 */ | 489 */ |
| 4025 bool _isInitializedVariableDeclaration() { | 490 bool isInitializedVariableDeclaration() { |
| 4026 if (_matchesKeyword(Keyword.FINAL) || _matchesKeyword(Keyword.VAR)) { | 491 Keyword keyword = _currentToken.keyword; |
| 492 if (keyword == Keyword.FINAL || keyword == Keyword.VAR) { |
| 4027 // An expression cannot start with a keyword other than 'const', | 493 // An expression cannot start with a keyword other than 'const', |
| 4028 // 'rethrow', or 'throw'. | 494 // 'rethrow', or 'throw'. |
| 4029 return true; | 495 return true; |
| 4030 } | 496 } |
| 4031 if (_matchesKeyword(Keyword.CONST)) { | 497 if (keyword == Keyword.CONST) { |
| 4032 // Look to see whether we might be at the start of a list or map literal, | 498 // Look to see whether we might be at the start of a list or map literal, |
| 4033 // otherwise this should be the start of a variable declaration. | 499 // otherwise this should be the start of a variable declaration. |
| 4034 return !_peek().matchesAny([ | 500 return !_peek().matchesAny(const <TokenType>[ |
| 4035 TokenType.LT, | 501 TokenType.LT, |
| 4036 TokenType.OPEN_CURLY_BRACKET, | 502 TokenType.OPEN_CURLY_BRACKET, |
| 4037 TokenType.OPEN_SQUARE_BRACKET, | 503 TokenType.OPEN_SQUARE_BRACKET, |
| 4038 TokenType.INDEX | 504 TokenType.INDEX |
| 4039 ]); | 505 ]); |
| 4040 } | 506 } |
| 4041 bool allowAdditionalTokens = true; | 507 bool allowAdditionalTokens = true; |
| 4042 // We know that we have an identifier, and need to see whether it might be | 508 // We know that we have an identifier, and need to see whether it might be |
| 4043 // a type name. | 509 // a type name. |
| 4044 if (_currentToken.type != TokenType.IDENTIFIER) { | 510 if (_currentToken.type != TokenType.IDENTIFIER) { |
| 4045 allowAdditionalTokens = false; | 511 allowAdditionalTokens = false; |
| 4046 } | 512 } |
| 4047 Token token = _skipTypeName(_currentToken); | 513 Token token = skipTypeName(_currentToken); |
| 4048 if (token == null) { | 514 if (token == null) { |
| 4049 // There was no type name, so this can't be a declaration. | 515 // There was no type name, so this can't be a declaration. |
| 4050 return false; | 516 return false; |
| 4051 } | 517 } |
| 4052 if (token.type != TokenType.IDENTIFIER) { | 518 if (token.type != TokenType.IDENTIFIER) { |
| 4053 allowAdditionalTokens = false; | 519 allowAdditionalTokens = false; |
| 4054 } | 520 } |
| 4055 token = _skipSimpleIdentifier(token); | 521 token = skipSimpleIdentifier(token); |
| 4056 if (token == null) { | 522 if (token == null) { |
| 4057 return false; | 523 return false; |
| 4058 } | 524 } |
| 4059 TokenType type = token.type; | 525 TokenType type = token.type; |
| 4060 // Usual cases in valid code: | 526 // Usual cases in valid code: |
| 4061 // String v = ''; | 527 // String v = ''; |
| 4062 // String v, v2; | 528 // String v, v2; |
| 4063 // String v; | 529 // String v; |
| 4064 // for (String item in items) {} | 530 // for (String item in items) {} |
| 4065 if (type == TokenType.EQ || | 531 if (type == TokenType.EQ || |
| 4066 type == TokenType.COMMA || | 532 type == TokenType.COMMA || |
| 4067 type == TokenType.SEMICOLON || | 533 type == TokenType.SEMICOLON || |
| 4068 _tokenMatchesKeyword(token, Keyword.IN)) { | 534 token.keyword == Keyword.IN) { |
| 4069 return true; | 535 return true; |
| 4070 } | 536 } |
| 4071 // It is OK to parse as a variable declaration in these cases: | 537 // It is OK to parse as a variable declaration in these cases: |
| 4072 // String v } | 538 // String v } |
| 4073 // String v if (true) print('OK'); | 539 // String v if (true) print('OK'); |
| 4074 // String v { print(42); } | 540 // String v { print(42); } |
| 4075 // ...but not in these cases: | 541 // ...but not in these cases: |
| 4076 // get getterName { | 542 // get getterName { |
| 4077 // String get getterName | 543 // String get getterName |
| 4078 if (allowAdditionalTokens) { | 544 if (allowAdditionalTokens) { |
| 4079 if (type == TokenType.CLOSE_CURLY_BRACKET || | 545 if (type == TokenType.CLOSE_CURLY_BRACKET || |
| 4080 type == TokenType.KEYWORD || | 546 type == TokenType.KEYWORD || |
| 4081 type == TokenType.IDENTIFIER || | 547 type == TokenType.IDENTIFIER || |
| 4082 type == TokenType.OPEN_CURLY_BRACKET) { | 548 type == TokenType.OPEN_CURLY_BRACKET) { |
| 4083 return true; | 549 return true; |
| 4084 } | 550 } |
| 4085 } | 551 } |
| 4086 return false; | 552 return false; |
| 4087 } | 553 } |
| 4088 | 554 |
| 4089 bool _isLikelyParameterList() { | |
| 4090 if (_matches(TokenType.OPEN_PAREN)) { | |
| 4091 return true; | |
| 4092 } | |
| 4093 if (!parseGenericMethods) { | |
| 4094 return false; | |
| 4095 } | |
| 4096 Token token = _skipTypeArgumentList(_currentToken); | |
| 4097 return token != null && _tokenMatches(token, TokenType.OPEN_PAREN); | |
| 4098 } | |
| 4099 | |
| 4100 /** | |
| 4101 * Given that we have just found bracketed text within the given [comment], | |
| 4102 * look to see whether that text is (a) followed by a parenthesized link | |
| 4103 * address, (b) followed by a colon, or (c) followed by optional whitespace | |
| 4104 * and another square bracket. The [rightIndex] is the index of the right | |
| 4105 * bracket. Return `true` if the bracketed text is followed by a link address. | |
| 4106 * | |
| 4107 * This method uses the syntax described by the | |
| 4108 * <a href="http://daringfireball.net/projects/markdown/syntax">markdown</a> | |
| 4109 * project. | |
| 4110 */ | |
| 4111 bool _isLinkText(String comment, int rightIndex) { | |
| 4112 int length = comment.length; | |
| 4113 int index = rightIndex + 1; | |
| 4114 if (index >= length) { | |
| 4115 return false; | |
| 4116 } | |
| 4117 int nextChar = comment.codeUnitAt(index); | |
| 4118 if (nextChar == 0x28 || nextChar == 0x3A) { | |
| 4119 return true; | |
| 4120 } | |
| 4121 while (Character.isWhitespace(nextChar)) { | |
| 4122 index = index + 1; | |
| 4123 if (index >= length) { | |
| 4124 return false; | |
| 4125 } | |
| 4126 nextChar = comment.codeUnitAt(index); | |
| 4127 } | |
| 4128 return nextChar == 0x5B; | |
| 4129 } | |
| 4130 | |
| 4131 /** | |
| 4132 * Return `true` if the given [startToken] appears to be the beginning of an | |
| 4133 * operator declaration. | |
| 4134 */ | |
| 4135 bool _isOperator(Token startToken) { | |
| 4136 // Accept any operator here, even if it is not user definable. | |
| 4137 if (!startToken.isOperator) { | |
| 4138 return false; | |
| 4139 } | |
| 4140 // Token "=" means that it is actually field initializer. | |
| 4141 if (startToken.type == TokenType.EQ) { | |
| 4142 return false; | |
| 4143 } | |
| 4144 // Consume all operator tokens. | |
| 4145 Token token = startToken.next; | |
| 4146 while (token.isOperator) { | |
| 4147 token = token.next; | |
| 4148 } | |
| 4149 // Formal parameter list is expect now. | |
| 4150 return _tokenMatches(token, TokenType.OPEN_PAREN); | |
| 4151 } | |
| 4152 | |
| 4153 /** | 555 /** |
| 4154 * Return `true` if the current token appears to be the beginning of a switch | 556 * Return `true` if the current token appears to be the beginning of a switch |
| 4155 * member. | 557 * member. |
| 4156 */ | 558 */ |
| 4157 bool _isSwitchMember() { | 559 bool isSwitchMember() { |
| 4158 Token token = _currentToken; | 560 Token token = _currentToken; |
| 4159 while (_tokenMatches(token, TokenType.IDENTIFIER) && | 561 while (_tokenMatches(token, TokenType.IDENTIFIER) && |
| 4160 _tokenMatches(token.next, TokenType.COLON)) { | 562 _tokenMatches(token.next, TokenType.COLON)) { |
| 4161 token = token.next.next; | 563 token = token.next.next; |
| 4162 } | 564 } |
| 4163 if (token.type == TokenType.KEYWORD) { | 565 Keyword keyword = token.keyword; |
| 4164 Keyword keyword = (token as KeywordToken).keyword; | 566 return keyword == Keyword.CASE || keyword == Keyword.DEFAULT; |
| 4165 return keyword == Keyword.CASE || keyword == Keyword.DEFAULT; | |
| 4166 } | |
| 4167 return false; | |
| 4168 } | |
| 4169 | |
| 4170 /** | |
| 4171 * Return `true` if the [startToken] appears to be the first token of a type | |
| 4172 * name that is followed by a variable or field formal parameter. | |
| 4173 */ | |
| 4174 bool _isTypedIdentifier(Token startToken) { | |
| 4175 Token token = _skipReturnType(startToken); | |
| 4176 if (token == null) { | |
| 4177 return false; | |
| 4178 } else if (_tokenMatchesIdentifier(token)) { | |
| 4179 return true; | |
| 4180 } else if (_tokenMatchesKeyword(token, Keyword.THIS) && | |
| 4181 _tokenMatches(token.next, TokenType.PERIOD) && | |
| 4182 _tokenMatchesIdentifier(token.next.next)) { | |
| 4183 return true; | |
| 4184 } else if (_tokenMatchesKeyword(startToken, Keyword.VOID)) { | |
| 4185 // The keyword 'void' isn't a valid identifier, so it should be assumed to | |
| 4186 // be a type name. | |
| 4187 return true; | |
| 4188 } else if (startToken.next != token && | |
| 4189 !_tokenMatches(token, TokenType.OPEN_PAREN)) { | |
| 4190 // The type is more than a simple identifier, so it should be assumed to | |
| 4191 // be a type name. | |
| 4192 return true; | |
| 4193 } | |
| 4194 return false; | |
| 4195 } | |
| 4196 | |
| 4197 /** | |
| 4198 * Increments the error reporting lock level. If level is more than `0`, then | |
| 4199 * [reportError] wont report any error. | |
| 4200 */ | |
| 4201 void _lockErrorListener() { | |
| 4202 _errorListenerLock++; | |
| 4203 } | |
| 4204 | |
| 4205 /** | |
| 4206 * Return `true` if the current token has the given [type]. Note that the | |
| 4207 * method [_matchesGt] should be used if the argument to this method would be | |
| 4208 * [TokenType.GT]. | |
| 4209 */ | |
| 4210 bool _matches(TokenType type) => _currentToken.type == type; | |
| 4211 | |
| 4212 /** | |
| 4213 * Return `true` if the current token has a type of [TokenType.GT]. Note that | |
| 4214 * this method, unlike other variants, will modify the token stream if | |
| 4215 * possible to match desired type. In particular, if the next token is either | |
| 4216 * a '>>' or '>>>', the token stream will be re-written and `true` will be | |
| 4217 * returned. | |
| 4218 */ | |
| 4219 bool _matchesGt() { | |
| 4220 TokenType currentType = _currentToken.type; | |
| 4221 if (currentType == TokenType.GT) { | |
| 4222 return true; | |
| 4223 } else if (currentType == TokenType.GT_GT) { | |
| 4224 Token first = _createToken(_currentToken, TokenType.GT); | |
| 4225 Token second = new Token(TokenType.GT, _currentToken.offset + 1); | |
| 4226 second.setNext(_currentToken.next); | |
| 4227 first.setNext(second); | |
| 4228 _currentToken.previous.setNext(first); | |
| 4229 _currentToken = first; | |
| 4230 return true; | |
| 4231 } else if (currentType == TokenType.GT_EQ) { | |
| 4232 Token first = _createToken(_currentToken, TokenType.GT); | |
| 4233 Token second = new Token(TokenType.EQ, _currentToken.offset + 1); | |
| 4234 second.setNext(_currentToken.next); | |
| 4235 first.setNext(second); | |
| 4236 _currentToken.previous.setNext(first); | |
| 4237 _currentToken = first; | |
| 4238 return true; | |
| 4239 } else if (currentType == TokenType.GT_GT_EQ) { | |
| 4240 int offset = _currentToken.offset; | |
| 4241 Token first = _createToken(_currentToken, TokenType.GT); | |
| 4242 Token second = new Token(TokenType.GT, offset + 1); | |
| 4243 Token third = new Token(TokenType.EQ, offset + 2); | |
| 4244 third.setNext(_currentToken.next); | |
| 4245 second.setNext(third); | |
| 4246 first.setNext(second); | |
| 4247 _currentToken.previous.setNext(first); | |
| 4248 _currentToken = first; | |
| 4249 return true; | |
| 4250 } | |
| 4251 return false; | |
| 4252 } | |
| 4253 | |
| 4254 /** | |
| 4255 * Return `true` if the current token is a valid identifier. Valid identifiers | |
| 4256 * include built-in identifiers (pseudo-keywords). | |
| 4257 */ | |
| 4258 bool _matchesIdentifier() => _tokenMatchesIdentifier(_currentToken); | |
| 4259 | |
| 4260 /** | |
| 4261 * Return `true` if the current token matches the given [keyword]. | |
| 4262 */ | |
| 4263 bool _matchesKeyword(Keyword keyword) => | |
| 4264 _tokenMatchesKeyword(_currentToken, keyword); | |
| 4265 | |
| 4266 /** | |
| 4267 * Return `true` if the current token matches the given [identifier]. | |
| 4268 */ | |
| 4269 bool _matchesString(String identifier) => | |
| 4270 _currentToken.type == TokenType.IDENTIFIER && | |
| 4271 _currentToken.lexeme == identifier; | |
| 4272 | |
| 4273 /** | |
| 4274 * If the current token has the given [type], then advance to the next token | |
| 4275 * and return `true`. Otherwise, return `false` without advancing. This method | |
| 4276 * should not be invoked with an argument value of [TokenType.GT]. | |
| 4277 */ | |
| 4278 bool _optional(TokenType type) { | |
| 4279 if (_matches(type)) { | |
| 4280 _advance(); | |
| 4281 return true; | |
| 4282 } | |
| 4283 return false; | |
| 4284 } | 567 } |
| 4285 | 568 |
| 4286 /** | 569 /** |
| 4287 * Parse an additive expression. Return the additive expression that was | 570 * Parse an additive expression. Return the additive expression that was |
| 4288 * parsed. | 571 * parsed. |
| 4289 * | 572 * |
| 4290 * additiveExpression ::= | 573 * additiveExpression ::= |
| 4291 * multiplicativeExpression (additiveOperator multiplicativeExpression
)* | 574 * multiplicativeExpression (additiveOperator multiplicativeExpression
)* |
| 4292 * | 'super' (additiveOperator multiplicativeExpression)+ | 575 * | 'super' (additiveOperator multiplicativeExpression)+ |
| 4293 */ | 576 */ |
| 4294 Expression _parseAdditiveExpression() { | 577 Expression parseAdditiveExpression() { |
| 4295 Expression expression; | 578 Expression expression; |
| 4296 if (_matchesKeyword(Keyword.SUPER) && | 579 if (_currentToken.keyword == Keyword.SUPER && |
| 4297 _currentToken.next.type.isAdditiveOperator) { | 580 _currentToken.next.type.isAdditiveOperator) { |
| 4298 expression = new SuperExpression(getAndAdvance()); | 581 expression = new SuperExpression(getAndAdvance()); |
| 4299 } else { | 582 } else { |
| 4300 expression = _parseMultiplicativeExpression(); | 583 expression = parseMultiplicativeExpression(); |
| 4301 } | 584 } |
| 4302 while (_currentToken.type.isAdditiveOperator) { | 585 while (_currentToken.type.isAdditiveOperator) { |
| 4303 Token operator = getAndAdvance(); | |
| 4304 expression = new BinaryExpression( | 586 expression = new BinaryExpression( |
| 4305 expression, operator, _parseMultiplicativeExpression()); | 587 expression, getAndAdvance(), parseMultiplicativeExpression()); |
| 4306 } | 588 } |
| 4307 return expression; | 589 return expression; |
| 4308 } | 590 } |
| 4309 | 591 |
| 4310 /** | 592 /** |
| 593 * Parse an annotation. Return the annotation that was parsed. |
| 594 * |
| 595 * This method assumes that the current token matches [TokenType.AT]. |
| 596 * |
| 597 * annotation ::= |
| 598 * '@' qualified ('.' identifier)? arguments? |
| 599 */ |
| 600 Annotation parseAnnotation() { |
| 601 Token atSign = getAndAdvance(); |
| 602 Identifier name = parsePrefixedIdentifier(); |
| 603 Token period = null; |
| 604 SimpleIdentifier constructorName = null; |
| 605 if (_matches(TokenType.PERIOD)) { |
| 606 period = getAndAdvance(); |
| 607 constructorName = parseSimpleIdentifier(); |
| 608 } |
| 609 ArgumentList arguments = null; |
| 610 if (_matches(TokenType.OPEN_PAREN)) { |
| 611 arguments = parseArgumentList(); |
| 612 } |
| 613 return new Annotation(atSign, name, period, constructorName, arguments); |
| 614 } |
| 615 |
| 616 /** |
| 617 * Parse an argument. Return the argument that was parsed. |
| 618 * |
| 619 * argument ::= |
| 620 * namedArgument |
| 621 * | expression |
| 622 * |
| 623 * namedArgument ::= |
| 624 * label expression |
| 625 */ |
| 626 Expression parseArgument() { |
| 627 // TODO(brianwilkerson) Consider returning a wrapper indicating whether the |
| 628 // expression is a named expression in order to remove the 'is' check in |
| 629 // 'parseArgumentList'. |
| 630 // |
| 631 // Both namedArgument and expression can start with an identifier, but only |
| 632 // namedArgument can have an identifier followed by a colon. |
| 633 // |
| 634 if (_matchesIdentifier() && _tokenMatches(_peek(), TokenType.COLON)) { |
| 635 return new NamedExpression(parseLabel(), parseExpression2()); |
| 636 } else { |
| 637 return parseExpression2(); |
| 638 } |
| 639 } |
| 640 |
| 641 /** |
| 642 * Parse a list of arguments. Return the argument list that was parsed. |
| 643 * |
| 644 * This method assumes that the current token matches [TokenType.OPEN_PAREN]. |
| 645 * |
| 646 * arguments ::= |
| 647 * '(' argumentList? ')' |
| 648 * |
| 649 * argumentList ::= |
| 650 * namedArgument (',' namedArgument)* |
| 651 * | expressionList (',' namedArgument)* |
| 652 */ |
| 653 ArgumentList parseArgumentList() { |
| 654 Token leftParenthesis = getAndAdvance(); |
| 655 if (_matches(TokenType.CLOSE_PAREN)) { |
| 656 return new ArgumentList(leftParenthesis, null, getAndAdvance()); |
| 657 } |
| 658 // |
| 659 // Even though unnamed arguments must all appear before any named arguments, |
| 660 // we allow them to appear in any order so that we can recover faster. |
| 661 // |
| 662 bool wasInInitializer = _inInitializer; |
| 663 _inInitializer = false; |
| 664 try { |
| 665 Expression argument = parseArgument(); |
| 666 List<Expression> arguments = <Expression>[argument]; |
| 667 bool foundNamedArgument = argument is NamedExpression; |
| 668 bool generatedError = false; |
| 669 while (_optional(TokenType.COMMA)) { |
| 670 if (_matches(TokenType.CLOSE_PAREN)) { |
| 671 break; |
| 672 } |
| 673 argument = parseArgument(); |
| 674 arguments.add(argument); |
| 675 if (argument is NamedExpression) { |
| 676 foundNamedArgument = true; |
| 677 } else if (foundNamedArgument) { |
| 678 if (!generatedError) { |
| 679 if (!argument.isSynthetic) { |
| 680 // Report the error, once, but allow the arguments to be in any |
| 681 // order in the AST. |
| 682 _reportErrorForCurrentToken( |
| 683 ParserErrorCode.POSITIONAL_AFTER_NAMED_ARGUMENT); |
| 684 generatedError = true; |
| 685 } |
| 686 } |
| 687 } |
| 688 } |
| 689 // Recovery: If the next token is not a right parenthesis, look at the |
| 690 // left parenthesis to see whether there is a matching right parenthesis. |
| 691 // If there is, then we're more likely missing a comma and should go back |
| 692 // to parsing arguments. |
| 693 Token rightParenthesis = _expect(TokenType.CLOSE_PAREN); |
| 694 return new ArgumentList(leftParenthesis, arguments, rightParenthesis); |
| 695 } finally { |
| 696 _inInitializer = wasInInitializer; |
| 697 } |
| 698 } |
| 699 |
| 700 /** |
| 4311 * Parse an assert statement. Return the assert statement. | 701 * Parse an assert statement. Return the assert statement. |
| 4312 * | 702 * |
| 703 * This method assumes that the current token matches `Keyword.ASSERT`. |
| 704 * |
| 4313 * assertStatement ::= | 705 * assertStatement ::= |
| 4314 * 'assert' '(' conditionalExpression ')' ';' | 706 * 'assert' '(' expression [',' expression] ')' ';' |
| 4315 */ | 707 */ |
| 4316 AssertStatement _parseAssertStatement() { | 708 AssertStatement parseAssertStatement() { |
| 4317 Token keyword = _expectKeyword(Keyword.ASSERT); | 709 Token keyword = getAndAdvance(); |
| 4318 Token leftParen = _expect(TokenType.OPEN_PAREN); | 710 Token leftParen = _expect(TokenType.OPEN_PAREN); |
| 4319 Expression expression = parseExpression2(); | 711 Expression expression = parseExpression2(); |
| 4320 if (expression is AssignmentExpression) { | 712 Token comma; |
| 4321 _reportErrorForNode( | 713 Expression message; |
| 4322 ParserErrorCode.ASSERT_DOES_NOT_TAKE_ASSIGNMENT, expression); | 714 if (_matches(TokenType.COMMA)) { |
| 4323 } else if (expression is CascadeExpression) { | 715 comma = getAndAdvance(); |
| 4324 _reportErrorForNode( | 716 message = parseExpression2(); |
| 4325 ParserErrorCode.ASSERT_DOES_NOT_TAKE_CASCADE, expression); | |
| 4326 } else if (expression is ThrowExpression) { | |
| 4327 _reportErrorForNode( | |
| 4328 ParserErrorCode.ASSERT_DOES_NOT_TAKE_THROW, expression); | |
| 4329 } else if (expression is RethrowExpression) { | |
| 4330 _reportErrorForNode( | |
| 4331 ParserErrorCode.ASSERT_DOES_NOT_TAKE_RETHROW, expression); | |
| 4332 } | 717 } |
| 4333 Token rightParen = _expect(TokenType.CLOSE_PAREN); | 718 Token rightParen = _expect(TokenType.CLOSE_PAREN); |
| 4334 Token semicolon = _expect(TokenType.SEMICOLON); | 719 Token semicolon = _expect(TokenType.SEMICOLON); |
| 4335 return new AssertStatement( | 720 return new AssertStatement( |
| 4336 keyword, leftParen, expression, rightParen, semicolon); | 721 keyword, leftParen, expression, comma, message, rightParen, semicolon); |
| 4337 } | 722 } |
| 4338 | 723 |
| 4339 /** | 724 /** |
| 4340 * Parse an assignable expression. The [primaryAllowed] is `true` if the | 725 * Parse an assignable expression. The [primaryAllowed] is `true` if the |
| 4341 * expression is allowed to be a primary without any assignable selector. | 726 * expression is allowed to be a primary without any assignable selector. |
| 4342 * Return the assignable expression that was parsed. | 727 * Return the assignable expression that was parsed. |
| 4343 * | 728 * |
| 4344 * assignableExpression ::= | 729 * assignableExpression ::= |
| 4345 * primary (arguments* assignableSelector)+ | 730 * primary (arguments* assignableSelector)+ |
| 4346 * | 'super' unconditionalAssignableSelector | 731 * | 'super' unconditionalAssignableSelector |
| 4347 * | identifier | 732 * | identifier |
| 4348 */ | 733 */ |
| 4349 Expression _parseAssignableExpression(bool primaryAllowed) { | 734 Expression parseAssignableExpression(bool primaryAllowed) { |
| 4350 if (_matchesKeyword(Keyword.SUPER)) { | 735 if (_matchesKeyword(Keyword.SUPER)) { |
| 4351 return _parseAssignableSelector( | 736 return parseAssignableSelector( |
| 4352 new SuperExpression(getAndAdvance()), false, | 737 new SuperExpression(getAndAdvance()), false, |
| 4353 allowConditional: false); | 738 allowConditional: false); |
| 4354 } | 739 } |
| 4355 // | 740 return _parseAssignableExpressionNotStartingWithSuper(primaryAllowed); |
| 4356 // A primary expression can start with an identifier. We resolve the | |
| 4357 // ambiguity by determining whether the primary consists of anything other | |
| 4358 // than an identifier and/or is followed by an assignableSelector. | |
| 4359 // | |
| 4360 Expression expression = _parsePrimaryExpression(); | |
| 4361 bool isOptional = primaryAllowed || expression is SimpleIdentifier; | |
| 4362 while (true) { | |
| 4363 while (_isLikelyParameterList()) { | |
| 4364 TypeArgumentList typeArguments = null; | |
| 4365 if (_matches(TokenType.LT)) { | |
| 4366 typeArguments = parseTypeArgumentList(); | |
| 4367 } | |
| 4368 ArgumentList argumentList = parseArgumentList(); | |
| 4369 if (expression is SimpleIdentifier) { | |
| 4370 expression = new MethodInvocation(null, null, | |
| 4371 expression as SimpleIdentifier, typeArguments, argumentList); | |
| 4372 } else if (expression is PrefixedIdentifier) { | |
| 4373 PrefixedIdentifier identifier = expression as PrefixedIdentifier; | |
| 4374 expression = new MethodInvocation( | |
| 4375 identifier.prefix, | |
| 4376 identifier.period, | |
| 4377 identifier.identifier, | |
| 4378 typeArguments, | |
| 4379 argumentList); | |
| 4380 } else if (expression is PropertyAccess) { | |
| 4381 PropertyAccess access = expression as PropertyAccess; | |
| 4382 expression = new MethodInvocation(access.target, access.operator, | |
| 4383 access.propertyName, typeArguments, argumentList); | |
| 4384 } else { | |
| 4385 expression = new FunctionExpressionInvocation( | |
| 4386 expression, typeArguments, argumentList); | |
| 4387 } | |
| 4388 if (!primaryAllowed) { | |
| 4389 isOptional = false; | |
| 4390 } | |
| 4391 } | |
| 4392 Expression selectorExpression = _parseAssignableSelector( | |
| 4393 expression, isOptional || (expression is PrefixedIdentifier)); | |
| 4394 if (identical(selectorExpression, expression)) { | |
| 4395 if (!isOptional && (expression is PrefixedIdentifier)) { | |
| 4396 PrefixedIdentifier identifier = expression as PrefixedIdentifier; | |
| 4397 expression = new PropertyAccess( | |
| 4398 identifier.prefix, identifier.period, identifier.identifier); | |
| 4399 } | |
| 4400 return expression; | |
| 4401 } | |
| 4402 expression = selectorExpression; | |
| 4403 isOptional = true; | |
| 4404 } | |
| 4405 } | 741 } |
| 4406 | 742 |
| 4407 /** | 743 /** |
| 4408 * Parse an assignable selector. The [prefix] is the expression preceding the | 744 * Parse an assignable selector. The [prefix] is the expression preceding the |
| 4409 * selector. The [optional] is `true` if the selector is optional. Return the | 745 * selector. The [optional] is `true` if the selector is optional. Return the |
| 4410 * assignable selector that was parsed, or the original prefix if there was no | 746 * assignable selector that was parsed, or the original prefix if there was no |
| 4411 * assignable selector. If [allowConditional] is false, then the '?.' | 747 * assignable selector. If [allowConditional] is false, then the '?.' |
| 4412 * operator will still be parsed, but a parse error will be generated. | 748 * operator will still be parsed, but a parse error will be generated. |
| 4413 * | 749 * |
| 4414 * unconditionalAssignableSelector ::= | 750 * unconditionalAssignableSelector ::= |
| 4415 * '[' expression ']' | 751 * '[' expression ']' |
| 4416 * | '.' identifier | 752 * | '.' identifier |
| 4417 * | 753 * |
| 4418 * assignableSelector ::= | 754 * assignableSelector ::= |
| 4419 * unconditionalAssignableSelector | 755 * unconditionalAssignableSelector |
| 4420 * | '?.' identifier | 756 * | '?.' identifier |
| 4421 */ | 757 */ |
| 4422 Expression _parseAssignableSelector(Expression prefix, bool optional, | 758 Expression parseAssignableSelector(Expression prefix, bool optional, |
| 4423 {bool allowConditional: true}) { | 759 {bool allowConditional: true}) { |
| 4424 if (_matches(TokenType.OPEN_SQUARE_BRACKET)) { | 760 TokenType type = _currentToken.type; |
| 761 if (type == TokenType.OPEN_SQUARE_BRACKET) { |
| 4425 Token leftBracket = getAndAdvance(); | 762 Token leftBracket = getAndAdvance(); |
| 4426 bool wasInInitializer = _inInitializer; | 763 bool wasInInitializer = _inInitializer; |
| 4427 _inInitializer = false; | 764 _inInitializer = false; |
| 4428 try { | 765 try { |
| 4429 Expression index = parseExpression2(); | 766 Expression index = parseExpression2(); |
| 4430 Token rightBracket = _expect(TokenType.CLOSE_SQUARE_BRACKET); | 767 Token rightBracket = _expect(TokenType.CLOSE_SQUARE_BRACKET); |
| 4431 return new IndexExpression.forTarget( | 768 return new IndexExpression.forTarget( |
| 4432 prefix, leftBracket, index, rightBracket); | 769 prefix, leftBracket, index, rightBracket); |
| 4433 } finally { | 770 } finally { |
| 4434 _inInitializer = wasInInitializer; | 771 _inInitializer = wasInInitializer; |
| 4435 } | 772 } |
| 4436 } else if (_matches(TokenType.PERIOD) || | |
| 4437 _matches(TokenType.QUESTION_PERIOD)) { | |
| 4438 if (_matches(TokenType.QUESTION_PERIOD) && !allowConditional) { | |
| 4439 _reportErrorForCurrentToken( | |
| 4440 ParserErrorCode.INVALID_OPERATOR_FOR_SUPER, [_currentToken.lexeme]); | |
| 4441 } | |
| 4442 Token operator = getAndAdvance(); | |
| 4443 return new PropertyAccess(prefix, operator, parseSimpleIdentifier()); | |
| 4444 } else { | 773 } else { |
| 4445 if (!optional) { | 774 bool isQuestionPeriod = type == TokenType.QUESTION_PERIOD; |
| 4446 // Report the missing selector. | 775 if (type == TokenType.PERIOD || isQuestionPeriod) { |
| 4447 _reportErrorForCurrentToken( | 776 if (isQuestionPeriod && !allowConditional) { |
| 4448 ParserErrorCode.MISSING_ASSIGNABLE_SELECTOR); | 777 _reportErrorForCurrentToken( |
| 4449 } | 778 ParserErrorCode.INVALID_OPERATOR_FOR_SUPER, |
| 4450 return prefix; | 779 [_currentToken.lexeme]); |
| 780 } |
| 781 Token operator = getAndAdvance(); |
| 782 return new PropertyAccess(prefix, operator, parseSimpleIdentifier()); |
| 783 } else { |
| 784 if (!optional) { |
| 785 // Report the missing selector. |
| 786 _reportErrorForCurrentToken( |
| 787 ParserErrorCode.MISSING_ASSIGNABLE_SELECTOR); |
| 788 } |
| 789 return prefix; |
| 790 } |
| 4451 } | 791 } |
| 4452 } | 792 } |
| 4453 | 793 |
| 4454 /** | 794 /** |
| 4455 * Parse a await expression. Return the await expression that was parsed. | 795 * Parse a await expression. Return the await expression that was parsed. |
| 4456 * | 796 * |
| 797 * This method assumes that the current token matches `_AWAIT`. |
| 798 * |
| 4457 * awaitExpression ::= | 799 * awaitExpression ::= |
| 4458 * 'await' unaryExpression | 800 * 'await' unaryExpression |
| 4459 */ | 801 */ |
| 4460 AwaitExpression _parseAwaitExpression() { | 802 AwaitExpression parseAwaitExpression() { |
| 4461 Token awaitToken = getAndAdvance(); | 803 Token awaitToken = getAndAdvance(); |
| 4462 Expression expression = _parseUnaryExpression(); | 804 Expression expression = parseUnaryExpression(); |
| 4463 return new AwaitExpression(awaitToken, expression); | 805 return new AwaitExpression(awaitToken, expression); |
| 4464 } | 806 } |
| 4465 | 807 |
| 4466 /** | 808 /** |
| 4467 * Parse a bitwise and expression. Return the bitwise and expression that was | 809 * Parse a bitwise and expression. Return the bitwise and expression that was |
| 4468 * parsed. | 810 * parsed. |
| 4469 * | 811 * |
| 4470 * bitwiseAndExpression ::= | 812 * bitwiseAndExpression ::= |
| 4471 * shiftExpression ('&' shiftExpression)* | 813 * shiftExpression ('&' shiftExpression)* |
| 4472 * | 'super' ('&' shiftExpression)+ | 814 * | 'super' ('&' shiftExpression)+ |
| 4473 */ | 815 */ |
| 4474 Expression _parseBitwiseAndExpression() { | 816 Expression parseBitwiseAndExpression() { |
| 4475 Expression expression; | 817 Expression expression; |
| 4476 if (_matchesKeyword(Keyword.SUPER) && | 818 if (_currentToken.keyword == Keyword.SUPER && |
| 4477 _tokenMatches(_peek(), TokenType.AMPERSAND)) { | 819 _currentToken.next.type == TokenType.AMPERSAND) { |
| 4478 expression = new SuperExpression(getAndAdvance()); | 820 expression = new SuperExpression(getAndAdvance()); |
| 4479 } else { | 821 } else { |
| 4480 expression = _parseShiftExpression(); | 822 expression = parseShiftExpression(); |
| 4481 } | 823 } |
| 4482 while (_matches(TokenType.AMPERSAND)) { | 824 while (_currentToken.type == TokenType.AMPERSAND) { |
| 4483 Token operator = getAndAdvance(); | 825 expression = new BinaryExpression( |
| 4484 expression = | 826 expression, getAndAdvance(), parseShiftExpression()); |
| 4485 new BinaryExpression(expression, operator, _parseShiftExpression()); | 827 } |
| 828 return expression; |
| 829 } |
| 830 |
| 831 /** |
| 832 * Parse a bitwise or expression. Return the bitwise or expression that was |
| 833 * parsed. |
| 834 * |
| 835 * bitwiseOrExpression ::= |
| 836 * bitwiseXorExpression ('|' bitwiseXorExpression)* |
| 837 * | 'super' ('|' bitwiseXorExpression)+ |
| 838 */ |
| 839 Expression parseBitwiseOrExpression() { |
| 840 Expression expression; |
| 841 if (_currentToken.keyword == Keyword.SUPER && |
| 842 _currentToken.next.type == TokenType.BAR) { |
| 843 expression = new SuperExpression(getAndAdvance()); |
| 844 } else { |
| 845 expression = parseBitwiseXorExpression(); |
| 846 } |
| 847 while (_currentToken.type == TokenType.BAR) { |
| 848 expression = new BinaryExpression( |
| 849 expression, getAndAdvance(), parseBitwiseXorExpression()); |
| 4486 } | 850 } |
| 4487 return expression; | 851 return expression; |
| 4488 } | 852 } |
| 4489 | 853 |
| 4490 /** | 854 /** |
| 4491 * Parse a bitwise exclusive-or expression. Return the bitwise exclusive-or | 855 * Parse a bitwise exclusive-or expression. Return the bitwise exclusive-or |
| 4492 * expression that was parsed. | 856 * expression that was parsed. |
| 4493 * | 857 * |
| 4494 * bitwiseXorExpression ::= | 858 * bitwiseXorExpression ::= |
| 4495 * bitwiseAndExpression ('^' bitwiseAndExpression)* | 859 * bitwiseAndExpression ('^' bitwiseAndExpression)* |
| 4496 * | 'super' ('^' bitwiseAndExpression)+ | 860 * | 'super' ('^' bitwiseAndExpression)+ |
| 4497 */ | 861 */ |
| 4498 Expression _parseBitwiseXorExpression() { | 862 Expression parseBitwiseXorExpression() { |
| 4499 Expression expression; | 863 Expression expression; |
| 4500 if (_matchesKeyword(Keyword.SUPER) && | 864 if (_currentToken.keyword == Keyword.SUPER && |
| 4501 _tokenMatches(_peek(), TokenType.CARET)) { | 865 _currentToken.next.type == TokenType.CARET) { |
| 4502 expression = new SuperExpression(getAndAdvance()); | 866 expression = new SuperExpression(getAndAdvance()); |
| 4503 } else { | 867 } else { |
| 4504 expression = _parseBitwiseAndExpression(); | 868 expression = parseBitwiseAndExpression(); |
| 4505 } | 869 } |
| 4506 while (_matches(TokenType.CARET)) { | 870 while (_currentToken.type == TokenType.CARET) { |
| 4507 Token operator = getAndAdvance(); | |
| 4508 expression = new BinaryExpression( | 871 expression = new BinaryExpression( |
| 4509 expression, operator, _parseBitwiseAndExpression()); | 872 expression, getAndAdvance(), parseBitwiseAndExpression()); |
| 4510 } | 873 } |
| 4511 return expression; | 874 return expression; |
| 4512 } | 875 } |
| 4513 | 876 |
| 4514 /** | 877 /** |
| 878 * Parse a block. Return the block that was parsed. |
| 879 * |
| 880 * This method assumes that the current token matches |
| 881 * [TokenType.OPEN_CURLY_BRACKET]. |
| 882 * |
| 883 * block ::= |
| 884 * '{' statements '}' |
| 885 */ |
| 886 Block parseBlock() { |
| 887 bool isEndOfBlock() { |
| 888 TokenType type = _currentToken.type; |
| 889 return type == TokenType.EOF || type == TokenType.CLOSE_CURLY_BRACKET; |
| 890 } |
| 891 |
| 892 Token leftBracket = getAndAdvance(); |
| 893 List<Statement> statements = <Statement>[]; |
| 894 Token statementStart = _currentToken; |
| 895 while (!isEndOfBlock()) { |
| 896 Statement statement = parseStatement2(); |
| 897 if (identical(_currentToken, statementStart)) { |
| 898 // Ensure that we are making progress and report an error if we're not. |
| 899 _reportErrorForToken(ParserErrorCode.UNEXPECTED_TOKEN, _currentToken, |
| 900 [_currentToken.lexeme]); |
| 901 _advance(); |
| 902 } else if (statement != null) { |
| 903 statements.add(statement); |
| 904 } |
| 905 statementStart = _currentToken; |
| 906 } |
| 907 // Recovery: If the next token is not a right curly bracket, look at the |
| 908 // left curly bracket to see whether there is a matching right bracket. If |
| 909 // there is, then we're more likely missing a semi-colon and should go back |
| 910 // to parsing statements. |
| 911 Token rightBracket = _expect(TokenType.CLOSE_CURLY_BRACKET); |
| 912 return new Block(leftBracket, statements, rightBracket); |
| 913 } |
| 914 |
| 915 /** |
| 4515 * Parse a break statement. Return the break statement that was parsed. | 916 * Parse a break statement. Return the break statement that was parsed. |
| 4516 * | 917 * |
| 918 * This method assumes that the current token matches `Keyword.BREAK`. |
| 919 * |
| 4517 * breakStatement ::= | 920 * breakStatement ::= |
| 4518 * 'break' identifier? ';' | 921 * 'break' identifier? ';' |
| 4519 */ | 922 */ |
| 4520 Statement _parseBreakStatement() { | 923 Statement parseBreakStatement() { |
| 4521 Token breakKeyword = _expectKeyword(Keyword.BREAK); | 924 Token breakKeyword = getAndAdvance(); |
| 4522 SimpleIdentifier label = null; | 925 SimpleIdentifier label = null; |
| 4523 if (_matchesIdentifier()) { | 926 if (_matchesIdentifier()) { |
| 4524 label = parseSimpleIdentifier(); | 927 label = _parseSimpleIdentifierUnchecked(); |
| 4525 } | 928 } |
| 4526 if (!_inLoop && !_inSwitch && label == null) { | 929 if (!_inLoop && !_inSwitch && label == null) { |
| 4527 _reportErrorForToken(ParserErrorCode.BREAK_OUTSIDE_OF_LOOP, breakKeyword); | 930 _reportErrorForToken(ParserErrorCode.BREAK_OUTSIDE_OF_LOOP, breakKeyword); |
| 4528 } | 931 } |
| 4529 Token semicolon = _expect(TokenType.SEMICOLON); | 932 Token semicolon = _expect(TokenType.SEMICOLON); |
| 4530 return new BreakStatement(breakKeyword, label, semicolon); | 933 return new BreakStatement(breakKeyword, label, semicolon); |
| 4531 } | 934 } |
| 4532 | 935 |
| 4533 /** | 936 /** |
| 4534 * Parse a cascade section. Return the expression representing the cascaded | 937 * Parse a cascade section. Return the expression representing the cascaded |
| 4535 * method invocation. | 938 * method invocation. |
| 4536 * | 939 * |
| 940 * This method assumes that the current token matches |
| 941 * `TokenType.PERIOD_PERIOD`. |
| 942 * |
| 4537 * cascadeSection ::= | 943 * cascadeSection ::= |
| 4538 * '..' (cascadeSelector typeArguments? arguments*) | 944 * '..' (cascadeSelector typeArguments? arguments*) |
| 4539 * (assignableSelector typeArguments? arguments*)* cascadeAssignment? | 945 * (assignableSelector typeArguments? arguments*)* cascadeAssignment? |
| 4540 * | 946 * |
| 4541 * cascadeSelector ::= | 947 * cascadeSelector ::= |
| 4542 * '[' expression ']' | 948 * '[' expression ']' |
| 4543 * | identifier | 949 * | identifier |
| 4544 * | 950 * |
| 4545 * cascadeAssignment ::= | 951 * cascadeAssignment ::= |
| 4546 * assignmentOperator expressionWithoutCascade | 952 * assignmentOperator expressionWithoutCascade |
| 4547 */ | 953 */ |
| 4548 Expression _parseCascadeSection() { | 954 Expression parseCascadeSection() { |
| 4549 Token period = _expect(TokenType.PERIOD_PERIOD); | 955 Token period = getAndAdvance(); |
| 4550 Expression expression = null; | 956 Expression expression = null; |
| 4551 SimpleIdentifier functionName = null; | 957 SimpleIdentifier functionName = null; |
| 4552 if (_matchesIdentifier()) { | 958 if (_matchesIdentifier()) { |
| 4553 functionName = parseSimpleIdentifier(); | 959 functionName = _parseSimpleIdentifierUnchecked(); |
| 4554 } else if (_currentToken.type == TokenType.OPEN_SQUARE_BRACKET) { | 960 } else if (_currentToken.type == TokenType.OPEN_SQUARE_BRACKET) { |
| 4555 Token leftBracket = getAndAdvance(); | 961 Token leftBracket = getAndAdvance(); |
| 4556 bool wasInInitializer = _inInitializer; | 962 bool wasInInitializer = _inInitializer; |
| 4557 _inInitializer = false; | 963 _inInitializer = false; |
| 4558 try { | 964 try { |
| 4559 Expression index = parseExpression2(); | 965 Expression index = parseExpression2(); |
| 4560 Token rightBracket = _expect(TokenType.CLOSE_SQUARE_BRACKET); | 966 Token rightBracket = _expect(TokenType.CLOSE_SQUARE_BRACKET); |
| 4561 expression = new IndexExpression.forCascade( | 967 expression = new IndexExpression.forCascade( |
| 4562 period, leftBracket, index, rightBracket); | 968 period, leftBracket, index, rightBracket); |
| 4563 period = null; | 969 period = null; |
| 4564 } finally { | 970 } finally { |
| 4565 _inInitializer = wasInInitializer; | 971 _inInitializer = wasInInitializer; |
| 4566 } | 972 } |
| 4567 } else { | 973 } else { |
| 4568 _reportErrorForToken(ParserErrorCode.MISSING_IDENTIFIER, _currentToken, | 974 _reportErrorForToken(ParserErrorCode.MISSING_IDENTIFIER, _currentToken, |
| 4569 [_currentToken.lexeme]); | 975 [_currentToken.lexeme]); |
| 4570 functionName = _createSyntheticIdentifier(); | 976 functionName = createSyntheticIdentifier(); |
| 4571 } | 977 } |
| 4572 assert((expression == null && functionName != null) || | 978 assert((expression == null && functionName != null) || |
| 4573 (expression != null && functionName == null)); | 979 (expression != null && functionName == null)); |
| 4574 if (_isLikelyParameterList()) { | 980 if (_isLikelyArgumentList()) { |
| 4575 while (_isLikelyParameterList()) { | 981 do { |
| 4576 TypeArgumentList typeArguments = null; | 982 TypeArgumentList typeArguments = _parseOptionalTypeArguments(); |
| 4577 if (_matches(TokenType.LT)) { | |
| 4578 typeArguments = parseTypeArgumentList(); | |
| 4579 } | |
| 4580 if (functionName != null) { | 983 if (functionName != null) { |
| 4581 expression = new MethodInvocation(expression, period, functionName, | 984 expression = new MethodInvocation(expression, period, functionName, |
| 4582 typeArguments, parseArgumentList()); | 985 typeArguments, parseArgumentList()); |
| 4583 period = null; | 986 period = null; |
| 4584 functionName = null; | 987 functionName = null; |
| 4585 } else if (expression == null) { | 988 } else if (expression == null) { |
| 4586 // It should not be possible to get here. | 989 // It should not be possible to get here. |
| 4587 expression = new MethodInvocation(expression, period, | 990 expression = new MethodInvocation(expression, period, |
| 4588 _createSyntheticIdentifier(), typeArguments, parseArgumentList()); | 991 createSyntheticIdentifier(), typeArguments, parseArgumentList()); |
| 4589 } else { | 992 } else { |
| 4590 expression = new FunctionExpressionInvocation( | 993 expression = new FunctionExpressionInvocation( |
| 4591 expression, typeArguments, parseArgumentList()); | 994 expression, typeArguments, parseArgumentList()); |
| 4592 } | 995 } |
| 4593 } | 996 } while (_isLikelyArgumentList()); |
| 4594 } else if (functionName != null) { | 997 } else if (functionName != null) { |
| 4595 expression = new PropertyAccess(expression, period, functionName); | 998 expression = new PropertyAccess(expression, period, functionName); |
| 4596 period = null; | 999 period = null; |
| 4597 } | 1000 } |
| 4598 assert(expression != null); | 1001 assert(expression != null); |
| 4599 bool progress = true; | 1002 bool progress = true; |
| 4600 while (progress) { | 1003 while (progress) { |
| 4601 progress = false; | 1004 progress = false; |
| 4602 Expression selector = _parseAssignableSelector(expression, true); | 1005 Expression selector = parseAssignableSelector(expression, true); |
| 4603 if (!identical(selector, expression)) { | 1006 if (!identical(selector, expression)) { |
| 4604 expression = selector; | 1007 expression = selector; |
| 4605 progress = true; | 1008 progress = true; |
| 4606 while (_isLikelyParameterList()) { | 1009 while (_isLikelyArgumentList()) { |
| 4607 TypeArgumentList typeArguments = null; | 1010 TypeArgumentList typeArguments = _parseOptionalTypeArguments(); |
| 4608 if (_matches(TokenType.LT)) { | 1011 Expression currentExpression = expression; |
| 4609 typeArguments = parseTypeArgumentList(); | 1012 if (currentExpression is PropertyAccess) { |
| 4610 } | |
| 4611 if (expression is PropertyAccess) { | |
| 4612 PropertyAccess propertyAccess = expression as PropertyAccess; | |
| 4613 expression = new MethodInvocation( | 1013 expression = new MethodInvocation( |
| 4614 propertyAccess.target, | 1014 currentExpression.target, |
| 4615 propertyAccess.operator, | 1015 currentExpression.operator, |
| 4616 propertyAccess.propertyName, | 1016 currentExpression.propertyName, |
| 4617 typeArguments, | 1017 typeArguments, |
| 4618 parseArgumentList()); | 1018 parseArgumentList()); |
| 4619 } else { | 1019 } else { |
| 4620 expression = new FunctionExpressionInvocation( | 1020 expression = new FunctionExpressionInvocation( |
| 4621 expression, typeArguments, parseArgumentList()); | 1021 expression, typeArguments, parseArgumentList()); |
| 4622 } | 1022 } |
| 4623 } | 1023 } |
| 4624 } | 1024 } |
| 4625 } | 1025 } |
| 4626 if (_currentToken.type.isAssignmentOperator) { | 1026 if (_currentToken.type.isAssignmentOperator) { |
| 4627 Token operator = getAndAdvance(); | 1027 Token operator = getAndAdvance(); |
| 4628 _ensureAssignable(expression); | 1028 _ensureAssignable(expression); |
| 4629 expression = new AssignmentExpression( | 1029 expression = new AssignmentExpression( |
| 4630 expression, operator, parseExpressionWithoutCascade()); | 1030 expression, operator, parseExpressionWithoutCascade()); |
| 4631 } | 1031 } |
| 4632 return expression; | 1032 return expression; |
| 4633 } | 1033 } |
| 4634 | 1034 |
| 4635 /** | 1035 /** |
| 4636 * Parse a class declaration. The [commentAndMetadata] is the metadata to be | 1036 * Parse a class declaration. The [commentAndMetadata] is the metadata to be |
| 4637 * associated with the member. The [abstractKeyword] is the token for the | 1037 * associated with the member. The [abstractKeyword] is the token for the |
| 4638 * keyword 'abstract', or `null` if the keyword was not given. Return the | 1038 * keyword 'abstract', or `null` if the keyword was not given. Return the |
| 4639 * class declaration that was parsed. | 1039 * class declaration that was parsed. |
| 4640 * | 1040 * |
| 1041 * This method assumes that the current token matches `Keyword.CLASS`. |
| 1042 * |
| 4641 * classDeclaration ::= | 1043 * classDeclaration ::= |
| 4642 * metadata 'abstract'? 'class' name typeParameterList? (extendsClause
withClause?)? implementsClause? '{' classMembers '}' | | 1044 * metadata 'abstract'? 'class' name typeParameterList? (extendsClause
withClause?)? implementsClause? '{' classMembers '}' | |
| 4643 * metadata 'abstract'? 'class' mixinApplicationClass | 1045 * metadata 'abstract'? 'class' mixinApplicationClass |
| 4644 */ | 1046 */ |
| 4645 CompilationUnitMember _parseClassDeclaration( | 1047 CompilationUnitMember parseClassDeclaration( |
| 4646 CommentAndMetadata commentAndMetadata, Token abstractKeyword) { | 1048 CommentAndMetadata commentAndMetadata, Token abstractKeyword) { |
| 4647 Token keyword = _expectKeyword(Keyword.CLASS); | 1049 // |
| 4648 if (_matchesIdentifier()) { | 1050 // Parse the name and type parameters. |
| 4649 Token next = _peek(); | 1051 // |
| 4650 if (_tokenMatches(next, TokenType.LT)) { | 1052 Token keyword = getAndAdvance(); |
| 4651 next = _skipTypeParameterList(next); | 1053 SimpleIdentifier name = parseSimpleIdentifier(isDeclaration: true); |
| 4652 if (next != null && _tokenMatches(next, TokenType.EQ)) { | |
| 4653 return _parseClassTypeAlias( | |
| 4654 commentAndMetadata, abstractKeyword, keyword); | |
| 4655 } | |
| 4656 } else if (_tokenMatches(next, TokenType.EQ)) { | |
| 4657 return _parseClassTypeAlias( | |
| 4658 commentAndMetadata, abstractKeyword, keyword); | |
| 4659 } | |
| 4660 } | |
| 4661 SimpleIdentifier name = parseSimpleIdentifier(); | |
| 4662 String className = name.name; | 1054 String className = name.name; |
| 4663 TypeParameterList typeParameters = null; | 1055 TypeParameterList typeParameters = null; |
| 4664 if (_matches(TokenType.LT)) { | 1056 TokenType type = _currentToken.type; |
| 1057 if (type == TokenType.LT) { |
| 4665 typeParameters = parseTypeParameterList(); | 1058 typeParameters = parseTypeParameterList(); |
| 1059 type = _currentToken.type; |
| 1060 } |
| 1061 // |
| 1062 // Check to see whether this might be a class type alias rather than a class |
| 1063 // declaration. |
| 1064 // |
| 1065 if (type == TokenType.EQ) { |
| 1066 return _parseClassTypeAliasAfterName( |
| 1067 commentAndMetadata, abstractKeyword, keyword, name, typeParameters); |
| 4666 } | 1068 } |
| 4667 // | 1069 // |
| 4668 // Parse the clauses. The parser accepts clauses in any order, but will | 1070 // Parse the clauses. The parser accepts clauses in any order, but will |
| 4669 // generate errors if they are not in the order required by the | 1071 // generate errors if they are not in the order required by the |
| 4670 // specification. | 1072 // specification. |
| 4671 // | 1073 // |
| 4672 ExtendsClause extendsClause = null; | 1074 ExtendsClause extendsClause = null; |
| 4673 WithClause withClause = null; | 1075 WithClause withClause = null; |
| 4674 ImplementsClause implementsClause = null; | 1076 ImplementsClause implementsClause = null; |
| 4675 bool foundClause = true; | 1077 bool foundClause = true; |
| 4676 while (foundClause) { | 1078 while (foundClause) { |
| 4677 if (_matchesKeyword(Keyword.EXTENDS)) { | 1079 Keyword keyword = _currentToken.keyword; |
| 1080 if (keyword == Keyword.EXTENDS) { |
| 4678 if (extendsClause == null) { | 1081 if (extendsClause == null) { |
| 4679 extendsClause = parseExtendsClause(); | 1082 extendsClause = parseExtendsClause(); |
| 4680 if (withClause != null) { | 1083 if (withClause != null) { |
| 4681 _reportErrorForToken( | 1084 _reportErrorForToken( |
| 4682 ParserErrorCode.WITH_BEFORE_EXTENDS, withClause.withKeyword); | 1085 ParserErrorCode.WITH_BEFORE_EXTENDS, withClause.withKeyword); |
| 4683 } else if (implementsClause != null) { | 1086 } else if (implementsClause != null) { |
| 4684 _reportErrorForToken(ParserErrorCode.IMPLEMENTS_BEFORE_EXTENDS, | 1087 _reportErrorForToken(ParserErrorCode.IMPLEMENTS_BEFORE_EXTENDS, |
| 4685 implementsClause.implementsKeyword); | 1088 implementsClause.implementsKeyword); |
| 4686 } | 1089 } |
| 4687 } else { | 1090 } else { |
| 4688 _reportErrorForToken(ParserErrorCode.MULTIPLE_EXTENDS_CLAUSES, | 1091 _reportErrorForToken(ParserErrorCode.MULTIPLE_EXTENDS_CLAUSES, |
| 4689 extendsClause.extendsKeyword); | 1092 extendsClause.extendsKeyword); |
| 4690 parseExtendsClause(); | 1093 parseExtendsClause(); |
| 4691 } | 1094 } |
| 4692 } else if (_matchesKeyword(Keyword.WITH)) { | 1095 } else if (keyword == Keyword.WITH) { |
| 4693 if (withClause == null) { | 1096 if (withClause == null) { |
| 4694 withClause = parseWithClause(); | 1097 withClause = parseWithClause(); |
| 4695 if (implementsClause != null) { | 1098 if (implementsClause != null) { |
| 4696 _reportErrorForToken(ParserErrorCode.IMPLEMENTS_BEFORE_WITH, | 1099 _reportErrorForToken(ParserErrorCode.IMPLEMENTS_BEFORE_WITH, |
| 4697 implementsClause.implementsKeyword); | 1100 implementsClause.implementsKeyword); |
| 4698 } | 1101 } |
| 4699 } else { | 1102 } else { |
| 4700 _reportErrorForToken( | 1103 _reportErrorForToken( |
| 4701 ParserErrorCode.MULTIPLE_WITH_CLAUSES, withClause.withKeyword); | 1104 ParserErrorCode.MULTIPLE_WITH_CLAUSES, withClause.withKeyword); |
| 4702 parseWithClause(); | 1105 parseWithClause(); |
| 4703 // TODO(brianwilkerson) Should we merge the list of applied mixins | 1106 // TODO(brianwilkerson) Should we merge the list of applied mixins |
| 4704 // into a single list? | 1107 // into a single list? |
| 4705 } | 1108 } |
| 4706 } else if (_matchesKeyword(Keyword.IMPLEMENTS)) { | 1109 } else if (keyword == Keyword.IMPLEMENTS) { |
| 4707 if (implementsClause == null) { | 1110 if (implementsClause == null) { |
| 4708 implementsClause = parseImplementsClause(); | 1111 implementsClause = parseImplementsClause(); |
| 4709 } else { | 1112 } else { |
| 4710 _reportErrorForToken(ParserErrorCode.MULTIPLE_IMPLEMENTS_CLAUSES, | 1113 _reportErrorForToken(ParserErrorCode.MULTIPLE_IMPLEMENTS_CLAUSES, |
| 4711 implementsClause.implementsKeyword); | 1114 implementsClause.implementsKeyword); |
| 4712 parseImplementsClause(); | 1115 parseImplementsClause(); |
| 4713 // TODO(brianwilkerson) Should we merge the list of implemented | 1116 // TODO(brianwilkerson) Should we merge the list of implemented |
| 4714 // classes into a single list? | 1117 // classes into a single list? |
| 4715 } | 1118 } |
| 4716 } else { | 1119 } else { |
| (...skipping 11 matching lines...) Expand all Loading... |
| 4728 if (_matchesString(_NATIVE) && _tokenMatches(_peek(), TokenType.STRING)) { | 1131 if (_matchesString(_NATIVE) && _tokenMatches(_peek(), TokenType.STRING)) { |
| 4729 nativeClause = _parseNativeClause(); | 1132 nativeClause = _parseNativeClause(); |
| 4730 } | 1133 } |
| 4731 // | 1134 // |
| 4732 // Parse the body of the class. | 1135 // Parse the body of the class. |
| 4733 // | 1136 // |
| 4734 Token leftBracket = null; | 1137 Token leftBracket = null; |
| 4735 List<ClassMember> members = null; | 1138 List<ClassMember> members = null; |
| 4736 Token rightBracket = null; | 1139 Token rightBracket = null; |
| 4737 if (_matches(TokenType.OPEN_CURLY_BRACKET)) { | 1140 if (_matches(TokenType.OPEN_CURLY_BRACKET)) { |
| 4738 leftBracket = _expect(TokenType.OPEN_CURLY_BRACKET); | 1141 leftBracket = getAndAdvance(); |
| 4739 members = _parseClassMembers(className, _getEndToken(leftBracket)); | 1142 members = _parseClassMembers(className, _getEndToken(leftBracket)); |
| 4740 rightBracket = _expect(TokenType.CLOSE_CURLY_BRACKET); | 1143 rightBracket = _expect(TokenType.CLOSE_CURLY_BRACKET); |
| 4741 } else { | 1144 } else { |
| 1145 // Recovery: Check for an unmatched closing curly bracket and parse |
| 1146 // members until it is reached. |
| 4742 leftBracket = _createSyntheticToken(TokenType.OPEN_CURLY_BRACKET); | 1147 leftBracket = _createSyntheticToken(TokenType.OPEN_CURLY_BRACKET); |
| 4743 rightBracket = _createSyntheticToken(TokenType.CLOSE_CURLY_BRACKET); | 1148 rightBracket = _createSyntheticToken(TokenType.CLOSE_CURLY_BRACKET); |
| 4744 _reportErrorForCurrentToken(ParserErrorCode.MISSING_CLASS_BODY); | 1149 _reportErrorForCurrentToken(ParserErrorCode.MISSING_CLASS_BODY); |
| 4745 } | 1150 } |
| 4746 ClassDeclaration classDeclaration = new ClassDeclaration( | 1151 ClassDeclaration classDeclaration = new ClassDeclaration( |
| 4747 commentAndMetadata.comment, | 1152 commentAndMetadata.comment, |
| 4748 commentAndMetadata.metadata, | 1153 commentAndMetadata.metadata, |
| 4749 abstractKeyword, | 1154 abstractKeyword, |
| 4750 keyword, | 1155 keyword, |
| 4751 name, | 1156 name, |
| 4752 typeParameters, | 1157 typeParameters, |
| 4753 extendsClause, | 1158 extendsClause, |
| 4754 withClause, | 1159 withClause, |
| 4755 implementsClause, | 1160 implementsClause, |
| 4756 leftBracket, | 1161 leftBracket, |
| 4757 members, | 1162 members, |
| 4758 rightBracket); | 1163 rightBracket); |
| 4759 classDeclaration.nativeClause = nativeClause; | 1164 classDeclaration.nativeClause = nativeClause; |
| 4760 return classDeclaration; | 1165 return classDeclaration; |
| 4761 } | 1166 } |
| 4762 | 1167 |
| 4763 /** | 1168 /** |
| 4764 * Parse a list of class members. The [className] is the name of the class | 1169 * Parse a class member. The [className] is the name of the class containing |
| 4765 * whose members are being parsed. The [closingBracket] is the closing bracket | 1170 * the member being parsed. Return the class member that was parsed, or `null` |
| 4766 * for the class, or `null` if the closing bracket is missing. Return the list | 1171 * if what was found was not a valid class member. |
| 4767 * of class members that were parsed. | 1172 * |
| 4768 * | 1173 * classMemberDefinition ::= |
| 4769 * classMembers ::= | 1174 * declaration ';' |
| 4770 * (metadata memberDefinition)* | 1175 * | methodSignature functionBody |
| 4771 */ | 1176 */ |
| 4772 List<ClassMember> _parseClassMembers(String className, Token closingBracket) { | 1177 ClassMember parseClassMember(String className) { |
| 4773 List<ClassMember> members = new List<ClassMember>(); | 1178 CommentAndMetadata commentAndMetadata = parseCommentAndMetadata(); |
| 4774 Token memberStart = _currentToken; | 1179 Modifiers modifiers = parseModifiers(); |
| 4775 while (!_matches(TokenType.EOF) && | 1180 Keyword keyword = _currentToken.keyword; |
| 4776 !_matches(TokenType.CLOSE_CURLY_BRACKET) && | 1181 if (keyword == Keyword.VOID) { |
| 4777 (closingBracket != null || | 1182 TypeName returnType = |
| 4778 (!_matchesKeyword(Keyword.CLASS) && | 1183 new TypeName(new SimpleIdentifier(getAndAdvance()), null); |
| 4779 !_matchesKeyword(Keyword.TYPEDEF)))) { | 1184 keyword = _currentToken.keyword; |
| 4780 if (_matches(TokenType.SEMICOLON)) { | 1185 Token next = _peek(); |
| 4781 _reportErrorForToken(ParserErrorCode.UNEXPECTED_TOKEN, _currentToken, | 1186 bool isFollowedByIdentifier = _tokenMatchesIdentifier(next); |
| 4782 [_currentToken.lexeme]); | 1187 if (keyword == Keyword.GET && isFollowedByIdentifier) { |
| 4783 _advance(); | 1188 _validateModifiersForGetterOrSetterOrMethod(modifiers); |
| 1189 return parseGetter(commentAndMetadata, modifiers.externalKeyword, |
| 1190 modifiers.staticKeyword, returnType); |
| 1191 } else if (keyword == Keyword.SET && isFollowedByIdentifier) { |
| 1192 _validateModifiersForGetterOrSetterOrMethod(modifiers); |
| 1193 return parseSetter(commentAndMetadata, modifiers.externalKeyword, |
| 1194 modifiers.staticKeyword, returnType); |
| 1195 } else if (keyword == Keyword.OPERATOR && _isOperator(next)) { |
| 1196 _validateModifiersForOperator(modifiers); |
| 1197 return _parseOperatorAfterKeyword(commentAndMetadata, |
| 1198 modifiers.externalKeyword, returnType, getAndAdvance()); |
| 1199 } else if (_matchesIdentifier() && |
| 1200 _peek().matchesAny(const <TokenType>[ |
| 1201 TokenType.OPEN_PAREN, |
| 1202 TokenType.OPEN_CURLY_BRACKET, |
| 1203 TokenType.FUNCTION, |
| 1204 TokenType.LT |
| 1205 ])) { |
| 1206 _validateModifiersForGetterOrSetterOrMethod(modifiers); |
| 1207 return _parseMethodDeclarationAfterReturnType(commentAndMetadata, |
| 1208 modifiers.externalKeyword, modifiers.staticKeyword, returnType); |
| 4784 } else { | 1209 } else { |
| 4785 ClassMember member = parseClassMember(className); | 1210 // |
| 4786 if (member != null) { | 1211 // We have found an error of some kind. Try to recover. |
| 4787 members.add(member); | 1212 // |
| 1213 if (_matchesIdentifier()) { |
| 1214 if (_peek().matchesAny(const <TokenType>[ |
| 1215 TokenType.EQ, |
| 1216 TokenType.COMMA, |
| 1217 TokenType.SEMICOLON |
| 1218 ])) { |
| 1219 // |
| 1220 // We appear to have a variable declaration with a type of "void". |
| 1221 // |
| 1222 _reportErrorForNode(ParserErrorCode.VOID_VARIABLE, returnType); |
| 1223 return parseInitializedIdentifierList( |
| 1224 commentAndMetadata, |
| 1225 modifiers.staticKeyword, |
| 1226 _validateModifiersForField(modifiers), |
| 1227 returnType); |
| 1228 } |
| 4788 } | 1229 } |
| 4789 } | 1230 if (_isOperator(_currentToken)) { |
| 4790 if (identical(_currentToken, memberStart)) { | 1231 // |
| 4791 _reportErrorForToken(ParserErrorCode.UNEXPECTED_TOKEN, _currentToken, | 1232 // We appear to have found an operator declaration without the |
| 4792 [_currentToken.lexeme]); | 1233 // 'operator' keyword. |
| 4793 _advance(); | 1234 // |
| 4794 } | 1235 _validateModifiersForOperator(modifiers); |
| 4795 memberStart = _currentToken; | 1236 return parseOperator( |
| 4796 } | 1237 commentAndMetadata, modifiers.externalKeyword, returnType); |
| 4797 return members; | 1238 } |
| 4798 } | 1239 _reportErrorForToken( |
| 4799 | 1240 ParserErrorCode.EXPECTED_EXECUTABLE, _currentToken); |
| 4800 /** | 1241 return null; |
| 1242 } |
| 1243 } |
| 1244 Token next = _peek(); |
| 1245 bool isFollowedByIdentifier = _tokenMatchesIdentifier(next); |
| 1246 if (keyword == Keyword.GET && isFollowedByIdentifier) { |
| 1247 _validateModifiersForGetterOrSetterOrMethod(modifiers); |
| 1248 return parseGetter(commentAndMetadata, modifiers.externalKeyword, |
| 1249 modifiers.staticKeyword, null); |
| 1250 } else if (keyword == Keyword.SET && isFollowedByIdentifier) { |
| 1251 _validateModifiersForGetterOrSetterOrMethod(modifiers); |
| 1252 return parseSetter(commentAndMetadata, modifiers.externalKeyword, |
| 1253 modifiers.staticKeyword, null); |
| 1254 } else if (keyword == Keyword.OPERATOR && _isOperator(next)) { |
| 1255 _validateModifiersForOperator(modifiers); |
| 1256 return _parseOperatorAfterKeyword( |
| 1257 commentAndMetadata, modifiers.externalKeyword, null, getAndAdvance()); |
| 1258 } else if (!_matchesIdentifier()) { |
| 1259 // |
| 1260 // Recover from an error. |
| 1261 // |
| 1262 if (_matchesKeyword(Keyword.CLASS)) { |
| 1263 _reportErrorForCurrentToken(ParserErrorCode.CLASS_IN_CLASS); |
| 1264 // TODO(brianwilkerson) We don't currently have any way to capture the |
| 1265 // class that was parsed. |
| 1266 parseClassDeclaration(commentAndMetadata, null); |
| 1267 return null; |
| 1268 } else if (_matchesKeyword(Keyword.ABSTRACT) && |
| 1269 _tokenMatchesKeyword(_peek(), Keyword.CLASS)) { |
| 1270 _reportErrorForToken(ParserErrorCode.CLASS_IN_CLASS, _peek()); |
| 1271 // TODO(brianwilkerson) We don't currently have any way to capture the |
| 1272 // class that was parsed. |
| 1273 parseClassDeclaration(commentAndMetadata, getAndAdvance()); |
| 1274 return null; |
| 1275 } else if (_matchesKeyword(Keyword.ENUM)) { |
| 1276 _reportErrorForToken(ParserErrorCode.ENUM_IN_CLASS, _peek()); |
| 1277 // TODO(brianwilkerson) We don't currently have any way to capture the |
| 1278 // enum that was parsed. |
| 1279 parseEnumDeclaration(commentAndMetadata); |
| 1280 return null; |
| 1281 } else if (_isOperator(_currentToken)) { |
| 1282 // |
| 1283 // We appear to have found an operator declaration without the |
| 1284 // 'operator' keyword. |
| 1285 // |
| 1286 _validateModifiersForOperator(modifiers); |
| 1287 return parseOperator( |
| 1288 commentAndMetadata, modifiers.externalKeyword, null); |
| 1289 } |
| 1290 Token keyword = modifiers.varKeyword; |
| 1291 if (keyword == null) { |
| 1292 keyword = modifiers.finalKeyword; |
| 1293 } |
| 1294 if (keyword == null) { |
| 1295 keyword = modifiers.constKeyword; |
| 1296 } |
| 1297 if (keyword != null) { |
| 1298 // |
| 1299 // We appear to have found an incomplete field declaration. |
| 1300 // |
| 1301 _reportErrorForCurrentToken(ParserErrorCode.MISSING_IDENTIFIER); |
| 1302 VariableDeclaration variable = |
| 1303 new VariableDeclaration(createSyntheticIdentifier(), null, null); |
| 1304 List<VariableDeclaration> variables = <VariableDeclaration>[variable]; |
| 1305 return new FieldDeclaration( |
| 1306 commentAndMetadata.comment, |
| 1307 commentAndMetadata.metadata, |
| 1308 null, |
| 1309 new VariableDeclarationList(null, null, keyword, null, variables), |
| 1310 _expect(TokenType.SEMICOLON)); |
| 1311 } |
| 1312 _reportErrorForToken( |
| 1313 ParserErrorCode.EXPECTED_CLASS_MEMBER, _currentToken); |
| 1314 if (commentAndMetadata.comment != null || |
| 1315 commentAndMetadata.hasMetadata) { |
| 1316 // |
| 1317 // We appear to have found an incomplete declaration at the end of the |
| 1318 // class. At this point it consists of a metadata, which we don't want |
| 1319 // to loose, so we'll treat it as a method declaration with a missing |
| 1320 // name, parameters and empty body. |
| 1321 // |
| 1322 return new MethodDeclaration( |
| 1323 commentAndMetadata.comment, |
| 1324 commentAndMetadata.metadata, |
| 1325 null, |
| 1326 null, |
| 1327 null, |
| 1328 null, |
| 1329 null, |
| 1330 createSyntheticIdentifier(isDeclaration: true), |
| 1331 null, |
| 1332 new FormalParameterList( |
| 1333 null, <FormalParameter>[], null, null, null), |
| 1334 new EmptyFunctionBody(_createSyntheticToken(TokenType.SEMICOLON))); |
| 1335 } |
| 1336 return null; |
| 1337 } else if (_tokenMatches(next, TokenType.PERIOD) && |
| 1338 _tokenMatchesIdentifier(_peekAt(2)) && |
| 1339 _tokenMatches(_peekAt(3), TokenType.OPEN_PAREN)) { |
| 1340 return _parseConstructor( |
| 1341 commentAndMetadata, |
| 1342 modifiers.externalKeyword, |
| 1343 _validateModifiersForConstructor(modifiers), |
| 1344 modifiers.factoryKeyword, |
| 1345 parseSimpleIdentifier(), |
| 1346 getAndAdvance(), |
| 1347 parseSimpleIdentifier(isDeclaration: true), |
| 1348 parseFormalParameterList()); |
| 1349 } else if (_tokenMatches(next, TokenType.OPEN_PAREN)) { |
| 1350 TypeName returnType = _parseOptionalTypeNameComment(); |
| 1351 SimpleIdentifier methodName = parseSimpleIdentifier(isDeclaration: true); |
| 1352 TypeParameterList typeParameters = _parseGenericCommentTypeParameters(); |
| 1353 FormalParameterList parameters = parseFormalParameterList(); |
| 1354 if (_matches(TokenType.COLON) || |
| 1355 modifiers.factoryKeyword != null || |
| 1356 methodName.name == className) { |
| 1357 return _parseConstructor( |
| 1358 commentAndMetadata, |
| 1359 modifiers.externalKeyword, |
| 1360 _validateModifiersForConstructor(modifiers), |
| 1361 modifiers.factoryKeyword, |
| 1362 new SimpleIdentifier(methodName.token, isDeclaration: false), |
| 1363 null, |
| 1364 null, |
| 1365 parameters); |
| 1366 } |
| 1367 _validateModifiersForGetterOrSetterOrMethod(modifiers); |
| 1368 _validateFormalParameterList(parameters); |
| 1369 return _parseMethodDeclarationAfterParameters( |
| 1370 commentAndMetadata, |
| 1371 modifiers.externalKeyword, |
| 1372 modifiers.staticKeyword, |
| 1373 returnType, |
| 1374 methodName, |
| 1375 typeParameters, |
| 1376 parameters); |
| 1377 } else if (next.matchesAny(const <TokenType>[ |
| 1378 TokenType.EQ, |
| 1379 TokenType.COMMA, |
| 1380 TokenType.SEMICOLON |
| 1381 ])) { |
| 1382 if (modifiers.constKeyword == null && |
| 1383 modifiers.finalKeyword == null && |
| 1384 modifiers.varKeyword == null) { |
| 1385 _reportErrorForCurrentToken( |
| 1386 ParserErrorCode.MISSING_CONST_FINAL_VAR_OR_TYPE); |
| 1387 } |
| 1388 return parseInitializedIdentifierList(commentAndMetadata, |
| 1389 modifiers.staticKeyword, _validateModifiersForField(modifiers), null); |
| 1390 } else if (keyword == Keyword.TYPEDEF) { |
| 1391 _reportErrorForCurrentToken(ParserErrorCode.TYPEDEF_IN_CLASS); |
| 1392 // TODO(brianwilkerson) We don't currently have any way to capture the |
| 1393 // function type alias that was parsed. |
| 1394 _parseFunctionTypeAlias(commentAndMetadata, getAndAdvance()); |
| 1395 return null; |
| 1396 } else if (parseGenericMethods) { |
| 1397 Token token = _skipTypeParameterList(_peek()); |
| 1398 if (token != null && _tokenMatches(token, TokenType.OPEN_PAREN)) { |
| 1399 return _parseMethodDeclarationAfterReturnType(commentAndMetadata, |
| 1400 modifiers.externalKeyword, modifiers.staticKeyword, null); |
| 1401 } |
| 1402 } |
| 1403 TypeName type = _parseTypeNameAfterIdentifier(); |
| 1404 keyword = _currentToken.keyword; |
| 1405 next = _peek(); |
| 1406 isFollowedByIdentifier = _tokenMatchesIdentifier(next); |
| 1407 if (keyword == Keyword.GET && isFollowedByIdentifier) { |
| 1408 _validateModifiersForGetterOrSetterOrMethod(modifiers); |
| 1409 return parseGetter(commentAndMetadata, modifiers.externalKeyword, |
| 1410 modifiers.staticKeyword, type); |
| 1411 } else if (keyword == Keyword.SET && isFollowedByIdentifier) { |
| 1412 _validateModifiersForGetterOrSetterOrMethod(modifiers); |
| 1413 return parseSetter(commentAndMetadata, modifiers.externalKeyword, |
| 1414 modifiers.staticKeyword, type); |
| 1415 } else if (keyword == Keyword.OPERATOR && _isOperator(next)) { |
| 1416 _validateModifiersForOperator(modifiers); |
| 1417 return _parseOperatorAfterKeyword( |
| 1418 commentAndMetadata, modifiers.externalKeyword, type, getAndAdvance()); |
| 1419 } else if (!_matchesIdentifier()) { |
| 1420 if (_matches(TokenType.CLOSE_CURLY_BRACKET)) { |
| 1421 // |
| 1422 // We appear to have found an incomplete declaration at the end of the |
| 1423 // class. At this point it consists of a type name, so we'll treat it as |
| 1424 // a field declaration with a missing field name and semicolon. |
| 1425 // |
| 1426 return parseInitializedIdentifierList( |
| 1427 commentAndMetadata, |
| 1428 modifiers.staticKeyword, |
| 1429 _validateModifiersForField(modifiers), |
| 1430 type); |
| 1431 } |
| 1432 if (_isOperator(_currentToken)) { |
| 1433 // |
| 1434 // We appear to have found an operator declaration without the |
| 1435 // 'operator' keyword. |
| 1436 // |
| 1437 _validateModifiersForOperator(modifiers); |
| 1438 return parseOperator( |
| 1439 commentAndMetadata, modifiers.externalKeyword, type); |
| 1440 } |
| 1441 // |
| 1442 // We appear to have found an incomplete declaration before another |
| 1443 // declaration. At this point it consists of a type name, so we'll treat |
| 1444 // it as a field declaration with a missing field name and semicolon. |
| 1445 // |
| 1446 _reportErrorForToken( |
| 1447 ParserErrorCode.EXPECTED_CLASS_MEMBER, _currentToken); |
| 1448 try { |
| 1449 _lockErrorListener(); |
| 1450 return parseInitializedIdentifierList( |
| 1451 commentAndMetadata, |
| 1452 modifiers.staticKeyword, |
| 1453 _validateModifiersForField(modifiers), |
| 1454 type); |
| 1455 } finally { |
| 1456 _unlockErrorListener(); |
| 1457 } |
| 1458 } else if (_tokenMatches(next, TokenType.OPEN_PAREN)) { |
| 1459 SimpleIdentifier methodName = |
| 1460 _parseSimpleIdentifierUnchecked(isDeclaration: true); |
| 1461 TypeParameterList typeParameters = _parseGenericCommentTypeParameters(); |
| 1462 FormalParameterList parameters = parseFormalParameterList(); |
| 1463 if (methodName.name == className) { |
| 1464 _reportErrorForNode(ParserErrorCode.CONSTRUCTOR_WITH_RETURN_TYPE, type); |
| 1465 return _parseConstructor( |
| 1466 commentAndMetadata, |
| 1467 modifiers.externalKeyword, |
| 1468 _validateModifiersForConstructor(modifiers), |
| 1469 modifiers.factoryKeyword, |
| 1470 new SimpleIdentifier(methodName.token, isDeclaration: true), |
| 1471 null, |
| 1472 null, |
| 1473 parameters); |
| 1474 } |
| 1475 _validateModifiersForGetterOrSetterOrMethod(modifiers); |
| 1476 _validateFormalParameterList(parameters); |
| 1477 return _parseMethodDeclarationAfterParameters( |
| 1478 commentAndMetadata, |
| 1479 modifiers.externalKeyword, |
| 1480 modifiers.staticKeyword, |
| 1481 type, |
| 1482 methodName, |
| 1483 typeParameters, |
| 1484 parameters); |
| 1485 } else if (parseGenericMethods && _tokenMatches(next, TokenType.LT)) { |
| 1486 return _parseMethodDeclarationAfterReturnType(commentAndMetadata, |
| 1487 modifiers.externalKeyword, modifiers.staticKeyword, type); |
| 1488 } else if (_tokenMatches(next, TokenType.OPEN_CURLY_BRACKET)) { |
| 1489 // We have found "TypeName identifier {", and are guessing that this is a |
| 1490 // getter without the keyword 'get'. |
| 1491 _validateModifiersForGetterOrSetterOrMethod(modifiers); |
| 1492 _reportErrorForCurrentToken(ParserErrorCode.MISSING_GET); |
| 1493 _currentToken = _injectToken( |
| 1494 new Parser_SyntheticKeywordToken(Keyword.GET, _currentToken.offset)); |
| 1495 return parseGetter(commentAndMetadata, modifiers.externalKeyword, |
| 1496 modifiers.staticKeyword, type); |
| 1497 } |
| 1498 return parseInitializedIdentifierList(commentAndMetadata, |
| 1499 modifiers.staticKeyword, _validateModifiersForField(modifiers), type); |
| 1500 } |
| 1501 |
| 1502 /** |
| 4801 * Parse a class type alias. The [commentAndMetadata] is the metadata to be | 1503 * Parse a class type alias. The [commentAndMetadata] is the metadata to be |
| 4802 * associated with the member. The [abstractKeyword] is the token representing | 1504 * associated with the member. The [abstractKeyword] is the token representing |
| 4803 * the 'abstract' keyword. The [classKeyword] is the token representing the | 1505 * the 'abstract' keyword. The [classKeyword] is the token representing the |
| 4804 * 'class' keyword. Return the class type alias that was parsed. | 1506 * 'class' keyword. Return the class type alias that was parsed. |
| 4805 * | 1507 * |
| 1508 * This method assumes that the current token matches an identifier. |
| 1509 * |
| 4806 * classTypeAlias ::= | 1510 * classTypeAlias ::= |
| 4807 * identifier typeParameters? '=' 'abstract'? mixinApplication | 1511 * identifier typeParameters? '=' 'abstract'? mixinApplication |
| 4808 * | 1512 * |
| 4809 * mixinApplication ::= | 1513 * mixinApplication ::= |
| 4810 * type withClause implementsClause? ';' | 1514 * type withClause implementsClause? ';' |
| 4811 */ | 1515 */ |
| 4812 ClassTypeAlias _parseClassTypeAlias(CommentAndMetadata commentAndMetadata, | 1516 ClassTypeAlias parseClassTypeAlias(CommentAndMetadata commentAndMetadata, |
| 4813 Token abstractKeyword, Token classKeyword) { | 1517 Token abstractKeyword, Token classKeyword) { |
| 4814 SimpleIdentifier className = parseSimpleIdentifier(); | 1518 SimpleIdentifier className = |
| 1519 _parseSimpleIdentifierUnchecked(isDeclaration: true); |
| 4815 TypeParameterList typeParameters = null; | 1520 TypeParameterList typeParameters = null; |
| 4816 if (_matches(TokenType.LT)) { | 1521 if (_matches(TokenType.LT)) { |
| 4817 typeParameters = parseTypeParameterList(); | 1522 typeParameters = parseTypeParameterList(); |
| 4818 } | 1523 } |
| 4819 Token equals = _expect(TokenType.EQ); | 1524 return _parseClassTypeAliasAfterName(commentAndMetadata, abstractKeyword, |
| 4820 TypeName superclass = parseTypeName(); | 1525 classKeyword, className, typeParameters); |
| 4821 WithClause withClause = null; | |
| 4822 if (_matchesKeyword(Keyword.WITH)) { | |
| 4823 withClause = parseWithClause(); | |
| 4824 } else { | |
| 4825 _reportErrorForCurrentToken( | |
| 4826 ParserErrorCode.EXPECTED_TOKEN, [Keyword.WITH.syntax]); | |
| 4827 } | |
| 4828 ImplementsClause implementsClause = null; | |
| 4829 if (_matchesKeyword(Keyword.IMPLEMENTS)) { | |
| 4830 implementsClause = parseImplementsClause(); | |
| 4831 } | |
| 4832 Token semicolon; | |
| 4833 if (_matches(TokenType.SEMICOLON)) { | |
| 4834 semicolon = getAndAdvance(); | |
| 4835 } else { | |
| 4836 if (_matches(TokenType.OPEN_CURLY_BRACKET)) { | |
| 4837 _reportErrorForCurrentToken( | |
| 4838 ParserErrorCode.EXPECTED_TOKEN, [TokenType.SEMICOLON.lexeme]); | |
| 4839 Token leftBracket = getAndAdvance(); | |
| 4840 _parseClassMembers(className.name, _getEndToken(leftBracket)); | |
| 4841 _expect(TokenType.CLOSE_CURLY_BRACKET); | |
| 4842 } else { | |
| 4843 _reportErrorForToken(ParserErrorCode.EXPECTED_TOKEN, | |
| 4844 _currentToken.previous, [TokenType.SEMICOLON.lexeme]); | |
| 4845 } | |
| 4846 semicolon = _createSyntheticToken(TokenType.SEMICOLON); | |
| 4847 } | |
| 4848 return new ClassTypeAlias( | |
| 4849 commentAndMetadata.comment, | |
| 4850 commentAndMetadata.metadata, | |
| 4851 classKeyword, | |
| 4852 className, | |
| 4853 typeParameters, | |
| 4854 equals, | |
| 4855 abstractKeyword, | |
| 4856 superclass, | |
| 4857 withClause, | |
| 4858 implementsClause, | |
| 4859 semicolon); | |
| 4860 } | 1526 } |
| 4861 | 1527 |
| 4862 /** | 1528 /** |
| 4863 * Parse a list of combinators in a directive. Return the combinators that | 1529 * Parse a single combinator. Return the combinator that was parsed, or `null` |
| 4864 * were parsed. | 1530 * if no combinator is found. |
| 4865 * | 1531 * |
| 4866 * combinator ::= | 1532 * combinator ::= |
| 4867 * 'show' identifier (',' identifier)* | 1533 * 'show' identifier (',' identifier)* |
| 4868 * | 'hide' identifier (',' identifier)* | 1534 * | 'hide' identifier (',' identifier)* |
| 4869 */ | 1535 */ |
| 4870 List<Combinator> _parseCombinators() { | 1536 Combinator parseCombinator() { |
| 4871 List<Combinator> combinators = new List<Combinator>(); | 1537 if (_matchesString(_SHOW)) { |
| 1538 return new ShowCombinator(getAndAdvance(), parseIdentifierList()); |
| 1539 } else if (_matchesString(_HIDE)) { |
| 1540 return new HideCombinator(getAndAdvance(), parseIdentifierList()); |
| 1541 } |
| 1542 return null; |
| 1543 } |
| 1544 |
| 1545 /** |
| 1546 * Parse a list of combinators in a directive. Return the combinators that |
| 1547 * were parsed, or `null` if there are no combinators. |
| 1548 * |
| 1549 * combinator ::= |
| 1550 * 'show' identifier (',' identifier)* |
| 1551 * | 'hide' identifier (',' identifier)* |
| 1552 */ |
| 1553 List<Combinator> parseCombinators() { |
| 1554 List<Combinator> combinators = null; |
| 4872 while (true) { | 1555 while (true) { |
| 4873 Combinator combinator = parseCombinator(); | 1556 Combinator combinator = parseCombinator(); |
| 4874 if (combinator == null) { | 1557 if (combinator == null) { |
| 4875 break; | 1558 break; |
| 4876 } | 1559 } |
| 1560 combinators ??= <Combinator>[]; |
| 4877 combinators.add(combinator); | 1561 combinators.add(combinator); |
| 4878 } | 1562 } |
| 4879 return combinators; | 1563 return combinators; |
| 4880 } | 1564 } |
| 4881 | 1565 |
| 4882 /** | 1566 /** |
| 4883 * Parse the documentation comment and metadata preceding a declaration. This | 1567 * Parse the documentation comment and metadata preceding a declaration. This |
| 4884 * method allows any number of documentation comments to occur before, after | 1568 * method allows any number of documentation comments to occur before, after |
| 4885 * or between the metadata, but only returns the last (right-most) | 1569 * or between the metadata, but only returns the last (right-most) |
| 4886 * documentation comment that is found. Return the documentation comment and | 1570 * documentation comment that is found. Return the documentation comment and |
| 4887 * metadata that were parsed. | 1571 * metadata that were parsed. |
| 4888 * | 1572 * |
| 4889 * metadata ::= | 1573 * metadata ::= |
| 4890 * annotation* | 1574 * annotation* |
| 4891 */ | 1575 */ |
| 4892 CommentAndMetadata _parseCommentAndMetadata() { | 1576 CommentAndMetadata parseCommentAndMetadata() { |
| 4893 Comment comment = _parseDocumentationComment(); | 1577 // TODO(brianwilkerson) Consider making the creation of documentation |
| 4894 List<Annotation> metadata = new List<Annotation>(); | 1578 // comments be lazy. |
| 1579 List<DocumentationCommentToken> tokens = parseDocumentationCommentTokens(); |
| 1580 List<Annotation> metadata = null; |
| 4895 while (_matches(TokenType.AT)) { | 1581 while (_matches(TokenType.AT)) { |
| 1582 metadata ??= <Annotation>[]; |
| 4896 metadata.add(parseAnnotation()); | 1583 metadata.add(parseAnnotation()); |
| 4897 Comment optionalComment = _parseDocumentationComment(); | 1584 List<DocumentationCommentToken> optionalTokens = |
| 4898 if (optionalComment != null) { | 1585 parseDocumentationCommentTokens(); |
| 4899 comment = optionalComment; | 1586 if (optionalTokens != null) { |
| 1587 tokens = optionalTokens; |
| 4900 } | 1588 } |
| 4901 } | 1589 } |
| 4902 return new CommentAndMetadata(comment, metadata); | 1590 return new CommentAndMetadata(parseDocumentationComment(tokens), metadata); |
| 4903 } | 1591 } |
| 4904 | 1592 |
| 4905 /** | 1593 /** |
| 4906 * Parse a comment reference from the source between square brackets. The | 1594 * Parse a comment reference from the source between square brackets. The |
| 4907 * [referenceSource] is the source occurring between the square brackets | 1595 * [referenceSource] is the source occurring between the square brackets |
| 4908 * within a documentation comment. The [sourceOffset] is the offset of the | 1596 * within a documentation comment. The [sourceOffset] is the offset of the |
| 4909 * first character of the reference source. Return the comment reference that | 1597 * first character of the reference source. Return the comment reference that |
| 4910 * was parsed, or `null` if no reference could be found. | 1598 * was parsed, or `null` if no reference could be found. |
| 4911 * | 1599 * |
| 4912 * commentReference ::= | 1600 * commentReference ::= |
| 4913 * 'new'? prefixedIdentifier | 1601 * 'new'? prefixedIdentifier |
| 4914 */ | 1602 */ |
| 4915 CommentReference _parseCommentReference( | 1603 CommentReference parseCommentReference( |
| 4916 String referenceSource, int sourceOffset) { | 1604 String referenceSource, int sourceOffset) { |
| 4917 // TODO(brianwilkerson) The errors are not getting the right offset/length | 1605 // TODO(brianwilkerson) The errors are not getting the right offset/length |
| 4918 // and are being duplicated. | 1606 // and are being duplicated. |
| 4919 if (referenceSource.length == 0) { | |
| 4920 Token syntheticToken = | |
| 4921 new SyntheticStringToken(TokenType.IDENTIFIER, "", sourceOffset); | |
| 4922 return new CommentReference(null, new SimpleIdentifier(syntheticToken)); | |
| 4923 } | |
| 4924 try { | 1607 try { |
| 4925 BooleanErrorListener listener = new BooleanErrorListener(); | 1608 BooleanErrorListener listener = new BooleanErrorListener(); |
| 4926 Scanner scanner = new Scanner( | 1609 Scanner scanner = new Scanner( |
| 4927 null, new SubSequenceReader(referenceSource, sourceOffset), listener); | 1610 null, new SubSequenceReader(referenceSource, sourceOffset), listener); |
| 4928 scanner.setSourceStart(1, 1); | 1611 scanner.setSourceStart(1, 1); |
| 4929 Token firstToken = scanner.tokenize(); | 1612 Token firstToken = scanner.tokenize(); |
| 4930 if (listener.errorReported) { | 1613 if (listener.errorReported) { |
| 4931 return null; | 1614 return null; |
| 4932 } | 1615 } |
| 1616 if (firstToken.type == TokenType.EOF) { |
| 1617 Token syntheticToken = |
| 1618 new SyntheticStringToken(TokenType.IDENTIFIER, "", sourceOffset); |
| 1619 syntheticToken.setNext(firstToken); |
| 1620 return new CommentReference(null, new SimpleIdentifier(syntheticToken)); |
| 1621 } |
| 4933 Token newKeyword = null; | 1622 Token newKeyword = null; |
| 4934 if (_tokenMatchesKeyword(firstToken, Keyword.NEW)) { | 1623 if (_tokenMatchesKeyword(firstToken, Keyword.NEW)) { |
| 4935 newKeyword = firstToken; | 1624 newKeyword = firstToken; |
| 4936 firstToken = firstToken.next; | 1625 firstToken = firstToken.next; |
| 4937 } | 1626 } |
| 4938 if (_tokenMatchesIdentifier(firstToken)) { | 1627 if (firstToken.isUserDefinableOperator) { |
| 1628 if (firstToken.next.type != TokenType.EOF) { |
| 1629 return null; |
| 1630 } |
| 1631 Identifier identifier = new SimpleIdentifier(firstToken); |
| 1632 return new CommentReference(null, identifier); |
| 1633 } else if (_tokenMatchesKeyword(firstToken, Keyword.OPERATOR)) { |
| 1634 Token secondToken = firstToken.next; |
| 1635 if (secondToken.isUserDefinableOperator) { |
| 1636 if (secondToken.next.type != TokenType.EOF) { |
| 1637 return null; |
| 1638 } |
| 1639 Identifier identifier = new SimpleIdentifier(secondToken); |
| 1640 return new CommentReference(null, identifier); |
| 1641 } |
| 1642 return null; |
| 1643 } else if (_tokenMatchesIdentifier(firstToken)) { |
| 4939 Token secondToken = firstToken.next; | 1644 Token secondToken = firstToken.next; |
| 4940 Token thirdToken = secondToken.next; | 1645 Token thirdToken = secondToken.next; |
| 4941 Token nextToken; | 1646 Token nextToken; |
| 4942 Identifier identifier; | 1647 Identifier identifier; |
| 4943 if (_tokenMatches(secondToken, TokenType.PERIOD) && | 1648 if (_tokenMatches(secondToken, TokenType.PERIOD)) { |
| 4944 _tokenMatchesIdentifier(thirdToken)) { | 1649 if (thirdToken.isUserDefinableOperator) { |
| 4945 identifier = new PrefixedIdentifier(new SimpleIdentifier(firstToken), | 1650 identifier = new PrefixedIdentifier( |
| 4946 secondToken, new SimpleIdentifier(thirdToken)); | 1651 new SimpleIdentifier(firstToken), |
| 4947 nextToken = thirdToken.next; | 1652 secondToken, |
| 1653 new SimpleIdentifier(thirdToken)); |
| 1654 nextToken = thirdToken.next; |
| 1655 } else if (_tokenMatchesKeyword(thirdToken, Keyword.OPERATOR)) { |
| 1656 Token fourthToken = thirdToken.next; |
| 1657 if (fourthToken.isUserDefinableOperator) { |
| 1658 identifier = new PrefixedIdentifier( |
| 1659 new SimpleIdentifier(firstToken), |
| 1660 secondToken, |
| 1661 new SimpleIdentifier(fourthToken)); |
| 1662 nextToken = fourthToken.next; |
| 1663 } else { |
| 1664 return null; |
| 1665 } |
| 1666 } else if (_tokenMatchesIdentifier(thirdToken)) { |
| 1667 identifier = new PrefixedIdentifier( |
| 1668 new SimpleIdentifier(firstToken), |
| 1669 secondToken, |
| 1670 new SimpleIdentifier(thirdToken)); |
| 1671 nextToken = thirdToken.next; |
| 1672 } |
| 4948 } else { | 1673 } else { |
| 4949 identifier = new SimpleIdentifier(firstToken); | 1674 identifier = new SimpleIdentifier(firstToken); |
| 4950 nextToken = firstToken.next; | 1675 nextToken = firstToken.next; |
| 4951 } | 1676 } |
| 4952 if (nextToken.type != TokenType.EOF) { | 1677 if (nextToken.type != TokenType.EOF) { |
| 4953 return null; | 1678 return null; |
| 4954 } | 1679 } |
| 4955 return new CommentReference(newKeyword, identifier); | 1680 return new CommentReference(newKeyword, identifier); |
| 4956 } else if (_tokenMatchesKeyword(firstToken, Keyword.THIS) || | 1681 } else { |
| 4957 _tokenMatchesKeyword(firstToken, Keyword.NULL) || | 1682 Keyword keyword = firstToken.keyword; |
| 4958 _tokenMatchesKeyword(firstToken, Keyword.TRUE) || | 1683 if (keyword == Keyword.THIS || |
| 4959 _tokenMatchesKeyword(firstToken, Keyword.FALSE)) { | 1684 keyword == Keyword.NULL || |
| 4960 // TODO(brianwilkerson) If we want to support this we will need to | 1685 keyword == Keyword.TRUE || |
| 4961 // extend the definition of CommentReference to take an expression | 1686 keyword == Keyword.FALSE) { |
| 4962 // rather than an identifier. For now we just ignore it to reduce the | 1687 // TODO(brianwilkerson) If we want to support this we will need to |
| 4963 // number of errors produced, but that's probably not a valid long term | 1688 // extend the definition of CommentReference to take an expression |
| 4964 // approach. | 1689 // rather than an identifier. For now we just ignore it to reduce the |
| 4965 return null; | 1690 // number of errors produced, but that's probably not a valid long ter
m |
| 1691 // approach. |
| 1692 return null; |
| 1693 } |
| 4966 } | 1694 } |
| 4967 } catch (exception) { | 1695 } catch (exception) { |
| 4968 // Ignored because we assume that it wasn't a real comment reference. | 1696 // Ignored because we assume that it wasn't a real comment reference. |
| 4969 } | 1697 } |
| 4970 return null; | 1698 return null; |
| 4971 } | 1699 } |
| 4972 | 1700 |
| 4973 /** | 1701 /** |
| 4974 * Parse all of the comment references occurring in the given array of | 1702 * Parse all of the comment references occurring in the given array of |
| 4975 * documentation comments. The [tokens] are the comment tokens representing | 1703 * documentation comments. The [tokens] are the comment tokens representing |
| 4976 * the documentation comments to be parsed. Return the comment references that | 1704 * the documentation comments to be parsed. Return the comment references that |
| 4977 * were parsed. | 1705 * were parsed. |
| 4978 * | 1706 * |
| 4979 * commentReference ::= | 1707 * commentReference ::= |
| 4980 * '[' 'new'? qualified ']' libraryReference? | 1708 * '[' 'new'? qualified ']' libraryReference? |
| 4981 * | 1709 * |
| 4982 * libraryReference ::= | 1710 * libraryReference ::= |
| 4983 * '(' stringLiteral ')' | 1711 * '(' stringLiteral ')' |
| 4984 */ | 1712 */ |
| 4985 List<CommentReference> _parseCommentReferences( | 1713 List<CommentReference> parseCommentReferences( |
| 4986 List<DocumentationCommentToken> tokens) { | 1714 List<DocumentationCommentToken> tokens) { |
| 4987 List<CommentReference> references = new List<CommentReference>(); | 1715 List<CommentReference> references = <CommentReference>[]; |
| 1716 bool isInGitHubCodeBlock = false; |
| 4988 for (DocumentationCommentToken token in tokens) { | 1717 for (DocumentationCommentToken token in tokens) { |
| 4989 String comment = token.lexeme; | 1718 String comment = token.lexeme; |
| 1719 // Skip GitHub code blocks. |
| 1720 // https://help.github.com/articles/creating-and-highlighting-code-blocks/ |
| 1721 if (tokens.length != 1) { |
| 1722 if (comment.indexOf('```') != -1) { |
| 1723 isInGitHubCodeBlock = !isInGitHubCodeBlock; |
| 1724 } |
| 1725 if (isInGitHubCodeBlock) { |
| 1726 continue; |
| 1727 } |
| 1728 } |
| 1729 // Remove GitHub include code. |
| 1730 comment = _removeGitHubInlineCode(comment); |
| 1731 // Find references. |
| 4990 int length = comment.length; | 1732 int length = comment.length; |
| 4991 List<List<int>> codeBlockRanges = _getCodeBlockRanges(comment); | 1733 List<List<int>> codeBlockRanges = _getCodeBlockRanges(comment); |
| 4992 int leftIndex = comment.indexOf('['); | 1734 int leftIndex = comment.indexOf('['); |
| 4993 while (leftIndex >= 0 && leftIndex + 1 < length) { | 1735 while (leftIndex >= 0 && leftIndex + 1 < length) { |
| 4994 List<int> range = _findRange(codeBlockRanges, leftIndex); | 1736 List<int> range = _findRange(codeBlockRanges, leftIndex); |
| 4995 if (range == null) { | 1737 if (range == null) { |
| 4996 int nameOffset = token.offset + leftIndex + 1; | 1738 int nameOffset = token.offset + leftIndex + 1; |
| 4997 int rightIndex = JavaString.indexOf(comment, ']', leftIndex); | 1739 int rightIndex = comment.indexOf(']', leftIndex); |
| 4998 if (rightIndex >= 0) { | 1740 if (rightIndex >= 0) { |
| 4999 int firstChar = comment.codeUnitAt(leftIndex + 1); | 1741 int firstChar = comment.codeUnitAt(leftIndex + 1); |
| 5000 if (firstChar != 0x27 && firstChar != 0x22) { | 1742 if (firstChar != 0x27 && firstChar != 0x22) { |
| 5001 if (_isLinkText(comment, rightIndex)) { | 1743 if (_isLinkText(comment, rightIndex)) { |
| 5002 // TODO(brianwilkerson) Handle the case where there's a library | 1744 // TODO(brianwilkerson) Handle the case where there's a library |
| 5003 // URI in the link text. | 1745 // URI in the link text. |
| 5004 } else { | 1746 } else { |
| 5005 CommentReference reference = _parseCommentReference( | 1747 CommentReference reference = parseCommentReference( |
| 5006 comment.substring(leftIndex + 1, rightIndex), nameOffset); | 1748 comment.substring(leftIndex + 1, rightIndex), nameOffset); |
| 5007 if (reference != null) { | 1749 if (reference != null) { |
| 5008 references.add(reference); | 1750 references.add(reference); |
| 5009 token.references.add(reference.beginToken); | 1751 token.references.add(reference.beginToken); |
| 5010 } | 1752 } |
| 5011 } | 1753 } |
| 5012 } | 1754 } |
| 5013 } else { | 1755 } else { |
| 5014 // terminating ']' is not typed yet | 1756 // terminating ']' is not typed yet |
| 5015 int charAfterLeft = comment.codeUnitAt(leftIndex + 1); | 1757 int charAfterLeft = comment.codeUnitAt(leftIndex + 1); |
| 1758 Token nameToken; |
| 5016 if (Character.isLetterOrDigit(charAfterLeft)) { | 1759 if (Character.isLetterOrDigit(charAfterLeft)) { |
| 5017 int nameEnd = StringUtilities.indexOfFirstNotLetterDigit( | 1760 int nameEnd = StringUtilities.indexOfFirstNotLetterDigit( |
| 5018 comment, leftIndex + 1); | 1761 comment, leftIndex + 1); |
| 5019 String name = comment.substring(leftIndex + 1, nameEnd); | 1762 String name = comment.substring(leftIndex + 1, nameEnd); |
| 5020 Token nameToken = | 1763 nameToken = |
| 5021 new StringToken(TokenType.IDENTIFIER, name, nameOffset); | 1764 new StringToken(TokenType.IDENTIFIER, name, nameOffset); |
| 5022 references.add( | |
| 5023 new CommentReference(null, new SimpleIdentifier(nameToken))); | |
| 5024 } else { | 1765 } else { |
| 5025 Token nameToken = new SyntheticStringToken( | 1766 nameToken = new SyntheticStringToken( |
| 5026 TokenType.IDENTIFIER, "", nameOffset); | 1767 TokenType.IDENTIFIER, '', nameOffset); |
| 5027 references.add( | |
| 5028 new CommentReference(null, new SimpleIdentifier(nameToken))); | |
| 5029 } | 1768 } |
| 1769 nameToken.setNext(new SimpleToken(TokenType.EOF, nameToken.end)); |
| 1770 references.add( |
| 1771 new CommentReference(null, new SimpleIdentifier(nameToken))); |
| 1772 token.references.add(nameToken); |
| 5030 // next character | 1773 // next character |
| 5031 rightIndex = leftIndex + 1; | 1774 rightIndex = leftIndex + 1; |
| 5032 } | 1775 } |
| 5033 leftIndex = JavaString.indexOf(comment, '[', rightIndex); | 1776 leftIndex = comment.indexOf('[', rightIndex); |
| 5034 } else { | 1777 } else { |
| 5035 leftIndex = JavaString.indexOf(comment, '[', range[1] + 1); | 1778 leftIndex = comment.indexOf('[', range[1]); |
| 5036 } | 1779 } |
| 5037 } | 1780 } |
| 5038 } | 1781 } |
| 5039 return references; | 1782 return references; |
| 5040 } | 1783 } |
| 5041 | 1784 |
| 5042 /** | 1785 /** |
| 1786 * Parse a compilation unit, starting with the given [token]. Return the |
| 1787 * compilation unit that was parsed. |
| 1788 */ |
| 1789 CompilationUnit parseCompilationUnit(Token token) { |
| 1790 _currentToken = token; |
| 1791 return parseCompilationUnit2(); |
| 1792 } |
| 1793 |
| 1794 /** |
| 1795 * Parse a compilation unit. Return the compilation unit that was parsed. |
| 1796 * |
| 1797 * Specified: |
| 1798 * |
| 1799 * compilationUnit ::= |
| 1800 * scriptTag? directive* topLevelDeclaration* |
| 1801 * |
| 1802 * Actual: |
| 1803 * |
| 1804 * compilationUnit ::= |
| 1805 * scriptTag? topLevelElement* |
| 1806 * |
| 1807 * topLevelElement ::= |
| 1808 * directive |
| 1809 * | topLevelDeclaration |
| 1810 */ |
| 1811 CompilationUnit parseCompilationUnit2() { |
| 1812 Token firstToken = _currentToken; |
| 1813 ScriptTag scriptTag = null; |
| 1814 if (_matches(TokenType.SCRIPT_TAG)) { |
| 1815 scriptTag = new ScriptTag(getAndAdvance()); |
| 1816 } |
| 1817 // |
| 1818 // Even though all directives must appear before declarations and must occur |
| 1819 // in a given order, we allow directives and declarations to occur in any |
| 1820 // order so that we can recover better. |
| 1821 // |
| 1822 bool libraryDirectiveFound = false; |
| 1823 bool partOfDirectiveFound = false; |
| 1824 bool partDirectiveFound = false; |
| 1825 bool directiveFoundAfterDeclaration = false; |
| 1826 List<Directive> directives = <Directive>[]; |
| 1827 List<CompilationUnitMember> declarations = <CompilationUnitMember>[]; |
| 1828 Token memberStart = _currentToken; |
| 1829 TokenType type = _currentToken.type; |
| 1830 while (type != TokenType.EOF) { |
| 1831 CommentAndMetadata commentAndMetadata = parseCommentAndMetadata(); |
| 1832 Keyword keyword = _currentToken.keyword; |
| 1833 TokenType nextType = _currentToken.next.type; |
| 1834 if ((keyword == Keyword.IMPORT || |
| 1835 keyword == Keyword.EXPORT || |
| 1836 keyword == Keyword.LIBRARY || |
| 1837 keyword == Keyword.PART) && |
| 1838 nextType != TokenType.PERIOD && |
| 1839 nextType != TokenType.LT && |
| 1840 nextType != TokenType.OPEN_PAREN) { |
| 1841 Directive parseDirective() { |
| 1842 if (keyword == Keyword.IMPORT) { |
| 1843 if (partDirectiveFound) { |
| 1844 _reportErrorForCurrentToken( |
| 1845 ParserErrorCode.IMPORT_DIRECTIVE_AFTER_PART_DIRECTIVE); |
| 1846 } |
| 1847 return parseImportDirective(commentAndMetadata); |
| 1848 } else if (keyword == Keyword.EXPORT) { |
| 1849 if (partDirectiveFound) { |
| 1850 _reportErrorForCurrentToken( |
| 1851 ParserErrorCode.EXPORT_DIRECTIVE_AFTER_PART_DIRECTIVE); |
| 1852 } |
| 1853 return parseExportDirective(commentAndMetadata); |
| 1854 } else if (keyword == Keyword.LIBRARY) { |
| 1855 if (libraryDirectiveFound) { |
| 1856 _reportErrorForCurrentToken( |
| 1857 ParserErrorCode.MULTIPLE_LIBRARY_DIRECTIVES); |
| 1858 } else { |
| 1859 if (directives.length > 0) { |
| 1860 _reportErrorForCurrentToken( |
| 1861 ParserErrorCode.LIBRARY_DIRECTIVE_NOT_FIRST); |
| 1862 } |
| 1863 libraryDirectiveFound = true; |
| 1864 } |
| 1865 return parseLibraryDirective(commentAndMetadata); |
| 1866 } else if (keyword == Keyword.PART) { |
| 1867 if (_tokenMatchesString(_peek(), _OF)) { |
| 1868 partOfDirectiveFound = true; |
| 1869 return _parsePartOfDirective(commentAndMetadata); |
| 1870 } else { |
| 1871 partDirectiveFound = true; |
| 1872 return _parsePartDirective(commentAndMetadata); |
| 1873 } |
| 1874 } else { |
| 1875 // Internal error: this method should not have been invoked if the |
| 1876 // current token was something other than one of the above. |
| 1877 throw new StateError( |
| 1878 "parseDirective invoked in an invalid state (currentToken = $_cu
rrentToken)"); |
| 1879 } |
| 1880 } |
| 1881 |
| 1882 Directive directive = parseDirective(); |
| 1883 if (declarations.length > 0 && !directiveFoundAfterDeclaration) { |
| 1884 _reportErrorForToken(ParserErrorCode.DIRECTIVE_AFTER_DECLARATION, |
| 1885 directive.beginToken); |
| 1886 directiveFoundAfterDeclaration = true; |
| 1887 } |
| 1888 directives.add(directive); |
| 1889 } else if (type == TokenType.SEMICOLON) { |
| 1890 // TODO(brianwilkerson) Consider moving this error detection into |
| 1891 // _parseCompilationUnitMember (in the places where EXPECTED_EXECUTABLE |
| 1892 // is being generated). |
| 1893 _reportErrorForToken(ParserErrorCode.UNEXPECTED_TOKEN, _currentToken, |
| 1894 [_currentToken.lexeme]); |
| 1895 _advance(); |
| 1896 } else { |
| 1897 CompilationUnitMember member = |
| 1898 parseCompilationUnitMember(commentAndMetadata); |
| 1899 if (member != null) { |
| 1900 declarations.add(member); |
| 1901 } |
| 1902 } |
| 1903 if (identical(_currentToken, memberStart)) { |
| 1904 _reportErrorForToken(ParserErrorCode.UNEXPECTED_TOKEN, _currentToken, |
| 1905 [_currentToken.lexeme]); |
| 1906 _advance(); |
| 1907 while (!_matches(TokenType.EOF) && |
| 1908 !_couldBeStartOfCompilationUnitMember()) { |
| 1909 _advance(); |
| 1910 } |
| 1911 } |
| 1912 memberStart = _currentToken; |
| 1913 type = _currentToken.type; |
| 1914 } |
| 1915 if (partOfDirectiveFound && directives.length > 1) { |
| 1916 // TODO(brianwilkerson) Improve error reporting when both a library and |
| 1917 // part-of directive are found. |
| 1918 // if (libraryDirectiveFound) { |
| 1919 // int directiveCount = directives.length; |
| 1920 // for (int i = 0; i < directiveCount; i++) { |
| 1921 // Directive directive = directives[i]; |
| 1922 // if (directive is PartOfDirective) { |
| 1923 // _reportErrorForToken( |
| 1924 // ParserErrorCode.PART_OF_IN_LIBRARY, directive.partKeyword); |
| 1925 // } |
| 1926 // } |
| 1927 // } else { |
| 1928 bool firstPartOf = true; |
| 1929 int directiveCount = directives.length; |
| 1930 for (int i = 0; i < directiveCount; i++) { |
| 1931 Directive directive = directives[i]; |
| 1932 if (directive is PartOfDirective) { |
| 1933 if (firstPartOf) { |
| 1934 firstPartOf = false; |
| 1935 } else { |
| 1936 _reportErrorForToken(ParserErrorCode.MULTIPLE_PART_OF_DIRECTIVES, |
| 1937 directive.partKeyword); |
| 1938 } |
| 1939 } else { |
| 1940 _reportErrorForToken(ParserErrorCode.NON_PART_OF_DIRECTIVE_IN_PART, |
| 1941 directives[i].keyword); |
| 1942 } |
| 1943 // } |
| 1944 } |
| 1945 } |
| 1946 return new CompilationUnit( |
| 1947 firstToken, scriptTag, directives, declarations, _currentToken); |
| 1948 } |
| 1949 |
| 1950 /** |
| 5043 * Parse a compilation unit member. The [commentAndMetadata] is the metadata | 1951 * Parse a compilation unit member. The [commentAndMetadata] is the metadata |
| 5044 * to be associated with the member. Return the compilation unit member that | 1952 * to be associated with the member. Return the compilation unit member that |
| 5045 * was parsed, or `null` if what was parsed could not be represented as a | 1953 * was parsed, or `null` if what was parsed could not be represented as a |
| 5046 * compilation unit member. | 1954 * compilation unit member. |
| 5047 * | 1955 * |
| 5048 * compilationUnitMember ::= | 1956 * compilationUnitMember ::= |
| 5049 * classDefinition | 1957 * classDefinition |
| 5050 * | functionTypeAlias | 1958 * | functionTypeAlias |
| 5051 * | external functionSignature | 1959 * | external functionSignature |
| 5052 * | external getterSignature | 1960 * | external getterSignature |
| 5053 * | external setterSignature | 1961 * | external setterSignature |
| 5054 * | functionSignature functionBody | 1962 * | functionSignature functionBody |
| 5055 * | returnType? getOrSet identifier formalParameterList functionBody | 1963 * | returnType? getOrSet identifier formalParameterList functionBody |
| 5056 * | (final | const) type? staticFinalDeclarationList ';' | 1964 * | (final | const) type? staticFinalDeclarationList ';' |
| 5057 * | variableDeclaration ';' | 1965 * | variableDeclaration ';' |
| 5058 */ | 1966 */ |
| 5059 CompilationUnitMember _parseCompilationUnitMember( | 1967 CompilationUnitMember parseCompilationUnitMember( |
| 5060 CommentAndMetadata commentAndMetadata) { | 1968 CommentAndMetadata commentAndMetadata) { |
| 5061 Modifiers modifiers = _parseModifiers(); | 1969 Modifiers modifiers = parseModifiers(); |
| 5062 if (_matchesKeyword(Keyword.CLASS)) { | 1970 Keyword keyword = _currentToken.keyword; |
| 5063 return _parseClassDeclaration( | 1971 if (keyword == Keyword.CLASS) { |
| 1972 return parseClassDeclaration( |
| 5064 commentAndMetadata, _validateModifiersForClass(modifiers)); | 1973 commentAndMetadata, _validateModifiersForClass(modifiers)); |
| 5065 } else if (_matchesKeyword(Keyword.TYPEDEF) && | 1974 } |
| 5066 !_tokenMatches(_peek(), TokenType.PERIOD) && | 1975 Token next = _peek(); |
| 5067 !_tokenMatches(_peek(), TokenType.LT) && | 1976 TokenType nextType = next.type; |
| 5068 !_tokenMatches(_peek(), TokenType.OPEN_PAREN)) { | 1977 if (keyword == Keyword.TYPEDEF && |
| 1978 nextType != TokenType.PERIOD && |
| 1979 nextType != TokenType.LT && |
| 1980 nextType != TokenType.OPEN_PAREN) { |
| 5069 _validateModifiersForTypedef(modifiers); | 1981 _validateModifiersForTypedef(modifiers); |
| 5070 return _parseTypeAlias(commentAndMetadata); | 1982 return parseTypeAlias(commentAndMetadata); |
| 5071 } else if (_matchesKeyword(Keyword.ENUM)) { | 1983 } else if (keyword == Keyword.ENUM) { |
| 5072 _validateModifiersForEnum(modifiers); | 1984 _validateModifiersForEnum(modifiers); |
| 5073 return _parseEnumDeclaration(commentAndMetadata); | 1985 return parseEnumDeclaration(commentAndMetadata); |
| 5074 } | 1986 } else if (keyword == Keyword.VOID) { |
| 5075 if (_matchesKeyword(Keyword.VOID)) { | 1987 TypeName returnType = |
| 5076 TypeName returnType = parseReturnType(); | 1988 new TypeName(new SimpleIdentifier(getAndAdvance()), null); |
| 5077 if ((_matchesKeyword(Keyword.GET) || _matchesKeyword(Keyword.SET)) && | 1989 keyword = _currentToken.keyword; |
| 5078 _tokenMatchesIdentifier(_peek())) { | 1990 next = _peek(); |
| 1991 if ((keyword == Keyword.GET || keyword == Keyword.SET) && |
| 1992 _tokenMatchesIdentifier(next)) { |
| 5079 _validateModifiersForTopLevelFunction(modifiers); | 1993 _validateModifiersForTopLevelFunction(modifiers); |
| 5080 return _parseFunctionDeclaration( | 1994 return parseFunctionDeclaration( |
| 5081 commentAndMetadata, modifiers.externalKeyword, returnType); | 1995 commentAndMetadata, modifiers.externalKeyword, returnType); |
| 5082 } else if (_matchesKeyword(Keyword.OPERATOR) && _isOperator(_peek())) { | 1996 } else if (keyword == Keyword.OPERATOR && _isOperator(next)) { |
| 5083 _reportErrorForToken(ParserErrorCode.TOP_LEVEL_OPERATOR, _currentToken); | 1997 _reportErrorForToken(ParserErrorCode.TOP_LEVEL_OPERATOR, _currentToken); |
| 5084 return _convertToFunctionDeclaration(_parseOperator( | 1998 return _convertToFunctionDeclaration(_parseOperatorAfterKeyword( |
| 5085 commentAndMetadata, modifiers.externalKeyword, returnType)); | 1999 commentAndMetadata, |
| 2000 modifiers.externalKeyword, |
| 2001 returnType, |
| 2002 getAndAdvance())); |
| 5086 } else if (_matchesIdentifier() && | 2003 } else if (_matchesIdentifier() && |
| 5087 _peek().matchesAny([ | 2004 next.matchesAny(const <TokenType>[ |
| 5088 TokenType.OPEN_PAREN, | 2005 TokenType.OPEN_PAREN, |
| 5089 TokenType.OPEN_CURLY_BRACKET, | 2006 TokenType.OPEN_CURLY_BRACKET, |
| 5090 TokenType.FUNCTION | 2007 TokenType.FUNCTION, |
| 2008 TokenType.LT |
| 5091 ])) { | 2009 ])) { |
| 5092 _validateModifiersForTopLevelFunction(modifiers); | 2010 _validateModifiersForTopLevelFunction(modifiers); |
| 5093 return _parseFunctionDeclaration( | 2011 return parseFunctionDeclaration( |
| 5094 commentAndMetadata, modifiers.externalKeyword, returnType); | 2012 commentAndMetadata, modifiers.externalKeyword, returnType); |
| 5095 } else { | 2013 } else { |
| 5096 // | 2014 // |
| 5097 // We have found an error of some kind. Try to recover. | 2015 // We have found an error of some kind. Try to recover. |
| 5098 // | 2016 // |
| 5099 if (_matchesIdentifier()) { | 2017 if (_matchesIdentifier()) { |
| 5100 if (_peek().matchesAny( | 2018 if (next.matchesAny(const <TokenType>[ |
| 5101 [TokenType.EQ, TokenType.COMMA, TokenType.SEMICOLON])) { | 2019 TokenType.EQ, |
| 2020 TokenType.COMMA, |
| 2021 TokenType.SEMICOLON |
| 2022 ])) { |
| 5102 // | 2023 // |
| 5103 // We appear to have a variable declaration with a type of "void". | 2024 // We appear to have a variable declaration with a type of "void". |
| 5104 // | 2025 // |
| 5105 _reportErrorForNode(ParserErrorCode.VOID_VARIABLE, returnType); | 2026 _reportErrorForNode(ParserErrorCode.VOID_VARIABLE, returnType); |
| 5106 return new TopLevelVariableDeclaration( | 2027 return new TopLevelVariableDeclaration( |
| 5107 commentAndMetadata.comment, | 2028 commentAndMetadata.comment, |
| 5108 commentAndMetadata.metadata, | 2029 commentAndMetadata.metadata, |
| 5109 _parseVariableDeclarationListAfterType(null, | 2030 parseVariableDeclarationListAfterType(null, |
| 5110 _validateModifiersForTopLevelVariable(modifiers), null), | 2031 _validateModifiersForTopLevelVariable(modifiers), null), |
| 5111 _expect(TokenType.SEMICOLON)); | 2032 _expect(TokenType.SEMICOLON)); |
| 5112 } | 2033 } |
| 5113 } | 2034 } |
| 5114 _reportErrorForToken( | 2035 _reportErrorForToken( |
| 5115 ParserErrorCode.EXPECTED_EXECUTABLE, _currentToken); | 2036 ParserErrorCode.EXPECTED_EXECUTABLE, _currentToken); |
| 5116 return null; | 2037 return null; |
| 5117 } | 2038 } |
| 5118 } else if ((_matchesKeyword(Keyword.GET) || _matchesKeyword(Keyword.SET)) && | 2039 } else if ((keyword == Keyword.GET || keyword == Keyword.SET) && |
| 5119 _tokenMatchesIdentifier(_peek())) { | 2040 _tokenMatchesIdentifier(next)) { |
| 5120 _validateModifiersForTopLevelFunction(modifiers); | 2041 _validateModifiersForTopLevelFunction(modifiers); |
| 5121 return _parseFunctionDeclaration( | 2042 return parseFunctionDeclaration( |
| 5122 commentAndMetadata, modifiers.externalKeyword, null); | 2043 commentAndMetadata, modifiers.externalKeyword, null); |
| 5123 } else if (_matchesKeyword(Keyword.OPERATOR) && _isOperator(_peek())) { | 2044 } else if (keyword == Keyword.OPERATOR && _isOperator(next)) { |
| 5124 _reportErrorForToken(ParserErrorCode.TOP_LEVEL_OPERATOR, _currentToken); | 2045 _reportErrorForToken(ParserErrorCode.TOP_LEVEL_OPERATOR, _currentToken); |
| 5125 return _convertToFunctionDeclaration( | 2046 return _convertToFunctionDeclaration(_parseOperatorAfterKeyword( |
| 5126 _parseOperator(commentAndMetadata, modifiers.externalKeyword, null)); | 2047 commentAndMetadata, |
| 2048 modifiers.externalKeyword, |
| 2049 null, |
| 2050 getAndAdvance())); |
| 5127 } else if (!_matchesIdentifier()) { | 2051 } else if (!_matchesIdentifier()) { |
| 5128 Token keyword = modifiers.varKeyword; | 2052 Token keyword = modifiers.varKeyword; |
| 5129 if (keyword == null) { | 2053 if (keyword == null) { |
| 5130 keyword = modifiers.finalKeyword; | 2054 keyword = modifiers.finalKeyword; |
| 5131 } | 2055 } |
| 5132 if (keyword == null) { | 2056 if (keyword == null) { |
| 5133 keyword = modifiers.constKeyword; | 2057 keyword = modifiers.constKeyword; |
| 5134 } | 2058 } |
| 5135 if (keyword != null) { | 2059 if (keyword != null) { |
| 5136 // | 2060 // |
| 5137 // We appear to have found an incomplete top-level variable declaration. | 2061 // We appear to have found an incomplete top-level variable declaration. |
| 5138 // | 2062 // |
| 5139 _reportErrorForCurrentToken(ParserErrorCode.MISSING_IDENTIFIER); | 2063 _reportErrorForCurrentToken(ParserErrorCode.MISSING_IDENTIFIER); |
| 5140 List<VariableDeclaration> variables = new List<VariableDeclaration>(); | 2064 VariableDeclaration variable = |
| 5141 variables.add( | 2065 new VariableDeclaration(createSyntheticIdentifier(), null, null); |
| 5142 new VariableDeclaration(_createSyntheticIdentifier(), null, null)); | 2066 List<VariableDeclaration> variables = <VariableDeclaration>[variable]; |
| 5143 return new TopLevelVariableDeclaration( | 2067 return new TopLevelVariableDeclaration( |
| 5144 commentAndMetadata.comment, | 2068 commentAndMetadata.comment, |
| 5145 commentAndMetadata.metadata, | 2069 commentAndMetadata.metadata, |
| 5146 new VariableDeclarationList(null, null, keyword, null, variables), | 2070 new VariableDeclarationList(null, null, keyword, null, variables), |
| 5147 _expectSemicolon()); | 2071 _expect(TokenType.SEMICOLON)); |
| 5148 } | 2072 } |
| 5149 _reportErrorForToken(ParserErrorCode.EXPECTED_EXECUTABLE, _currentToken); | 2073 _reportErrorForToken(ParserErrorCode.EXPECTED_EXECUTABLE, _currentToken); |
| 5150 return null; | 2074 return null; |
| 5151 } else if (_tokenMatches(_peek(), TokenType.OPEN_PAREN)) { | 2075 } else if (_isPeekGenericTypeParametersAndOpenParen()) { |
| 2076 return parseFunctionDeclaration( |
| 2077 commentAndMetadata, modifiers.externalKeyword, null); |
| 2078 } else if (_tokenMatches(next, TokenType.OPEN_PAREN)) { |
| 2079 TypeName returnType = _parseOptionalTypeNameComment(); |
| 5152 _validateModifiersForTopLevelFunction(modifiers); | 2080 _validateModifiersForTopLevelFunction(modifiers); |
| 5153 return _parseFunctionDeclaration( | 2081 return parseFunctionDeclaration( |
| 5154 commentAndMetadata, modifiers.externalKeyword, null); | 2082 commentAndMetadata, modifiers.externalKeyword, returnType); |
| 5155 } else if (_peek() | 2083 } else if (next.matchesAny(const <TokenType>[ |
| 5156 .matchesAny([TokenType.EQ, TokenType.COMMA, TokenType.SEMICOLON])) { | 2084 TokenType.EQ, |
| 2085 TokenType.COMMA, |
| 2086 TokenType.SEMICOLON |
| 2087 ])) { |
| 5157 if (modifiers.constKeyword == null && | 2088 if (modifiers.constKeyword == null && |
| 5158 modifiers.finalKeyword == null && | 2089 modifiers.finalKeyword == null && |
| 5159 modifiers.varKeyword == null) { | 2090 modifiers.varKeyword == null) { |
| 5160 _reportErrorForCurrentToken( | 2091 _reportErrorForCurrentToken( |
| 5161 ParserErrorCode.MISSING_CONST_FINAL_VAR_OR_TYPE); | 2092 ParserErrorCode.MISSING_CONST_FINAL_VAR_OR_TYPE); |
| 5162 } | 2093 } |
| 5163 return new TopLevelVariableDeclaration( | 2094 return new TopLevelVariableDeclaration( |
| 5164 commentAndMetadata.comment, | 2095 commentAndMetadata.comment, |
| 5165 commentAndMetadata.metadata, | 2096 commentAndMetadata.metadata, |
| 5166 _parseVariableDeclarationListAfterType( | 2097 parseVariableDeclarationListAfterType( |
| 5167 null, _validateModifiersForTopLevelVariable(modifiers), null), | 2098 null, _validateModifiersForTopLevelVariable(modifiers), null), |
| 5168 _expect(TokenType.SEMICOLON)); | 2099 _expect(TokenType.SEMICOLON)); |
| 5169 } | 2100 } |
| 5170 TypeName returnType = parseReturnType(); | 2101 TypeName returnType = parseReturnType(); |
| 5171 if ((_matchesKeyword(Keyword.GET) || _matchesKeyword(Keyword.SET)) && | 2102 keyword = _currentToken.keyword; |
| 5172 _tokenMatchesIdentifier(_peek())) { | 2103 next = _peek(); |
| 2104 if ((keyword == Keyword.GET || keyword == Keyword.SET) && |
| 2105 _tokenMatchesIdentifier(next)) { |
| 5173 _validateModifiersForTopLevelFunction(modifiers); | 2106 _validateModifiersForTopLevelFunction(modifiers); |
| 5174 return _parseFunctionDeclaration( | 2107 return parseFunctionDeclaration( |
| 5175 commentAndMetadata, modifiers.externalKeyword, returnType); | 2108 commentAndMetadata, modifiers.externalKeyword, returnType); |
| 5176 } else if (_matchesKeyword(Keyword.OPERATOR) && _isOperator(_peek())) { | 2109 } else if (keyword == Keyword.OPERATOR && _isOperator(next)) { |
| 5177 _reportErrorForToken(ParserErrorCode.TOP_LEVEL_OPERATOR, _currentToken); | 2110 _reportErrorForToken(ParserErrorCode.TOP_LEVEL_OPERATOR, _currentToken); |
| 5178 return _convertToFunctionDeclaration(_parseOperator( | 2111 return _convertToFunctionDeclaration(_parseOperatorAfterKeyword( |
| 5179 commentAndMetadata, modifiers.externalKeyword, returnType)); | 2112 commentAndMetadata, |
| 2113 modifiers.externalKeyword, |
| 2114 returnType, |
| 2115 getAndAdvance())); |
| 5180 } else if (_matches(TokenType.AT)) { | 2116 } else if (_matches(TokenType.AT)) { |
| 5181 return new TopLevelVariableDeclaration( | 2117 return new TopLevelVariableDeclaration( |
| 5182 commentAndMetadata.comment, | 2118 commentAndMetadata.comment, |
| 5183 commentAndMetadata.metadata, | 2119 commentAndMetadata.metadata, |
| 5184 _parseVariableDeclarationListAfterType(null, | 2120 parseVariableDeclarationListAfterType(null, |
| 5185 _validateModifiersForTopLevelVariable(modifiers), returnType), | 2121 _validateModifiersForTopLevelVariable(modifiers), returnType), |
| 5186 _expect(TokenType.SEMICOLON)); | 2122 _expect(TokenType.SEMICOLON)); |
| 5187 } else if (!_matchesIdentifier()) { | 2123 } else if (!_matchesIdentifier()) { |
| 5188 // TODO(brianwilkerson) Generalize this error. We could also be parsing a | 2124 // TODO(brianwilkerson) Generalize this error. We could also be parsing a |
| 5189 // top-level variable at this point. | 2125 // top-level variable at this point. |
| 5190 _reportErrorForToken(ParserErrorCode.EXPECTED_EXECUTABLE, _currentToken); | 2126 _reportErrorForToken(ParserErrorCode.EXPECTED_EXECUTABLE, _currentToken); |
| 5191 Token semicolon; | 2127 Token semicolon; |
| 5192 if (_matches(TokenType.SEMICOLON)) { | 2128 if (_matches(TokenType.SEMICOLON)) { |
| 5193 semicolon = getAndAdvance(); | 2129 semicolon = getAndAdvance(); |
| 5194 } else { | 2130 } else { |
| 5195 semicolon = _createSyntheticToken(TokenType.SEMICOLON); | 2131 semicolon = _createSyntheticToken(TokenType.SEMICOLON); |
| 5196 } | 2132 } |
| 5197 List<VariableDeclaration> variables = new List<VariableDeclaration>(); | 2133 VariableDeclaration variable = |
| 5198 variables.add( | 2134 new VariableDeclaration(createSyntheticIdentifier(), null, null); |
| 5199 new VariableDeclaration(_createSyntheticIdentifier(), null, null)); | 2135 List<VariableDeclaration> variables = <VariableDeclaration>[variable]; |
| 5200 return new TopLevelVariableDeclaration( | 2136 return new TopLevelVariableDeclaration( |
| 5201 commentAndMetadata.comment, | 2137 commentAndMetadata.comment, |
| 5202 commentAndMetadata.metadata, | 2138 commentAndMetadata.metadata, |
| 5203 new VariableDeclarationList(null, null, null, returnType, variables), | 2139 new VariableDeclarationList(null, null, null, returnType, variables), |
| 5204 semicolon); | 2140 semicolon); |
| 5205 } | 2141 } else if (next.matchesAny(const <TokenType>[ |
| 5206 if (_peek().matchesAny([ | |
| 5207 TokenType.OPEN_PAREN, | 2142 TokenType.OPEN_PAREN, |
| 5208 TokenType.FUNCTION, | 2143 TokenType.FUNCTION, |
| 5209 TokenType.OPEN_CURLY_BRACKET | 2144 TokenType.OPEN_CURLY_BRACKET, |
| 2145 TokenType.LT |
| 5210 ])) { | 2146 ])) { |
| 5211 _validateModifiersForTopLevelFunction(modifiers); | 2147 _validateModifiersForTopLevelFunction(modifiers); |
| 5212 return _parseFunctionDeclaration( | 2148 return parseFunctionDeclaration( |
| 5213 commentAndMetadata, modifiers.externalKeyword, returnType); | 2149 commentAndMetadata, modifiers.externalKeyword, returnType); |
| 5214 } | 2150 } |
| 5215 return new TopLevelVariableDeclaration( | 2151 return new TopLevelVariableDeclaration( |
| 5216 commentAndMetadata.comment, | 2152 commentAndMetadata.comment, |
| 5217 commentAndMetadata.metadata, | 2153 commentAndMetadata.metadata, |
| 5218 _parseVariableDeclarationListAfterType( | 2154 parseVariableDeclarationListAfterType( |
| 5219 null, _validateModifiersForTopLevelVariable(modifiers), returnType), | 2155 null, _validateModifiersForTopLevelVariable(modifiers), returnType), |
| 5220 _expect(TokenType.SEMICOLON)); | 2156 _expect(TokenType.SEMICOLON)); |
| 5221 } | 2157 } |
| 5222 | 2158 |
| 5223 /** | 2159 /** |
| 2160 * Parse a conditional expression. Return the conditional expression that was |
| 2161 * parsed. |
| 2162 * |
| 2163 * conditionalExpression ::= |
| 2164 * ifNullExpression ('?' expressionWithoutCascade ':' expressionWithou
tCascade)? |
| 2165 */ |
| 2166 Expression parseConditionalExpression() { |
| 2167 Expression condition = parseIfNullExpression(); |
| 2168 if (_currentToken.type != TokenType.QUESTION) { |
| 2169 return condition; |
| 2170 } |
| 2171 Token question = getAndAdvance(); |
| 2172 Expression thenExpression = parseExpressionWithoutCascade(); |
| 2173 Token colon = _expect(TokenType.COLON); |
| 2174 Expression elseExpression = parseExpressionWithoutCascade(); |
| 2175 return new ConditionalExpression( |
| 2176 condition, question, thenExpression, colon, elseExpression); |
| 2177 } |
| 2178 |
| 2179 /** |
| 2180 * Parse a configuration in either an import or export directive. |
| 2181 * |
| 2182 * This method assumes that the current token matches `Keyword.IF`. |
| 2183 * |
| 2184 * configuration ::= |
| 2185 * 'if' '(' test ')' uri |
| 2186 * |
| 2187 * test ::= |
| 2188 * dottedName ('==' stringLiteral)? |
| 2189 * |
| 2190 * dottedName ::= |
| 2191 * identifier ('.' identifier)* |
| 2192 */ |
| 2193 Configuration parseConfiguration() { |
| 2194 Token ifKeyword = getAndAdvance(); |
| 2195 Token leftParenthesis = _expect(TokenType.OPEN_PAREN); |
| 2196 DottedName name = parseDottedName(); |
| 2197 Token equalToken = null; |
| 2198 StringLiteral value = null; |
| 2199 if (_matches(TokenType.EQ_EQ)) { |
| 2200 equalToken = getAndAdvance(); |
| 2201 value = parseStringLiteral(); |
| 2202 if (value is StringInterpolation) { |
| 2203 _reportErrorForNode( |
| 2204 ParserErrorCode.INVALID_LITERAL_IN_CONFIGURATION, value); |
| 2205 } |
| 2206 } |
| 2207 Token rightParenthesis = _expect(TokenType.CLOSE_PAREN); |
| 2208 StringLiteral libraryUri = _parseUri(); |
| 2209 return new Configuration(ifKeyword, leftParenthesis, name, equalToken, |
| 2210 value, rightParenthesis, libraryUri); |
| 2211 } |
| 2212 |
| 2213 /** |
| 5224 * Parse a const expression. Return the const expression that was parsed. | 2214 * Parse a const expression. Return the const expression that was parsed. |
| 5225 * | 2215 * |
| 2216 * This method assumes that the current token matches `Keyword.CONST`. |
| 2217 * |
| 5226 * constExpression ::= | 2218 * constExpression ::= |
| 5227 * instanceCreationExpression | 2219 * instanceCreationExpression |
| 5228 * | listLiteral | 2220 * | listLiteral |
| 5229 * | mapLiteral | 2221 * | mapLiteral |
| 5230 */ | 2222 */ |
| 5231 Expression _parseConstExpression() { | 2223 Expression parseConstExpression() { |
| 5232 Token keyword = _expectKeyword(Keyword.CONST); | 2224 Token keyword = getAndAdvance(); |
| 5233 if (_matches(TokenType.OPEN_SQUARE_BRACKET) || _matches(TokenType.INDEX)) { | 2225 TokenType type = _currentToken.type; |
| 5234 return _parseListLiteral(keyword, null); | 2226 if (type == TokenType.LT || _injectGenericCommentTypeList()) { |
| 5235 } else if (_matches(TokenType.OPEN_CURLY_BRACKET)) { | 2227 return parseListOrMapLiteral(keyword); |
| 5236 return _parseMapLiteral(keyword, null); | 2228 } else if (type == TokenType.OPEN_SQUARE_BRACKET || |
| 5237 } else if (_matches(TokenType.LT)) { | 2229 type == TokenType.INDEX) { |
| 5238 return _parseListOrMapLiteral(keyword); | 2230 return parseListLiteral(keyword, null); |
| 5239 } | 2231 } else if (type == TokenType.OPEN_CURLY_BRACKET) { |
| 5240 return _parseInstanceCreationExpression(keyword); | 2232 return parseMapLiteral(keyword, null); |
| 5241 } | 2233 } |
| 5242 | 2234 return parseInstanceCreationExpression(keyword); |
| 5243 ConstructorDeclaration _parseConstructor( | 2235 } |
| 5244 CommentAndMetadata commentAndMetadata, | 2236 |
| 5245 Token externalKeyword, | 2237 /** |
| 5246 Token constKeyword, | 2238 * Parse a field initializer within a constructor. The flag [hasThis] should |
| 5247 Token factoryKeyword, | 2239 * be true if the current token is `this`. Return the field initializer that |
| 5248 SimpleIdentifier returnType, | 2240 * was parsed. |
| 5249 Token period, | |
| 5250 SimpleIdentifier name, | |
| 5251 FormalParameterList parameters) { | |
| 5252 bool bodyAllowed = externalKeyword == null; | |
| 5253 Token separator = null; | |
| 5254 List<ConstructorInitializer> initializers = null; | |
| 5255 if (_matches(TokenType.COLON)) { | |
| 5256 separator = getAndAdvance(); | |
| 5257 initializers = new List<ConstructorInitializer>(); | |
| 5258 do { | |
| 5259 if (_matchesKeyword(Keyword.THIS)) { | |
| 5260 if (_tokenMatches(_peek(), TokenType.OPEN_PAREN)) { | |
| 5261 bodyAllowed = false; | |
| 5262 initializers.add(_parseRedirectingConstructorInvocation()); | |
| 5263 } else if (_tokenMatches(_peek(), TokenType.PERIOD) && | |
| 5264 _tokenMatches(_peekAt(3), TokenType.OPEN_PAREN)) { | |
| 5265 bodyAllowed = false; | |
| 5266 initializers.add(_parseRedirectingConstructorInvocation()); | |
| 5267 } else { | |
| 5268 initializers.add(_parseConstructorFieldInitializer()); | |
| 5269 } | |
| 5270 } else if (_matchesKeyword(Keyword.SUPER)) { | |
| 5271 initializers.add(_parseSuperConstructorInvocation()); | |
| 5272 } else if (_matches(TokenType.OPEN_CURLY_BRACKET) || | |
| 5273 _matches(TokenType.FUNCTION)) { | |
| 5274 _reportErrorForCurrentToken(ParserErrorCode.MISSING_INITIALIZER); | |
| 5275 } else { | |
| 5276 initializers.add(_parseConstructorFieldInitializer()); | |
| 5277 } | |
| 5278 } while (_optional(TokenType.COMMA)); | |
| 5279 if (factoryKeyword != null) { | |
| 5280 _reportErrorForToken( | |
| 5281 ParserErrorCode.FACTORY_WITH_INITIALIZERS, factoryKeyword); | |
| 5282 } | |
| 5283 } | |
| 5284 ConstructorName redirectedConstructor = null; | |
| 5285 FunctionBody body; | |
| 5286 if (_matches(TokenType.EQ)) { | |
| 5287 separator = getAndAdvance(); | |
| 5288 redirectedConstructor = parseConstructorName(); | |
| 5289 body = new EmptyFunctionBody(_expect(TokenType.SEMICOLON)); | |
| 5290 if (factoryKeyword == null) { | |
| 5291 _reportErrorForNode( | |
| 5292 ParserErrorCode.REDIRECTION_IN_NON_FACTORY_CONSTRUCTOR, | |
| 5293 redirectedConstructor); | |
| 5294 } | |
| 5295 } else { | |
| 5296 body = _parseFunctionBody( | |
| 5297 true, ParserErrorCode.MISSING_FUNCTION_BODY, false); | |
| 5298 if (constKeyword != null && | |
| 5299 factoryKeyword != null && | |
| 5300 externalKeyword == null) { | |
| 5301 _reportErrorForToken(ParserErrorCode.CONST_FACTORY, factoryKeyword); | |
| 5302 } else if (body is EmptyFunctionBody) { | |
| 5303 if (factoryKeyword != null && | |
| 5304 externalKeyword == null && | |
| 5305 _parseFunctionBodies) { | |
| 5306 _reportErrorForToken( | |
| 5307 ParserErrorCode.FACTORY_WITHOUT_BODY, factoryKeyword); | |
| 5308 } | |
| 5309 } else { | |
| 5310 if (constKeyword != null) { | |
| 5311 _reportErrorForNode( | |
| 5312 ParserErrorCode.CONST_CONSTRUCTOR_WITH_BODY, body); | |
| 5313 } else if (!bodyAllowed) { | |
| 5314 _reportErrorForNode( | |
| 5315 ParserErrorCode.EXTERNAL_CONSTRUCTOR_WITH_BODY, body); | |
| 5316 } | |
| 5317 } | |
| 5318 } | |
| 5319 return new ConstructorDeclaration( | |
| 5320 commentAndMetadata.comment, | |
| 5321 commentAndMetadata.metadata, | |
| 5322 externalKeyword, | |
| 5323 constKeyword, | |
| 5324 factoryKeyword, | |
| 5325 returnType, | |
| 5326 period, | |
| 5327 name, | |
| 5328 parameters, | |
| 5329 separator, | |
| 5330 initializers, | |
| 5331 redirectedConstructor, | |
| 5332 body); | |
| 5333 } | |
| 5334 | |
| 5335 /** | |
| 5336 * Parse a field initializer within a constructor. Return the field | |
| 5337 * initializer that was parsed. | |
| 5338 * | 2241 * |
| 5339 * fieldInitializer: | 2242 * fieldInitializer: |
| 5340 * ('this' '.')? identifier '=' conditionalExpression cascadeSection* | 2243 * ('this' '.')? identifier '=' conditionalExpression cascadeSection* |
| 5341 */ | 2244 */ |
| 5342 ConstructorFieldInitializer _parseConstructorFieldInitializer() { | 2245 ConstructorFieldInitializer parseConstructorFieldInitializer(bool hasThis) { |
| 5343 Token keyword = null; | 2246 Token keywordToken = null; |
| 5344 Token period = null; | 2247 Token period = null; |
| 5345 if (_matchesKeyword(Keyword.THIS)) { | 2248 if (hasThis) { |
| 5346 keyword = getAndAdvance(); | 2249 keywordToken = getAndAdvance(); |
| 5347 period = _expect(TokenType.PERIOD); | 2250 period = _expect(TokenType.PERIOD); |
| 5348 } | 2251 } |
| 5349 SimpleIdentifier fieldName = parseSimpleIdentifier(); | 2252 SimpleIdentifier fieldName = parseSimpleIdentifier(); |
| 5350 Token equals = null; | 2253 Token equals = null; |
| 5351 if (_matches(TokenType.EQ)) { | 2254 TokenType type = _currentToken.type; |
| 2255 if (type == TokenType.EQ) { |
| 5352 equals = getAndAdvance(); | 2256 equals = getAndAdvance(); |
| 5353 } else if (!_matchesKeyword(Keyword.THIS) && | |
| 5354 !_matchesKeyword(Keyword.SUPER) && | |
| 5355 !_matches(TokenType.OPEN_CURLY_BRACKET) && | |
| 5356 !_matches(TokenType.FUNCTION)) { | |
| 5357 _reportErrorForCurrentToken( | |
| 5358 ParserErrorCode.MISSING_ASSIGNMENT_IN_INITIALIZER); | |
| 5359 equals = _createSyntheticToken(TokenType.EQ); | |
| 5360 } else { | 2257 } else { |
| 5361 _reportErrorForCurrentToken( | 2258 _reportErrorForCurrentToken( |
| 5362 ParserErrorCode.MISSING_ASSIGNMENT_IN_INITIALIZER); | 2259 ParserErrorCode.MISSING_ASSIGNMENT_IN_INITIALIZER); |
| 5363 return new ConstructorFieldInitializer(keyword, period, fieldName, | 2260 Keyword keyword = _currentToken.keyword; |
| 5364 _createSyntheticToken(TokenType.EQ), _createSyntheticIdentifier()); | 2261 if (keyword != Keyword.THIS && |
| 2262 keyword != Keyword.SUPER && |
| 2263 type != TokenType.OPEN_CURLY_BRACKET && |
| 2264 type != TokenType.FUNCTION) { |
| 2265 equals = _createSyntheticToken(TokenType.EQ); |
| 2266 } else { |
| 2267 return new ConstructorFieldInitializer(keywordToken, period, fieldName, |
| 2268 _createSyntheticToken(TokenType.EQ), createSyntheticIdentifier()); |
| 2269 } |
| 5365 } | 2270 } |
| 5366 bool wasInInitializer = _inInitializer; | 2271 bool wasInInitializer = _inInitializer; |
| 5367 _inInitializer = true; | 2272 _inInitializer = true; |
| 5368 try { | 2273 try { |
| 5369 Expression expression = parseConditionalExpression(); | 2274 Expression expression = parseConditionalExpression(); |
| 5370 TokenType tokenType = _currentToken.type; | 2275 if (_matches(TokenType.PERIOD_PERIOD)) { |
| 5371 if (tokenType == TokenType.PERIOD_PERIOD) { | 2276 List<Expression> cascadeSections = <Expression>[]; |
| 5372 List<Expression> cascadeSections = new List<Expression>(); | 2277 do { |
| 5373 while (tokenType == TokenType.PERIOD_PERIOD) { | 2278 Expression section = parseCascadeSection(); |
| 5374 Expression section = _parseCascadeSection(); | |
| 5375 if (section != null) { | 2279 if (section != null) { |
| 5376 cascadeSections.add(section); | 2280 cascadeSections.add(section); |
| 5377 } | 2281 } |
| 5378 tokenType = _currentToken.type; | 2282 } while (_matches(TokenType.PERIOD_PERIOD)); |
| 5379 } | |
| 5380 expression = new CascadeExpression(expression, cascadeSections); | 2283 expression = new CascadeExpression(expression, cascadeSections); |
| 5381 } | 2284 } |
| 5382 return new ConstructorFieldInitializer( | 2285 return new ConstructorFieldInitializer( |
| 5383 keyword, period, fieldName, equals, expression); | 2286 keywordToken, period, fieldName, equals, expression); |
| 5384 } finally { | 2287 } finally { |
| 5385 _inInitializer = wasInInitializer; | 2288 _inInitializer = wasInInitializer; |
| 5386 } | 2289 } |
| 5387 } | 2290 } |
| 5388 | 2291 |
| 5389 /** | 2292 /** |
| 2293 * Parse the name of a constructor. Return the constructor name that was |
| 2294 * parsed. |
| 2295 * |
| 2296 * constructorName: |
| 2297 * type ('.' identifier)? |
| 2298 */ |
| 2299 ConstructorName parseConstructorName() { |
| 2300 TypeName type = parseTypeName(false); |
| 2301 Token period = null; |
| 2302 SimpleIdentifier name = null; |
| 2303 if (_matches(TokenType.PERIOD)) { |
| 2304 period = getAndAdvance(); |
| 2305 name = parseSimpleIdentifier(); |
| 2306 } |
| 2307 return new ConstructorName(type, period, name); |
| 2308 } |
| 2309 |
| 2310 /** |
| 5390 * Parse a continue statement. Return the continue statement that was parsed. | 2311 * Parse a continue statement. Return the continue statement that was parsed. |
| 5391 * | 2312 * |
| 2313 * This method assumes that the current token matches `Keyword.CONTINUE`. |
| 2314 * |
| 5392 * continueStatement ::= | 2315 * continueStatement ::= |
| 5393 * 'continue' identifier? ';' | 2316 * 'continue' identifier? ';' |
| 5394 */ | 2317 */ |
| 5395 Statement _parseContinueStatement() { | 2318 Statement parseContinueStatement() { |
| 5396 Token continueKeyword = _expectKeyword(Keyword.CONTINUE); | 2319 Token continueKeyword = getAndAdvance(); |
| 5397 if (!_inLoop && !_inSwitch) { | 2320 if (!_inLoop && !_inSwitch) { |
| 5398 _reportErrorForToken( | 2321 _reportErrorForToken( |
| 5399 ParserErrorCode.CONTINUE_OUTSIDE_OF_LOOP, continueKeyword); | 2322 ParserErrorCode.CONTINUE_OUTSIDE_OF_LOOP, continueKeyword); |
| 5400 } | 2323 } |
| 5401 SimpleIdentifier label = null; | 2324 SimpleIdentifier label = null; |
| 5402 if (_matchesIdentifier()) { | 2325 if (_matchesIdentifier()) { |
| 5403 label = parseSimpleIdentifier(); | 2326 label = _parseSimpleIdentifierUnchecked(); |
| 5404 } | 2327 } |
| 5405 if (_inSwitch && !_inLoop && label == null) { | 2328 if (_inSwitch && !_inLoop && label == null) { |
| 5406 _reportErrorForToken( | 2329 _reportErrorForToken( |
| 5407 ParserErrorCode.CONTINUE_WITHOUT_LABEL_IN_CASE, continueKeyword); | 2330 ParserErrorCode.CONTINUE_WITHOUT_LABEL_IN_CASE, continueKeyword); |
| 5408 } | 2331 } |
| 5409 Token semicolon = _expect(TokenType.SEMICOLON); | 2332 Token semicolon = _expect(TokenType.SEMICOLON); |
| 5410 return new ContinueStatement(continueKeyword, label, semicolon); | 2333 return new ContinueStatement(continueKeyword, label, semicolon); |
| 5411 } | 2334 } |
| 5412 | 2335 |
| 5413 /** | 2336 /** |
| 5414 * Parse a directive. The [commentAndMetadata] is the metadata to be | 2337 * Parse a directive. The [commentAndMetadata] is the metadata to be |
| 5415 * associated with the directive. Return the directive that was parsed. | 2338 * associated with the directive. Return the directive that was parsed. |
| 5416 * | 2339 * |
| 5417 * directive ::= | 2340 * directive ::= |
| 5418 * exportDirective | 2341 * exportDirective |
| 5419 * | libraryDirective | 2342 * | libraryDirective |
| 5420 * | importDirective | 2343 * | importDirective |
| 5421 * | partDirective | 2344 * | partDirective |
| 5422 */ | 2345 */ |
| 5423 Directive _parseDirective(CommentAndMetadata commentAndMetadata) { | 2346 Directive parseDirective(CommentAndMetadata commentAndMetadata) { |
| 5424 if (_matchesKeyword(Keyword.IMPORT)) { | 2347 if (_matchesKeyword(Keyword.IMPORT)) { |
| 5425 return _parseImportDirective(commentAndMetadata); | 2348 return parseImportDirective(commentAndMetadata); |
| 5426 } else if (_matchesKeyword(Keyword.EXPORT)) { | 2349 } else if (_matchesKeyword(Keyword.EXPORT)) { |
| 5427 return _parseExportDirective(commentAndMetadata); | 2350 return parseExportDirective(commentAndMetadata); |
| 5428 } else if (_matchesKeyword(Keyword.LIBRARY)) { | 2351 } else if (_matchesKeyword(Keyword.LIBRARY)) { |
| 5429 return _parseLibraryDirective(commentAndMetadata); | 2352 return parseLibraryDirective(commentAndMetadata); |
| 5430 } else if (_matchesKeyword(Keyword.PART)) { | 2353 } else if (_matchesKeyword(Keyword.PART)) { |
| 5431 return _parsePartDirective(commentAndMetadata); | 2354 return parsePartOrPartOfDirective(commentAndMetadata); |
| 5432 } else { | 2355 } else { |
| 5433 // Internal error: this method should not have been invoked if the current | 2356 // Internal error: this method should not have been invoked if the current |
| 5434 // token was something other than one of the above. | 2357 // token was something other than one of the above. |
| 5435 throw new IllegalStateException( | 2358 throw new StateError( |
| 5436 "parseDirective invoked in an invalid state; currentToken = $_currentT
oken"); | 2359 "parseDirective invoked in an invalid state; currentToken = $_currentT
oken"); |
| 5437 } | 2360 } |
| 5438 } | 2361 } |
| 5439 | 2362 |
| 5440 /** | 2363 /** |
| 2364 * Parse the script tag and directives in a compilation unit, starting with |
| 2365 * the given [token], until the first non-directive is encountered. The |
| 2366 * remainder of the compilation unit will not be parsed. Specifically, if |
| 2367 * there are directives later in the file, they will not be parsed. Return the |
| 2368 * compilation unit that was parsed. |
| 2369 */ |
| 2370 CompilationUnit parseDirectives(Token token) { |
| 2371 _currentToken = token; |
| 2372 return parseDirectives2(); |
| 2373 } |
| 2374 |
| 2375 /** |
| 5441 * Parse the script tag and directives in a compilation unit until the first | 2376 * Parse the script tag and directives in a compilation unit until the first |
| 5442 * non-directive is encountered. Return the compilation unit that was parsed. | 2377 * non-directive is encountered. Return the compilation unit that was parsed. |
| 5443 * | 2378 * |
| 5444 * compilationUnit ::= | 2379 * compilationUnit ::= |
| 5445 * scriptTag? directive* | 2380 * scriptTag? directive* |
| 5446 */ | 2381 */ |
| 5447 CompilationUnit _parseDirectives() { | 2382 CompilationUnit parseDirectives2() { |
| 5448 Token firstToken = _currentToken; | 2383 Token firstToken = _currentToken; |
| 5449 ScriptTag scriptTag = null; | 2384 ScriptTag scriptTag = null; |
| 5450 if (_matches(TokenType.SCRIPT_TAG)) { | 2385 if (_matches(TokenType.SCRIPT_TAG)) { |
| 5451 scriptTag = new ScriptTag(getAndAdvance()); | 2386 scriptTag = new ScriptTag(getAndAdvance()); |
| 5452 } | 2387 } |
| 5453 List<Directive> directives = new List<Directive>(); | 2388 List<Directive> directives = <Directive>[]; |
| 5454 while (!_matches(TokenType.EOF)) { | 2389 while (!_matches(TokenType.EOF)) { |
| 5455 CommentAndMetadata commentAndMetadata = _parseCommentAndMetadata(); | 2390 CommentAndMetadata commentAndMetadata = parseCommentAndMetadata(); |
| 5456 if ((_matchesKeyword(Keyword.IMPORT) || | 2391 Keyword keyword = _currentToken.keyword; |
| 5457 _matchesKeyword(Keyword.EXPORT) || | 2392 TokenType type = _peek().type; |
| 5458 _matchesKeyword(Keyword.LIBRARY) || | 2393 if ((keyword == Keyword.IMPORT || |
| 5459 _matchesKeyword(Keyword.PART)) && | 2394 keyword == Keyword.EXPORT || |
| 5460 !_tokenMatches(_peek(), TokenType.PERIOD) && | 2395 keyword == Keyword.LIBRARY || |
| 5461 !_tokenMatches(_peek(), TokenType.LT) && | 2396 keyword == Keyword.PART) && |
| 5462 !_tokenMatches(_peek(), TokenType.OPEN_PAREN)) { | 2397 type != TokenType.PERIOD && |
| 5463 directives.add(_parseDirective(commentAndMetadata)); | 2398 type != TokenType.LT && |
| 2399 type != TokenType.OPEN_PAREN) { |
| 2400 directives.add(parseDirective(commentAndMetadata)); |
| 5464 } else if (_matches(TokenType.SEMICOLON)) { | 2401 } else if (_matches(TokenType.SEMICOLON)) { |
| 5465 _advance(); | 2402 _advance(); |
| 5466 } else { | 2403 } else { |
| 5467 while (!_matches(TokenType.EOF)) { | 2404 while (!_matches(TokenType.EOF)) { |
| 5468 _advance(); | 2405 _advance(); |
| 5469 } | 2406 } |
| 5470 return new CompilationUnit(firstToken, scriptTag, directives, | 2407 return new CompilationUnit( |
| 5471 new List<CompilationUnitMember>(), _currentToken); | 2408 firstToken, scriptTag, directives, null, _currentToken); |
| 5472 } | 2409 } |
| 5473 } | 2410 } |
| 5474 return new CompilationUnit(firstToken, scriptTag, directives, | 2411 return new CompilationUnit( |
| 5475 new List<CompilationUnitMember>(), _currentToken); | 2412 firstToken, scriptTag, directives, null, _currentToken); |
| 5476 } | 2413 } |
| 5477 | 2414 |
| 5478 /** | 2415 /** |
| 2416 * Parse a documentation comment based on the given list of documentation |
| 2417 * comment tokens. Return the documentation comment that was parsed, or `null` |
| 2418 * if there was no comment. |
| 2419 * |
| 2420 * documentationComment ::= |
| 2421 * multiLineComment? |
| 2422 * | singleLineComment* |
| 2423 */ |
| 2424 Comment parseDocumentationComment(List<DocumentationCommentToken> tokens) { |
| 2425 if (tokens == null) { |
| 2426 return null; |
| 2427 } |
| 2428 List<CommentReference> references = parseCommentReferences(tokens); |
| 2429 return Comment.createDocumentationCommentWithReferences(tokens, references); |
| 2430 } |
| 2431 |
| 2432 /** |
| 5479 * Parse a documentation comment. Return the documentation comment that was | 2433 * Parse a documentation comment. Return the documentation comment that was |
| 5480 * parsed, or `null` if there was no comment. | 2434 * parsed, or `null` if there was no comment. |
| 5481 * | 2435 * |
| 5482 * documentationComment ::= | 2436 * documentationComment ::= |
| 5483 * multiLineComment? | 2437 * multiLineComment? |
| 5484 * | singleLineComment* | 2438 * | singleLineComment* |
| 5485 */ | 2439 */ |
| 5486 Comment _parseDocumentationComment() { | 2440 List<DocumentationCommentToken> parseDocumentationCommentTokens() { |
| 5487 List<DocumentationCommentToken> documentationTokens = | 2441 List<DocumentationCommentToken> tokens = <DocumentationCommentToken>[]; |
| 5488 <DocumentationCommentToken>[]; | |
| 5489 CommentToken commentToken = _currentToken.precedingComments; | 2442 CommentToken commentToken = _currentToken.precedingComments; |
| 5490 while (commentToken != null) { | 2443 while (commentToken != null) { |
| 5491 if (commentToken is DocumentationCommentToken) { | 2444 if (commentToken is DocumentationCommentToken) { |
| 5492 if (documentationTokens.isNotEmpty) { | 2445 if (tokens.isNotEmpty) { |
| 5493 if (commentToken.type == TokenType.SINGLE_LINE_COMMENT) { | 2446 if (commentToken.type == TokenType.SINGLE_LINE_COMMENT) { |
| 5494 if (documentationTokens[0].type != TokenType.SINGLE_LINE_COMMENT) { | 2447 if (tokens[0].type != TokenType.SINGLE_LINE_COMMENT) { |
| 5495 documentationTokens.clear(); | 2448 tokens.clear(); |
| 5496 } | 2449 } |
| 5497 } else { | 2450 } else { |
| 5498 documentationTokens.clear(); | 2451 tokens.clear(); |
| 5499 } | 2452 } |
| 5500 } | 2453 } |
| 5501 documentationTokens.add(commentToken); | 2454 tokens.add(commentToken); |
| 5502 } | 2455 } |
| 5503 commentToken = commentToken.next; | 2456 commentToken = commentToken.next; |
| 5504 } | 2457 } |
| 5505 if (documentationTokens.isEmpty) { | 2458 return tokens.isEmpty ? null : tokens; |
| 5506 return null; | |
| 5507 } | |
| 5508 List<CommentReference> references = | |
| 5509 _parseCommentReferences(documentationTokens); | |
| 5510 return Comment.createDocumentationCommentWithReferences( | |
| 5511 documentationTokens, references); | |
| 5512 } | 2459 } |
| 5513 | 2460 |
| 5514 /** | 2461 /** |
| 5515 * Parse a do statement. Return the do statement that was parsed. | 2462 * Parse a do statement. Return the do statement that was parsed. |
| 5516 * | 2463 * |
| 2464 * This method assumes that the current token matches `Keyword.DO`. |
| 2465 * |
| 5517 * doStatement ::= | 2466 * doStatement ::= |
| 5518 * 'do' statement 'while' '(' expression ')' ';' | 2467 * 'do' statement 'while' '(' expression ')' ';' |
| 5519 */ | 2468 */ |
| 5520 Statement _parseDoStatement() { | 2469 Statement parseDoStatement() { |
| 5521 bool wasInLoop = _inLoop; | 2470 bool wasInLoop = _inLoop; |
| 5522 _inLoop = true; | 2471 _inLoop = true; |
| 5523 try { | 2472 try { |
| 5524 Token doKeyword = _expectKeyword(Keyword.DO); | 2473 Token doKeyword = getAndAdvance(); |
| 5525 Statement body = parseStatement2(); | 2474 Statement body = parseStatement2(); |
| 5526 Token whileKeyword = _expectKeyword(Keyword.WHILE); | 2475 Token whileKeyword = _expectKeyword(Keyword.WHILE); |
| 5527 Token leftParenthesis = _expect(TokenType.OPEN_PAREN); | 2476 Token leftParenthesis = _expect(TokenType.OPEN_PAREN); |
| 5528 Expression condition = parseExpression2(); | 2477 Expression condition = parseExpression2(); |
| 5529 Token rightParenthesis = _expect(TokenType.CLOSE_PAREN); | 2478 Token rightParenthesis = _expect(TokenType.CLOSE_PAREN); |
| 5530 Token semicolon = _expect(TokenType.SEMICOLON); | 2479 Token semicolon = _expect(TokenType.SEMICOLON); |
| 5531 return new DoStatement(doKeyword, body, whileKeyword, leftParenthesis, | 2480 return new DoStatement(doKeyword, body, whileKeyword, leftParenthesis, |
| 5532 condition, rightParenthesis, semicolon); | 2481 condition, rightParenthesis, semicolon); |
| 5533 } finally { | 2482 } finally { |
| 5534 _inLoop = wasInLoop; | 2483 _inLoop = wasInLoop; |
| 5535 } | 2484 } |
| 5536 } | 2485 } |
| 5537 | 2486 |
| 5538 /** | 2487 /** |
| 2488 * Parse a dotted name. Return the dotted name that was parsed. |
| 2489 * |
| 2490 * dottedName ::= |
| 2491 * identifier ('.' identifier)* |
| 2492 */ |
| 2493 DottedName parseDottedName() { |
| 2494 List<SimpleIdentifier> components = <SimpleIdentifier>[ |
| 2495 parseSimpleIdentifier() |
| 2496 ]; |
| 2497 while (_optional(TokenType.PERIOD)) { |
| 2498 components.add(parseSimpleIdentifier()); |
| 2499 } |
| 2500 return new DottedName(components); |
| 2501 } |
| 2502 |
| 2503 /** |
| 5539 * Parse an empty statement. Return the empty statement that was parsed. | 2504 * Parse an empty statement. Return the empty statement that was parsed. |
| 5540 * | 2505 * |
| 2506 * This method assumes that the current token matches `TokenType.SEMICOLON`. |
| 2507 * |
| 5541 * emptyStatement ::= | 2508 * emptyStatement ::= |
| 5542 * ';' | 2509 * ';' |
| 5543 */ | 2510 */ |
| 5544 Statement _parseEmptyStatement() => new EmptyStatement(getAndAdvance()); | 2511 Statement parseEmptyStatement() => new EmptyStatement(getAndAdvance()); |
| 5545 | |
| 5546 EnumConstantDeclaration _parseEnumConstantDeclaration() { | |
| 5547 CommentAndMetadata commentAndMetadata = _parseCommentAndMetadata(); | |
| 5548 SimpleIdentifier name; | |
| 5549 if (_matchesIdentifier()) { | |
| 5550 name = parseSimpleIdentifier(); | |
| 5551 } else { | |
| 5552 name = _createSyntheticIdentifier(); | |
| 5553 } | |
| 5554 if (commentAndMetadata.metadata.isNotEmpty) { | |
| 5555 _reportErrorForNode(ParserErrorCode.ANNOTATION_ON_ENUM_CONSTANT, | |
| 5556 commentAndMetadata.metadata[0]); | |
| 5557 } | |
| 5558 return new EnumConstantDeclaration( | |
| 5559 commentAndMetadata.comment, commentAndMetadata.metadata, name); | |
| 5560 } | |
| 5561 | 2512 |
| 5562 /** | 2513 /** |
| 5563 * Parse an enum declaration. The [commentAndMetadata] is the metadata to be | 2514 * Parse an enum declaration. The [commentAndMetadata] is the metadata to be |
| 5564 * associated with the member. Return the enum declaration that was parsed. | 2515 * associated with the member. Return the enum declaration that was parsed. |
| 5565 * | 2516 * |
| 2517 * This method assumes that the current token matches `Keyword.ENUM`. |
| 2518 * |
| 5566 * enumType ::= | 2519 * enumType ::= |
| 5567 * metadata 'enum' id '{' id (',' id)* (',')? '}' | 2520 * metadata 'enum' id '{' id (',' id)* (',')? '}' |
| 5568 */ | 2521 */ |
| 5569 EnumDeclaration _parseEnumDeclaration(CommentAndMetadata commentAndMetadata) { | 2522 EnumDeclaration parseEnumDeclaration(CommentAndMetadata commentAndMetadata) { |
| 5570 Token keyword = _expectKeyword(Keyword.ENUM); | 2523 Token keyword = getAndAdvance(); |
| 5571 SimpleIdentifier name = parseSimpleIdentifier(); | 2524 SimpleIdentifier name = parseSimpleIdentifier(isDeclaration: true); |
| 5572 Token leftBracket = null; | 2525 Token leftBracket = null; |
| 5573 List<EnumConstantDeclaration> constants = | 2526 List<EnumConstantDeclaration> constants = <EnumConstantDeclaration>[]; |
| 5574 new List<EnumConstantDeclaration>(); | |
| 5575 Token rightBracket = null; | 2527 Token rightBracket = null; |
| 5576 if (_matches(TokenType.OPEN_CURLY_BRACKET)) { | 2528 if (_matches(TokenType.OPEN_CURLY_BRACKET)) { |
| 5577 leftBracket = _expect(TokenType.OPEN_CURLY_BRACKET); | 2529 leftBracket = getAndAdvance(); |
| 5578 if (_matchesIdentifier() || _matches(TokenType.AT)) { | 2530 if (_matchesIdentifier() || _matches(TokenType.AT)) { |
| 5579 constants.add(_parseEnumConstantDeclaration()); | 2531 constants.add(_parseEnumConstantDeclaration()); |
| 5580 } else if (_matches(TokenType.COMMA) && | 2532 } else if (_matches(TokenType.COMMA) && |
| 5581 _tokenMatchesIdentifier(_peek())) { | 2533 _tokenMatchesIdentifier(_peek())) { |
| 5582 constants.add(_parseEnumConstantDeclaration()); | 2534 constants.add(_parseEnumConstantDeclaration()); |
| 5583 _reportErrorForCurrentToken(ParserErrorCode.MISSING_IDENTIFIER); | 2535 _reportErrorForCurrentToken(ParserErrorCode.MISSING_IDENTIFIER); |
| 5584 } else { | 2536 } else { |
| 5585 constants.add(_parseEnumConstantDeclaration()); | 2537 constants.add(_parseEnumConstantDeclaration()); |
| 5586 _reportErrorForCurrentToken(ParserErrorCode.EMPTY_ENUM_BODY); | 2538 _reportErrorForCurrentToken(ParserErrorCode.EMPTY_ENUM_BODY); |
| 5587 } | 2539 } |
| (...skipping 20 matching lines...) Expand all Loading... |
| 5608 } | 2560 } |
| 5609 | 2561 |
| 5610 /** | 2562 /** |
| 5611 * Parse an equality expression. Return the equality expression that was | 2563 * Parse an equality expression. Return the equality expression that was |
| 5612 * parsed. | 2564 * parsed. |
| 5613 * | 2565 * |
| 5614 * equalityExpression ::= | 2566 * equalityExpression ::= |
| 5615 * relationalExpression (equalityOperator relationalExpression)? | 2567 * relationalExpression (equalityOperator relationalExpression)? |
| 5616 * | 'super' equalityOperator relationalExpression | 2568 * | 'super' equalityOperator relationalExpression |
| 5617 */ | 2569 */ |
| 5618 Expression _parseEqualityExpression() { | 2570 Expression parseEqualityExpression() { |
| 5619 Expression expression; | 2571 Expression expression; |
| 5620 if (_matchesKeyword(Keyword.SUPER) && | 2572 if (_currentToken.keyword == Keyword.SUPER && |
| 5621 _currentToken.next.type.isEqualityOperator) { | 2573 _currentToken.next.type.isEqualityOperator) { |
| 5622 expression = new SuperExpression(getAndAdvance()); | 2574 expression = new SuperExpression(getAndAdvance()); |
| 5623 } else { | 2575 } else { |
| 5624 expression = _parseRelationalExpression(); | 2576 expression = parseRelationalExpression(); |
| 5625 } | 2577 } |
| 5626 bool leftEqualityExpression = false; | 2578 bool leftEqualityExpression = false; |
| 5627 while (_currentToken.type.isEqualityOperator) { | 2579 while (_currentToken.type.isEqualityOperator) { |
| 5628 Token operator = getAndAdvance(); | |
| 5629 if (leftEqualityExpression) { | 2580 if (leftEqualityExpression) { |
| 5630 _reportErrorForNode( | 2581 _reportErrorForNode( |
| 5631 ParserErrorCode.EQUALITY_CANNOT_BE_EQUALITY_OPERAND, expression); | 2582 ParserErrorCode.EQUALITY_CANNOT_BE_EQUALITY_OPERAND, expression); |
| 5632 } | 2583 } |
| 5633 expression = new BinaryExpression( | 2584 expression = new BinaryExpression( |
| 5634 expression, operator, _parseRelationalExpression()); | 2585 expression, getAndAdvance(), parseRelationalExpression()); |
| 5635 leftEqualityExpression = true; | 2586 leftEqualityExpression = true; |
| 5636 } | 2587 } |
| 5637 return expression; | 2588 return expression; |
| 5638 } | 2589 } |
| 5639 | 2590 |
| 5640 /** | 2591 /** |
| 5641 * Parse an export directive. The [commentAndMetadata] is the metadata to be | 2592 * Parse an export directive. The [commentAndMetadata] is the metadata to be |
| 5642 * associated with the directive. Return the export directive that was parsed. | 2593 * associated with the directive. Return the export directive that was parsed. |
| 5643 * | 2594 * |
| 2595 * This method assumes that the current token matches `Keyword.EXPORT`. |
| 2596 * |
| 5644 * exportDirective ::= | 2597 * exportDirective ::= |
| 5645 * metadata 'export' stringLiteral combinator*';' | 2598 * metadata 'export' stringLiteral configuration* combinator*';' |
| 5646 */ | 2599 */ |
| 5647 ExportDirective _parseExportDirective(CommentAndMetadata commentAndMetadata) { | 2600 ExportDirective parseExportDirective(CommentAndMetadata commentAndMetadata) { |
| 5648 Token exportKeyword = _expectKeyword(Keyword.EXPORT); | 2601 Token exportKeyword = getAndAdvance(); |
| 5649 StringLiteral libraryUri = _parseUri(); | 2602 StringLiteral libraryUri = _parseUri(); |
| 5650 List<Combinator> combinators = _parseCombinators(); | 2603 List<Configuration> configurations = _parseConfigurations(); |
| 5651 Token semicolon = _expectSemicolon(); | 2604 List<Combinator> combinators = parseCombinators(); |
| 2605 Token semicolon = _expect(TokenType.SEMICOLON); |
| 5652 return new ExportDirective( | 2606 return new ExportDirective( |
| 5653 commentAndMetadata.comment, | 2607 commentAndMetadata.comment, |
| 5654 commentAndMetadata.metadata, | 2608 commentAndMetadata.metadata, |
| 5655 exportKeyword, | 2609 exportKeyword, |
| 5656 libraryUri, | 2610 libraryUri, |
| 2611 configurations, |
| 5657 combinators, | 2612 combinators, |
| 5658 semicolon); | 2613 semicolon); |
| 5659 } | 2614 } |
| 5660 | 2615 |
| 5661 /** | 2616 /** |
| 2617 * Parse an expression, starting with the given [token]. Return the expression |
| 2618 * that was parsed, or `null` if the tokens do not represent a recognizable |
| 2619 * expression. |
| 2620 */ |
| 2621 Expression parseExpression(Token token) { |
| 2622 _currentToken = token; |
| 2623 return parseExpression2(); |
| 2624 } |
| 2625 |
| 2626 /** |
| 2627 * Parse an expression that might contain a cascade. Return the expression |
| 2628 * that was parsed. |
| 2629 * |
| 2630 * expression ::= |
| 2631 * assignableExpression assignmentOperator expression |
| 2632 * | conditionalExpression cascadeSection* |
| 2633 * | throwExpression |
| 2634 */ |
| 2635 Expression parseExpression2() { |
| 2636 Keyword keyword = _currentToken.keyword; |
| 2637 if (keyword == Keyword.THROW) { |
| 2638 return parseThrowExpression(); |
| 2639 } else if (keyword == Keyword.RETHROW) { |
| 2640 // TODO(brianwilkerson) Rethrow is a statement again. |
| 2641 return parseRethrowExpression(); |
| 2642 } |
| 2643 // |
| 2644 // assignableExpression is a subset of conditionalExpression, so we can |
| 2645 // parse a conditional expression and then determine whether it is followed |
| 2646 // by an assignmentOperator, checking for conformance to the restricted |
| 2647 // grammar after making that determination. |
| 2648 // |
| 2649 Expression expression = parseConditionalExpression(); |
| 2650 TokenType type = _currentToken.type; |
| 2651 if (type == TokenType.PERIOD_PERIOD) { |
| 2652 List<Expression> cascadeSections = <Expression>[]; |
| 2653 do { |
| 2654 Expression section = parseCascadeSection(); |
| 2655 if (section != null) { |
| 2656 cascadeSections.add(section); |
| 2657 } |
| 2658 } while (_currentToken.type == TokenType.PERIOD_PERIOD); |
| 2659 return new CascadeExpression(expression, cascadeSections); |
| 2660 } else if (type.isAssignmentOperator) { |
| 2661 Token operator = getAndAdvance(); |
| 2662 _ensureAssignable(expression); |
| 2663 return new AssignmentExpression(expression, operator, parseExpression2()); |
| 2664 } |
| 2665 return expression; |
| 2666 } |
| 2667 |
| 2668 /** |
| 5662 * Parse a list of expressions. Return the expression that was parsed. | 2669 * Parse a list of expressions. Return the expression that was parsed. |
| 5663 * | 2670 * |
| 5664 * expressionList ::= | 2671 * expressionList ::= |
| 5665 * expression (',' expression)* | 2672 * expression (',' expression)* |
| 5666 */ | 2673 */ |
| 5667 List<Expression> _parseExpressionList() { | 2674 List<Expression> parseExpressionList() { |
| 5668 List<Expression> expressions = new List<Expression>(); | 2675 List<Expression> expressions = <Expression>[parseExpression2()]; |
| 5669 expressions.add(parseExpression2()); | |
| 5670 while (_optional(TokenType.COMMA)) { | 2676 while (_optional(TokenType.COMMA)) { |
| 5671 expressions.add(parseExpression2()); | 2677 expressions.add(parseExpression2()); |
| 5672 } | 2678 } |
| 5673 return expressions; | 2679 return expressions; |
| 5674 } | 2680 } |
| 5675 | 2681 |
| 5676 /** | 2682 /** |
| 2683 * Parse an expression that does not contain any cascades. Return the |
| 2684 * expression that was parsed. |
| 2685 * |
| 2686 * expressionWithoutCascade ::= |
| 2687 * assignableExpression assignmentOperator expressionWithoutCascade |
| 2688 * | conditionalExpression |
| 2689 * | throwExpressionWithoutCascade |
| 2690 */ |
| 2691 Expression parseExpressionWithoutCascade() { |
| 2692 if (_matchesKeyword(Keyword.THROW)) { |
| 2693 return parseThrowExpressionWithoutCascade(); |
| 2694 } else if (_matchesKeyword(Keyword.RETHROW)) { |
| 2695 return parseRethrowExpression(); |
| 2696 } |
| 2697 // |
| 2698 // assignableExpression is a subset of conditionalExpression, so we can |
| 2699 // parse a conditional expression and then determine whether it is followed |
| 2700 // by an assignmentOperator, checking for conformance to the restricted |
| 2701 // grammar after making that determination. |
| 2702 // |
| 2703 Expression expression = parseConditionalExpression(); |
| 2704 if (_currentToken.type.isAssignmentOperator) { |
| 2705 Token operator = getAndAdvance(); |
| 2706 _ensureAssignable(expression); |
| 2707 expression = new AssignmentExpression( |
| 2708 expression, operator, parseExpressionWithoutCascade()); |
| 2709 } |
| 2710 return expression; |
| 2711 } |
| 2712 |
| 2713 /** |
| 2714 * Parse a class extends clause. Return the class extends clause that was |
| 2715 * parsed. |
| 2716 * |
| 2717 * This method assumes that the current token matches `Keyword.EXTENDS`. |
| 2718 * |
| 2719 * classExtendsClause ::= |
| 2720 * 'extends' type |
| 2721 */ |
| 2722 ExtendsClause parseExtendsClause() { |
| 2723 Token keyword = getAndAdvance(); |
| 2724 TypeName superclass = parseTypeName(false); |
| 2725 _mustNotBeNullable(superclass, ParserErrorCode.NULLABLE_TYPE_IN_EXTENDS); |
| 2726 return new ExtendsClause(keyword, superclass); |
| 2727 } |
| 2728 |
| 2729 /** |
| 5677 * Parse the 'final', 'const', 'var' or type preceding a variable declaration. | 2730 * Parse the 'final', 'const', 'var' or type preceding a variable declaration. |
| 5678 * The [optional] is `true` if the keyword and type are optional. Return the | 2731 * The [optional] is `true` if the keyword and type are optional. Return the |
| 5679 * 'final', 'const', 'var' or type that was parsed. | 2732 * 'final', 'const', 'var' or type that was parsed. |
| 5680 * | 2733 * |
| 5681 * finalConstVarOrType ::= | 2734 * finalConstVarOrType ::= |
| 5682 * 'final' type? | 2735 * 'final' type? |
| 5683 * | 'const' type? | 2736 * | 'const' type? |
| 5684 * | 'var' | 2737 * | 'var' |
| 5685 * | type | 2738 * | type |
| 5686 */ | 2739 */ |
| 5687 FinalConstVarOrType _parseFinalConstVarOrType(bool optional) { | 2740 FinalConstVarOrType parseFinalConstVarOrType(bool optional) { |
| 5688 Token keyword = null; | 2741 Token keywordToken = null; |
| 5689 TypeName type = null; | 2742 TypeName type = null; |
| 5690 if (_matchesKeyword(Keyword.FINAL) || _matchesKeyword(Keyword.CONST)) { | 2743 Keyword keyword = _currentToken.keyword; |
| 5691 keyword = getAndAdvance(); | 2744 if (keyword == Keyword.FINAL || keyword == Keyword.CONST) { |
| 2745 keywordToken = getAndAdvance(); |
| 5692 if (_isTypedIdentifier(_currentToken)) { | 2746 if (_isTypedIdentifier(_currentToken)) { |
| 5693 type = parseTypeName(); | 2747 type = parseTypeName(false); |
| 2748 } else { |
| 2749 // Support `final/*=T*/ x;` |
| 2750 type = _parseOptionalTypeNameComment(); |
| 5694 } | 2751 } |
| 5695 } else if (_matchesKeyword(Keyword.VAR)) { | 2752 } else if (keyword == Keyword.VAR) { |
| 5696 keyword = getAndAdvance(); | 2753 keywordToken = getAndAdvance(); |
| 2754 // Support `var/*=T*/ x;` |
| 2755 type = _parseOptionalTypeNameComment(); |
| 2756 if (type != null) { |
| 2757 // Clear the keyword to prevent an error. |
| 2758 keywordToken = null; |
| 2759 } |
| 2760 } else if (_isTypedIdentifier(_currentToken)) { |
| 2761 type = parseReturnType(); |
| 2762 } else if (!optional) { |
| 2763 _reportErrorForCurrentToken( |
| 2764 ParserErrorCode.MISSING_CONST_FINAL_VAR_OR_TYPE); |
| 5697 } else { | 2765 } else { |
| 5698 if (_isTypedIdentifier(_currentToken)) { | 2766 // Support parameters such as `(/*=K*/ key, /*=V*/ value)` |
| 5699 type = parseReturnType(); | 2767 // This is not supported if the type is required. |
| 5700 } else if (!optional) { | 2768 type = _parseOptionalTypeNameComment(); |
| 5701 _reportErrorForCurrentToken( | |
| 5702 ParserErrorCode.MISSING_CONST_FINAL_VAR_OR_TYPE); | |
| 5703 } | |
| 5704 } | 2769 } |
| 5705 return new FinalConstVarOrType(keyword, type); | 2770 return new FinalConstVarOrType(keywordToken, type); |
| 5706 } | 2771 } |
| 5707 | 2772 |
| 5708 /** | 2773 /** |
| 5709 * Parse a formal parameter. At most one of `isOptional` and `isNamed` can be | 2774 * Parse a formal parameter. At most one of `isOptional` and `isNamed` can be |
| 5710 * `true`. The [kind] is the kind of parameter being expected based on the | 2775 * `true`. The [kind] is the kind of parameter being expected based on the |
| 5711 * presence or absence of group delimiters. Return the formal parameter that | 2776 * presence or absence of group delimiters. Return the formal parameter that |
| 5712 * was parsed. | 2777 * was parsed. |
| 5713 * | 2778 * |
| 5714 * defaultFormalParameter ::= | 2779 * defaultFormalParameter ::= |
| 5715 * normalFormalParameter ('=' expression)? | 2780 * normalFormalParameter ('=' expression)? |
| 5716 * | 2781 * |
| 5717 * defaultNamedParameter ::= | 2782 * defaultNamedParameter ::= |
| 5718 * normalFormalParameter (':' expression)? | 2783 * normalFormalParameter (':' expression)? |
| 5719 */ | 2784 */ |
| 5720 FormalParameter _parseFormalParameter(ParameterKind kind) { | 2785 FormalParameter parseFormalParameter(ParameterKind kind) { |
| 5721 NormalFormalParameter parameter = parseNormalFormalParameter(); | 2786 NormalFormalParameter parameter = parseNormalFormalParameter(); |
| 5722 if (_matches(TokenType.EQ)) { | 2787 TokenType type = _currentToken.type; |
| 5723 Token seperator = getAndAdvance(); | 2788 if (type == TokenType.EQ) { |
| 2789 Token separator = getAndAdvance(); |
| 5724 Expression defaultValue = parseExpression2(); | 2790 Expression defaultValue = parseExpression2(); |
| 5725 if (kind == ParameterKind.NAMED) { | 2791 if (kind == ParameterKind.NAMED) { |
| 5726 _reportErrorForToken( | 2792 _reportErrorForToken( |
| 5727 ParserErrorCode.WRONG_SEPARATOR_FOR_NAMED_PARAMETER, seperator); | 2793 ParserErrorCode.WRONG_SEPARATOR_FOR_NAMED_PARAMETER, separator); |
| 5728 } else if (kind == ParameterKind.REQUIRED) { | 2794 } else if (kind == ParameterKind.REQUIRED) { |
| 5729 _reportErrorForNode( | 2795 _reportErrorForNode( |
| 5730 ParserErrorCode.POSITIONAL_PARAMETER_OUTSIDE_GROUP, parameter); | 2796 ParserErrorCode.POSITIONAL_PARAMETER_OUTSIDE_GROUP, parameter); |
| 5731 } | 2797 } |
| 5732 return new DefaultFormalParameter( | 2798 return new DefaultFormalParameter( |
| 5733 parameter, kind, seperator, defaultValue); | 2799 parameter, kind, separator, defaultValue); |
| 5734 } else if (_matches(TokenType.COLON)) { | 2800 } else if (type == TokenType.COLON) { |
| 5735 Token seperator = getAndAdvance(); | 2801 Token separator = getAndAdvance(); |
| 5736 Expression defaultValue = parseExpression2(); | 2802 Expression defaultValue = parseExpression2(); |
| 5737 if (kind == ParameterKind.POSITIONAL) { | 2803 if (kind == ParameterKind.POSITIONAL) { |
| 5738 _reportErrorForToken( | 2804 _reportErrorForToken( |
| 5739 ParserErrorCode.WRONG_SEPARATOR_FOR_POSITIONAL_PARAMETER, | 2805 ParserErrorCode.WRONG_SEPARATOR_FOR_POSITIONAL_PARAMETER, |
| 5740 seperator); | 2806 separator); |
| 5741 } else if (kind == ParameterKind.REQUIRED) { | 2807 } else if (kind == ParameterKind.REQUIRED) { |
| 5742 _reportErrorForNode( | 2808 _reportErrorForNode( |
| 5743 ParserErrorCode.NAMED_PARAMETER_OUTSIDE_GROUP, parameter); | 2809 ParserErrorCode.NAMED_PARAMETER_OUTSIDE_GROUP, parameter); |
| 5744 } | 2810 } |
| 5745 return new DefaultFormalParameter( | 2811 return new DefaultFormalParameter( |
| 5746 parameter, kind, seperator, defaultValue); | 2812 parameter, kind, separator, defaultValue); |
| 5747 } else if (kind != ParameterKind.REQUIRED) { | 2813 } else if (kind != ParameterKind.REQUIRED) { |
| 5748 return new DefaultFormalParameter(parameter, kind, null, null); | 2814 return new DefaultFormalParameter(parameter, kind, null, null); |
| 5749 } | 2815 } |
| 5750 return parameter; | 2816 return parameter; |
| 5751 } | 2817 } |
| 5752 | 2818 |
| 5753 /** | 2819 /** |
| 2820 * Parse a list of formal parameters. Return the formal parameters that were |
| 2821 * parsed. |
| 2822 * |
| 2823 * formalParameterList ::= |
| 2824 * '(' ')' |
| 2825 * | '(' normalFormalParameters (',' optionalFormalParameters)? ')' |
| 2826 * | '(' optionalFormalParameters ')' |
| 2827 * |
| 2828 * normalFormalParameters ::= |
| 2829 * normalFormalParameter (',' normalFormalParameter)* |
| 2830 * |
| 2831 * optionalFormalParameters ::= |
| 2832 * optionalPositionalFormalParameters |
| 2833 * | namedFormalParameters |
| 2834 * |
| 2835 * optionalPositionalFormalParameters ::= |
| 2836 * '[' defaultFormalParameter (',' defaultFormalParameter)* ']' |
| 2837 * |
| 2838 * namedFormalParameters ::= |
| 2839 * '{' defaultNamedParameter (',' defaultNamedParameter)* '}' |
| 2840 */ |
| 2841 FormalParameterList parseFormalParameterList() { |
| 2842 if (_matches(TokenType.OPEN_PAREN)) { |
| 2843 return _parseFormalParameterListUnchecked(); |
| 2844 } |
| 2845 // TODO(brianwilkerson) Improve the error message. |
| 2846 _reportErrorForCurrentToken( |
| 2847 ParserErrorCode.EXPECTED_TOKEN, [TokenType.OPEN_PAREN.lexeme]); |
| 2848 // Recovery: Check for an unmatched closing paren and parse parameters until |
| 2849 // it is reached. |
| 2850 return _parseFormalParameterListAfterParen( |
| 2851 _createSyntheticToken(TokenType.OPEN_PAREN)); |
| 2852 } |
| 2853 |
| 2854 /** |
| 5754 * Parse a for statement. Return the for statement that was parsed. | 2855 * Parse a for statement. Return the for statement that was parsed. |
| 5755 * | 2856 * |
| 5756 * forStatement ::= | 2857 * forStatement ::= |
| 5757 * 'for' '(' forLoopParts ')' statement | 2858 * 'for' '(' forLoopParts ')' statement |
| 5758 * | 2859 * |
| 5759 * forLoopParts ::= | 2860 * forLoopParts ::= |
| 5760 * forInitializerStatement expression? ';' expressionList? | 2861 * forInitializerStatement expression? ';' expressionList? |
| 5761 * | declaredIdentifier 'in' expression | 2862 * | declaredIdentifier 'in' expression |
| 5762 * | identifier 'in' expression | 2863 * | identifier 'in' expression |
| 5763 * | 2864 * |
| 5764 * forInitializerStatement ::= | 2865 * forInitializerStatement ::= |
| 5765 * localVariableDeclaration ';' | 2866 * localVariableDeclaration ';' |
| 5766 * | expression? ';' | 2867 * | expression? ';' |
| 5767 */ | 2868 */ |
| 5768 Statement _parseForStatement() { | 2869 Statement parseForStatement() { |
| 5769 bool wasInLoop = _inLoop; | 2870 bool wasInLoop = _inLoop; |
| 5770 _inLoop = true; | 2871 _inLoop = true; |
| 5771 try { | 2872 try { |
| 5772 Token awaitKeyword = null; | 2873 Token awaitKeyword = null; |
| 5773 if (_matchesString(_AWAIT)) { | 2874 if (_matchesString(_AWAIT)) { |
| 5774 awaitKeyword = getAndAdvance(); | 2875 awaitKeyword = getAndAdvance(); |
| 5775 } | 2876 } |
| 5776 Token forKeyword = _expectKeyword(Keyword.FOR); | 2877 Token forKeyword = _expectKeyword(Keyword.FOR); |
| 5777 Token leftParenthesis = _expect(TokenType.OPEN_PAREN); | 2878 Token leftParenthesis = _expect(TokenType.OPEN_PAREN); |
| 5778 VariableDeclarationList variableList = null; | 2879 VariableDeclarationList variableList = null; |
| 5779 Expression initialization = null; | 2880 Expression initialization = null; |
| 5780 if (!_matches(TokenType.SEMICOLON)) { | 2881 if (!_matches(TokenType.SEMICOLON)) { |
| 5781 CommentAndMetadata commentAndMetadata = _parseCommentAndMetadata(); | 2882 CommentAndMetadata commentAndMetadata = parseCommentAndMetadata(); |
| 5782 if (_matchesIdentifier() && | 2883 if (_matchesIdentifier() && |
| 5783 (_tokenMatchesKeyword(_peek(), Keyword.IN) || | 2884 (_tokenMatchesKeyword(_peek(), Keyword.IN) || |
| 5784 _tokenMatches(_peek(), TokenType.COLON))) { | 2885 _tokenMatches(_peek(), TokenType.COLON))) { |
| 5785 List<VariableDeclaration> variables = new List<VariableDeclaration>(); | 2886 SimpleIdentifier variableName = _parseSimpleIdentifierUnchecked(); |
| 5786 SimpleIdentifier variableName = parseSimpleIdentifier(); | |
| 5787 variables.add(new VariableDeclaration(variableName, null, null)); | |
| 5788 variableList = new VariableDeclarationList(commentAndMetadata.comment, | 2887 variableList = new VariableDeclarationList(commentAndMetadata.comment, |
| 5789 commentAndMetadata.metadata, null, null, variables); | 2888 commentAndMetadata.metadata, null, null, <VariableDeclaration>[ |
| 5790 } else if (_isInitializedVariableDeclaration()) { | 2889 new VariableDeclaration(variableName, null, null) |
| 2890 ]); |
| 2891 } else if (isInitializedVariableDeclaration()) { |
| 5791 variableList = | 2892 variableList = |
| 5792 _parseVariableDeclarationListAfterMetadata(commentAndMetadata); | 2893 parseVariableDeclarationListAfterMetadata(commentAndMetadata); |
| 5793 } else { | 2894 } else { |
| 5794 initialization = parseExpression2(); | 2895 initialization = parseExpression2(); |
| 5795 } | 2896 } |
| 5796 if (_matchesKeyword(Keyword.IN) || _matches(TokenType.COLON)) { | 2897 TokenType type = _currentToken.type; |
| 5797 if (_matches(TokenType.COLON)) { | 2898 if (_matchesKeyword(Keyword.IN) || type == TokenType.COLON) { |
| 2899 if (type == TokenType.COLON) { |
| 5798 _reportErrorForCurrentToken(ParserErrorCode.COLON_IN_PLACE_OF_IN); | 2900 _reportErrorForCurrentToken(ParserErrorCode.COLON_IN_PLACE_OF_IN); |
| 5799 } | 2901 } |
| 5800 DeclaredIdentifier loopVariable = null; | 2902 DeclaredIdentifier loopVariable = null; |
| 5801 SimpleIdentifier identifier = null; | 2903 SimpleIdentifier identifier = null; |
| 5802 if (variableList == null) { | 2904 if (variableList == null) { |
| 5803 // We found: <expression> 'in' | 2905 // We found: <expression> 'in' |
| 5804 _reportErrorForCurrentToken( | 2906 _reportErrorForCurrentToken( |
| 5805 ParserErrorCode.MISSING_VARIABLE_IN_FOR_EACH); | 2907 ParserErrorCode.MISSING_VARIABLE_IN_FOR_EACH); |
| 5806 } else { | 2908 } else { |
| 5807 NodeList<VariableDeclaration> variables = variableList.variables; | 2909 NodeList<VariableDeclaration> variables = variableList.variables; |
| 5808 if (variables.length > 1) { | 2910 if (variables.length > 1) { |
| 5809 _reportErrorForCurrentToken( | 2911 _reportErrorForCurrentToken( |
| 5810 ParserErrorCode.MULTIPLE_VARIABLES_IN_FOR_EACH, | 2912 ParserErrorCode.MULTIPLE_VARIABLES_IN_FOR_EACH, |
| 5811 [variables.length.toString()]); | 2913 [variables.length.toString()]); |
| 5812 } | 2914 } |
| 5813 VariableDeclaration variable = variables[0]; | 2915 VariableDeclaration variable = variables[0]; |
| 5814 if (variable.initializer != null) { | 2916 if (variable.initializer != null) { |
| 5815 _reportErrorForCurrentToken( | 2917 _reportErrorForCurrentToken( |
| 5816 ParserErrorCode.INITIALIZED_VARIABLE_IN_FOR_EACH); | 2918 ParserErrorCode.INITIALIZED_VARIABLE_IN_FOR_EACH); |
| 5817 } | 2919 } |
| 5818 Token keyword = variableList.keyword; | 2920 Token keyword = variableList.keyword; |
| 5819 TypeName type = variableList.type; | 2921 TypeName type = variableList.type; |
| 5820 if (keyword != null || type != null) { | 2922 if (keyword != null || type != null) { |
| 5821 loopVariable = new DeclaredIdentifier(commentAndMetadata.comment, | 2923 loopVariable = new DeclaredIdentifier( |
| 5822 commentAndMetadata.metadata, keyword, type, variable.name); | 2924 commentAndMetadata.comment, |
| 2925 commentAndMetadata.metadata, |
| 2926 keyword, |
| 2927 type, |
| 2928 new SimpleIdentifier(variable.name.token, |
| 2929 isDeclaration: true)); |
| 5823 } else { | 2930 } else { |
| 5824 if (!commentAndMetadata.metadata.isEmpty) { | 2931 if (commentAndMetadata.hasMetadata) { |
| 5825 // TODO(jwren) metadata isn't allowed before the identifier in | 2932 // TODO(jwren) metadata isn't allowed before the identifier in |
| 5826 // "identifier in expression", add warning if commentAndMetadata | 2933 // "identifier in expression", add warning if commentAndMetadata |
| 5827 // has content | 2934 // has content |
| 5828 } | 2935 } |
| 5829 identifier = variable.name; | 2936 identifier = variable.name; |
| 5830 } | 2937 } |
| 5831 } | 2938 } |
| 5832 Token inKeyword = getAndAdvance(); | 2939 Token inKeyword = getAndAdvance(); |
| 5833 Expression iterator = parseExpression2(); | 2940 Expression iterator = parseExpression2(); |
| 5834 Token rightParenthesis = _expect(TokenType.CLOSE_PAREN); | 2941 Token rightParenthesis = _expect(TokenType.CLOSE_PAREN); |
| (...skipping 17 matching lines...) Expand all Loading... |
| 5852 inKeyword, | 2959 inKeyword, |
| 5853 iterator, | 2960 iterator, |
| 5854 rightParenthesis, | 2961 rightParenthesis, |
| 5855 body); | 2962 body); |
| 5856 } | 2963 } |
| 5857 } | 2964 } |
| 5858 if (awaitKeyword != null) { | 2965 if (awaitKeyword != null) { |
| 5859 _reportErrorForToken( | 2966 _reportErrorForToken( |
| 5860 ParserErrorCode.INVALID_AWAIT_IN_FOR, awaitKeyword); | 2967 ParserErrorCode.INVALID_AWAIT_IN_FOR, awaitKeyword); |
| 5861 } | 2968 } |
| 5862 Token leftSeparator = _expectSemicolon(); | 2969 Token leftSeparator = _expect(TokenType.SEMICOLON); |
| 5863 Expression condition = null; | 2970 Expression condition = null; |
| 5864 if (!_matches(TokenType.SEMICOLON)) { | 2971 if (!_matches(TokenType.SEMICOLON)) { |
| 5865 condition = parseExpression2(); | 2972 condition = parseExpression2(); |
| 5866 } | 2973 } |
| 5867 Token rightSeparator = _expectSemicolon(); | 2974 Token rightSeparator = _expect(TokenType.SEMICOLON); |
| 5868 List<Expression> updaters = null; | 2975 List<Expression> updaters = null; |
| 5869 if (!_matches(TokenType.CLOSE_PAREN)) { | 2976 if (!_matches(TokenType.CLOSE_PAREN)) { |
| 5870 updaters = _parseExpressionList(); | 2977 updaters = parseExpressionList(); |
| 5871 } | 2978 } |
| 5872 Token rightParenthesis = _expect(TokenType.CLOSE_PAREN); | 2979 Token rightParenthesis = _expect(TokenType.CLOSE_PAREN); |
| 5873 Statement body = parseStatement2(); | 2980 Statement body = parseStatement2(); |
| 5874 return new ForStatement( | 2981 return new ForStatement( |
| 5875 forKeyword, | 2982 forKeyword, |
| 5876 leftParenthesis, | 2983 leftParenthesis, |
| 5877 variableList, | 2984 variableList, |
| 5878 initialization, | 2985 initialization, |
| 5879 leftSeparator, | 2986 leftSeparator, |
| 5880 condition, | 2987 condition, |
| (...skipping 14 matching lines...) Expand all Loading... |
| 5895 * not have a terminating semicolon. Return the function body that was parsed. | 3002 * not have a terminating semicolon. Return the function body that was parsed. |
| 5896 * | 3003 * |
| 5897 * functionBody ::= | 3004 * functionBody ::= |
| 5898 * '=>' expression ';' | 3005 * '=>' expression ';' |
| 5899 * | block | 3006 * | block |
| 5900 * | 3007 * |
| 5901 * functionExpressionBody ::= | 3008 * functionExpressionBody ::= |
| 5902 * '=>' expression | 3009 * '=>' expression |
| 5903 * | block | 3010 * | block |
| 5904 */ | 3011 */ |
| 5905 FunctionBody _parseFunctionBody( | 3012 FunctionBody parseFunctionBody( |
| 5906 bool mayBeEmpty, ParserErrorCode emptyErrorCode, bool inExpression) { | 3013 bool mayBeEmpty, ParserErrorCode emptyErrorCode, bool inExpression) { |
| 5907 bool wasInAsync = _inAsync; | 3014 bool wasInAsync = _inAsync; |
| 5908 bool wasInGenerator = _inGenerator; | 3015 bool wasInGenerator = _inGenerator; |
| 5909 bool wasInLoop = _inLoop; | 3016 bool wasInLoop = _inLoop; |
| 5910 bool wasInSwitch = _inSwitch; | 3017 bool wasInSwitch = _inSwitch; |
| 5911 _inAsync = false; | 3018 _inAsync = false; |
| 5912 _inGenerator = false; | 3019 _inGenerator = false; |
| 5913 _inLoop = false; | 3020 _inLoop = false; |
| 5914 _inSwitch = false; | 3021 _inSwitch = false; |
| 5915 try { | 3022 try { |
| 5916 if (_matches(TokenType.SEMICOLON)) { | 3023 TokenType type = _currentToken.type; |
| 3024 if (type == TokenType.SEMICOLON) { |
| 5917 if (!mayBeEmpty) { | 3025 if (!mayBeEmpty) { |
| 5918 _reportErrorForCurrentToken(emptyErrorCode); | 3026 _reportErrorForCurrentToken(emptyErrorCode); |
| 5919 } | 3027 } |
| 5920 return new EmptyFunctionBody(getAndAdvance()); | 3028 return new EmptyFunctionBody(getAndAdvance()); |
| 5921 } else if (_matchesString(_NATIVE)) { | |
| 5922 Token nativeToken = getAndAdvance(); | |
| 5923 StringLiteral stringLiteral = null; | |
| 5924 if (_matches(TokenType.STRING)) { | |
| 5925 stringLiteral = parseStringLiteral(); | |
| 5926 } | |
| 5927 return new NativeFunctionBody( | |
| 5928 nativeToken, stringLiteral, _expect(TokenType.SEMICOLON)); | |
| 5929 } | 3029 } |
| 5930 Token keyword = null; | 3030 Token keyword = null; |
| 5931 Token star = null; | 3031 Token star = null; |
| 5932 if (_matchesString(ASYNC)) { | 3032 bool foundAsync = false; |
| 5933 keyword = getAndAdvance(); | 3033 bool foundSync = false; |
| 5934 if (_matches(TokenType.STAR)) { | 3034 if (type == TokenType.IDENTIFIER) { |
| 5935 star = getAndAdvance(); | 3035 String lexeme = _currentToken.lexeme; |
| 5936 _inGenerator = true; | 3036 if (lexeme == ASYNC) { |
| 5937 } | 3037 foundAsync = true; |
| 5938 _inAsync = true; | 3038 keyword = getAndAdvance(); |
| 5939 } else if (_matchesString(SYNC)) { | 3039 if (_matches(TokenType.STAR)) { |
| 5940 keyword = getAndAdvance(); | 3040 star = getAndAdvance(); |
| 5941 if (_matches(TokenType.STAR)) { | 3041 _inGenerator = true; |
| 5942 star = getAndAdvance(); | 3042 } |
| 5943 _inGenerator = true; | 3043 type = _currentToken.type; |
| 3044 _inAsync = true; |
| 3045 } else if (lexeme == SYNC) { |
| 3046 foundSync = true; |
| 3047 keyword = getAndAdvance(); |
| 3048 if (_matches(TokenType.STAR)) { |
| 3049 star = getAndAdvance(); |
| 3050 _inGenerator = true; |
| 3051 } |
| 3052 type = _currentToken.type; |
| 5944 } | 3053 } |
| 5945 } | 3054 } |
| 5946 if (_matches(TokenType.FUNCTION)) { | 3055 if (type == TokenType.FUNCTION) { |
| 5947 if (keyword != null) { | 3056 if (keyword != null) { |
| 5948 if (!_tokenMatchesString(keyword, ASYNC)) { | 3057 if (!foundAsync) { |
| 5949 _reportErrorForToken(ParserErrorCode.INVALID_SYNC, keyword); | 3058 _reportErrorForToken(ParserErrorCode.INVALID_SYNC, keyword); |
| 5950 keyword = null; | 3059 keyword = null; |
| 5951 } else if (star != null) { | 3060 } else if (star != null) { |
| 5952 _reportErrorForToken( | 3061 _reportErrorForToken( |
| 5953 ParserErrorCode.INVALID_STAR_AFTER_ASYNC, star); | 3062 ParserErrorCode.INVALID_STAR_AFTER_ASYNC, star); |
| 5954 } | 3063 } |
| 5955 } | 3064 } |
| 5956 Token functionDefinition = getAndAdvance(); | 3065 Token functionDefinition = getAndAdvance(); |
| 5957 if (_matchesKeyword(Keyword.RETURN)) { | 3066 if (_matchesKeyword(Keyword.RETURN)) { |
| 5958 _reportErrorForToken(ParserErrorCode.UNEXPECTED_TOKEN, _currentToken, | 3067 _reportErrorForToken(ParserErrorCode.UNEXPECTED_TOKEN, _currentToken, |
| 5959 [_currentToken.lexeme]); | 3068 [_currentToken.lexeme]); |
| 5960 _advance(); | 3069 _advance(); |
| 5961 } | 3070 } |
| 5962 Expression expression = parseExpression2(); | 3071 Expression expression = parseExpression2(); |
| 5963 Token semicolon = null; | 3072 Token semicolon = null; |
| 5964 if (!inExpression) { | 3073 if (!inExpression) { |
| 5965 semicolon = _expect(TokenType.SEMICOLON); | 3074 semicolon = _expect(TokenType.SEMICOLON); |
| 5966 } | 3075 } |
| 5967 if (!_parseFunctionBodies) { | 3076 if (!_parseFunctionBodies) { |
| 5968 return new EmptyFunctionBody( | 3077 return new EmptyFunctionBody( |
| 5969 _createSyntheticToken(TokenType.SEMICOLON)); | 3078 _createSyntheticToken(TokenType.SEMICOLON)); |
| 5970 } | 3079 } |
| 5971 return new ExpressionFunctionBody( | 3080 return new ExpressionFunctionBody( |
| 5972 keyword, functionDefinition, expression, semicolon); | 3081 keyword, functionDefinition, expression, semicolon); |
| 5973 } else if (_matches(TokenType.OPEN_CURLY_BRACKET)) { | 3082 } else if (type == TokenType.OPEN_CURLY_BRACKET) { |
| 5974 if (keyword != null) { | 3083 if (keyword != null) { |
| 5975 if (_tokenMatchesString(keyword, SYNC) && star == null) { | 3084 if (foundSync && star == null) { |
| 5976 _reportErrorForToken( | 3085 _reportErrorForToken( |
| 5977 ParserErrorCode.MISSING_STAR_AFTER_SYNC, keyword); | 3086 ParserErrorCode.MISSING_STAR_AFTER_SYNC, keyword); |
| 5978 } | 3087 } |
| 5979 } | 3088 } |
| 5980 if (!_parseFunctionBodies) { | 3089 if (!_parseFunctionBodies) { |
| 5981 _skipBlock(); | 3090 _skipBlock(); |
| 5982 return new EmptyFunctionBody( | 3091 return new EmptyFunctionBody( |
| 5983 _createSyntheticToken(TokenType.SEMICOLON)); | 3092 _createSyntheticToken(TokenType.SEMICOLON)); |
| 5984 } | 3093 } |
| 5985 return new BlockFunctionBody(keyword, star, parseBlock()); | 3094 return new BlockFunctionBody(keyword, star, parseBlock()); |
| 3095 } else if (_matchesString(_NATIVE)) { |
| 3096 Token nativeToken = getAndAdvance(); |
| 3097 StringLiteral stringLiteral = null; |
| 3098 if (_matches(TokenType.STRING)) { |
| 3099 stringLiteral = _parseStringLiteralUnchecked(); |
| 3100 } |
| 3101 return new NativeFunctionBody( |
| 3102 nativeToken, stringLiteral, _expect(TokenType.SEMICOLON)); |
| 5986 } else { | 3103 } else { |
| 5987 // Invalid function body | 3104 // Invalid function body |
| 5988 _reportErrorForCurrentToken(emptyErrorCode); | 3105 _reportErrorForCurrentToken(emptyErrorCode); |
| 5989 return new EmptyFunctionBody( | 3106 return new EmptyFunctionBody( |
| 5990 _createSyntheticToken(TokenType.SEMICOLON)); | 3107 _createSyntheticToken(TokenType.SEMICOLON)); |
| 5991 } | 3108 } |
| 5992 } finally { | 3109 } finally { |
| 5993 _inAsync = wasInAsync; | 3110 _inAsync = wasInAsync; |
| 5994 _inGenerator = wasInGenerator; | 3111 _inGenerator = wasInGenerator; |
| 5995 _inLoop = wasInLoop; | 3112 _inLoop = wasInLoop; |
| 5996 _inSwitch = wasInSwitch; | 3113 _inSwitch = wasInSwitch; |
| 5997 } | 3114 } |
| 5998 } | 3115 } |
| 5999 | 3116 |
| 6000 /** | 3117 /** |
| 6001 * Parse a function declaration. The [commentAndMetadata] is the documentation | 3118 * Parse a function declaration. The [commentAndMetadata] is the documentation |
| 6002 * comment and metadata to be associated with the declaration. The | 3119 * comment and metadata to be associated with the declaration. The |
| 6003 * [externalKeyword] is the 'external' keyword, or `null` if the function is | 3120 * [externalKeyword] is the 'external' keyword, or `null` if the function is |
| 6004 * not external. The [returnType] is the return type, or `null` if there is no | 3121 * not external. The [returnType] is the return type, or `null` if there is no |
| 6005 * return type. The [isStatement] is `true` if the function declaration is | 3122 * return type. The [isStatement] is `true` if the function declaration is |
| 6006 * being parsed as a statement. Return the function declaration that was | 3123 * being parsed as a statement. Return the function declaration that was |
| 6007 * parsed. | 3124 * parsed. |
| 6008 * | 3125 * |
| 6009 * functionDeclaration ::= | 3126 * functionDeclaration ::= |
| 6010 * functionSignature functionBody | 3127 * functionSignature functionBody |
| 6011 * | returnType? getOrSet identifier formalParameterList functionBody | 3128 * | returnType? getOrSet identifier formalParameterList functionBody |
| 6012 */ | 3129 */ |
| 6013 FunctionDeclaration _parseFunctionDeclaration( | 3130 FunctionDeclaration parseFunctionDeclaration( |
| 6014 CommentAndMetadata commentAndMetadata, | 3131 CommentAndMetadata commentAndMetadata, |
| 6015 Token externalKeyword, | 3132 Token externalKeyword, |
| 6016 TypeName returnType) { | 3133 TypeName returnType) { |
| 6017 Token keyword = null; | 3134 Token keywordToken = null; |
| 6018 bool isGetter = false; | 3135 bool isGetter = false; |
| 6019 if (_matchesKeyword(Keyword.GET) && | 3136 Keyword keyword = _currentToken.keyword; |
| 6020 !_tokenMatches(_peek(), TokenType.OPEN_PAREN)) { | 3137 SimpleIdentifier name = null; |
| 6021 keyword = getAndAdvance(); | 3138 if (keyword == Keyword.GET) { |
| 3139 keywordToken = getAndAdvance(); |
| 6022 isGetter = true; | 3140 isGetter = true; |
| 6023 } else if (_matchesKeyword(Keyword.SET) && | 3141 } else if (keyword == Keyword.SET) { |
| 6024 !_tokenMatches(_peek(), TokenType.OPEN_PAREN)) { | 3142 keywordToken = getAndAdvance(); |
| 6025 keyword = getAndAdvance(); | |
| 6026 } | 3143 } |
| 6027 SimpleIdentifier name = parseSimpleIdentifier(); | 3144 if (keywordToken != null && _matches(TokenType.OPEN_PAREN)) { |
| 6028 TypeParameterList typeParameters = null; | 3145 name = new SimpleIdentifier(keywordToken, isDeclaration: true); |
| 6029 if (parseGenericMethods && _matches(TokenType.LT)) { | 3146 keywordToken = null; |
| 6030 typeParameters = parseTypeParameterList(); | 3147 isGetter = false; |
| 3148 } else { |
| 3149 name = parseSimpleIdentifier(isDeclaration: true); |
| 6031 } | 3150 } |
| 3151 TypeParameterList typeParameters = _parseGenericMethodTypeParameters(); |
| 6032 FormalParameterList parameters = null; | 3152 FormalParameterList parameters = null; |
| 6033 if (!isGetter) { | 3153 if (!isGetter) { |
| 6034 if (_matches(TokenType.OPEN_PAREN)) { | 3154 if (_matches(TokenType.OPEN_PAREN)) { |
| 6035 parameters = parseFormalParameterList(); | 3155 parameters = _parseFormalParameterListUnchecked(); |
| 6036 _validateFormalParameterList(parameters); | 3156 _validateFormalParameterList(parameters); |
| 6037 } else { | 3157 } else { |
| 6038 _reportErrorForCurrentToken( | 3158 _reportErrorForCurrentToken( |
| 6039 ParserErrorCode.MISSING_FUNCTION_PARAMETERS); | 3159 ParserErrorCode.MISSING_FUNCTION_PARAMETERS); |
| 6040 parameters = new FormalParameterList( | 3160 parameters = new FormalParameterList( |
| 6041 _createSyntheticToken(TokenType.OPEN_PAREN), | 3161 _createSyntheticToken(TokenType.OPEN_PAREN), |
| 6042 null, | 3162 null, |
| 6043 null, | 3163 null, |
| 6044 null, | 3164 null, |
| 6045 _createSyntheticToken(TokenType.CLOSE_PAREN)); | 3165 _createSyntheticToken(TokenType.CLOSE_PAREN)); |
| 6046 } | 3166 } |
| 6047 } else if (_matches(TokenType.OPEN_PAREN)) { | 3167 } else if (_matches(TokenType.OPEN_PAREN)) { |
| 6048 _reportErrorForCurrentToken(ParserErrorCode.GETTER_WITH_PARAMETERS); | 3168 _reportErrorForCurrentToken(ParserErrorCode.GETTER_WITH_PARAMETERS); |
| 6049 parseFormalParameterList(); | 3169 _parseFormalParameterListUnchecked(); |
| 6050 } | 3170 } |
| 6051 FunctionBody body; | 3171 FunctionBody body; |
| 6052 if (externalKeyword == null) { | 3172 if (externalKeyword == null) { |
| 6053 body = _parseFunctionBody( | 3173 body = parseFunctionBody( |
| 6054 false, ParserErrorCode.MISSING_FUNCTION_BODY, false); | 3174 false, ParserErrorCode.MISSING_FUNCTION_BODY, false); |
| 6055 } else { | 3175 } else { |
| 6056 body = new EmptyFunctionBody(_expect(TokenType.SEMICOLON)); | 3176 body = new EmptyFunctionBody(_expect(TokenType.SEMICOLON)); |
| 6057 } | 3177 } |
| 6058 // if (!isStatement && matches(TokenType.SEMICOLON)) { | 3178 // if (!isStatement && matches(TokenType.SEMICOLON)) { |
| 6059 // // TODO(brianwilkerson) Improve this error message. | 3179 // // TODO(brianwilkerson) Improve this error message. |
| 6060 // reportError(ParserErrorCode.UNEXPECTED_TOKEN, currentToken.getLexeme
()); | 3180 // reportError(ParserErrorCode.UNEXPECTED_TOKEN, currentToken.getLexeme
()); |
| 6061 // advance(); | 3181 // advance(); |
| 6062 // } | 3182 // } |
| 6063 return new FunctionDeclaration( | 3183 return new FunctionDeclaration( |
| 6064 commentAndMetadata.comment, | 3184 commentAndMetadata.comment, |
| 6065 commentAndMetadata.metadata, | 3185 commentAndMetadata.metadata, |
| 6066 externalKeyword, | 3186 externalKeyword, |
| 6067 returnType, | 3187 returnType, |
| 6068 keyword, | 3188 keywordToken, |
| 6069 name, | 3189 name, |
| 6070 new FunctionExpression(typeParameters, parameters, body)); | 3190 new FunctionExpression(typeParameters, parameters, body)); |
| 6071 } | 3191 } |
| 6072 | 3192 |
| 6073 /** | 3193 /** |
| 6074 * Parse a function declaration statement. Return the function declaration | 3194 * Parse a function declaration statement. Return the function declaration |
| 6075 * statement that was parsed. | 3195 * statement that was parsed. |
| 6076 * | 3196 * |
| 6077 * functionDeclarationStatement ::= | 3197 * functionDeclarationStatement ::= |
| 6078 * functionSignature functionBody | 3198 * functionSignature functionBody |
| 6079 */ | 3199 */ |
| 6080 Statement _parseFunctionDeclarationStatement() { | 3200 Statement parseFunctionDeclarationStatement() { |
| 6081 Modifiers modifiers = _parseModifiers(); | 3201 Modifiers modifiers = parseModifiers(); |
| 6082 _validateModifiersForFunctionDeclarationStatement(modifiers); | 3202 _validateModifiersForFunctionDeclarationStatement(modifiers); |
| 6083 return _parseFunctionDeclarationStatementAfterReturnType( | 3203 return _parseFunctionDeclarationStatementAfterReturnType( |
| 6084 _parseCommentAndMetadata(), _parseOptionalReturnType()); | 3204 parseCommentAndMetadata(), _parseOptionalReturnType()); |
| 6085 } | 3205 } |
| 6086 | 3206 |
| 6087 /** | 3207 /** |
| 6088 * Parse a function declaration statement. The [commentAndMetadata] is the | 3208 * Parse a function expression. Return the function expression that was |
| 6089 * documentation comment and metadata to be associated with the declaration. | 3209 * parsed. |
| 6090 * The [returnType] is the return type, or `null` if there is no return type. | |
| 6091 * Return the function declaration statement that was parsed. | |
| 6092 * | 3210 * |
| 6093 * functionDeclarationStatement ::= | 3211 * functionExpression ::= |
| 6094 * functionSignature functionBody | 3212 * typeParameters? formalParameterList functionExpressionBody |
| 6095 */ | 3213 */ |
| 6096 Statement _parseFunctionDeclarationStatementAfterReturnType( | 3214 FunctionExpression parseFunctionExpression() { |
| 6097 CommentAndMetadata commentAndMetadata, TypeName returnType) { | 3215 TypeParameterList typeParameters = _parseGenericMethodTypeParameters(); |
| 6098 FunctionDeclaration declaration = | 3216 FormalParameterList parameters = parseFormalParameterList(); |
| 6099 _parseFunctionDeclaration(commentAndMetadata, null, returnType); | 3217 _validateFormalParameterList(parameters); |
| 6100 Token propertyKeyword = declaration.propertyKeyword; | 3218 FunctionBody body = |
| 6101 if (propertyKeyword != null) { | 3219 parseFunctionBody(false, ParserErrorCode.MISSING_FUNCTION_BODY, true); |
| 6102 if ((propertyKeyword as KeywordToken).keyword == Keyword.GET) { | 3220 return new FunctionExpression(typeParameters, parameters, body); |
| 6103 _reportErrorForToken( | |
| 6104 ParserErrorCode.GETTER_IN_FUNCTION, propertyKeyword); | |
| 6105 } else { | |
| 6106 _reportErrorForToken( | |
| 6107 ParserErrorCode.SETTER_IN_FUNCTION, propertyKeyword); | |
| 6108 } | |
| 6109 } | |
| 6110 return new FunctionDeclarationStatement(declaration); | |
| 6111 } | 3221 } |
| 6112 | 3222 |
| 6113 /** | 3223 /** |
| 6114 * Parse a function type alias. The [commentAndMetadata] is the metadata to be | |
| 6115 * associated with the member. The [keyword] is the token representing the | |
| 6116 * 'typedef' keyword. Return the function type alias that was parsed. | |
| 6117 * | |
| 6118 * functionTypeAlias ::= | |
| 6119 * functionPrefix typeParameterList? formalParameterList ';' | |
| 6120 * | |
| 6121 * functionPrefix ::= | |
| 6122 * returnType? name | |
| 6123 */ | |
| 6124 FunctionTypeAlias _parseFunctionTypeAlias( | |
| 6125 CommentAndMetadata commentAndMetadata, Token keyword) { | |
| 6126 TypeName returnType = null; | |
| 6127 if (hasReturnTypeInTypeAlias) { | |
| 6128 returnType = parseReturnType(); | |
| 6129 } | |
| 6130 SimpleIdentifier name = parseSimpleIdentifier(); | |
| 6131 TypeParameterList typeParameters = null; | |
| 6132 if (_matches(TokenType.LT)) { | |
| 6133 typeParameters = parseTypeParameterList(); | |
| 6134 } | |
| 6135 if (_matches(TokenType.SEMICOLON) || _matches(TokenType.EOF)) { | |
| 6136 _reportErrorForCurrentToken(ParserErrorCode.MISSING_TYPEDEF_PARAMETERS); | |
| 6137 FormalParameterList parameters = new FormalParameterList( | |
| 6138 _createSyntheticToken(TokenType.OPEN_PAREN), | |
| 6139 null, | |
| 6140 null, | |
| 6141 null, | |
| 6142 _createSyntheticToken(TokenType.CLOSE_PAREN)); | |
| 6143 Token semicolon = _expect(TokenType.SEMICOLON); | |
| 6144 return new FunctionTypeAlias( | |
| 6145 commentAndMetadata.comment, | |
| 6146 commentAndMetadata.metadata, | |
| 6147 keyword, | |
| 6148 returnType, | |
| 6149 name, | |
| 6150 typeParameters, | |
| 6151 parameters, | |
| 6152 semicolon); | |
| 6153 } else if (!_matches(TokenType.OPEN_PAREN)) { | |
| 6154 _reportErrorForCurrentToken(ParserErrorCode.MISSING_TYPEDEF_PARAMETERS); | |
| 6155 // TODO(brianwilkerson) Recover from this error. At the very least we | |
| 6156 // should skip to the start of the next valid compilation unit member, | |
| 6157 // allowing for the possibility of finding the typedef parameters before | |
| 6158 // that point. | |
| 6159 return new FunctionTypeAlias( | |
| 6160 commentAndMetadata.comment, | |
| 6161 commentAndMetadata.metadata, | |
| 6162 keyword, | |
| 6163 returnType, | |
| 6164 name, | |
| 6165 typeParameters, | |
| 6166 new FormalParameterList(_createSyntheticToken(TokenType.OPEN_PAREN), | |
| 6167 null, null, null, _createSyntheticToken(TokenType.CLOSE_PAREN)), | |
| 6168 _createSyntheticToken(TokenType.SEMICOLON)); | |
| 6169 } | |
| 6170 FormalParameterList parameters = parseFormalParameterList(); | |
| 6171 _validateFormalParameterList(parameters); | |
| 6172 Token semicolon = _expect(TokenType.SEMICOLON); | |
| 6173 return new FunctionTypeAlias( | |
| 6174 commentAndMetadata.comment, | |
| 6175 commentAndMetadata.metadata, | |
| 6176 keyword, | |
| 6177 returnType, | |
| 6178 name, | |
| 6179 typeParameters, | |
| 6180 parameters, | |
| 6181 semicolon); | |
| 6182 } | |
| 6183 | |
| 6184 /** | |
| 6185 * Parse a getter. The [commentAndMetadata] is the documentation comment and | 3224 * Parse a getter. The [commentAndMetadata] is the documentation comment and |
| 6186 * metadata to be associated with the declaration. The externalKeyword] is the | 3225 * metadata to be associated with the declaration. The externalKeyword] is the |
| 6187 * 'external' token. The staticKeyword] is the static keyword, or `null` if | 3226 * 'external' token. The staticKeyword] is the static keyword, or `null` if |
| 6188 * the getter is not static. The [returnType] the return type that has already | 3227 * the getter is not static. The [returnType] the return type that has already |
| 6189 * been parsed, or `null` if there was no return type. Return the getter that | 3228 * been parsed, or `null` if there was no return type. Return the getter that |
| 6190 * was parsed. | 3229 * was parsed. |
| 6191 * | 3230 * |
| 3231 * This method assumes that the current token matches `Keyword.GET`. |
| 3232 * |
| 6192 * getter ::= | 3233 * getter ::= |
| 6193 * getterSignature functionBody? | 3234 * getterSignature functionBody? |
| 6194 * | 3235 * |
| 6195 * getterSignature ::= | 3236 * getterSignature ::= |
| 6196 * 'external'? 'static'? returnType? 'get' identifier | 3237 * 'external'? 'static'? returnType? 'get' identifier |
| 6197 */ | 3238 */ |
| 6198 MethodDeclaration _parseGetter(CommentAndMetadata commentAndMetadata, | 3239 MethodDeclaration parseGetter(CommentAndMetadata commentAndMetadata, |
| 6199 Token externalKeyword, Token staticKeyword, TypeName returnType) { | 3240 Token externalKeyword, Token staticKeyword, TypeName returnType) { |
| 6200 Token propertyKeyword = _expectKeyword(Keyword.GET); | 3241 Token propertyKeyword = getAndAdvance(); |
| 6201 SimpleIdentifier name = parseSimpleIdentifier(); | 3242 SimpleIdentifier name = parseSimpleIdentifier(isDeclaration: true); |
| 6202 if (_matches(TokenType.OPEN_PAREN) && | 3243 if (_matches(TokenType.OPEN_PAREN) && |
| 6203 _tokenMatches(_peek(), TokenType.CLOSE_PAREN)) { | 3244 _tokenMatches(_peek(), TokenType.CLOSE_PAREN)) { |
| 6204 _reportErrorForCurrentToken(ParserErrorCode.GETTER_WITH_PARAMETERS); | 3245 _reportErrorForCurrentToken(ParserErrorCode.GETTER_WITH_PARAMETERS); |
| 6205 _advance(); | 3246 _advance(); |
| 6206 _advance(); | 3247 _advance(); |
| 6207 } | 3248 } |
| 6208 FunctionBody body = _parseFunctionBody( | 3249 FunctionBody body = parseFunctionBody( |
| 6209 externalKeyword != null || staticKeyword == null, | 3250 externalKeyword != null || staticKeyword == null, |
| 6210 ParserErrorCode.STATIC_GETTER_WITHOUT_BODY, | 3251 ParserErrorCode.STATIC_GETTER_WITHOUT_BODY, |
| 6211 false); | 3252 false); |
| 6212 if (externalKeyword != null && body is! EmptyFunctionBody) { | 3253 if (externalKeyword != null && body is! EmptyFunctionBody) { |
| 6213 _reportErrorForCurrentToken(ParserErrorCode.EXTERNAL_GETTER_WITH_BODY); | 3254 _reportErrorForCurrentToken(ParserErrorCode.EXTERNAL_GETTER_WITH_BODY); |
| 6214 } | 3255 } |
| 6215 return new MethodDeclaration( | 3256 return new MethodDeclaration( |
| 6216 commentAndMetadata.comment, | 3257 commentAndMetadata.comment, |
| 6217 commentAndMetadata.metadata, | 3258 commentAndMetadata.metadata, |
| 6218 externalKeyword, | 3259 externalKeyword, |
| 6219 staticKeyword, | 3260 staticKeyword, |
| 6220 returnType, | 3261 returnType, |
| 6221 propertyKeyword, | 3262 propertyKeyword, |
| 6222 null, | 3263 null, |
| 6223 name, | 3264 name, |
| 6224 null, | 3265 null, |
| 6225 null, | 3266 null, |
| 6226 body); | 3267 body); |
| 6227 } | 3268 } |
| 6228 | 3269 |
| 6229 /** | 3270 /** |
| 6230 * Parse a list of identifiers. Return the list of identifiers that were | 3271 * Parse a list of identifiers. Return the list of identifiers that were |
| 6231 * parsed. | 3272 * parsed. |
| 6232 * | 3273 * |
| 6233 * identifierList ::= | 3274 * identifierList ::= |
| 6234 * identifier (',' identifier)* | 3275 * identifier (',' identifier)* |
| 6235 */ | 3276 */ |
| 6236 List<SimpleIdentifier> _parseIdentifierList() { | 3277 List<SimpleIdentifier> parseIdentifierList() { |
| 6237 List<SimpleIdentifier> identifiers = new List<SimpleIdentifier>(); | 3278 List<SimpleIdentifier> identifiers = <SimpleIdentifier>[ |
| 6238 identifiers.add(parseSimpleIdentifier()); | 3279 parseSimpleIdentifier() |
| 6239 while (_matches(TokenType.COMMA)) { | 3280 ]; |
| 6240 _advance(); | 3281 while (_optional(TokenType.COMMA)) { |
| 6241 identifiers.add(parseSimpleIdentifier()); | 3282 identifiers.add(parseSimpleIdentifier()); |
| 6242 } | 3283 } |
| 6243 return identifiers; | 3284 return identifiers; |
| 6244 } | 3285 } |
| 6245 | 3286 |
| 6246 /** | 3287 /** |
| 3288 * Parse an if-null expression. Return the if-null expression that was |
| 3289 * parsed. |
| 3290 * |
| 3291 * ifNullExpression ::= logicalOrExpression ('??' logicalOrExpression)* |
| 3292 */ |
| 3293 Expression parseIfNullExpression() { |
| 3294 Expression expression = parseLogicalOrExpression(); |
| 3295 while (_currentToken.type == TokenType.QUESTION_QUESTION) { |
| 3296 expression = new BinaryExpression( |
| 3297 expression, getAndAdvance(), parseLogicalOrExpression()); |
| 3298 } |
| 3299 return expression; |
| 3300 } |
| 3301 |
| 3302 /** |
| 6247 * Parse an if statement. Return the if statement that was parsed. | 3303 * Parse an if statement. Return the if statement that was parsed. |
| 6248 * | 3304 * |
| 3305 * This method assumes that the current token matches `Keyword.IF`. |
| 3306 * |
| 6249 * ifStatement ::= | 3307 * ifStatement ::= |
| 6250 * 'if' '(' expression ')' statement ('else' statement)? | 3308 * 'if' '(' expression ')' statement ('else' statement)? |
| 6251 */ | 3309 */ |
| 6252 Statement _parseIfStatement() { | 3310 Statement parseIfStatement() { |
| 6253 Token ifKeyword = _expectKeyword(Keyword.IF); | 3311 Token ifKeyword = getAndAdvance(); |
| 6254 Token leftParenthesis = _expect(TokenType.OPEN_PAREN); | 3312 Token leftParenthesis = _expect(TokenType.OPEN_PAREN); |
| 6255 Expression condition = parseExpression2(); | 3313 Expression condition = parseExpression2(); |
| 6256 Token rightParenthesis = _expect(TokenType.CLOSE_PAREN); | 3314 Token rightParenthesis = _expect(TokenType.CLOSE_PAREN); |
| 6257 Statement thenStatement = parseStatement2(); | 3315 Statement thenStatement = parseStatement2(); |
| 6258 Token elseKeyword = null; | 3316 Token elseKeyword = null; |
| 6259 Statement elseStatement = null; | 3317 Statement elseStatement = null; |
| 6260 if (_matchesKeyword(Keyword.ELSE)) { | 3318 if (_matchesKeyword(Keyword.ELSE)) { |
| 6261 elseKeyword = getAndAdvance(); | 3319 elseKeyword = getAndAdvance(); |
| 6262 elseStatement = parseStatement2(); | 3320 elseStatement = parseStatement2(); |
| 6263 } | 3321 } |
| 6264 return new IfStatement(ifKeyword, leftParenthesis, condition, | 3322 return new IfStatement(ifKeyword, leftParenthesis, condition, |
| 6265 rightParenthesis, thenStatement, elseKeyword, elseStatement); | 3323 rightParenthesis, thenStatement, elseKeyword, elseStatement); |
| 6266 } | 3324 } |
| 6267 | 3325 |
| 6268 /** | 3326 /** |
| 3327 * Parse an implements clause. Return the implements clause that was parsed. |
| 3328 * |
| 3329 * This method assumes that the current token matches `Keyword.IMPLEMENTS`. |
| 3330 * |
| 3331 * implementsClause ::= |
| 3332 * 'implements' type (',' type)* |
| 3333 */ |
| 3334 ImplementsClause parseImplementsClause() { |
| 3335 Token keyword = getAndAdvance(); |
| 3336 List<TypeName> interfaces = <TypeName>[]; |
| 3337 do { |
| 3338 TypeName typeName = parseTypeName(false); |
| 3339 _mustNotBeNullable(typeName, ParserErrorCode.NULLABLE_TYPE_IN_IMPLEMENTS); |
| 3340 interfaces.add(typeName); |
| 3341 } while (_optional(TokenType.COMMA)); |
| 3342 return new ImplementsClause(keyword, interfaces); |
| 3343 } |
| 3344 |
| 3345 /** |
| 6269 * Parse an import directive. The [commentAndMetadata] is the metadata to be | 3346 * Parse an import directive. The [commentAndMetadata] is the metadata to be |
| 6270 * associated with the directive. Return the import directive that was parsed. | 3347 * associated with the directive. Return the import directive that was parsed. |
| 6271 * | 3348 * |
| 3349 * This method assumes that the current token matches `Keyword.IMPORT`. |
| 3350 * |
| 6272 * importDirective ::= | 3351 * importDirective ::= |
| 6273 * metadata 'import' stringLiteral (deferred)? ('as' identifier)? comb
inator*';' | 3352 * metadata 'import' stringLiteral configuration* (deferred)? ('as' id
entifier)? combinator*';' |
| 6274 */ | 3353 */ |
| 6275 ImportDirective _parseImportDirective(CommentAndMetadata commentAndMetadata) { | 3354 ImportDirective parseImportDirective(CommentAndMetadata commentAndMetadata) { |
| 6276 Token importKeyword = _expectKeyword(Keyword.IMPORT); | 3355 Token importKeyword = getAndAdvance(); |
| 6277 StringLiteral libraryUri = _parseUri(); | 3356 StringLiteral libraryUri = _parseUri(); |
| 3357 List<Configuration> configurations = _parseConfigurations(); |
| 6278 Token deferredToken = null; | 3358 Token deferredToken = null; |
| 6279 Token asToken = null; | 3359 Token asToken = null; |
| 6280 SimpleIdentifier prefix = null; | 3360 SimpleIdentifier prefix = null; |
| 6281 if (_matchesKeyword(Keyword.DEFERRED)) { | 3361 if (_matchesKeyword(Keyword.DEFERRED)) { |
| 6282 deferredToken = getAndAdvance(); | 3362 deferredToken = getAndAdvance(); |
| 6283 } | 3363 } |
| 6284 if (_matchesKeyword(Keyword.AS)) { | 3364 if (_matchesKeyword(Keyword.AS)) { |
| 6285 asToken = getAndAdvance(); | 3365 asToken = getAndAdvance(); |
| 6286 prefix = parseSimpleIdentifier(); | 3366 prefix = parseSimpleIdentifier(isDeclaration: true); |
| 6287 } else if (deferredToken != null) { | 3367 } else if (deferredToken != null) { |
| 6288 _reportErrorForCurrentToken( | 3368 _reportErrorForCurrentToken( |
| 6289 ParserErrorCode.MISSING_PREFIX_IN_DEFERRED_IMPORT); | 3369 ParserErrorCode.MISSING_PREFIX_IN_DEFERRED_IMPORT); |
| 6290 } else if (!_matches(TokenType.SEMICOLON) && | 3370 } else if (!_matches(TokenType.SEMICOLON) && |
| 6291 !_matchesString(_SHOW) && | 3371 !_matchesString(_SHOW) && |
| 6292 !_matchesString(_HIDE)) { | 3372 !_matchesString(_HIDE)) { |
| 6293 Token nextToken = _peek(); | 3373 Token nextToken = _peek(); |
| 6294 if (_tokenMatchesKeyword(nextToken, Keyword.AS) || | 3374 if (_tokenMatchesKeyword(nextToken, Keyword.AS) || |
| 6295 _tokenMatchesString(nextToken, _SHOW) || | 3375 _tokenMatchesString(nextToken, _SHOW) || |
| 6296 _tokenMatchesString(nextToken, _HIDE)) { | 3376 _tokenMatchesString(nextToken, _HIDE)) { |
| 6297 _reportErrorForCurrentToken( | 3377 _reportErrorForCurrentToken( |
| 6298 ParserErrorCode.UNEXPECTED_TOKEN, [_currentToken]); | 3378 ParserErrorCode.UNEXPECTED_TOKEN, [_currentToken]); |
| 6299 _advance(); | 3379 _advance(); |
| 6300 if (_matchesKeyword(Keyword.AS)) { | 3380 if (_matchesKeyword(Keyword.AS)) { |
| 6301 asToken = getAndAdvance(); | 3381 asToken = getAndAdvance(); |
| 6302 prefix = parseSimpleIdentifier(); | 3382 prefix = parseSimpleIdentifier(isDeclaration: true); |
| 6303 } | 3383 } |
| 6304 } | 3384 } |
| 6305 } | 3385 } |
| 6306 List<Combinator> combinators = _parseCombinators(); | 3386 List<Combinator> combinators = parseCombinators(); |
| 6307 Token semicolon = _expectSemicolon(); | 3387 Token semicolon = _expect(TokenType.SEMICOLON); |
| 6308 return new ImportDirective( | 3388 return new ImportDirective( |
| 6309 commentAndMetadata.comment, | 3389 commentAndMetadata.comment, |
| 6310 commentAndMetadata.metadata, | 3390 commentAndMetadata.metadata, |
| 6311 importKeyword, | 3391 importKeyword, |
| 6312 libraryUri, | 3392 libraryUri, |
| 3393 configurations, |
| 6313 deferredToken, | 3394 deferredToken, |
| 6314 asToken, | 3395 asToken, |
| 6315 prefix, | 3396 prefix, |
| 6316 combinators, | 3397 combinators, |
| 6317 semicolon); | 3398 semicolon); |
| 6318 } | 3399 } |
| 6319 | 3400 |
| 6320 /** | 3401 /** |
| 6321 * Parse a list of initialized identifiers. The [commentAndMetadata] is the | 3402 * Parse a list of initialized identifiers. The [commentAndMetadata] is the |
| 6322 * documentation comment and metadata to be associated with the declaration. | 3403 * documentation comment and metadata to be associated with the declaration. |
| 6323 * The [staticKeyword] is the static keyword, or `null` if the getter is not | 3404 * The [staticKeyword] is the static keyword, or `null` if the getter is not |
| 6324 * static. The [keyword] is the token representing the 'final', 'const' or | 3405 * static. The [keyword] is the token representing the 'final', 'const' or |
| 6325 * 'var' keyword, or `null` if there is no keyword. The [type] is the type | 3406 * 'var' keyword, or `null` if there is no keyword. The [type] is the type |
| 6326 * that has already been parsed, or `null` if 'var' was provided. Return the | 3407 * that has already been parsed, or `null` if 'var' was provided. Return the |
| 6327 * getter that was parsed. | 3408 * getter that was parsed. |
| 6328 * | 3409 * |
| 6329 * ?? ::= | 3410 * ?? ::= |
| 6330 * 'static'? ('var' | type) initializedIdentifierList ';' | 3411 * 'static'? ('var' | type) initializedIdentifierList ';' |
| 6331 * | 'final' type? initializedIdentifierList ';' | 3412 * | 'final' type? initializedIdentifierList ';' |
| 6332 * | 3413 * |
| 6333 * initializedIdentifierList ::= | 3414 * initializedIdentifierList ::= |
| 6334 * initializedIdentifier (',' initializedIdentifier)* | 3415 * initializedIdentifier (',' initializedIdentifier)* |
| 6335 * | 3416 * |
| 6336 * initializedIdentifier ::= | 3417 * initializedIdentifier ::= |
| 6337 * identifier ('=' expression)? | 3418 * identifier ('=' expression)? |
| 6338 */ | 3419 */ |
| 6339 FieldDeclaration _parseInitializedIdentifierList( | 3420 FieldDeclaration parseInitializedIdentifierList( |
| 6340 CommentAndMetadata commentAndMetadata, | 3421 CommentAndMetadata commentAndMetadata, |
| 6341 Token staticKeyword, | 3422 Token staticKeyword, |
| 6342 Token keyword, | 3423 Token keyword, |
| 6343 TypeName type) { | 3424 TypeName type) { |
| 6344 VariableDeclarationList fieldList = | 3425 VariableDeclarationList fieldList = |
| 6345 _parseVariableDeclarationListAfterType(null, keyword, type); | 3426 parseVariableDeclarationListAfterType(null, keyword, type); |
| 6346 return new FieldDeclaration( | 3427 return new FieldDeclaration( |
| 6347 commentAndMetadata.comment, | 3428 commentAndMetadata.comment, |
| 6348 commentAndMetadata.metadata, | 3429 commentAndMetadata.metadata, |
| 6349 staticKeyword, | 3430 staticKeyword, |
| 6350 fieldList, | 3431 fieldList, |
| 6351 _expect(TokenType.SEMICOLON)); | 3432 _expect(TokenType.SEMICOLON)); |
| 6352 } | 3433 } |
| 6353 | 3434 |
| 6354 /** | 3435 /** |
| 6355 * Parse an instance creation expression. The [keyword] is the 'new' or | 3436 * Parse an instance creation expression. The [keyword] is the 'new' or |
| 6356 * 'const' keyword that introduces the expression. Return the instance | 3437 * 'const' keyword that introduces the expression. Return the instance |
| 6357 * creation expression that was parsed. | 3438 * creation expression that was parsed. |
| 6358 * | 3439 * |
| 6359 * instanceCreationExpression ::= | 3440 * instanceCreationExpression ::= |
| 6360 * ('new' | 'const') type ('.' identifier)? argumentList | 3441 * ('new' | 'const') type ('.' identifier)? argumentList |
| 6361 */ | 3442 */ |
| 6362 InstanceCreationExpression _parseInstanceCreationExpression(Token keyword) { | 3443 InstanceCreationExpression parseInstanceCreationExpression(Token keyword) { |
| 6363 ConstructorName constructorName = parseConstructorName(); | 3444 ConstructorName constructorName = parseConstructorName(); |
| 6364 ArgumentList argumentList = parseArgumentList(); | 3445 ArgumentList argumentList = _parseArgumentListChecked(); |
| 6365 return new InstanceCreationExpression( | 3446 return new InstanceCreationExpression( |
| 6366 keyword, constructorName, argumentList); | 3447 keyword, constructorName, argumentList); |
| 6367 } | 3448 } |
| 6368 | 3449 |
| 6369 /** | 3450 /** |
| 3451 * Parse a label. Return the label that was parsed. |
| 3452 * |
| 3453 * This method assumes that the current token matches an identifier and that |
| 3454 * the following token matches `TokenType.COLON`. |
| 3455 * |
| 3456 * label ::= |
| 3457 * identifier ':' |
| 3458 */ |
| 3459 Label parseLabel({bool isDeclaration: false}) { |
| 3460 SimpleIdentifier label = |
| 3461 _parseSimpleIdentifierUnchecked(isDeclaration: isDeclaration); |
| 3462 Token colon = getAndAdvance(); |
| 3463 return new Label(label, colon); |
| 3464 } |
| 3465 |
| 3466 /** |
| 6370 * Parse a library directive. The [commentAndMetadata] is the metadata to be | 3467 * Parse a library directive. The [commentAndMetadata] is the metadata to be |
| 6371 * associated with the directive. Return the library directive that was | 3468 * associated with the directive. Return the library directive that was |
| 6372 * parsed. | 3469 * parsed. |
| 6373 * | 3470 * |
| 3471 * This method assumes that the current token matches `Keyword.LIBRARY`. |
| 3472 * |
| 6374 * libraryDirective ::= | 3473 * libraryDirective ::= |
| 6375 * metadata 'library' identifier ';' | 3474 * metadata 'library' identifier ';' |
| 6376 */ | 3475 */ |
| 6377 LibraryDirective _parseLibraryDirective( | 3476 LibraryDirective parseLibraryDirective( |
| 6378 CommentAndMetadata commentAndMetadata) { | 3477 CommentAndMetadata commentAndMetadata) { |
| 6379 Token keyword = _expectKeyword(Keyword.LIBRARY); | 3478 Token keyword = getAndAdvance(); |
| 6380 LibraryIdentifier libraryName = _parseLibraryName( | 3479 LibraryIdentifier libraryName = _parseLibraryName( |
| 6381 ParserErrorCode.MISSING_NAME_IN_LIBRARY_DIRECTIVE, keyword); | 3480 ParserErrorCode.MISSING_NAME_IN_LIBRARY_DIRECTIVE, keyword); |
| 6382 Token semicolon = _expect(TokenType.SEMICOLON); | 3481 Token semicolon = _expect(TokenType.SEMICOLON); |
| 6383 return new LibraryDirective(commentAndMetadata.comment, | 3482 return new LibraryDirective(commentAndMetadata.comment, |
| 6384 commentAndMetadata.metadata, keyword, libraryName, semicolon); | 3483 commentAndMetadata.metadata, keyword, libraryName, semicolon); |
| 6385 } | 3484 } |
| 6386 | 3485 |
| 6387 /** | 3486 /** |
| 6388 * Parse a library name. The [missingNameError] is the error code to be used | 3487 * Parse a library identifier. Return the library identifier that was parsed. |
| 6389 * if the library name is missing. The [missingNameToken] is the token | |
| 6390 * associated with the error produced if the library name is missing. Return | |
| 6391 * the library name that was parsed. | |
| 6392 * | 3488 * |
| 6393 * libraryName ::= | 3489 * libraryIdentifier ::= |
| 6394 * libraryIdentifier | 3490 * identifier ('.' identifier)* |
| 6395 */ | 3491 */ |
| 6396 LibraryIdentifier _parseLibraryName( | 3492 LibraryIdentifier parseLibraryIdentifier() { |
| 6397 ParserErrorCode missingNameError, Token missingNameToken) { | 3493 List<SimpleIdentifier> components = <SimpleIdentifier>[]; |
| 6398 if (_matchesIdentifier()) { | 3494 components.add(parseSimpleIdentifier()); |
| 6399 return parseLibraryIdentifier(); | 3495 while (_optional(TokenType.PERIOD)) { |
| 6400 } else if (_matches(TokenType.STRING)) { | 3496 components.add(parseSimpleIdentifier()); |
| 6401 // TODO(brianwilkerson) Recovery: This should be extended to handle | |
| 6402 // arbitrary tokens until we can find a token that can start a compilation | |
| 6403 // unit member. | |
| 6404 StringLiteral string = parseStringLiteral(); | |
| 6405 _reportErrorForNode(ParserErrorCode.NON_IDENTIFIER_LIBRARY_NAME, string); | |
| 6406 } else { | |
| 6407 _reportErrorForToken(missingNameError, missingNameToken); | |
| 6408 } | 3497 } |
| 6409 List<SimpleIdentifier> components = new List<SimpleIdentifier>(); | |
| 6410 components.add(_createSyntheticIdentifier()); | |
| 6411 return new LibraryIdentifier(components); | 3498 return new LibraryIdentifier(components); |
| 6412 } | 3499 } |
| 6413 | 3500 |
| 6414 /** | 3501 /** |
| 6415 * Parse a list literal. The [modifier] is the 'const' modifier appearing | 3502 * Parse a list literal. The [modifier] is the 'const' modifier appearing |
| 6416 * before the literal, or `null` if there is no modifier. The [typeArguments] | 3503 * before the literal, or `null` if there is no modifier. The [typeArguments] |
| 6417 * is the type arguments appearing before the literal, or `null` if there are | 3504 * is the type arguments appearing before the literal, or `null` if there are |
| 6418 * no type arguments. Return the list literal that was parsed. | 3505 * no type arguments. Return the list literal that was parsed. |
| 6419 * | 3506 * |
| 3507 * This method assumes that the current token matches either |
| 3508 * `TokenType.OPEN_SQUARE_BRACKET` or `TokenType.INDEX`. |
| 3509 * |
| 6420 * listLiteral ::= | 3510 * listLiteral ::= |
| 6421 * 'const'? typeArguments? '[' (expressionList ','?)? ']' | 3511 * 'const'? typeArguments? '[' (expressionList ','?)? ']' |
| 6422 */ | 3512 */ |
| 6423 ListLiteral _parseListLiteral( | 3513 ListLiteral parseListLiteral(Token modifier, TypeArgumentList typeArguments) { |
| 6424 Token modifier, TypeArgumentList typeArguments) { | |
| 6425 // may be empty list literal | |
| 6426 if (_matches(TokenType.INDEX)) { | 3514 if (_matches(TokenType.INDEX)) { |
| 3515 // Split the token into two separate tokens. |
| 6427 BeginToken leftBracket = _createToken( | 3516 BeginToken leftBracket = _createToken( |
| 6428 _currentToken, TokenType.OPEN_SQUARE_BRACKET, | 3517 _currentToken, TokenType.OPEN_SQUARE_BRACKET, |
| 6429 isBegin: true); | 3518 isBegin: true); |
| 6430 Token rightBracket = | 3519 Token rightBracket = |
| 6431 new Token(TokenType.CLOSE_SQUARE_BRACKET, _currentToken.offset + 1); | 3520 new Token(TokenType.CLOSE_SQUARE_BRACKET, _currentToken.offset + 1); |
| 6432 leftBracket.endToken = rightBracket; | 3521 leftBracket.endToken = rightBracket; |
| 6433 rightBracket.setNext(_currentToken.next); | 3522 rightBracket.setNext(_currentToken.next); |
| 6434 leftBracket.setNext(rightBracket); | 3523 leftBracket.setNext(rightBracket); |
| 6435 _currentToken.previous.setNext(leftBracket); | 3524 _currentToken.previous.setNext(leftBracket); |
| 6436 _currentToken = _currentToken.next; | 3525 _currentToken = _currentToken.next; |
| 6437 return new ListLiteral( | 3526 return new ListLiteral( |
| 6438 modifier, typeArguments, leftBracket, null, rightBracket); | 3527 modifier, typeArguments, leftBracket, null, rightBracket); |
| 6439 } | 3528 } |
| 6440 // open | 3529 Token leftBracket = getAndAdvance(); |
| 6441 Token leftBracket = _expect(TokenType.OPEN_SQUARE_BRACKET); | |
| 6442 if (_matches(TokenType.CLOSE_SQUARE_BRACKET)) { | 3530 if (_matches(TokenType.CLOSE_SQUARE_BRACKET)) { |
| 6443 return new ListLiteral( | 3531 return new ListLiteral( |
| 6444 modifier, typeArguments, leftBracket, null, getAndAdvance()); | 3532 modifier, typeArguments, leftBracket, null, getAndAdvance()); |
| 6445 } | 3533 } |
| 6446 bool wasInInitializer = _inInitializer; | 3534 bool wasInInitializer = _inInitializer; |
| 6447 _inInitializer = false; | 3535 _inInitializer = false; |
| 6448 try { | 3536 try { |
| 6449 List<Expression> elements = new List<Expression>(); | 3537 List<Expression> elements = <Expression>[parseExpression2()]; |
| 6450 elements.add(parseExpression2()); | |
| 6451 while (_optional(TokenType.COMMA)) { | 3538 while (_optional(TokenType.COMMA)) { |
| 6452 if (_matches(TokenType.CLOSE_SQUARE_BRACKET)) { | 3539 if (_matches(TokenType.CLOSE_SQUARE_BRACKET)) { |
| 6453 return new ListLiteral( | 3540 return new ListLiteral( |
| 6454 modifier, typeArguments, leftBracket, elements, getAndAdvance()); | 3541 modifier, typeArguments, leftBracket, elements, getAndAdvance()); |
| 6455 } | 3542 } |
| 6456 elements.add(parseExpression2()); | 3543 elements.add(parseExpression2()); |
| 6457 } | 3544 } |
| 6458 Token rightBracket = _expect(TokenType.CLOSE_SQUARE_BRACKET); | 3545 Token rightBracket = _expect(TokenType.CLOSE_SQUARE_BRACKET); |
| 6459 return new ListLiteral( | 3546 return new ListLiteral( |
| 6460 modifier, typeArguments, leftBracket, elements, rightBracket); | 3547 modifier, typeArguments, leftBracket, elements, rightBracket); |
| 6461 } finally { | 3548 } finally { |
| 6462 _inInitializer = wasInInitializer; | 3549 _inInitializer = wasInInitializer; |
| 6463 } | 3550 } |
| 6464 } | 3551 } |
| 6465 | 3552 |
| 6466 /** | 3553 /** |
| 6467 * Parse a list or map literal. The [modifier] is the 'const' modifier | 3554 * Parse a list or map literal. The [modifier] is the 'const' modifier |
| 6468 * appearing before the literal, or `null` if there is no modifier. Return the | 3555 * appearing before the literal, or `null` if there is no modifier. Return the |
| 6469 * list or map literal that was parsed. | 3556 * list or map literal that was parsed. |
| 6470 * | 3557 * |
| 6471 * listOrMapLiteral ::= | 3558 * listOrMapLiteral ::= |
| 6472 * listLiteral | 3559 * listLiteral |
| 6473 * | mapLiteral | 3560 * | mapLiteral |
| 6474 */ | 3561 */ |
| 6475 TypedLiteral _parseListOrMapLiteral(Token modifier) { | 3562 TypedLiteral parseListOrMapLiteral(Token modifier) { |
| 6476 TypeArgumentList typeArguments = null; | 3563 TypeArgumentList typeArguments = _parseOptionalTypeArguments(); |
| 6477 if (_matches(TokenType.LT)) { | |
| 6478 typeArguments = parseTypeArgumentList(); | |
| 6479 } | |
| 6480 if (_matches(TokenType.OPEN_CURLY_BRACKET)) { | 3564 if (_matches(TokenType.OPEN_CURLY_BRACKET)) { |
| 6481 return _parseMapLiteral(modifier, typeArguments); | 3565 return parseMapLiteral(modifier, typeArguments); |
| 6482 } else if (_matches(TokenType.OPEN_SQUARE_BRACKET) || | 3566 } else if (_matches(TokenType.OPEN_SQUARE_BRACKET) || |
| 6483 _matches(TokenType.INDEX)) { | 3567 _matches(TokenType.INDEX)) { |
| 6484 return _parseListLiteral(modifier, typeArguments); | 3568 return parseListLiteral(modifier, typeArguments); |
| 6485 } | 3569 } |
| 6486 _reportErrorForCurrentToken(ParserErrorCode.EXPECTED_LIST_OR_MAP_LITERAL); | 3570 _reportErrorForCurrentToken(ParserErrorCode.EXPECTED_LIST_OR_MAP_LITERAL); |
| 6487 return new ListLiteral( | 3571 return new ListLiteral( |
| 6488 modifier, | 3572 modifier, |
| 6489 typeArguments, | 3573 typeArguments, |
| 6490 _createSyntheticToken(TokenType.OPEN_SQUARE_BRACKET), | 3574 _createSyntheticToken(TokenType.OPEN_SQUARE_BRACKET), |
| 6491 null, | 3575 null, |
| 6492 _createSyntheticToken(TokenType.CLOSE_SQUARE_BRACKET)); | 3576 _createSyntheticToken(TokenType.CLOSE_SQUARE_BRACKET)); |
| 6493 } | 3577 } |
| 6494 | 3578 |
| 6495 /** | 3579 /** |
| 6496 * Parse a logical and expression. Return the logical and expression that was | 3580 * Parse a logical and expression. Return the logical and expression that was |
| 6497 * parsed. | 3581 * parsed. |
| 6498 * | 3582 * |
| 6499 * logicalAndExpression ::= | 3583 * logicalAndExpression ::= |
| 6500 * equalityExpression ('&&' equalityExpression)* | 3584 * equalityExpression ('&&' equalityExpression)* |
| 6501 */ | 3585 */ |
| 6502 Expression _parseLogicalAndExpression() { | 3586 Expression parseLogicalAndExpression() { |
| 6503 Expression expression = _parseEqualityExpression(); | 3587 Expression expression = parseEqualityExpression(); |
| 6504 while (_matches(TokenType.AMPERSAND_AMPERSAND)) { | 3588 while (_currentToken.type == TokenType.AMPERSAND_AMPERSAND) { |
| 6505 Token operator = getAndAdvance(); | |
| 6506 expression = new BinaryExpression( | 3589 expression = new BinaryExpression( |
| 6507 expression, operator, _parseEqualityExpression()); | 3590 expression, getAndAdvance(), parseEqualityExpression()); |
| 6508 } | 3591 } |
| 6509 return expression; | 3592 return expression; |
| 6510 } | 3593 } |
| 3594 |
| 3595 /** |
| 3596 * Parse a logical or expression. Return the logical or expression that was |
| 3597 * parsed. |
| 3598 * |
| 3599 * logicalOrExpression ::= |
| 3600 * logicalAndExpression ('||' logicalAndExpression)* |
| 3601 */ |
| 3602 Expression parseLogicalOrExpression() { |
| 3603 Expression expression = parseLogicalAndExpression(); |
| 3604 while (_currentToken.type == TokenType.BAR_BAR) { |
| 3605 expression = new BinaryExpression( |
| 3606 expression, getAndAdvance(), parseLogicalAndExpression()); |
| 3607 } |
| 3608 return expression; |
| 3609 } |
| 6511 | 3610 |
| 6512 /** | 3611 /** |
| 6513 * Parse a map literal. The [modifier] is the 'const' modifier appearing | 3612 * Parse a map literal. The [modifier] is the 'const' modifier appearing |
| 6514 * before the literal, or `null` if there is no modifier. The [typeArguments] | 3613 * before the literal, or `null` if there is no modifier. The [typeArguments] |
| 6515 * is the type arguments that were declared, or `null` if there are no type | 3614 * is the type arguments that were declared, or `null` if there are no type |
| 6516 * arguments. Return the map literal that was parsed. | 3615 * arguments. Return the map literal that was parsed. |
| 6517 * | 3616 * |
| 3617 * This method assumes that the current token matches |
| 3618 * `TokenType.OPEN_CURLY_BRACKET`. |
| 3619 * |
| 6518 * mapLiteral ::= | 3620 * mapLiteral ::= |
| 6519 * 'const'? typeArguments? '{' (mapLiteralEntry (',' mapLiteralEntry)*
','?)? '}' | 3621 * 'const'? typeArguments? '{' (mapLiteralEntry (',' mapLiteralEntry)*
','?)? '}' |
| 6520 */ | 3622 */ |
| 6521 MapLiteral _parseMapLiteral(Token modifier, TypeArgumentList typeArguments) { | 3623 MapLiteral parseMapLiteral(Token modifier, TypeArgumentList typeArguments) { |
| 6522 Token leftBracket = _expect(TokenType.OPEN_CURLY_BRACKET); | 3624 Token leftBracket = getAndAdvance(); |
| 6523 List<MapLiteralEntry> entries = new List<MapLiteralEntry>(); | |
| 6524 if (_matches(TokenType.CLOSE_CURLY_BRACKET)) { | 3625 if (_matches(TokenType.CLOSE_CURLY_BRACKET)) { |
| 6525 return new MapLiteral( | 3626 return new MapLiteral( |
| 6526 modifier, typeArguments, leftBracket, entries, getAndAdvance()); | 3627 modifier, typeArguments, leftBracket, null, getAndAdvance()); |
| 6527 } | 3628 } |
| 6528 bool wasInInitializer = _inInitializer; | 3629 bool wasInInitializer = _inInitializer; |
| 6529 _inInitializer = false; | 3630 _inInitializer = false; |
| 6530 try { | 3631 try { |
| 6531 entries.add(parseMapLiteralEntry()); | 3632 List<MapLiteralEntry> entries = <MapLiteralEntry>[parseMapLiteralEntry()]; |
| 6532 while (_optional(TokenType.COMMA)) { | 3633 while (_optional(TokenType.COMMA)) { |
| 6533 if (_matches(TokenType.CLOSE_CURLY_BRACKET)) { | 3634 if (_matches(TokenType.CLOSE_CURLY_BRACKET)) { |
| 6534 return new MapLiteral( | 3635 return new MapLiteral( |
| 6535 modifier, typeArguments, leftBracket, entries, getAndAdvance()); | 3636 modifier, typeArguments, leftBracket, entries, getAndAdvance()); |
| 6536 } | 3637 } |
| 6537 entries.add(parseMapLiteralEntry()); | 3638 entries.add(parseMapLiteralEntry()); |
| 6538 } | 3639 } |
| 6539 Token rightBracket = _expect(TokenType.CLOSE_CURLY_BRACKET); | 3640 Token rightBracket = _expect(TokenType.CLOSE_CURLY_BRACKET); |
| 6540 return new MapLiteral( | 3641 return new MapLiteral( |
| 6541 modifier, typeArguments, leftBracket, entries, rightBracket); | 3642 modifier, typeArguments, leftBracket, entries, rightBracket); |
| 6542 } finally { | 3643 } finally { |
| 6543 _inInitializer = wasInInitializer; | 3644 _inInitializer = wasInInitializer; |
| 6544 } | 3645 } |
| 6545 } | 3646 } |
| 6546 | 3647 |
| 6547 /** | 3648 /** |
| 6548 * Parse a method declaration. The [commentAndMetadata] is the documentation | 3649 * Parse a map literal entry. Return the map literal entry that was parsed. |
| 6549 * comment and metadata to be associated with the declaration. The | |
| 6550 * [externalKeyword] is the 'external' token. The [staticKeyword] is the | |
| 6551 * static keyword, or `null` if the getter is not static. The [returnType] is | |
| 6552 * the return type of the method. The [name] is the name of the method. The | |
| 6553 * [parameters] is the parameters to the method. Return the method declaration | |
| 6554 * that was parsed. | |
| 6555 * | 3650 * |
| 6556 * functionDeclaration ::= | 3651 * mapLiteralEntry ::= |
| 6557 * ('external' 'static'?)? functionSignature functionBody | 3652 * expression ':' expression |
| 6558 * | 'external'? functionSignature ';' | |
| 6559 */ | 3653 */ |
| 6560 MethodDeclaration _parseMethodDeclarationAfterParameters( | 3654 MapLiteralEntry parseMapLiteralEntry() { |
| 6561 CommentAndMetadata commentAndMetadata, | 3655 Expression key = parseExpression2(); |
| 6562 Token externalKeyword, | 3656 Token separator = _expect(TokenType.COLON); |
| 6563 Token staticKeyword, | 3657 Expression value = parseExpression2(); |
| 6564 TypeName returnType, | 3658 return new MapLiteralEntry(key, separator, value); |
| 6565 SimpleIdentifier name, | |
| 6566 TypeParameterList typeParameters, | |
| 6567 FormalParameterList parameters) { | |
| 6568 FunctionBody body = _parseFunctionBody( | |
| 6569 externalKeyword != null || staticKeyword == null, | |
| 6570 ParserErrorCode.MISSING_FUNCTION_BODY, | |
| 6571 false); | |
| 6572 if (externalKeyword != null) { | |
| 6573 if (body is! EmptyFunctionBody) { | |
| 6574 _reportErrorForNode(ParserErrorCode.EXTERNAL_METHOD_WITH_BODY, body); | |
| 6575 } | |
| 6576 } else if (staticKeyword != null) { | |
| 6577 if (body is EmptyFunctionBody && _parseFunctionBodies) { | |
| 6578 _reportErrorForNode(ParserErrorCode.ABSTRACT_STATIC_METHOD, body); | |
| 6579 } | |
| 6580 } | |
| 6581 return new MethodDeclaration( | |
| 6582 commentAndMetadata.comment, | |
| 6583 commentAndMetadata.metadata, | |
| 6584 externalKeyword, | |
| 6585 staticKeyword, | |
| 6586 returnType, | |
| 6587 null, | |
| 6588 null, | |
| 6589 name, | |
| 6590 typeParameters, | |
| 6591 parameters, | |
| 6592 body); | |
| 6593 } | 3659 } |
| 6594 | 3660 |
| 6595 /** | 3661 /** |
| 6596 * Parse a method declaration. The [commentAndMetadata] is the documentation | |
| 6597 * comment and metadata to be associated with the declaration. The | |
| 6598 * [externalKeyword] is the 'external' token. The [staticKeyword] is the | |
| 6599 * static keyword, or `null` if the getter is not static. The [returnType] is | |
| 6600 * the return type of the method. Return the method declaration that was | |
| 6601 * parsed. | |
| 6602 * | |
| 6603 * functionDeclaration ::= | |
| 6604 * 'external'? 'static'? functionSignature functionBody | |
| 6605 * | 'external'? functionSignature ';' | |
| 6606 */ | |
| 6607 MethodDeclaration _parseMethodDeclarationAfterReturnType( | |
| 6608 CommentAndMetadata commentAndMetadata, | |
| 6609 Token externalKeyword, | |
| 6610 Token staticKeyword, | |
| 6611 TypeName returnType) { | |
| 6612 SimpleIdentifier methodName = parseSimpleIdentifier(); | |
| 6613 TypeParameterList typeParameters = null; | |
| 6614 if (parseGenericMethods && _matches(TokenType.LT)) { | |
| 6615 typeParameters = parseTypeParameterList(); | |
| 6616 } | |
| 6617 FormalParameterList parameters; | |
| 6618 if (!_matches(TokenType.OPEN_PAREN) && | |
| 6619 (_matches(TokenType.OPEN_CURLY_BRACKET) || | |
| 6620 _matches(TokenType.FUNCTION))) { | |
| 6621 _reportErrorForToken( | |
| 6622 ParserErrorCode.MISSING_METHOD_PARAMETERS, _currentToken.previous); | |
| 6623 parameters = new FormalParameterList( | |
| 6624 _createSyntheticToken(TokenType.OPEN_PAREN), | |
| 6625 null, | |
| 6626 null, | |
| 6627 null, | |
| 6628 _createSyntheticToken(TokenType.CLOSE_PAREN)); | |
| 6629 } else { | |
| 6630 parameters = parseFormalParameterList(); | |
| 6631 } | |
| 6632 _validateFormalParameterList(parameters); | |
| 6633 return _parseMethodDeclarationAfterParameters( | |
| 6634 commentAndMetadata, | |
| 6635 externalKeyword, | |
| 6636 staticKeyword, | |
| 6637 returnType, | |
| 6638 methodName, | |
| 6639 typeParameters, | |
| 6640 parameters); | |
| 6641 } | |
| 6642 | |
| 6643 /** | |
| 6644 * Parse the modifiers preceding a declaration. This method allows the | 3662 * Parse the modifiers preceding a declaration. This method allows the |
| 6645 * modifiers to appear in any order but does generate errors for duplicated | 3663 * modifiers to appear in any order but does generate errors for duplicated |
| 6646 * modifiers. Checks for other problems, such as having the modifiers appear | 3664 * modifiers. Checks for other problems, such as having the modifiers appear |
| 6647 * in the wrong order or specifying both 'const' and 'final', are reported in | 3665 * in the wrong order or specifying both 'const' and 'final', are reported in |
| 6648 * one of the methods whose name is prefixed with `validateModifiersFor`. | 3666 * one of the methods whose name is prefixed with `validateModifiersFor`. |
| 6649 * Return the modifiers that were parsed. | 3667 * Return the modifiers that were parsed. |
| 6650 * | 3668 * |
| 6651 * modifiers ::= | 3669 * modifiers ::= |
| 6652 * ('abstract' | 'const' | 'external' | 'factory' | 'final' | 'static'
| 'var')* | 3670 * ('abstract' | 'const' | 'external' | 'factory' | 'final' | 'static'
| 'var')* |
| 6653 */ | 3671 */ |
| 6654 Modifiers _parseModifiers() { | 3672 Modifiers parseModifiers() { |
| 6655 Modifiers modifiers = new Modifiers(); | 3673 Modifiers modifiers = new Modifiers(); |
| 6656 bool progress = true; | 3674 bool progress = true; |
| 6657 while (progress) { | 3675 while (progress) { |
| 6658 if (_tokenMatches(_peek(), TokenType.PERIOD) || | 3676 TokenType nextType = _peek().type; |
| 6659 _tokenMatches(_peek(), TokenType.LT) || | 3677 if (nextType == TokenType.PERIOD || |
| 6660 _tokenMatches(_peek(), TokenType.OPEN_PAREN)) { | 3678 nextType == TokenType.LT || |
| 3679 nextType == TokenType.OPEN_PAREN) { |
| 6661 return modifiers; | 3680 return modifiers; |
| 6662 } | 3681 } |
| 6663 if (_matchesKeyword(Keyword.ABSTRACT)) { | 3682 Keyword keyword = _currentToken.keyword; |
| 3683 if (keyword == Keyword.ABSTRACT) { |
| 6664 if (modifiers.abstractKeyword != null) { | 3684 if (modifiers.abstractKeyword != null) { |
| 6665 _reportErrorForCurrentToken( | 3685 _reportErrorForCurrentToken( |
| 6666 ParserErrorCode.DUPLICATED_MODIFIER, [_currentToken.lexeme]); | 3686 ParserErrorCode.DUPLICATED_MODIFIER, [_currentToken.lexeme]); |
| 6667 _advance(); | 3687 _advance(); |
| 6668 } else { | 3688 } else { |
| 6669 modifiers.abstractKeyword = getAndAdvance(); | 3689 modifiers.abstractKeyword = getAndAdvance(); |
| 6670 } | 3690 } |
| 6671 } else if (_matchesKeyword(Keyword.CONST)) { | 3691 } else if (keyword == Keyword.CONST) { |
| 6672 if (modifiers.constKeyword != null) { | 3692 if (modifiers.constKeyword != null) { |
| 6673 _reportErrorForCurrentToken( | 3693 _reportErrorForCurrentToken( |
| 6674 ParserErrorCode.DUPLICATED_MODIFIER, [_currentToken.lexeme]); | 3694 ParserErrorCode.DUPLICATED_MODIFIER, [_currentToken.lexeme]); |
| 6675 _advance(); | 3695 _advance(); |
| 6676 } else { | 3696 } else { |
| 6677 modifiers.constKeyword = getAndAdvance(); | 3697 modifiers.constKeyword = getAndAdvance(); |
| 6678 } | 3698 } |
| 6679 } else if (_matchesKeyword(Keyword.EXTERNAL) && | 3699 } else if (keyword == Keyword.EXTERNAL) { |
| 6680 !_tokenMatches(_peek(), TokenType.PERIOD) && | |
| 6681 !_tokenMatches(_peek(), TokenType.LT)) { | |
| 6682 if (modifiers.externalKeyword != null) { | 3700 if (modifiers.externalKeyword != null) { |
| 6683 _reportErrorForCurrentToken( | 3701 _reportErrorForCurrentToken( |
| 6684 ParserErrorCode.DUPLICATED_MODIFIER, [_currentToken.lexeme]); | 3702 ParserErrorCode.DUPLICATED_MODIFIER, [_currentToken.lexeme]); |
| 6685 _advance(); | 3703 _advance(); |
| 6686 } else { | 3704 } else { |
| 6687 modifiers.externalKeyword = getAndAdvance(); | 3705 modifiers.externalKeyword = getAndAdvance(); |
| 6688 } | 3706 } |
| 6689 } else if (_matchesKeyword(Keyword.FACTORY) && | 3707 } else if (keyword == Keyword.FACTORY) { |
| 6690 !_tokenMatches(_peek(), TokenType.PERIOD) && | |
| 6691 !_tokenMatches(_peek(), TokenType.LT)) { | |
| 6692 if (modifiers.factoryKeyword != null) { | 3708 if (modifiers.factoryKeyword != null) { |
| 6693 _reportErrorForCurrentToken( | 3709 _reportErrorForCurrentToken( |
| 6694 ParserErrorCode.DUPLICATED_MODIFIER, [_currentToken.lexeme]); | 3710 ParserErrorCode.DUPLICATED_MODIFIER, [_currentToken.lexeme]); |
| 6695 _advance(); | 3711 _advance(); |
| 6696 } else { | 3712 } else { |
| 6697 modifiers.factoryKeyword = getAndAdvance(); | 3713 modifiers.factoryKeyword = getAndAdvance(); |
| 6698 } | 3714 } |
| 6699 } else if (_matchesKeyword(Keyword.FINAL)) { | 3715 } else if (keyword == Keyword.FINAL) { |
| 6700 if (modifiers.finalKeyword != null) { | 3716 if (modifiers.finalKeyword != null) { |
| 6701 _reportErrorForCurrentToken( | 3717 _reportErrorForCurrentToken( |
| 6702 ParserErrorCode.DUPLICATED_MODIFIER, [_currentToken.lexeme]); | 3718 ParserErrorCode.DUPLICATED_MODIFIER, [_currentToken.lexeme]); |
| 6703 _advance(); | 3719 _advance(); |
| 6704 } else { | 3720 } else { |
| 6705 modifiers.finalKeyword = getAndAdvance(); | 3721 modifiers.finalKeyword = getAndAdvance(); |
| 6706 } | 3722 } |
| 6707 } else if (_matchesKeyword(Keyword.STATIC) && | 3723 } else if (keyword == Keyword.STATIC) { |
| 6708 !_tokenMatches(_peek(), TokenType.PERIOD) && | |
| 6709 !_tokenMatches(_peek(), TokenType.LT)) { | |
| 6710 if (modifiers.staticKeyword != null) { | 3724 if (modifiers.staticKeyword != null) { |
| 6711 _reportErrorForCurrentToken( | 3725 _reportErrorForCurrentToken( |
| 6712 ParserErrorCode.DUPLICATED_MODIFIER, [_currentToken.lexeme]); | 3726 ParserErrorCode.DUPLICATED_MODIFIER, [_currentToken.lexeme]); |
| 6713 _advance(); | 3727 _advance(); |
| 6714 } else { | 3728 } else { |
| 6715 modifiers.staticKeyword = getAndAdvance(); | 3729 modifiers.staticKeyword = getAndAdvance(); |
| 6716 } | 3730 } |
| 6717 } else if (_matchesKeyword(Keyword.VAR)) { | 3731 } else if (keyword == Keyword.VAR) { |
| 6718 if (modifiers.varKeyword != null) { | 3732 if (modifiers.varKeyword != null) { |
| 6719 _reportErrorForCurrentToken( | 3733 _reportErrorForCurrentToken( |
| 6720 ParserErrorCode.DUPLICATED_MODIFIER, [_currentToken.lexeme]); | 3734 ParserErrorCode.DUPLICATED_MODIFIER, [_currentToken.lexeme]); |
| 6721 _advance(); | 3735 _advance(); |
| 6722 } else { | 3736 } else { |
| 6723 modifiers.varKeyword = getAndAdvance(); | 3737 modifiers.varKeyword = getAndAdvance(); |
| 6724 } | 3738 } |
| 6725 } else { | 3739 } else { |
| 6726 progress = false; | 3740 progress = false; |
| 6727 } | 3741 } |
| 6728 } | 3742 } |
| 6729 return modifiers; | 3743 return modifiers; |
| 6730 } | 3744 } |
| 6731 | 3745 |
| 6732 /** | 3746 /** |
| 6733 * Parse a multiplicative expression. Return the multiplicative expression | 3747 * Parse a multiplicative expression. Return the multiplicative expression |
| 6734 * that was parsed. | 3748 * that was parsed. |
| 6735 * | 3749 * |
| 6736 * multiplicativeExpression ::= | 3750 * multiplicativeExpression ::= |
| 6737 * unaryExpression (multiplicativeOperator unaryExpression)* | 3751 * unaryExpression (multiplicativeOperator unaryExpression)* |
| 6738 * | 'super' (multiplicativeOperator unaryExpression)+ | 3752 * | 'super' (multiplicativeOperator unaryExpression)+ |
| 6739 */ | 3753 */ |
| 6740 Expression _parseMultiplicativeExpression() { | 3754 Expression parseMultiplicativeExpression() { |
| 6741 Expression expression; | 3755 Expression expression; |
| 6742 if (_matchesKeyword(Keyword.SUPER) && | 3756 if (_currentToken.keyword == Keyword.SUPER && |
| 6743 _currentToken.next.type.isMultiplicativeOperator) { | 3757 _currentToken.next.type.isMultiplicativeOperator) { |
| 6744 expression = new SuperExpression(getAndAdvance()); | 3758 expression = new SuperExpression(getAndAdvance()); |
| 6745 } else { | 3759 } else { |
| 6746 expression = _parseUnaryExpression(); | 3760 expression = parseUnaryExpression(); |
| 6747 } | 3761 } |
| 6748 while (_currentToken.type.isMultiplicativeOperator) { | 3762 while (_currentToken.type.isMultiplicativeOperator) { |
| 6749 Token operator = getAndAdvance(); | 3763 expression = new BinaryExpression( |
| 6750 expression = | 3764 expression, getAndAdvance(), parseUnaryExpression()); |
| 6751 new BinaryExpression(expression, operator, _parseUnaryExpression()); | |
| 6752 } | 3765 } |
| 6753 return expression; | 3766 return expression; |
| 6754 } | 3767 } |
| 6755 | 3768 |
| 6756 /** | 3769 /** |
| 6757 * Parse a class native clause. Return the native clause that was parsed. | 3770 * Parse a new expression. Return the new expression that was parsed. |
| 6758 * | 3771 * |
| 6759 * classNativeClause ::= | 3772 * This method assumes that the current token matches `Keyword.NEW`. |
| 6760 * 'native' name | |
| 6761 */ | |
| 6762 NativeClause _parseNativeClause() { | |
| 6763 Token keyword = getAndAdvance(); | |
| 6764 StringLiteral name = parseStringLiteral(); | |
| 6765 return new NativeClause(keyword, name); | |
| 6766 } | |
| 6767 | |
| 6768 /** | |
| 6769 * Parse a new expression. Return the new expression that was parsed. | |
| 6770 * | 3773 * |
| 6771 * newExpression ::= | 3774 * newExpression ::= |
| 6772 * instanceCreationExpression | 3775 * instanceCreationExpression |
| 6773 */ | 3776 */ |
| 6774 InstanceCreationExpression _parseNewExpression() => | 3777 InstanceCreationExpression parseNewExpression() => |
| 6775 _parseInstanceCreationExpression(_expectKeyword(Keyword.NEW)); | 3778 parseInstanceCreationExpression(getAndAdvance()); |
| 6776 | 3779 |
| 6777 /** | 3780 /** |
| 6778 * Parse a non-labeled statement. Return the non-labeled statement that was | 3781 * Parse a non-labeled statement. Return the non-labeled statement that was |
| 6779 * parsed. | 3782 * parsed. |
| 6780 * | 3783 * |
| 6781 * nonLabeledStatement ::= | 3784 * nonLabeledStatement ::= |
| 6782 * block | 3785 * block |
| 6783 * | assertStatement | 3786 * | assertStatement |
| 6784 * | breakStatement | 3787 * | breakStatement |
| 6785 * | continueStatement | 3788 * | continueStatement |
| 6786 * | doStatement | 3789 * | doStatement |
| 6787 * | forStatement | 3790 * | forStatement |
| 6788 * | ifStatement | 3791 * | ifStatement |
| 6789 * | returnStatement | 3792 * | returnStatement |
| 6790 * | switchStatement | 3793 * | switchStatement |
| 6791 * | tryStatement | 3794 * | tryStatement |
| 6792 * | whileStatement | 3795 * | whileStatement |
| 6793 * | variableDeclarationList ';' | 3796 * | variableDeclarationList ';' |
| 6794 * | expressionStatement | 3797 * | expressionStatement |
| 6795 * | functionSignature functionBody | 3798 * | functionSignature functionBody |
| 6796 */ | 3799 */ |
| 6797 Statement _parseNonLabeledStatement() { | 3800 Statement parseNonLabeledStatement() { |
| 6798 // TODO(brianwilkerson) Pass the comment and metadata on where appropriate. | 3801 // TODO(brianwilkerson) Pass the comment and metadata on where appropriate. |
| 6799 CommentAndMetadata commentAndMetadata = _parseCommentAndMetadata(); | 3802 CommentAndMetadata commentAndMetadata = parseCommentAndMetadata(); |
| 6800 if (_matches(TokenType.OPEN_CURLY_BRACKET)) { | 3803 TokenType type = _currentToken.type; |
| 3804 if (type == TokenType.OPEN_CURLY_BRACKET) { |
| 6801 if (_tokenMatches(_peek(), TokenType.STRING)) { | 3805 if (_tokenMatches(_peek(), TokenType.STRING)) { |
| 6802 Token afterString = _skipStringLiteral(_currentToken.next); | 3806 Token afterString = skipStringLiteral(_currentToken.next); |
| 6803 if (afterString != null && afterString.type == TokenType.COLON) { | 3807 if (afterString != null && afterString.type == TokenType.COLON) { |
| 6804 return new ExpressionStatement( | 3808 return new ExpressionStatement( |
| 6805 parseExpression2(), _expect(TokenType.SEMICOLON)); | 3809 parseExpression2(), _expect(TokenType.SEMICOLON)); |
| 6806 } | 3810 } |
| 6807 } | 3811 } |
| 6808 return parseBlock(); | 3812 return parseBlock(); |
| 6809 } else if (_matches(TokenType.KEYWORD) && | 3813 } else if (type == TokenType.KEYWORD && |
| 6810 !(_currentToken as KeywordToken).keyword.isPseudoKeyword) { | 3814 !_currentToken.keyword.isPseudoKeyword) { |
| 6811 Keyword keyword = (_currentToken as KeywordToken).keyword; | 3815 Keyword keyword = _currentToken.keyword; |
| 6812 // TODO(jwren) compute some metrics to figure out a better order for this | 3816 // TODO(jwren) compute some metrics to figure out a better order for this |
| 6813 // if-then sequence to optimize performance | 3817 // if-then sequence to optimize performance |
| 6814 if (keyword == Keyword.ASSERT) { | 3818 if (keyword == Keyword.ASSERT) { |
| 6815 return _parseAssertStatement(); | 3819 return parseAssertStatement(); |
| 6816 } else if (keyword == Keyword.BREAK) { | 3820 } else if (keyword == Keyword.BREAK) { |
| 6817 return _parseBreakStatement(); | 3821 return parseBreakStatement(); |
| 6818 } else if (keyword == Keyword.CONTINUE) { | 3822 } else if (keyword == Keyword.CONTINUE) { |
| 6819 return _parseContinueStatement(); | 3823 return parseContinueStatement(); |
| 6820 } else if (keyword == Keyword.DO) { | 3824 } else if (keyword == Keyword.DO) { |
| 6821 return _parseDoStatement(); | 3825 return parseDoStatement(); |
| 6822 } else if (keyword == Keyword.FOR) { | 3826 } else if (keyword == Keyword.FOR) { |
| 6823 return _parseForStatement(); | 3827 return parseForStatement(); |
| 6824 } else if (keyword == Keyword.IF) { | 3828 } else if (keyword == Keyword.IF) { |
| 6825 return _parseIfStatement(); | 3829 return parseIfStatement(); |
| 6826 } else if (keyword == Keyword.RETHROW) { | 3830 } else if (keyword == Keyword.RETHROW) { |
| 6827 return new ExpressionStatement( | 3831 return new ExpressionStatement( |
| 6828 _parseRethrowExpression(), _expect(TokenType.SEMICOLON)); | 3832 parseRethrowExpression(), _expect(TokenType.SEMICOLON)); |
| 6829 } else if (keyword == Keyword.RETURN) { | 3833 } else if (keyword == Keyword.RETURN) { |
| 6830 return _parseReturnStatement(); | 3834 return parseReturnStatement(); |
| 6831 } else if (keyword == Keyword.SWITCH) { | 3835 } else if (keyword == Keyword.SWITCH) { |
| 6832 return _parseSwitchStatement(); | 3836 return parseSwitchStatement(); |
| 6833 } else if (keyword == Keyword.THROW) { | 3837 } else if (keyword == Keyword.THROW) { |
| 6834 return new ExpressionStatement( | 3838 return new ExpressionStatement( |
| 6835 _parseThrowExpression(), _expect(TokenType.SEMICOLON)); | 3839 parseThrowExpression(), _expect(TokenType.SEMICOLON)); |
| 6836 } else if (keyword == Keyword.TRY) { | 3840 } else if (keyword == Keyword.TRY) { |
| 6837 return _parseTryStatement(); | 3841 return parseTryStatement(); |
| 6838 } else if (keyword == Keyword.WHILE) { | 3842 } else if (keyword == Keyword.WHILE) { |
| 6839 return _parseWhileStatement(); | 3843 return parseWhileStatement(); |
| 6840 } else if (keyword == Keyword.VAR || keyword == Keyword.FINAL) { | 3844 } else if (keyword == Keyword.VAR || keyword == Keyword.FINAL) { |
| 6841 return _parseVariableDeclarationStatementAfterMetadata( | 3845 return parseVariableDeclarationStatementAfterMetadata( |
| 6842 commentAndMetadata); | 3846 commentAndMetadata); |
| 6843 } else if (keyword == Keyword.VOID) { | 3847 } else if (keyword == Keyword.VOID) { |
| 6844 TypeName returnType = parseReturnType(); | 3848 TypeName returnType = |
| 3849 new TypeName(new SimpleIdentifier(getAndAdvance()), null); |
| 3850 Token next = _currentToken.next; |
| 6845 if (_matchesIdentifier() && | 3851 if (_matchesIdentifier() && |
| 6846 _peek().matchesAny([ | 3852 next.matchesAny(const <TokenType>[ |
| 6847 TokenType.OPEN_PAREN, | 3853 TokenType.OPEN_PAREN, |
| 6848 TokenType.OPEN_CURLY_BRACKET, | 3854 TokenType.OPEN_CURLY_BRACKET, |
| 6849 TokenType.FUNCTION | 3855 TokenType.FUNCTION, |
| 3856 TokenType.LT |
| 6850 ])) { | 3857 ])) { |
| 6851 return _parseFunctionDeclarationStatementAfterReturnType( | 3858 return _parseFunctionDeclarationStatementAfterReturnType( |
| 6852 commentAndMetadata, returnType); | 3859 commentAndMetadata, returnType); |
| 6853 } else { | 3860 } else { |
| 6854 // | 3861 // |
| 6855 // We have found an error of some kind. Try to recover. | 3862 // We have found an error of some kind. Try to recover. |
| 6856 // | 3863 // |
| 6857 if (_matchesIdentifier()) { | 3864 if (_matchesIdentifier()) { |
| 6858 if (_peek().matchesAny( | 3865 if (next.matchesAny(const <TokenType>[ |
| 6859 [TokenType.EQ, TokenType.COMMA, TokenType.SEMICOLON])) { | 3866 TokenType.EQ, |
| 3867 TokenType.COMMA, |
| 3868 TokenType.SEMICOLON |
| 3869 ])) { |
| 6860 // | 3870 // |
| 6861 // We appear to have a variable declaration with a type of "void". | 3871 // We appear to have a variable declaration with a type of "void". |
| 6862 // | 3872 // |
| 6863 _reportErrorForNode(ParserErrorCode.VOID_VARIABLE, returnType); | 3873 _reportErrorForNode(ParserErrorCode.VOID_VARIABLE, returnType); |
| 6864 return _parseVariableDeclarationStatementAfterMetadata( | 3874 return parseVariableDeclarationStatementAfterMetadata( |
| 6865 commentAndMetadata); | 3875 commentAndMetadata); |
| 6866 } | 3876 } |
| 6867 } else if (_matches(TokenType.CLOSE_CURLY_BRACKET)) { | 3877 } else if (_matches(TokenType.CLOSE_CURLY_BRACKET)) { |
| 6868 // | 3878 // |
| 6869 // We appear to have found an incomplete statement at the end of a | 3879 // We appear to have found an incomplete statement at the end of a |
| 6870 // block. Parse it as a variable declaration. | 3880 // block. Parse it as a variable declaration. |
| 6871 // | 3881 // |
| 6872 return _parseVariableDeclarationStatementAfterType( | 3882 return _parseVariableDeclarationStatementAfterType( |
| 6873 commentAndMetadata, null, returnType); | 3883 commentAndMetadata, null, returnType); |
| 6874 } | 3884 } |
| 6875 _reportErrorForCurrentToken(ParserErrorCode.MISSING_STATEMENT); | 3885 _reportErrorForCurrentToken(ParserErrorCode.MISSING_STATEMENT); |
| 6876 // TODO(brianwilkerson) Recover from this error. | 3886 // TODO(brianwilkerson) Recover from this error. |
| 6877 return new EmptyStatement(_createSyntheticToken(TokenType.SEMICOLON)); | 3887 return new EmptyStatement(_createSyntheticToken(TokenType.SEMICOLON)); |
| 6878 } | 3888 } |
| 6879 } else if (keyword == Keyword.CONST) { | 3889 } else if (keyword == Keyword.CONST) { |
| 6880 if (_peek().matchesAny([ | 3890 Token next = _currentToken.next; |
| 3891 if (next.matchesAny(const <TokenType>[ |
| 6881 TokenType.LT, | 3892 TokenType.LT, |
| 6882 TokenType.OPEN_CURLY_BRACKET, | 3893 TokenType.OPEN_CURLY_BRACKET, |
| 6883 TokenType.OPEN_SQUARE_BRACKET, | 3894 TokenType.OPEN_SQUARE_BRACKET, |
| 6884 TokenType.INDEX | 3895 TokenType.INDEX |
| 6885 ])) { | 3896 ])) { |
| 6886 return new ExpressionStatement( | 3897 return new ExpressionStatement( |
| 6887 parseExpression2(), _expect(TokenType.SEMICOLON)); | 3898 parseExpression2(), _expect(TokenType.SEMICOLON)); |
| 6888 } else if (_tokenMatches(_peek(), TokenType.IDENTIFIER)) { | 3899 } else if (_tokenMatches(next, TokenType.IDENTIFIER)) { |
| 6889 Token afterType = _skipTypeName(_peek()); | 3900 Token afterType = skipTypeName(next); |
| 6890 if (afterType != null) { | 3901 if (afterType != null) { |
| 6891 if (_tokenMatches(afterType, TokenType.OPEN_PAREN) || | 3902 if (_tokenMatches(afterType, TokenType.OPEN_PAREN) || |
| 6892 (_tokenMatches(afterType, TokenType.PERIOD) && | 3903 (_tokenMatches(afterType, TokenType.PERIOD) && |
| 6893 _tokenMatches(afterType.next, TokenType.IDENTIFIER) && | 3904 _tokenMatches(afterType.next, TokenType.IDENTIFIER) && |
| 6894 _tokenMatches(afterType.next.next, TokenType.OPEN_PAREN))) { | 3905 _tokenMatches(afterType.next.next, TokenType.OPEN_PAREN))) { |
| 6895 return new ExpressionStatement( | 3906 return new ExpressionStatement( |
| 6896 parseExpression2(), _expect(TokenType.SEMICOLON)); | 3907 parseExpression2(), _expect(TokenType.SEMICOLON)); |
| 6897 } | 3908 } |
| 6898 } | 3909 } |
| 6899 } | 3910 } |
| 6900 return _parseVariableDeclarationStatementAfterMetadata( | 3911 return parseVariableDeclarationStatementAfterMetadata( |
| 6901 commentAndMetadata); | 3912 commentAndMetadata); |
| 6902 } else if (keyword == Keyword.NEW || | 3913 } else if (keyword == Keyword.NEW || |
| 6903 keyword == Keyword.TRUE || | 3914 keyword == Keyword.TRUE || |
| 6904 keyword == Keyword.FALSE || | 3915 keyword == Keyword.FALSE || |
| 6905 keyword == Keyword.NULL || | 3916 keyword == Keyword.NULL || |
| 6906 keyword == Keyword.SUPER || | 3917 keyword == Keyword.SUPER || |
| 6907 keyword == Keyword.THIS) { | 3918 keyword == Keyword.THIS) { |
| 6908 return new ExpressionStatement( | 3919 return new ExpressionStatement( |
| 6909 parseExpression2(), _expect(TokenType.SEMICOLON)); | 3920 parseExpression2(), _expect(TokenType.SEMICOLON)); |
| 6910 } else { | 3921 } else { |
| 6911 // | 3922 // |
| 6912 // We have found an error of some kind. Try to recover. | 3923 // We have found an error of some kind. Try to recover. |
| 6913 // | 3924 // |
| 6914 _reportErrorForCurrentToken(ParserErrorCode.MISSING_STATEMENT); | 3925 _reportErrorForCurrentToken(ParserErrorCode.MISSING_STATEMENT); |
| 6915 return new EmptyStatement(_createSyntheticToken(TokenType.SEMICOLON)); | 3926 return new EmptyStatement(_createSyntheticToken(TokenType.SEMICOLON)); |
| 6916 } | 3927 } |
| 6917 } else if (_inGenerator && _matchesString(_YIELD)) { | 3928 } else if (_inGenerator && _matchesString(_YIELD)) { |
| 6918 return _parseYieldStatement(); | 3929 return parseYieldStatement(); |
| 6919 } else if (_inAsync && _matchesString(_AWAIT)) { | 3930 } else if (_inAsync && _matchesString(_AWAIT)) { |
| 6920 if (_tokenMatchesKeyword(_peek(), Keyword.FOR)) { | 3931 if (_tokenMatchesKeyword(_peek(), Keyword.FOR)) { |
| 6921 return _parseForStatement(); | 3932 return parseForStatement(); |
| 6922 } | 3933 } |
| 6923 return new ExpressionStatement( | 3934 return new ExpressionStatement( |
| 6924 parseExpression2(), _expect(TokenType.SEMICOLON)); | 3935 parseExpression2(), _expect(TokenType.SEMICOLON)); |
| 6925 } else if (_matchesString(_AWAIT) && | 3936 } else if (_matchesString(_AWAIT) && |
| 6926 _tokenMatchesKeyword(_peek(), Keyword.FOR)) { | 3937 _tokenMatchesKeyword(_peek(), Keyword.FOR)) { |
| 6927 Token awaitToken = _currentToken; | 3938 Token awaitToken = _currentToken; |
| 6928 Statement statement = _parseForStatement(); | 3939 Statement statement = parseForStatement(); |
| 6929 if (statement is! ForStatement) { | 3940 if (statement is! ForStatement) { |
| 6930 _reportErrorForToken( | 3941 _reportErrorForToken( |
| 6931 CompileTimeErrorCode.ASYNC_FOR_IN_WRONG_CONTEXT, awaitToken); | 3942 CompileTimeErrorCode.ASYNC_FOR_IN_WRONG_CONTEXT, awaitToken); |
| 6932 } | 3943 } |
| 6933 return statement; | 3944 return statement; |
| 6934 } else if (_matches(TokenType.SEMICOLON)) { | 3945 } else if (type == TokenType.SEMICOLON) { |
| 6935 return _parseEmptyStatement(); | 3946 return parseEmptyStatement(); |
| 6936 } else if (_isInitializedVariableDeclaration()) { | 3947 } else if (isInitializedVariableDeclaration()) { |
| 6937 return _parseVariableDeclarationStatementAfterMetadata( | 3948 return parseVariableDeclarationStatementAfterMetadata(commentAndMetadata); |
| 6938 commentAndMetadata); | 3949 } else if (isFunctionDeclaration()) { |
| 6939 } else if (_isFunctionDeclaration()) { | 3950 return parseFunctionDeclarationStatement(); |
| 6940 return _parseFunctionDeclarationStatement(); | 3951 } else if (type == TokenType.CLOSE_CURLY_BRACKET) { |
| 6941 } else if (_matches(TokenType.CLOSE_CURLY_BRACKET)) { | |
| 6942 _reportErrorForCurrentToken(ParserErrorCode.MISSING_STATEMENT); | 3952 _reportErrorForCurrentToken(ParserErrorCode.MISSING_STATEMENT); |
| 6943 return new EmptyStatement(_createSyntheticToken(TokenType.SEMICOLON)); | 3953 return new EmptyStatement(_createSyntheticToken(TokenType.SEMICOLON)); |
| 6944 } else { | 3954 } else { |
| 6945 return new ExpressionStatement(parseExpression2(), _expectSemicolon()); | 3955 return new ExpressionStatement( |
| 3956 parseExpression2(), _expect(TokenType.SEMICOLON)); |
| 6946 } | 3957 } |
| 6947 } | 3958 } |
| 6948 | 3959 |
| 6949 /** | 3960 /** |
| 3961 * Parse a normal formal parameter. Return the normal formal parameter that |
| 3962 * was parsed. |
| 3963 * |
| 3964 * normalFormalParameter ::= |
| 3965 * functionSignature |
| 3966 * | fieldFormalParameter |
| 3967 * | simpleFormalParameter |
| 3968 * |
| 3969 * functionSignature: |
| 3970 * metadata returnType? identifier typeParameters? formalParameterList |
| 3971 * |
| 3972 * fieldFormalParameter ::= |
| 3973 * metadata finalConstVarOrType? 'this' '.' identifier |
| 3974 * |
| 3975 * simpleFormalParameter ::= |
| 3976 * declaredIdentifier |
| 3977 * | metadata identifier |
| 3978 */ |
| 3979 NormalFormalParameter parseNormalFormalParameter() { |
| 3980 CommentAndMetadata commentAndMetadata = parseCommentAndMetadata(); |
| 3981 FinalConstVarOrType holder = parseFinalConstVarOrType(true); |
| 3982 Token thisKeyword = null; |
| 3983 Token period = null; |
| 3984 if (_matchesKeyword(Keyword.THIS)) { |
| 3985 thisKeyword = getAndAdvance(); |
| 3986 period = _expect(TokenType.PERIOD); |
| 3987 } |
| 3988 SimpleIdentifier identifier = parseSimpleIdentifier(); |
| 3989 TypeParameterList typeParameters = _parseGenericMethodTypeParameters(); |
| 3990 if (_matches(TokenType.OPEN_PAREN)) { |
| 3991 FormalParameterList parameters = _parseFormalParameterListUnchecked(); |
| 3992 if (thisKeyword == null) { |
| 3993 if (holder.keyword != null) { |
| 3994 _reportErrorForToken( |
| 3995 ParserErrorCode.FUNCTION_TYPED_PARAMETER_VAR, holder.keyword); |
| 3996 } |
| 3997 Token question = null; |
| 3998 if (enableNnbd && _matches(TokenType.QUESTION)) { |
| 3999 question = getAndAdvance(); |
| 4000 } |
| 4001 return new FunctionTypedFormalParameter( |
| 4002 commentAndMetadata.comment, |
| 4003 commentAndMetadata.metadata, |
| 4004 holder.type, |
| 4005 new SimpleIdentifier(identifier.token, isDeclaration: true), |
| 4006 typeParameters, |
| 4007 parameters, |
| 4008 question: question); |
| 4009 } else { |
| 4010 return new FieldFormalParameter( |
| 4011 commentAndMetadata.comment, |
| 4012 commentAndMetadata.metadata, |
| 4013 holder.keyword, |
| 4014 holder.type, |
| 4015 thisKeyword, |
| 4016 period, |
| 4017 identifier, |
| 4018 typeParameters, |
| 4019 parameters); |
| 4020 } |
| 4021 } else if (typeParameters != null) { |
| 4022 // TODO(brianwilkerson) Report an error. It looks like a function-typed |
| 4023 // parameter with no parameter list. |
| 4024 //_reportErrorForToken(ParserErrorCode.MISSING_PARAMETERS, typeParameters.
endToken); |
| 4025 } |
| 4026 TypeName type = holder.type; |
| 4027 if (type != null) { |
| 4028 if (_tokenMatchesKeyword(type.name.beginToken, Keyword.VOID)) { |
| 4029 _reportErrorForToken( |
| 4030 ParserErrorCode.VOID_PARAMETER, type.name.beginToken); |
| 4031 } else if (holder.keyword != null && |
| 4032 _tokenMatchesKeyword(holder.keyword, Keyword.VAR)) { |
| 4033 _reportErrorForToken(ParserErrorCode.VAR_AND_TYPE, holder.keyword); |
| 4034 } |
| 4035 } |
| 4036 if (thisKeyword != null) { |
| 4037 // TODO(brianwilkerson) If there are type parameters but no parameters, |
| 4038 // should we create a synthetic empty parameter list here so we can |
| 4039 // capture the type parameters? |
| 4040 return new FieldFormalParameter( |
| 4041 commentAndMetadata.comment, |
| 4042 commentAndMetadata.metadata, |
| 4043 holder.keyword, |
| 4044 holder.type, |
| 4045 thisKeyword, |
| 4046 period, |
| 4047 identifier, |
| 4048 null, |
| 4049 null); |
| 4050 } |
| 4051 return new SimpleFormalParameter( |
| 4052 commentAndMetadata.comment, |
| 4053 commentAndMetadata.metadata, |
| 4054 holder.keyword, |
| 4055 holder.type, |
| 4056 new SimpleIdentifier(identifier.token, isDeclaration: true)); |
| 4057 } |
| 4058 |
| 4059 /** |
| 6950 * Parse an operator declaration. The [commentAndMetadata] is the | 4060 * Parse an operator declaration. The [commentAndMetadata] is the |
| 6951 * documentation comment and metadata to be associated with the declaration. | 4061 * documentation comment and metadata to be associated with the declaration. |
| 6952 * The [externalKeyword] is the 'external' token. The [returnType] is the | 4062 * The [externalKeyword] is the 'external' token. The [returnType] is the |
| 6953 * return type that has already been parsed, or `null` if there was no return | 4063 * return type that has already been parsed, or `null` if there was no return |
| 6954 * type. Return the operator declaration that was parsed. | 4064 * type. Return the operator declaration that was parsed. |
| 6955 * | 4065 * |
| 6956 * operatorDeclaration ::= | 4066 * operatorDeclaration ::= |
| 6957 * operatorSignature (';' | functionBody) | 4067 * operatorSignature (';' | functionBody) |
| 6958 * | 4068 * |
| 6959 * operatorSignature ::= | 4069 * operatorSignature ::= |
| 6960 * 'external'? returnType? 'operator' operator formalParameterList | 4070 * 'external'? returnType? 'operator' operator formalParameterList |
| 6961 */ | 4071 */ |
| 6962 MethodDeclaration _parseOperator(CommentAndMetadata commentAndMetadata, | 4072 MethodDeclaration parseOperator(CommentAndMetadata commentAndMetadata, |
| 6963 Token externalKeyword, TypeName returnType) { | 4073 Token externalKeyword, TypeName returnType) { |
| 6964 Token operatorKeyword; | 4074 Token operatorKeyword; |
| 6965 if (_matchesKeyword(Keyword.OPERATOR)) { | 4075 if (_matchesKeyword(Keyword.OPERATOR)) { |
| 6966 operatorKeyword = getAndAdvance(); | 4076 operatorKeyword = getAndAdvance(); |
| 6967 } else { | 4077 } else { |
| 6968 _reportErrorForToken( | 4078 _reportErrorForToken( |
| 6969 ParserErrorCode.MISSING_KEYWORD_OPERATOR, _currentToken); | 4079 ParserErrorCode.MISSING_KEYWORD_OPERATOR, _currentToken); |
| 6970 operatorKeyword = _createSyntheticKeyword(Keyword.OPERATOR); | 4080 operatorKeyword = _createSyntheticKeyword(Keyword.OPERATOR); |
| 6971 } | 4081 } |
| 6972 if (!_currentToken.isUserDefinableOperator) { | 4082 return _parseOperatorAfterKeyword( |
| 6973 _reportErrorForCurrentToken( | 4083 commentAndMetadata, externalKeyword, returnType, operatorKeyword); |
| 6974 ParserErrorCode.NON_USER_DEFINABLE_OPERATOR, [_currentToken.lexeme]); | |
| 6975 } | |
| 6976 SimpleIdentifier name = new SimpleIdentifier(getAndAdvance()); | |
| 6977 if (_matches(TokenType.EQ)) { | |
| 6978 Token previous = _currentToken.previous; | |
| 6979 if ((_tokenMatches(previous, TokenType.EQ_EQ) || | |
| 6980 _tokenMatches(previous, TokenType.BANG_EQ)) && | |
| 6981 _currentToken.offset == previous.offset + 2) { | |
| 6982 _reportErrorForCurrentToken(ParserErrorCode.INVALID_OPERATOR, | |
| 6983 ["${previous.lexeme}${_currentToken.lexeme}"]); | |
| 6984 _advance(); | |
| 6985 } | |
| 6986 } | |
| 6987 FormalParameterList parameters = parseFormalParameterList(); | |
| 6988 _validateFormalParameterList(parameters); | |
| 6989 FunctionBody body = | |
| 6990 _parseFunctionBody(true, ParserErrorCode.MISSING_FUNCTION_BODY, false); | |
| 6991 if (externalKeyword != null && body is! EmptyFunctionBody) { | |
| 6992 _reportErrorForCurrentToken(ParserErrorCode.EXTERNAL_OPERATOR_WITH_BODY); | |
| 6993 } | |
| 6994 return new MethodDeclaration( | |
| 6995 commentAndMetadata.comment, | |
| 6996 commentAndMetadata.metadata, | |
| 6997 externalKeyword, | |
| 6998 null, | |
| 6999 returnType, | |
| 7000 null, | |
| 7001 operatorKeyword, | |
| 7002 name, | |
| 7003 null, | |
| 7004 parameters, | |
| 7005 body); | |
| 7006 } | 4084 } |
| 7007 | 4085 |
| 7008 /** | 4086 /** |
| 7009 * Parse a return type if one is given, otherwise return `null` without | |
| 7010 * advancing. Return the return type that was parsed. | |
| 7011 */ | |
| 7012 TypeName _parseOptionalReturnType() { | |
| 7013 if (_matchesKeyword(Keyword.VOID)) { | |
| 7014 return parseReturnType(); | |
| 7015 } else if (_matchesIdentifier() && | |
| 7016 !_matchesKeyword(Keyword.GET) && | |
| 7017 !_matchesKeyword(Keyword.SET) && | |
| 7018 !_matchesKeyword(Keyword.OPERATOR) && | |
| 7019 (_tokenMatchesIdentifier(_peek()) || | |
| 7020 _tokenMatches(_peek(), TokenType.LT))) { | |
| 7021 return parseReturnType(); | |
| 7022 } else if (_matchesIdentifier() && | |
| 7023 _tokenMatches(_peek(), TokenType.PERIOD) && | |
| 7024 _tokenMatchesIdentifier(_peekAt(2)) && | |
| 7025 (_tokenMatchesIdentifier(_peekAt(3)) || | |
| 7026 _tokenMatches(_peekAt(3), TokenType.LT))) { | |
| 7027 return parseReturnType(); | |
| 7028 } | |
| 7029 return null; | |
| 7030 } | |
| 7031 | |
| 7032 /** | |
| 7033 * Parse a part or part-of directive. The [commentAndMetadata] is the metadata | 4087 * Parse a part or part-of directive. The [commentAndMetadata] is the metadata |
| 7034 * to be associated with the directive. Return the part or part-of directive | 4088 * to be associated with the directive. Return the part or part-of directive |
| 7035 * that was parsed. | 4089 * that was parsed. |
| 7036 * | 4090 * |
| 4091 * This method assumes that the current token matches `Keyword.PART`. |
| 4092 * |
| 7037 * partDirective ::= | 4093 * partDirective ::= |
| 7038 * metadata 'part' stringLiteral ';' | 4094 * metadata 'part' stringLiteral ';' |
| 7039 * | 4095 * |
| 7040 * partOfDirective ::= | 4096 * partOfDirective ::= |
| 7041 * metadata 'part' 'of' identifier ';' | 4097 * metadata 'part' 'of' identifier ';' |
| 7042 */ | 4098 */ |
| 7043 Directive _parsePartDirective(CommentAndMetadata commentAndMetadata) { | 4099 Directive parsePartOrPartOfDirective(CommentAndMetadata commentAndMetadata) { |
| 7044 Token partKeyword = _expectKeyword(Keyword.PART); | 4100 if (_tokenMatchesString(_peek(), _OF)) { |
| 7045 if (_matchesString(_OF)) { | 4101 return _parsePartOfDirective(commentAndMetadata); |
| 7046 Token ofKeyword = getAndAdvance(); | |
| 7047 LibraryIdentifier libraryName = _parseLibraryName( | |
| 7048 ParserErrorCode.MISSING_NAME_IN_PART_OF_DIRECTIVE, ofKeyword); | |
| 7049 Token semicolon = _expect(TokenType.SEMICOLON); | |
| 7050 return new PartOfDirective( | |
| 7051 commentAndMetadata.comment, | |
| 7052 commentAndMetadata.metadata, | |
| 7053 partKeyword, | |
| 7054 ofKeyword, | |
| 7055 libraryName, | |
| 7056 semicolon); | |
| 7057 } | 4102 } |
| 7058 StringLiteral partUri = _parseUri(); | 4103 return _parsePartDirective(commentAndMetadata); |
| 7059 Token semicolon = _expect(TokenType.SEMICOLON); | |
| 7060 return new PartDirective(commentAndMetadata.comment, | |
| 7061 commentAndMetadata.metadata, partKeyword, partUri, semicolon); | |
| 7062 } | 4104 } |
| 7063 | 4105 |
| 7064 /** | 4106 /** |
| 7065 * Parse a postfix expression. Return the postfix expression that was parsed. | 4107 * Parse a postfix expression. Return the postfix expression that was parsed. |
| 7066 * | 4108 * |
| 7067 * postfixExpression ::= | 4109 * postfixExpression ::= |
| 7068 * assignableExpression postfixOperator | 4110 * assignableExpression postfixOperator |
| 7069 * | primary selector* | 4111 * | primary selector* |
| 7070 * | 4112 * |
| 7071 * selector ::= | 4113 * selector ::= |
| 7072 * assignableSelector | 4114 * assignableSelector |
| 7073 * | argumentList | 4115 * | argumentList |
| 7074 */ | 4116 */ |
| 7075 Expression _parsePostfixExpression() { | 4117 Expression parsePostfixExpression() { |
| 7076 Expression operand = _parseAssignableExpression(true); | 4118 Expression operand = parseAssignableExpression(true); |
| 7077 if (_matches(TokenType.OPEN_SQUARE_BRACKET) || | 4119 TokenType type = _currentToken.type; |
| 7078 _matches(TokenType.PERIOD) || | 4120 if (type == TokenType.OPEN_SQUARE_BRACKET || |
| 7079 _matches(TokenType.QUESTION_PERIOD) || | 4121 type == TokenType.PERIOD || |
| 7080 _matches(TokenType.OPEN_PAREN) || | 4122 type == TokenType.QUESTION_PERIOD || |
| 7081 (parseGenericMethods && _matches(TokenType.LT))) { | 4123 type == TokenType.OPEN_PAREN || |
| 4124 (parseGenericMethods && type == TokenType.LT)) { |
| 7082 do { | 4125 do { |
| 7083 if (_isLikelyParameterList()) { | 4126 if (_isLikelyArgumentList()) { |
| 7084 TypeArgumentList typeArguments = null; | 4127 TypeArgumentList typeArguments = _parseOptionalTypeArguments(); |
| 7085 if (_matches(TokenType.LT)) { | |
| 7086 typeArguments = parseTypeArgumentList(); | |
| 7087 } | |
| 7088 ArgumentList argumentList = parseArgumentList(); | 4128 ArgumentList argumentList = parseArgumentList(); |
| 7089 if (operand is PropertyAccess) { | 4129 Expression currentOperand = operand; |
| 7090 PropertyAccess access = operand as PropertyAccess; | 4130 if (currentOperand is PropertyAccess) { |
| 7091 operand = new MethodInvocation(access.target, access.operator, | 4131 operand = new MethodInvocation( |
| 7092 access.propertyName, typeArguments, argumentList); | 4132 currentOperand.target, |
| 4133 currentOperand.operator, |
| 4134 currentOperand.propertyName, |
| 4135 typeArguments, |
| 4136 argumentList); |
| 7093 } else { | 4137 } else { |
| 7094 operand = new FunctionExpressionInvocation( | 4138 operand = new FunctionExpressionInvocation( |
| 7095 operand, typeArguments, argumentList); | 4139 operand, typeArguments, argumentList); |
| 7096 } | 4140 } |
| 7097 } else { | 4141 } else { |
| 7098 operand = _parseAssignableSelector(operand, true); | 4142 operand = parseAssignableSelector(operand, true); |
| 7099 } | 4143 } |
| 7100 } while (_matches(TokenType.OPEN_SQUARE_BRACKET) || | 4144 type = _currentToken.type; |
| 7101 _matches(TokenType.PERIOD) || | 4145 } while (type == TokenType.OPEN_SQUARE_BRACKET || |
| 7102 _matches(TokenType.QUESTION_PERIOD) || | 4146 type == TokenType.PERIOD || |
| 7103 _matches(TokenType.OPEN_PAREN)); | 4147 type == TokenType.QUESTION_PERIOD || |
| 4148 type == TokenType.OPEN_PAREN); |
| 7104 return operand; | 4149 return operand; |
| 7105 } | 4150 } |
| 7106 if (!_currentToken.type.isIncrementOperator) { | 4151 if (!_currentToken.type.isIncrementOperator) { |
| 7107 return operand; | 4152 return operand; |
| 7108 } | 4153 } |
| 7109 _ensureAssignable(operand); | 4154 _ensureAssignable(operand); |
| 7110 Token operator = getAndAdvance(); | 4155 Token operator = getAndAdvance(); |
| 7111 return new PostfixExpression(operand, operator); | 4156 return new PostfixExpression(operand, operator); |
| 7112 } | 4157 } |
| 7113 | 4158 |
| 7114 /** | 4159 /** |
| 4160 * Parse a prefixed identifier. Return the prefixed identifier that was |
| 4161 * parsed. |
| 4162 * |
| 4163 * prefixedIdentifier ::= |
| 4164 * identifier ('.' identifier)? |
| 4165 */ |
| 4166 Identifier parsePrefixedIdentifier() { |
| 4167 return _parsePrefixedIdentifierAfterIdentifier(parseSimpleIdentifier()); |
| 4168 } |
| 4169 |
| 4170 /** |
| 7115 * Parse a primary expression. Return the primary expression that was parsed. | 4171 * Parse a primary expression. Return the primary expression that was parsed. |
| 7116 * | 4172 * |
| 7117 * primary ::= | 4173 * primary ::= |
| 7118 * thisExpression | 4174 * thisExpression |
| 7119 * | 'super' unconditionalAssignableSelector | 4175 * | 'super' unconditionalAssignableSelector |
| 7120 * | functionExpression | 4176 * | functionExpression |
| 7121 * | literal | 4177 * | literal |
| 7122 * | identifier | 4178 * | identifier |
| 7123 * | newExpression | 4179 * | newExpression |
| 7124 * | constObjectExpression | 4180 * | constObjectExpression |
| 7125 * | '(' expression ')' | 4181 * | '(' expression ')' |
| 7126 * | argumentDefinitionTest | 4182 * | argumentDefinitionTest |
| 7127 * | 4183 * |
| 7128 * literal ::= | 4184 * literal ::= |
| 7129 * nullLiteral | 4185 * nullLiteral |
| 7130 * | booleanLiteral | 4186 * | booleanLiteral |
| 7131 * | numericLiteral | 4187 * | numericLiteral |
| 7132 * | stringLiteral | 4188 * | stringLiteral |
| 7133 * | symbolLiteral | 4189 * | symbolLiteral |
| 7134 * | mapLiteral | 4190 * | mapLiteral |
| 7135 * | listLiteral | 4191 * | listLiteral |
| 7136 */ | 4192 */ |
| 7137 Expression _parsePrimaryExpression() { | 4193 Expression parsePrimaryExpression() { |
| 7138 if (_matchesKeyword(Keyword.THIS)) { | 4194 if (_matchesIdentifier()) { |
| 4195 // TODO(brianwilkerson) The code below was an attempt to recover from an |
| 4196 // error case, but it needs to be applied as a recovery only after we |
| 4197 // know that parsing it as an identifier doesn't work. Leaving the code as |
| 4198 // a reminder of how to recover. |
| 4199 // if (isFunctionExpression(_peek())) { |
| 4200 // // |
| 4201 // // Function expressions were allowed to have names at one point, but t
his is now illegal. |
| 4202 // // |
| 4203 // reportError(ParserErrorCode.NAMED_FUNCTION_EXPRESSION, getAndAdvance()
); |
| 4204 // return parseFunctionExpression(); |
| 4205 // } |
| 4206 return _parsePrefixedIdentifierUnchecked(); |
| 4207 } |
| 4208 TokenType type = _currentToken.type; |
| 4209 if (type == TokenType.STRING) { |
| 4210 return parseStringLiteral(); |
| 4211 } else if (type == TokenType.INT) { |
| 4212 Token token = getAndAdvance(); |
| 4213 int value = null; |
| 4214 try { |
| 4215 value = int.parse(token.lexeme); |
| 4216 } on FormatException { |
| 4217 // The invalid format should have been reported by the scanner. |
| 4218 } |
| 4219 return new IntegerLiteral(token, value); |
| 4220 } |
| 4221 Keyword keyword = _currentToken.keyword; |
| 4222 if (keyword == Keyword.NULL) { |
| 4223 return new NullLiteral(getAndAdvance()); |
| 4224 } else if (keyword == Keyword.NEW) { |
| 4225 return parseNewExpression(); |
| 4226 } else if (keyword == Keyword.THIS) { |
| 7139 return new ThisExpression(getAndAdvance()); | 4227 return new ThisExpression(getAndAdvance()); |
| 7140 } else if (_matchesKeyword(Keyword.SUPER)) { | 4228 } else if (keyword == Keyword.SUPER) { |
| 7141 // TODO(paulberry): verify with Gilad that "super" must be followed by | 4229 // TODO(paulberry): verify with Gilad that "super" must be followed by |
| 7142 // unconditionalAssignableSelector in this case. | 4230 // unconditionalAssignableSelector in this case. |
| 7143 return _parseAssignableSelector( | 4231 return parseAssignableSelector( |
| 7144 new SuperExpression(getAndAdvance()), false, | 4232 new SuperExpression(getAndAdvance()), false, |
| 7145 allowConditional: false); | 4233 allowConditional: false); |
| 7146 } else if (_matchesKeyword(Keyword.NULL)) { | 4234 } else if (keyword == Keyword.FALSE) { |
| 7147 return new NullLiteral(getAndAdvance()); | |
| 7148 } else if (_matchesKeyword(Keyword.FALSE)) { | |
| 7149 return new BooleanLiteral(getAndAdvance(), false); | 4235 return new BooleanLiteral(getAndAdvance(), false); |
| 7150 } else if (_matchesKeyword(Keyword.TRUE)) { | 4236 } else if (keyword == Keyword.TRUE) { |
| 7151 return new BooleanLiteral(getAndAdvance(), true); | 4237 return new BooleanLiteral(getAndAdvance(), true); |
| 7152 } else if (_matches(TokenType.DOUBLE)) { | 4238 } |
| 4239 if (type == TokenType.DOUBLE) { |
| 7153 Token token = getAndAdvance(); | 4240 Token token = getAndAdvance(); |
| 7154 double value = 0.0; | 4241 double value = 0.0; |
| 7155 try { | 4242 try { |
| 7156 value = double.parse(token.lexeme); | 4243 value = double.parse(token.lexeme); |
| 7157 } on FormatException { | 4244 } on FormatException { |
| 7158 // The invalid format should have been reported by the scanner. | 4245 // The invalid format should have been reported by the scanner. |
| 7159 } | 4246 } |
| 7160 return new DoubleLiteral(token, value); | 4247 return new DoubleLiteral(token, value); |
| 7161 } else if (_matches(TokenType.HEXADECIMAL)) { | 4248 } else if (type == TokenType.HEXADECIMAL) { |
| 7162 Token token = getAndAdvance(); | 4249 Token token = getAndAdvance(); |
| 7163 int value = null; | 4250 int value = null; |
| 7164 try { | 4251 try { |
| 7165 value = int.parse(token.lexeme.substring(2), radix: 16); | 4252 value = int.parse(token.lexeme.substring(2), radix: 16); |
| 7166 } on FormatException { | 4253 } on FormatException { |
| 7167 // The invalid format should have been reported by the scanner. | 4254 // The invalid format should have been reported by the scanner. |
| 7168 } | 4255 } |
| 7169 return new IntegerLiteral(token, value); | 4256 return new IntegerLiteral(token, value); |
| 7170 } else if (_matches(TokenType.INT)) { | 4257 } else if (keyword == Keyword.CONST) { |
| 7171 Token token = getAndAdvance(); | 4258 return parseConstExpression(); |
| 7172 int value = null; | 4259 } else if (type == TokenType.OPEN_PAREN) { |
| 7173 try { | 4260 if (isFunctionExpression(_currentToken)) { |
| 7174 value = int.parse(token.lexeme); | |
| 7175 } on FormatException { | |
| 7176 // The invalid format should have been reported by the scanner. | |
| 7177 } | |
| 7178 return new IntegerLiteral(token, value); | |
| 7179 } else if (_matches(TokenType.STRING)) { | |
| 7180 return parseStringLiteral(); | |
| 7181 } else if (_matches(TokenType.OPEN_CURLY_BRACKET)) { | |
| 7182 return _parseMapLiteral(null, null); | |
| 7183 } else if (_matches(TokenType.OPEN_SQUARE_BRACKET) || | |
| 7184 _matches(TokenType.INDEX)) { | |
| 7185 return _parseListLiteral(null, null); | |
| 7186 } else if (_matchesIdentifier()) { | |
| 7187 // TODO(brianwilkerson) The code below was an attempt to recover from an | |
| 7188 // error case, but it needs to be applied as a recovery only after we | |
| 7189 // know that parsing it as an identifier doesn't work. Leaving the code as | |
| 7190 // a reminder of how to recover. | |
| 7191 // if (isFunctionExpression(peek())) { | |
| 7192 // // | |
| 7193 // // Function expressions were allowed to have names at one point,
but this is now illegal. | |
| 7194 // // | |
| 7195 // reportError(ParserErrorCode.NAMED_FUNCTION_EXPRESSION, getAndAdv
ance()); | |
| 7196 // return parseFunctionExpression(); | |
| 7197 // } | |
| 7198 return parsePrefixedIdentifier(); | |
| 7199 } else if (_matchesKeyword(Keyword.NEW)) { | |
| 7200 return _parseNewExpression(); | |
| 7201 } else if (_matchesKeyword(Keyword.CONST)) { | |
| 7202 return _parseConstExpression(); | |
| 7203 } else if (_matches(TokenType.OPEN_PAREN)) { | |
| 7204 if (_isFunctionExpression(_currentToken)) { | |
| 7205 return parseFunctionExpression(); | 4261 return parseFunctionExpression(); |
| 7206 } | 4262 } |
| 7207 Token leftParenthesis = getAndAdvance(); | 4263 Token leftParenthesis = getAndAdvance(); |
| 7208 bool wasInInitializer = _inInitializer; | 4264 bool wasInInitializer = _inInitializer; |
| 7209 _inInitializer = false; | 4265 _inInitializer = false; |
| 7210 try { | 4266 try { |
| 7211 Expression expression = parseExpression2(); | 4267 Expression expression = parseExpression2(); |
| 7212 Token rightParenthesis = _expect(TokenType.CLOSE_PAREN); | 4268 Token rightParenthesis = _expect(TokenType.CLOSE_PAREN); |
| 7213 return new ParenthesizedExpression( | 4269 return new ParenthesizedExpression( |
| 7214 leftParenthesis, expression, rightParenthesis); | 4270 leftParenthesis, expression, rightParenthesis); |
| 7215 } finally { | 4271 } finally { |
| 7216 _inInitializer = wasInInitializer; | 4272 _inInitializer = wasInInitializer; |
| 7217 } | 4273 } |
| 7218 } else if (_matches(TokenType.LT)) { | 4274 } else if (type == TokenType.LT || _injectGenericCommentTypeList()) { |
| 7219 return _parseListOrMapLiteral(null); | 4275 return parseListOrMapLiteral(null); |
| 7220 } else if (_matches(TokenType.QUESTION) && | 4276 } else if (type == TokenType.OPEN_CURLY_BRACKET) { |
| 4277 return parseMapLiteral(null, null); |
| 4278 } else if (type == TokenType.OPEN_SQUARE_BRACKET || |
| 4279 type == TokenType.INDEX) { |
| 4280 return parseListLiteral(null, null); |
| 4281 } else if (type == TokenType.QUESTION && |
| 7221 _tokenMatches(_peek(), TokenType.IDENTIFIER)) { | 4282 _tokenMatches(_peek(), TokenType.IDENTIFIER)) { |
| 7222 _reportErrorForCurrentToken( | 4283 _reportErrorForCurrentToken( |
| 7223 ParserErrorCode.UNEXPECTED_TOKEN, [_currentToken.lexeme]); | 4284 ParserErrorCode.UNEXPECTED_TOKEN, [_currentToken.lexeme]); |
| 7224 _advance(); | 4285 _advance(); |
| 7225 return _parsePrimaryExpression(); | 4286 return parsePrimaryExpression(); |
| 7226 } else if (_matchesKeyword(Keyword.VOID)) { | 4287 } else if (keyword == Keyword.VOID) { |
| 7227 // | 4288 // |
| 7228 // Recover from having a return type of "void" where a return type is not | 4289 // Recover from having a return type of "void" where a return type is not |
| 7229 // expected. | 4290 // expected. |
| 7230 // | 4291 // |
| 7231 // TODO(brianwilkerson) Improve this error message. | 4292 // TODO(brianwilkerson) Improve this error message. |
| 7232 _reportErrorForCurrentToken( | 4293 _reportErrorForCurrentToken( |
| 7233 ParserErrorCode.UNEXPECTED_TOKEN, [_currentToken.lexeme]); | 4294 ParserErrorCode.UNEXPECTED_TOKEN, [_currentToken.lexeme]); |
| 7234 _advance(); | 4295 _advance(); |
| 7235 return _parsePrimaryExpression(); | 4296 return parsePrimaryExpression(); |
| 7236 } else if (_matches(TokenType.HASH)) { | 4297 } else if (type == TokenType.HASH) { |
| 7237 return _parseSymbolLiteral(); | 4298 return parseSymbolLiteral(); |
| 7238 } else { | 4299 } else { |
| 7239 _reportErrorForCurrentToken(ParserErrorCode.MISSING_IDENTIFIER); | 4300 _reportErrorForCurrentToken(ParserErrorCode.MISSING_IDENTIFIER); |
| 7240 return _createSyntheticIdentifier(); | 4301 return createSyntheticIdentifier(); |
| 7241 } | 4302 } |
| 7242 } | 4303 } |
| 7243 | 4304 |
| 7244 /** | 4305 /** |
| 7245 * Parse a redirecting constructor invocation. Return the redirecting | 4306 * Parse a redirecting constructor invocation. The flag [hasPeriod] should be |
| 4307 * `true` if the `this` is followed by a period. Return the redirecting |
| 7246 * constructor invocation that was parsed. | 4308 * constructor invocation that was parsed. |
| 7247 * | 4309 * |
| 4310 * This method assumes that the current token matches `Keyword.THIS`. |
| 4311 * |
| 7248 * redirectingConstructorInvocation ::= | 4312 * redirectingConstructorInvocation ::= |
| 7249 * 'this' ('.' identifier)? arguments | 4313 * 'this' ('.' identifier)? arguments |
| 7250 */ | 4314 */ |
| 7251 RedirectingConstructorInvocation _parseRedirectingConstructorInvocation() { | 4315 RedirectingConstructorInvocation parseRedirectingConstructorInvocation( |
| 7252 Token keyword = _expectKeyword(Keyword.THIS); | 4316 bool hasPeriod) { |
| 4317 Token keyword = getAndAdvance(); |
| 7253 Token period = null; | 4318 Token period = null; |
| 7254 SimpleIdentifier constructorName = null; | 4319 SimpleIdentifier constructorName = null; |
| 7255 if (_matches(TokenType.PERIOD)) { | 4320 if (hasPeriod) { |
| 7256 period = getAndAdvance(); | 4321 period = getAndAdvance(); |
| 7257 constructorName = parseSimpleIdentifier(); | 4322 if (_matchesIdentifier()) { |
| 4323 constructorName = _parseSimpleIdentifierUnchecked(isDeclaration: false); |
| 4324 } else { |
| 4325 _reportErrorForCurrentToken(ParserErrorCode.MISSING_IDENTIFIER); |
| 4326 constructorName = createSyntheticIdentifier(isDeclaration: false); |
| 4327 _advance(); |
| 4328 } |
| 7258 } | 4329 } |
| 7259 ArgumentList argumentList = parseArgumentList(); | 4330 ArgumentList argumentList = _parseArgumentListChecked(); |
| 7260 return new RedirectingConstructorInvocation( | 4331 return new RedirectingConstructorInvocation( |
| 7261 keyword, period, constructorName, argumentList); | 4332 keyword, period, constructorName, argumentList); |
| 7262 } | 4333 } |
| 7263 | 4334 |
| 7264 /** | 4335 /** |
| 7265 * Parse a relational expression. Return the relational expression that was | 4336 * Parse a relational expression. Return the relational expression that was |
| 7266 * parsed. | 4337 * parsed. |
| 7267 * | 4338 * |
| 7268 * relationalExpression ::= | 4339 * relationalExpression ::= |
| 7269 * bitwiseOrExpression ('is' '!'? type | 'as' type | relationalOperato
r bitwiseOrExpression)? | 4340 * bitwiseOrExpression ('is' '!'? type | 'as' type | relationalOperato
r bitwiseOrExpression)? |
| 7270 * | 'super' relationalOperator bitwiseOrExpression | 4341 * | 'super' relationalOperator bitwiseOrExpression |
| 7271 */ | 4342 */ |
| 7272 Expression _parseRelationalExpression() { | 4343 Expression parseRelationalExpression() { |
| 7273 if (_matchesKeyword(Keyword.SUPER) && | 4344 if (_currentToken.keyword == Keyword.SUPER && |
| 7274 _currentToken.next.type.isRelationalOperator) { | 4345 _currentToken.next.type.isRelationalOperator) { |
| 7275 Expression expression = new SuperExpression(getAndAdvance()); | 4346 Expression expression = new SuperExpression(getAndAdvance()); |
| 7276 Token operator = getAndAdvance(); | 4347 Token operator = getAndAdvance(); |
| 7277 expression = new BinaryExpression( | 4348 return new BinaryExpression( |
| 7278 expression, operator, parseBitwiseOrExpression()); | 4349 expression, operator, parseBitwiseOrExpression()); |
| 7279 return expression; | |
| 7280 } | 4350 } |
| 7281 Expression expression = parseBitwiseOrExpression(); | 4351 Expression expression = parseBitwiseOrExpression(); |
| 7282 if (_matchesKeyword(Keyword.AS)) { | 4352 Keyword keyword = _currentToken.keyword; |
| 4353 if (keyword == Keyword.AS) { |
| 7283 Token asOperator = getAndAdvance(); | 4354 Token asOperator = getAndAdvance(); |
| 7284 expression = new AsExpression(expression, asOperator, parseTypeName()); | 4355 return new AsExpression(expression, asOperator, parseTypeName(true)); |
| 7285 } else if (_matchesKeyword(Keyword.IS)) { | 4356 } else if (keyword == Keyword.IS) { |
| 7286 Token isOperator = getAndAdvance(); | 4357 Token isOperator = getAndAdvance(); |
| 7287 Token notOperator = null; | 4358 Token notOperator = null; |
| 7288 if (_matches(TokenType.BANG)) { | 4359 if (_matches(TokenType.BANG)) { |
| 7289 notOperator = getAndAdvance(); | 4360 notOperator = getAndAdvance(); |
| 7290 } | 4361 } |
| 7291 expression = new IsExpression( | 4362 return new IsExpression( |
| 7292 expression, isOperator, notOperator, parseTypeName()); | 4363 expression, isOperator, notOperator, parseTypeName(true)); |
| 7293 } else if (_currentToken.type.isRelationalOperator) { | 4364 } else if (_currentToken.type.isRelationalOperator) { |
| 7294 Token operator = getAndAdvance(); | 4365 Token operator = getAndAdvance(); |
| 7295 expression = new BinaryExpression( | 4366 return new BinaryExpression( |
| 7296 expression, operator, parseBitwiseOrExpression()); | 4367 expression, operator, parseBitwiseOrExpression()); |
| 7297 } | 4368 } |
| 7298 return expression; | 4369 return expression; |
| 7299 } | 4370 } |
| 7300 | 4371 |
| 7301 /** | 4372 /** |
| 7302 * Parse a rethrow expression. Return the rethrow expression that was parsed. | 4373 * Parse a rethrow expression. Return the rethrow expression that was parsed. |
| 7303 * | 4374 * |
| 4375 * This method assumes that the current token matches `Keyword.RETHROW`. |
| 4376 * |
| 7304 * rethrowExpression ::= | 4377 * rethrowExpression ::= |
| 7305 * 'rethrow' | 4378 * 'rethrow' |
| 7306 */ | 4379 */ |
| 7307 Expression _parseRethrowExpression() => | 4380 Expression parseRethrowExpression() => new RethrowExpression(getAndAdvance()); |
| 7308 new RethrowExpression(_expectKeyword(Keyword.RETHROW)); | |
| 7309 | 4381 |
| 7310 /** | 4382 /** |
| 7311 * Parse a return statement. Return the return statement that was parsed. | 4383 * Parse a return statement. Return the return statement that was parsed. |
| 7312 * | 4384 * |
| 4385 * This method assumes that the current token matches `Keyword.RETURN`. |
| 4386 * |
| 7313 * returnStatement ::= | 4387 * returnStatement ::= |
| 7314 * 'return' expression? ';' | 4388 * 'return' expression? ';' |
| 7315 */ | 4389 */ |
| 7316 Statement _parseReturnStatement() { | 4390 Statement parseReturnStatement() { |
| 7317 Token returnKeyword = _expectKeyword(Keyword.RETURN); | 4391 Token returnKeyword = getAndAdvance(); |
| 7318 if (_matches(TokenType.SEMICOLON)) { | 4392 if (_matches(TokenType.SEMICOLON)) { |
| 7319 return new ReturnStatement(returnKeyword, null, getAndAdvance()); | 4393 return new ReturnStatement(returnKeyword, null, getAndAdvance()); |
| 7320 } | 4394 } |
| 7321 Expression expression = parseExpression2(); | 4395 Expression expression = parseExpression2(); |
| 7322 Token semicolon = _expect(TokenType.SEMICOLON); | 4396 Token semicolon = _expect(TokenType.SEMICOLON); |
| 7323 return new ReturnStatement(returnKeyword, expression, semicolon); | 4397 return new ReturnStatement(returnKeyword, expression, semicolon); |
| 7324 } | 4398 } |
| 7325 | 4399 |
| 7326 /** | 4400 /** |
| 4401 * Parse a return type. Return the return type that was parsed. |
| 4402 * |
| 4403 * returnType ::= |
| 4404 * 'void' |
| 4405 * | type |
| 4406 */ |
| 4407 TypeName parseReturnType() { |
| 4408 if (_currentToken.keyword == Keyword.VOID) { |
| 4409 return new TypeName(new SimpleIdentifier(getAndAdvance()), null); |
| 4410 } else { |
| 4411 return parseTypeName(false); |
| 4412 } |
| 4413 } |
| 4414 |
| 4415 /** |
| 7327 * Parse a setter. The [commentAndMetadata] is the documentation comment and | 4416 * Parse a setter. The [commentAndMetadata] is the documentation comment and |
| 7328 * metadata to be associated with the declaration. The [externalKeyword] is | 4417 * metadata to be associated with the declaration. The [externalKeyword] is |
| 7329 * the 'external' token. The [staticKeyword] is the static keyword, or `null` | 4418 * the 'external' token. The [staticKeyword] is the static keyword, or `null` |
| 7330 * if the setter is not static. The [returnType] is the return type that has | 4419 * if the setter is not static. The [returnType] is the return type that has |
| 7331 * already been parsed, or `null` if there was no return type. Return the | 4420 * already been parsed, or `null` if there was no return type. Return the |
| 7332 * setter that was parsed. | 4421 * setter that was parsed. |
| 7333 * | 4422 * |
| 4423 * This method assumes that the current token matches `Keyword.SET`. |
| 4424 * |
| 7334 * setter ::= | 4425 * setter ::= |
| 7335 * setterSignature functionBody? | 4426 * setterSignature functionBody? |
| 7336 * | 4427 * |
| 7337 * setterSignature ::= | 4428 * setterSignature ::= |
| 7338 * 'external'? 'static'? returnType? 'set' identifier formalParameterL
ist | 4429 * 'external'? 'static'? returnType? 'set' identifier formalParameterL
ist |
| 7339 */ | 4430 */ |
| 7340 MethodDeclaration _parseSetter(CommentAndMetadata commentAndMetadata, | 4431 MethodDeclaration parseSetter(CommentAndMetadata commentAndMetadata, |
| 7341 Token externalKeyword, Token staticKeyword, TypeName returnType) { | 4432 Token externalKeyword, Token staticKeyword, TypeName returnType) { |
| 7342 Token propertyKeyword = _expectKeyword(Keyword.SET); | 4433 Token propertyKeyword = getAndAdvance(); |
| 7343 SimpleIdentifier name = parseSimpleIdentifier(); | 4434 SimpleIdentifier name = parseSimpleIdentifier(isDeclaration: true); |
| 7344 FormalParameterList parameters = parseFormalParameterList(); | 4435 FormalParameterList parameters = parseFormalParameterList(); |
| 7345 _validateFormalParameterList(parameters); | 4436 _validateFormalParameterList(parameters); |
| 7346 FunctionBody body = _parseFunctionBody( | 4437 FunctionBody body = parseFunctionBody( |
| 7347 externalKeyword != null || staticKeyword == null, | 4438 externalKeyword != null || staticKeyword == null, |
| 7348 ParserErrorCode.STATIC_SETTER_WITHOUT_BODY, | 4439 ParserErrorCode.STATIC_SETTER_WITHOUT_BODY, |
| 7349 false); | 4440 false); |
| 7350 if (externalKeyword != null && body is! EmptyFunctionBody) { | 4441 if (externalKeyword != null && body is! EmptyFunctionBody) { |
| 7351 _reportErrorForCurrentToken(ParserErrorCode.EXTERNAL_SETTER_WITH_BODY); | 4442 _reportErrorForCurrentToken(ParserErrorCode.EXTERNAL_SETTER_WITH_BODY); |
| 7352 } | 4443 } |
| 7353 return new MethodDeclaration( | 4444 return new MethodDeclaration( |
| 7354 commentAndMetadata.comment, | 4445 commentAndMetadata.comment, |
| 7355 commentAndMetadata.metadata, | 4446 commentAndMetadata.metadata, |
| 7356 externalKeyword, | 4447 externalKeyword, |
| 7357 staticKeyword, | 4448 staticKeyword, |
| 7358 returnType, | 4449 returnType, |
| 7359 propertyKeyword, | 4450 propertyKeyword, |
| 7360 null, | 4451 null, |
| 7361 name, | 4452 name, |
| 7362 null, | 4453 null, |
| 7363 parameters, | 4454 parameters, |
| 7364 body); | 4455 body); |
| 7365 } | 4456 } |
| 7366 | 4457 |
| 7367 /** | 4458 /** |
| 7368 * Parse a shift expression. Return the shift expression that was parsed. | 4459 * Parse a shift expression. Return the shift expression that was parsed. |
| 7369 * | 4460 * |
| 7370 * shiftExpression ::= | 4461 * shiftExpression ::= |
| 7371 * additiveExpression (shiftOperator additiveExpression)* | 4462 * additiveExpression (shiftOperator additiveExpression)* |
| 7372 * | 'super' (shiftOperator additiveExpression)+ | 4463 * | 'super' (shiftOperator additiveExpression)+ |
| 7373 */ | 4464 */ |
| 7374 Expression _parseShiftExpression() { | 4465 Expression parseShiftExpression() { |
| 7375 Expression expression; | 4466 Expression expression; |
| 7376 if (_matchesKeyword(Keyword.SUPER) && | 4467 if (_currentToken.keyword == Keyword.SUPER && |
| 7377 _currentToken.next.type.isShiftOperator) { | 4468 _currentToken.next.type.isShiftOperator) { |
| 7378 expression = new SuperExpression(getAndAdvance()); | 4469 expression = new SuperExpression(getAndAdvance()); |
| 7379 } else { | 4470 } else { |
| 7380 expression = _parseAdditiveExpression(); | 4471 expression = parseAdditiveExpression(); |
| 7381 } | 4472 } |
| 7382 while (_currentToken.type.isShiftOperator) { | 4473 while (_currentToken.type.isShiftOperator) { |
| 7383 Token operator = getAndAdvance(); | |
| 7384 expression = new BinaryExpression( | 4474 expression = new BinaryExpression( |
| 7385 expression, operator, _parseAdditiveExpression()); | 4475 expression, getAndAdvance(), parseAdditiveExpression()); |
| 7386 } | 4476 } |
| 7387 return expression; | 4477 return expression; |
| 7388 } | 4478 } |
| 7389 | 4479 |
| 7390 /** | 4480 /** |
| 7391 * Parse a list of statements within a switch statement. Return the statements | 4481 * Parse a simple identifier. Return the simple identifier that was parsed. |
| 7392 * that were parsed. | |
| 7393 * | 4482 * |
| 7394 * statements ::= | 4483 * identifier ::= |
| 7395 * statement* | 4484 * IDENTIFIER |
| 7396 */ | 4485 */ |
| 7397 List<Statement> _parseStatementList() { | 4486 SimpleIdentifier parseSimpleIdentifier({bool isDeclaration: false}) { |
| 7398 List<Statement> statements = new List<Statement>(); | 4487 if (_matchesIdentifier()) { |
| 7399 Token statementStart = _currentToken; | 4488 return _parseSimpleIdentifierUnchecked(isDeclaration: isDeclaration); |
| 7400 while (!_matches(TokenType.EOF) && | |
| 7401 !_matches(TokenType.CLOSE_CURLY_BRACKET) && | |
| 7402 !_isSwitchMember()) { | |
| 7403 statements.add(parseStatement2()); | |
| 7404 if (identical(_currentToken, statementStart)) { | |
| 7405 _reportErrorForToken(ParserErrorCode.UNEXPECTED_TOKEN, _currentToken, | |
| 7406 [_currentToken.lexeme]); | |
| 7407 _advance(); | |
| 7408 } | |
| 7409 statementStart = _currentToken; | |
| 7410 } | 4489 } |
| 7411 return statements; | 4490 _reportErrorForCurrentToken(ParserErrorCode.MISSING_IDENTIFIER); |
| 4491 return createSyntheticIdentifier(isDeclaration: isDeclaration); |
| 7412 } | 4492 } |
| 7413 | 4493 |
| 7414 /** | 4494 /** |
| 7415 * Parse a string literal that contains interpolations. Return the string | 4495 * Parse a statement, starting with the given [token]. Return the statement |
| 7416 * literal that was parsed. | 4496 * that was parsed, or `null` if the tokens do not represent a recognizable |
| 4497 * statement. |
| 7417 */ | 4498 */ |
| 7418 StringInterpolation _parseStringInterpolation(Token string) { | 4499 Statement parseStatement(Token token) { |
| 7419 List<InterpolationElement> elements = new List<InterpolationElement>(); | 4500 _currentToken = token; |
| 7420 bool hasMore = _matches(TokenType.STRING_INTERPOLATION_EXPRESSION) || | 4501 return parseStatement2(); |
| 7421 _matches(TokenType.STRING_INTERPOLATION_IDENTIFIER); | 4502 } |
| 7422 elements.add(new InterpolationString( | 4503 |
| 7423 string, _computeStringValue(string.lexeme, true, !hasMore))); | 4504 /** |
| 7424 while (hasMore) { | 4505 * Parse a statement. Return the statement that was parsed. |
| 7425 if (_matches(TokenType.STRING_INTERPOLATION_EXPRESSION)) { | 4506 * |
| 7426 Token openToken = getAndAdvance(); | 4507 * statement ::= |
| 7427 bool wasInInitializer = _inInitializer; | 4508 * label* nonLabeledStatement |
| 7428 _inInitializer = false; | 4509 */ |
| 7429 try { | 4510 Statement parseStatement2() { |
| 7430 Expression expression = parseExpression2(); | 4511 List<Label> labels = null; |
| 7431 Token rightBracket = _expect(TokenType.CLOSE_CURLY_BRACKET); | 4512 while (_matchesIdentifier() && _currentToken.next.type == TokenType.COLON) { |
| 7432 elements.add( | 4513 Label label = parseLabel(isDeclaration: true); |
| 7433 new InterpolationExpression(openToken, expression, rightBracket)); | 4514 if (labels == null) { |
| 7434 } finally { | 4515 labels = <Label>[label]; |
| 7435 _inInitializer = wasInInitializer; | |
| 7436 } | |
| 7437 } else { | 4516 } else { |
| 7438 Token openToken = getAndAdvance(); | 4517 labels.add(label); |
| 7439 Expression expression = null; | |
| 7440 if (_matchesKeyword(Keyword.THIS)) { | |
| 7441 expression = new ThisExpression(getAndAdvance()); | |
| 7442 } else { | |
| 7443 expression = parseSimpleIdentifier(); | |
| 7444 } | |
| 7445 elements.add(new InterpolationExpression(openToken, expression, null)); | |
| 7446 } | |
| 7447 if (_matches(TokenType.STRING)) { | |
| 7448 string = getAndAdvance(); | |
| 7449 hasMore = _matches(TokenType.STRING_INTERPOLATION_EXPRESSION) || | |
| 7450 _matches(TokenType.STRING_INTERPOLATION_IDENTIFIER); | |
| 7451 elements.add(new InterpolationString( | |
| 7452 string, _computeStringValue(string.lexeme, false, !hasMore))); | |
| 7453 } else { | |
| 7454 hasMore = false; | |
| 7455 } | 4518 } |
| 7456 } | 4519 } |
| 7457 return new StringInterpolation(elements); | 4520 Statement statement = parseNonLabeledStatement(); |
| 4521 if (labels == null) { |
| 4522 return statement; |
| 4523 } |
| 4524 return new LabeledStatement(labels, statement); |
| 4525 } |
| 4526 |
| 4527 /** |
| 4528 * Parse a sequence of statements, starting with the given [token]. Return the |
| 4529 * statements that were parsed, or `null` if the tokens do not represent a |
| 4530 * recognizable sequence of statements. |
| 4531 */ |
| 4532 List<Statement> parseStatements(Token token) { |
| 4533 _currentToken = token; |
| 4534 return _parseStatementList(); |
| 4535 } |
| 4536 |
| 4537 /** |
| 4538 * Parse a string literal. Return the string literal that was parsed. |
| 4539 * |
| 4540 * stringLiteral ::= |
| 4541 * MULTI_LINE_STRING+ |
| 4542 * | SINGLE_LINE_STRING+ |
| 4543 */ |
| 4544 StringLiteral parseStringLiteral() { |
| 4545 if (_matches(TokenType.STRING)) { |
| 4546 return _parseStringLiteralUnchecked(); |
| 4547 } |
| 4548 _reportErrorForCurrentToken(ParserErrorCode.EXPECTED_STRING_LITERAL); |
| 4549 return createSyntheticStringLiteral(); |
| 7458 } | 4550 } |
| 7459 | 4551 |
| 7460 /** | 4552 /** |
| 7461 * Parse a super constructor invocation. Return the super constructor | 4553 * Parse a super constructor invocation. Return the super constructor |
| 7462 * invocation that was parsed. | 4554 * invocation that was parsed. |
| 7463 * | 4555 * |
| 4556 * This method assumes that the current token matches [Keyword.SUPER]. |
| 4557 * |
| 7464 * superConstructorInvocation ::= | 4558 * superConstructorInvocation ::= |
| 7465 * 'super' ('.' identifier)? arguments | 4559 * 'super' ('.' identifier)? arguments |
| 7466 */ | 4560 */ |
| 7467 SuperConstructorInvocation _parseSuperConstructorInvocation() { | 4561 SuperConstructorInvocation parseSuperConstructorInvocation() { |
| 7468 Token keyword = _expectKeyword(Keyword.SUPER); | 4562 Token keyword = getAndAdvance(); |
| 7469 Token period = null; | 4563 Token period = null; |
| 7470 SimpleIdentifier constructorName = null; | 4564 SimpleIdentifier constructorName = null; |
| 7471 if (_matches(TokenType.PERIOD)) { | 4565 if (_matches(TokenType.PERIOD)) { |
| 7472 period = getAndAdvance(); | 4566 period = getAndAdvance(); |
| 7473 constructorName = parseSimpleIdentifier(); | 4567 constructorName = parseSimpleIdentifier(); |
| 7474 } | 4568 } |
| 7475 ArgumentList argumentList = parseArgumentList(); | 4569 ArgumentList argumentList = _parseArgumentListChecked(); |
| 7476 return new SuperConstructorInvocation( | 4570 return new SuperConstructorInvocation( |
| 7477 keyword, period, constructorName, argumentList); | 4571 keyword, period, constructorName, argumentList); |
| 7478 } | 4572 } |
| 7479 | 4573 |
| 7480 /** | 4574 /** |
| 7481 * Parse a switch statement. Return the switch statement that was parsed. | 4575 * Parse a switch statement. Return the switch statement that was parsed. |
| 7482 * | 4576 * |
| 7483 * switchStatement ::= | 4577 * switchStatement ::= |
| 7484 * 'switch' '(' expression ')' '{' switchCase* defaultCase? '}' | 4578 * 'switch' '(' expression ')' '{' switchCase* defaultCase? '}' |
| 7485 * | 4579 * |
| 7486 * switchCase ::= | 4580 * switchCase ::= |
| 7487 * label* ('case' expression ':') statements | 4581 * label* ('case' expression ':') statements |
| 7488 * | 4582 * |
| 7489 * defaultCase ::= | 4583 * defaultCase ::= |
| 7490 * label* 'default' ':' statements | 4584 * label* 'default' ':' statements |
| 7491 */ | 4585 */ |
| 7492 SwitchStatement _parseSwitchStatement() { | 4586 SwitchStatement parseSwitchStatement() { |
| 7493 bool wasInSwitch = _inSwitch; | 4587 bool wasInSwitch = _inSwitch; |
| 7494 _inSwitch = true; | 4588 _inSwitch = true; |
| 7495 try { | 4589 try { |
| 7496 HashSet<String> definedLabels = new HashSet<String>(); | 4590 HashSet<String> definedLabels = new HashSet<String>(); |
| 7497 Token keyword = _expectKeyword(Keyword.SWITCH); | 4591 Token keyword = _expectKeyword(Keyword.SWITCH); |
| 7498 Token leftParenthesis = _expect(TokenType.OPEN_PAREN); | 4592 Token leftParenthesis = _expect(TokenType.OPEN_PAREN); |
| 7499 Expression expression = parseExpression2(); | 4593 Expression expression = parseExpression2(); |
| 7500 Token rightParenthesis = _expect(TokenType.CLOSE_PAREN); | 4594 Token rightParenthesis = _expect(TokenType.CLOSE_PAREN); |
| 7501 Token leftBracket = _expect(TokenType.OPEN_CURLY_BRACKET); | 4595 Token leftBracket = _expect(TokenType.OPEN_CURLY_BRACKET); |
| 7502 Token defaultKeyword = null; | 4596 Token defaultKeyword = null; |
| 7503 List<SwitchMember> members = new List<SwitchMember>(); | 4597 List<SwitchMember> members = <SwitchMember>[]; |
| 7504 while (!_matches(TokenType.EOF) && | 4598 TokenType type = _currentToken.type; |
| 7505 !_matches(TokenType.CLOSE_CURLY_BRACKET)) { | 4599 while (type != TokenType.EOF && type != TokenType.CLOSE_CURLY_BRACKET) { |
| 7506 List<Label> labels = new List<Label>(); | 4600 List<Label> labels = <Label>[]; |
| 7507 while ( | 4601 while ( |
| 7508 _matchesIdentifier() && _tokenMatches(_peek(), TokenType.COLON)) { | 4602 _matchesIdentifier() && _tokenMatches(_peek(), TokenType.COLON)) { |
| 7509 SimpleIdentifier identifier = parseSimpleIdentifier(); | 4603 SimpleIdentifier identifier = |
| 4604 _parseSimpleIdentifierUnchecked(isDeclaration: true); |
| 7510 String label = identifier.token.lexeme; | 4605 String label = identifier.token.lexeme; |
| 7511 if (definedLabels.contains(label)) { | 4606 if (definedLabels.contains(label)) { |
| 7512 _reportErrorForToken( | 4607 _reportErrorForToken( |
| 7513 ParserErrorCode.DUPLICATE_LABEL_IN_SWITCH_STATEMENT, | 4608 ParserErrorCode.DUPLICATE_LABEL_IN_SWITCH_STATEMENT, |
| 7514 identifier.token, | 4609 identifier.token, |
| 7515 [label]); | 4610 [label]); |
| 7516 } else { | 4611 } else { |
| 7517 definedLabels.add(label); | 4612 definedLabels.add(label); |
| 7518 } | 4613 } |
| 7519 Token colon = _expect(TokenType.COLON); | 4614 Token colon = getAndAdvance(); |
| 7520 labels.add(new Label(identifier, colon)); | 4615 labels.add(new Label(identifier, colon)); |
| 7521 } | 4616 } |
| 7522 if (_matchesKeyword(Keyword.CASE)) { | 4617 Keyword keyword = _currentToken.keyword; |
| 4618 if (keyword == Keyword.CASE) { |
| 7523 Token caseKeyword = getAndAdvance(); | 4619 Token caseKeyword = getAndAdvance(); |
| 7524 Expression caseExpression = parseExpression2(); | 4620 Expression caseExpression = parseExpression2(); |
| 7525 Token colon = _expect(TokenType.COLON); | 4621 Token colon = _expect(TokenType.COLON); |
| 7526 members.add(new SwitchCase(labels, caseKeyword, caseExpression, colon, | 4622 members.add(new SwitchCase(labels, caseKeyword, caseExpression, colon, |
| 7527 _parseStatementList())); | 4623 _parseStatementList())); |
| 7528 if (defaultKeyword != null) { | 4624 if (defaultKeyword != null) { |
| 7529 _reportErrorForToken( | 4625 _reportErrorForToken( |
| 7530 ParserErrorCode.SWITCH_HAS_CASE_AFTER_DEFAULT_CASE, | 4626 ParserErrorCode.SWITCH_HAS_CASE_AFTER_DEFAULT_CASE, |
| 7531 caseKeyword); | 4627 caseKeyword); |
| 7532 } | 4628 } |
| 7533 } else if (_matchesKeyword(Keyword.DEFAULT)) { | 4629 } else if (keyword == Keyword.DEFAULT) { |
| 7534 if (defaultKeyword != null) { | 4630 if (defaultKeyword != null) { |
| 7535 _reportErrorForToken( | 4631 _reportErrorForToken( |
| 7536 ParserErrorCode.SWITCH_HAS_MULTIPLE_DEFAULT_CASES, _peek()); | 4632 ParserErrorCode.SWITCH_HAS_MULTIPLE_DEFAULT_CASES, _peek()); |
| 7537 } | 4633 } |
| 7538 defaultKeyword = getAndAdvance(); | 4634 defaultKeyword = getAndAdvance(); |
| 7539 Token colon = _expect(TokenType.COLON); | 4635 Token colon = _expect(TokenType.COLON); |
| 7540 members.add(new SwitchDefault( | 4636 members.add(new SwitchDefault( |
| 7541 labels, defaultKeyword, colon, _parseStatementList())); | 4637 labels, defaultKeyword, colon, _parseStatementList())); |
| 7542 } else { | 4638 } else { |
| 7543 // We need to advance, otherwise we could end up in an infinite loop, | 4639 // We need to advance, otherwise we could end up in an infinite loop, |
| 7544 // but this could be a lot smarter about recovering from the error. | 4640 // but this could be a lot smarter about recovering from the error. |
| 7545 _reportErrorForCurrentToken(ParserErrorCode.EXPECTED_CASE_OR_DEFAULT); | 4641 _reportErrorForCurrentToken(ParserErrorCode.EXPECTED_CASE_OR_DEFAULT); |
| 7546 while (!_matches(TokenType.EOF) && | 4642 bool atEndOrNextMember() { |
| 7547 !_matches(TokenType.CLOSE_CURLY_BRACKET) && | 4643 TokenType type = _currentToken.type; |
| 7548 !_matchesKeyword(Keyword.CASE) && | 4644 if (type == TokenType.EOF || |
| 7549 !_matchesKeyword(Keyword.DEFAULT)) { | 4645 type == TokenType.CLOSE_CURLY_BRACKET) { |
| 4646 return true; |
| 4647 } |
| 4648 Keyword keyword = _currentToken.keyword; |
| 4649 return keyword == Keyword.CASE || keyword == Keyword.DEFAULT; |
| 4650 } |
| 4651 |
| 4652 while (!atEndOrNextMember()) { |
| 7550 _advance(); | 4653 _advance(); |
| 7551 } | 4654 } |
| 7552 } | 4655 } |
| 4656 type = _currentToken.type; |
| 7553 } | 4657 } |
| 7554 Token rightBracket = _expect(TokenType.CLOSE_CURLY_BRACKET); | 4658 Token rightBracket = _expect(TokenType.CLOSE_CURLY_BRACKET); |
| 7555 return new SwitchStatement(keyword, leftParenthesis, expression, | 4659 return new SwitchStatement(keyword, leftParenthesis, expression, |
| 7556 rightParenthesis, leftBracket, members, rightBracket); | 4660 rightParenthesis, leftBracket, members, rightBracket); |
| 7557 } finally { | 4661 } finally { |
| 7558 _inSwitch = wasInSwitch; | 4662 _inSwitch = wasInSwitch; |
| 7559 } | 4663 } |
| 7560 } | 4664 } |
| 7561 | 4665 |
| 7562 /** | 4666 /** |
| 7563 * Parse a symbol literal. Return the symbol literal that was parsed. | 4667 * Parse a symbol literal. Return the symbol literal that was parsed. |
| 7564 * | 4668 * |
| 4669 * This method assumes that the current token matches [TokenType.HASH]. |
| 4670 * |
| 7565 * symbolLiteral ::= | 4671 * symbolLiteral ::= |
| 7566 * '#' identifier ('.' identifier)* | 4672 * '#' identifier ('.' identifier)* |
| 7567 */ | 4673 */ |
| 7568 SymbolLiteral _parseSymbolLiteral() { | 4674 SymbolLiteral parseSymbolLiteral() { |
| 7569 Token poundSign = getAndAdvance(); | 4675 Token poundSign = getAndAdvance(); |
| 7570 List<Token> components = new List<Token>(); | 4676 List<Token> components = <Token>[]; |
| 7571 if (_matchesIdentifier()) { | 4677 if (_matchesIdentifier()) { |
| 7572 components.add(getAndAdvance()); | 4678 components.add(getAndAdvance()); |
| 7573 while (_matches(TokenType.PERIOD)) { | 4679 while (_optional(TokenType.PERIOD)) { |
| 7574 _advance(); | |
| 7575 if (_matchesIdentifier()) { | 4680 if (_matchesIdentifier()) { |
| 7576 components.add(getAndAdvance()); | 4681 components.add(getAndAdvance()); |
| 7577 } else { | 4682 } else { |
| 7578 _reportErrorForCurrentToken(ParserErrorCode.MISSING_IDENTIFIER); | 4683 _reportErrorForCurrentToken(ParserErrorCode.MISSING_IDENTIFIER); |
| 7579 components.add(_createSyntheticToken(TokenType.IDENTIFIER)); | 4684 components.add(_createSyntheticToken(TokenType.IDENTIFIER)); |
| 7580 break; | 4685 break; |
| 7581 } | 4686 } |
| 7582 } | 4687 } |
| 7583 } else if (_currentToken.isOperator) { | 4688 } else if (_currentToken.isOperator) { |
| 7584 components.add(getAndAdvance()); | 4689 components.add(getAndAdvance()); |
| 7585 } else if (_tokenMatchesKeyword(_currentToken, Keyword.VOID)) { | 4690 } else if (_matchesKeyword(Keyword.VOID)) { |
| 7586 components.add(getAndAdvance()); | 4691 components.add(getAndAdvance()); |
| 7587 } else { | 4692 } else { |
| 7588 _reportErrorForCurrentToken(ParserErrorCode.MISSING_IDENTIFIER); | 4693 _reportErrorForCurrentToken(ParserErrorCode.MISSING_IDENTIFIER); |
| 7589 components.add(_createSyntheticToken(TokenType.IDENTIFIER)); | 4694 components.add(_createSyntheticToken(TokenType.IDENTIFIER)); |
| 7590 } | 4695 } |
| 7591 return new SymbolLiteral(poundSign, components); | 4696 return new SymbolLiteral(poundSign, components); |
| 7592 } | 4697 } |
| 7593 | 4698 |
| 7594 /** | 4699 /** |
| 7595 * Parse a throw expression. Return the throw expression that was parsed. | 4700 * Parse a throw expression. Return the throw expression that was parsed. |
| 7596 * | 4701 * |
| 4702 * This method assumes that the current token matches [Keyword.THROW]. |
| 4703 * |
| 7597 * throwExpression ::= | 4704 * throwExpression ::= |
| 7598 * 'throw' expression | 4705 * 'throw' expression |
| 7599 */ | 4706 */ |
| 7600 Expression _parseThrowExpression() { | 4707 Expression parseThrowExpression() { |
| 7601 Token keyword = _expectKeyword(Keyword.THROW); | 4708 Token keyword = getAndAdvance(); |
| 7602 if (_matches(TokenType.SEMICOLON) || _matches(TokenType.CLOSE_PAREN)) { | 4709 TokenType type = _currentToken.type; |
| 4710 if (type == TokenType.SEMICOLON || type == TokenType.CLOSE_PAREN) { |
| 7603 _reportErrorForToken( | 4711 _reportErrorForToken( |
| 7604 ParserErrorCode.MISSING_EXPRESSION_IN_THROW, _currentToken); | 4712 ParserErrorCode.MISSING_EXPRESSION_IN_THROW, _currentToken); |
| 7605 return new ThrowExpression(keyword, _createSyntheticIdentifier()); | 4713 return new ThrowExpression(keyword, createSyntheticIdentifier()); |
| 7606 } | 4714 } |
| 7607 Expression expression = parseExpression2(); | 4715 Expression expression = parseExpression2(); |
| 7608 return new ThrowExpression(keyword, expression); | 4716 return new ThrowExpression(keyword, expression); |
| 7609 } | 4717 } |
| 7610 | 4718 |
| 7611 /** | 4719 /** |
| 7612 * Parse a throw expression. Return the throw expression that was parsed. | 4720 * Parse a throw expression. Return the throw expression that was parsed. |
| 7613 * | 4721 * |
| 4722 * This method assumes that the current token matches [Keyword.THROW]. |
| 4723 * |
| 7614 * throwExpressionWithoutCascade ::= | 4724 * throwExpressionWithoutCascade ::= |
| 7615 * 'throw' expressionWithoutCascade | 4725 * 'throw' expressionWithoutCascade |
| 7616 */ | 4726 */ |
| 7617 Expression _parseThrowExpressionWithoutCascade() { | 4727 Expression parseThrowExpressionWithoutCascade() { |
| 7618 Token keyword = _expectKeyword(Keyword.THROW); | 4728 Token keyword = getAndAdvance(); |
| 7619 if (_matches(TokenType.SEMICOLON) || _matches(TokenType.CLOSE_PAREN)) { | 4729 TokenType type = _currentToken.type; |
| 4730 if (type == TokenType.SEMICOLON || type == TokenType.CLOSE_PAREN) { |
| 7620 _reportErrorForToken( | 4731 _reportErrorForToken( |
| 7621 ParserErrorCode.MISSING_EXPRESSION_IN_THROW, _currentToken); | 4732 ParserErrorCode.MISSING_EXPRESSION_IN_THROW, _currentToken); |
| 7622 return new ThrowExpression(keyword, _createSyntheticIdentifier()); | 4733 return new ThrowExpression(keyword, createSyntheticIdentifier()); |
| 7623 } | 4734 } |
| 7624 Expression expression = parseExpressionWithoutCascade(); | 4735 Expression expression = parseExpressionWithoutCascade(); |
| 7625 return new ThrowExpression(keyword, expression); | 4736 return new ThrowExpression(keyword, expression); |
| 7626 } | 4737 } |
| 7627 | 4738 |
| 7628 /** | 4739 /** |
| 7629 * Parse a try statement. Return the try statement that was parsed. | 4740 * Parse a try statement. Return the try statement that was parsed. |
| 7630 * | 4741 * |
| 4742 * This method assumes that the current token matches [Keyword.TRY]. |
| 4743 * |
| 7631 * tryStatement ::= | 4744 * tryStatement ::= |
| 7632 * 'try' block (onPart+ finallyPart? | finallyPart) | 4745 * 'try' block (onPart+ finallyPart? | finallyPart) |
| 7633 * | 4746 * |
| 7634 * onPart ::= | 4747 * onPart ::= |
| 7635 * catchPart block | 4748 * catchPart block |
| 7636 * | 'on' type catchPart? block | 4749 * | 'on' type catchPart? block |
| 7637 * | 4750 * |
| 7638 * catchPart ::= | 4751 * catchPart ::= |
| 7639 * 'catch' '(' identifier (',' identifier)? ')' | 4752 * 'catch' '(' identifier (',' identifier)? ')' |
| 7640 * | 4753 * |
| 7641 * finallyPart ::= | 4754 * finallyPart ::= |
| 7642 * 'finally' block | 4755 * 'finally' block |
| 7643 */ | 4756 */ |
| 7644 Statement _parseTryStatement() { | 4757 Statement parseTryStatement() { |
| 7645 Token tryKeyword = _expectKeyword(Keyword.TRY); | 4758 Token tryKeyword = getAndAdvance(); |
| 7646 Block body = parseBlock(); | 4759 Block body = _parseBlockChecked(); |
| 7647 List<CatchClause> catchClauses = new List<CatchClause>(); | 4760 List<CatchClause> catchClauses = <CatchClause>[]; |
| 7648 Block finallyClause = null; | 4761 Block finallyClause = null; |
| 7649 while (_matchesString(_ON) || _matchesKeyword(Keyword.CATCH)) { | 4762 while (_matchesString(_ON) || _matchesKeyword(Keyword.CATCH)) { |
| 7650 Token onKeyword = null; | 4763 Token onKeyword = null; |
| 7651 TypeName exceptionType = null; | 4764 TypeName exceptionType = null; |
| 7652 if (_matchesString(_ON)) { | 4765 if (_matchesString(_ON)) { |
| 7653 onKeyword = getAndAdvance(); | 4766 onKeyword = getAndAdvance(); |
| 7654 exceptionType = parseTypeName(); | 4767 exceptionType = parseTypeName(false); |
| 7655 } | 4768 } |
| 7656 Token catchKeyword = null; | 4769 Token catchKeyword = null; |
| 7657 Token leftParenthesis = null; | 4770 Token leftParenthesis = null; |
| 7658 SimpleIdentifier exceptionParameter = null; | 4771 SimpleIdentifier exceptionParameter = null; |
| 7659 Token comma = null; | 4772 Token comma = null; |
| 7660 SimpleIdentifier stackTraceParameter = null; | 4773 SimpleIdentifier stackTraceParameter = null; |
| 7661 Token rightParenthesis = null; | 4774 Token rightParenthesis = null; |
| 7662 if (_matchesKeyword(Keyword.CATCH)) { | 4775 if (_matchesKeyword(Keyword.CATCH)) { |
| 7663 catchKeyword = getAndAdvance(); | 4776 catchKeyword = getAndAdvance(); |
| 7664 leftParenthesis = _expect(TokenType.OPEN_PAREN); | 4777 leftParenthesis = _expect(TokenType.OPEN_PAREN); |
| 7665 exceptionParameter = parseSimpleIdentifier(); | 4778 exceptionParameter = parseSimpleIdentifier(isDeclaration: true); |
| 7666 if (_matches(TokenType.COMMA)) { | 4779 if (_matches(TokenType.COMMA)) { |
| 7667 comma = getAndAdvance(); | 4780 comma = getAndAdvance(); |
| 7668 stackTraceParameter = parseSimpleIdentifier(); | 4781 stackTraceParameter = parseSimpleIdentifier(isDeclaration: true); |
| 7669 } | 4782 } |
| 7670 rightParenthesis = _expect(TokenType.CLOSE_PAREN); | 4783 rightParenthesis = _expect(TokenType.CLOSE_PAREN); |
| 7671 } | 4784 } |
| 7672 Block catchBody = parseBlock(); | 4785 Block catchBody = _parseBlockChecked(); |
| 7673 catchClauses.add(new CatchClause( | 4786 catchClauses.add(new CatchClause( |
| 7674 onKeyword, | 4787 onKeyword, |
| 7675 exceptionType, | 4788 exceptionType, |
| 7676 catchKeyword, | 4789 catchKeyword, |
| 7677 leftParenthesis, | 4790 leftParenthesis, |
| 7678 exceptionParameter, | 4791 exceptionParameter, |
| 7679 comma, | 4792 comma, |
| 7680 stackTraceParameter, | 4793 stackTraceParameter, |
| 7681 rightParenthesis, | 4794 rightParenthesis, |
| 7682 catchBody)); | 4795 catchBody)); |
| 7683 } | 4796 } |
| 7684 Token finallyKeyword = null; | 4797 Token finallyKeyword = null; |
| 7685 if (_matchesKeyword(Keyword.FINALLY)) { | 4798 if (_matchesKeyword(Keyword.FINALLY)) { |
| 7686 finallyKeyword = getAndAdvance(); | 4799 finallyKeyword = getAndAdvance(); |
| 7687 finallyClause = parseBlock(); | 4800 finallyClause = _parseBlockChecked(); |
| 7688 } else { | 4801 } else if (catchClauses.isEmpty) { |
| 7689 if (catchClauses.isEmpty) { | 4802 _reportErrorForCurrentToken(ParserErrorCode.MISSING_CATCH_OR_FINALLY); |
| 7690 _reportErrorForCurrentToken(ParserErrorCode.MISSING_CATCH_OR_FINALLY); | |
| 7691 } | |
| 7692 } | 4803 } |
| 7693 return new TryStatement( | 4804 return new TryStatement( |
| 7694 tryKeyword, body, catchClauses, finallyKeyword, finallyClause); | 4805 tryKeyword, body, catchClauses, finallyKeyword, finallyClause); |
| 7695 } | 4806 } |
| 7696 | 4807 |
| 7697 /** | 4808 /** |
| 7698 * Parse a type alias. The [commentAndMetadata] is the metadata to be | 4809 * Parse a type alias. The [commentAndMetadata] is the metadata to be |
| 7699 * associated with the member. Return the type alias that was parsed. | 4810 * associated with the member. Return the type alias that was parsed. |
| 7700 * | 4811 * |
| 4812 * This method assumes that the current token matches [Keyword.TYPEDEF]. |
| 4813 * |
| 7701 * typeAlias ::= | 4814 * typeAlias ::= |
| 7702 * 'typedef' typeAliasBody | 4815 * 'typedef' typeAliasBody |
| 7703 * | 4816 * |
| 7704 * typeAliasBody ::= | 4817 * typeAliasBody ::= |
| 7705 * classTypeAlias | 4818 * classTypeAlias |
| 7706 * | functionTypeAlias | 4819 * | functionTypeAlias |
| 7707 * | 4820 * |
| 7708 * classTypeAlias ::= | 4821 * classTypeAlias ::= |
| 7709 * identifier typeParameters? '=' 'abstract'? mixinApplication | 4822 * identifier typeParameters? '=' 'abstract'? mixinApplication |
| 7710 * | 4823 * |
| 7711 * mixinApplication ::= | 4824 * mixinApplication ::= |
| 7712 * qualified withClause implementsClause? ';' | 4825 * qualified withClause implementsClause? ';' |
| 7713 * | 4826 * |
| 7714 * functionTypeAlias ::= | 4827 * functionTypeAlias ::= |
| 7715 * functionPrefix typeParameterList? formalParameterList ';' | 4828 * functionPrefix typeParameterList? formalParameterList ';' |
| 7716 * | 4829 * |
| 7717 * functionPrefix ::= | 4830 * functionPrefix ::= |
| 7718 * returnType? name | 4831 * returnType? name |
| 7719 */ | 4832 */ |
| 7720 TypeAlias _parseTypeAlias(CommentAndMetadata commentAndMetadata) { | 4833 TypeAlias parseTypeAlias(CommentAndMetadata commentAndMetadata) { |
| 7721 Token keyword = _expectKeyword(Keyword.TYPEDEF); | 4834 Token keyword = getAndAdvance(); |
| 7722 if (_matchesIdentifier()) { | 4835 if (_matchesIdentifier()) { |
| 7723 Token next = _peek(); | 4836 Token next = _peek(); |
| 7724 if (_tokenMatches(next, TokenType.LT)) { | 4837 if (_tokenMatches(next, TokenType.LT)) { |
| 7725 next = _skipTypeParameterList(next); | 4838 next = _skipTypeParameterList(next); |
| 7726 if (next != null && _tokenMatches(next, TokenType.EQ)) { | 4839 if (next != null && _tokenMatches(next, TokenType.EQ)) { |
| 7727 TypeAlias typeAlias = | 4840 TypeAlias typeAlias = |
| 7728 _parseClassTypeAlias(commentAndMetadata, null, keyword); | 4841 parseClassTypeAlias(commentAndMetadata, null, keyword); |
| 7729 _reportErrorForToken( | 4842 _reportErrorForToken( |
| 7730 ParserErrorCode.DEPRECATED_CLASS_TYPE_ALIAS, keyword); | 4843 ParserErrorCode.DEPRECATED_CLASS_TYPE_ALIAS, keyword); |
| 7731 return typeAlias; | 4844 return typeAlias; |
| 7732 } | 4845 } |
| 7733 } else if (_tokenMatches(next, TokenType.EQ)) { | 4846 } else if (_tokenMatches(next, TokenType.EQ)) { |
| 7734 TypeAlias typeAlias = | 4847 TypeAlias typeAlias = |
| 7735 _parseClassTypeAlias(commentAndMetadata, null, keyword); | 4848 parseClassTypeAlias(commentAndMetadata, null, keyword); |
| 7736 _reportErrorForToken( | 4849 _reportErrorForToken( |
| 7737 ParserErrorCode.DEPRECATED_CLASS_TYPE_ALIAS, keyword); | 4850 ParserErrorCode.DEPRECATED_CLASS_TYPE_ALIAS, keyword); |
| 7738 return typeAlias; | 4851 return typeAlias; |
| 7739 } | 4852 } |
| 7740 } | 4853 } |
| 7741 return _parseFunctionTypeAlias(commentAndMetadata, keyword); | 4854 return _parseFunctionTypeAlias(commentAndMetadata, keyword); |
| 7742 } | 4855 } |
| 7743 | 4856 |
| 7744 /** | 4857 /** |
| 4858 * Parse a list of type arguments. Return the type argument list that was |
| 4859 * parsed. |
| 4860 * |
| 4861 * This method assumes that the current token matches `TokenType.LT`. |
| 4862 * |
| 4863 * typeArguments ::= |
| 4864 * '<' typeList '>' |
| 4865 * |
| 4866 * typeList ::= |
| 4867 * type (',' type)* |
| 4868 */ |
| 4869 TypeArgumentList parseTypeArgumentList() { |
| 4870 Token leftBracket = getAndAdvance(); |
| 4871 List<TypeName> arguments = <TypeName>[parseTypeName(false)]; |
| 4872 while (_optional(TokenType.COMMA)) { |
| 4873 arguments.add(parseTypeName(false)); |
| 4874 } |
| 4875 Token rightBracket = _expectGt(); |
| 4876 return new TypeArgumentList(leftBracket, arguments, rightBracket); |
| 4877 } |
| 4878 |
| 4879 /** |
| 4880 * Parse a type name. Return the type name that was parsed. |
| 4881 * |
| 4882 * type ::= |
| 4883 * qualified typeArguments? |
| 4884 */ |
| 4885 TypeName parseTypeName(bool inExpression) { |
| 4886 TypeName realType = _parseTypeName(inExpression); |
| 4887 // If this is followed by a generic method type comment, allow the comment |
| 4888 // type to replace the real type name. |
| 4889 // TODO(jmesserly): this feels like a big hammer. Can we restrict it to |
| 4890 // only work inside generic methods? |
| 4891 TypeName typeFromComment = _parseOptionalTypeNameComment(); |
| 4892 return typeFromComment ?? realType; |
| 4893 } |
| 4894 |
| 4895 /** |
| 4896 * Parse a type parameter. Return the type parameter that was parsed. |
| 4897 * |
| 4898 * typeParameter ::= |
| 4899 * metadata name ('extends' bound)? |
| 4900 */ |
| 4901 TypeParameter parseTypeParameter() { |
| 4902 CommentAndMetadata commentAndMetadata = parseCommentAndMetadata(); |
| 4903 SimpleIdentifier name = parseSimpleIdentifier(isDeclaration: true); |
| 4904 if (_matches(TokenType.QUESTION)) { |
| 4905 _reportErrorForCurrentToken(ParserErrorCode.NULLABLE_TYPE_PARAMETER); |
| 4906 _advance(); |
| 4907 } |
| 4908 if (_matchesKeyword(Keyword.EXTENDS)) { |
| 4909 Token keyword = getAndAdvance(); |
| 4910 TypeName bound = parseTypeName(false); |
| 4911 return new TypeParameter(commentAndMetadata.comment, |
| 4912 commentAndMetadata.metadata, name, keyword, bound); |
| 4913 } |
| 4914 return new TypeParameter(commentAndMetadata.comment, |
| 4915 commentAndMetadata.metadata, name, null, null); |
| 4916 } |
| 4917 |
| 4918 /** |
| 4919 * Parse a list of type parameters. Return the list of type parameters that |
| 4920 * were parsed. |
| 4921 * |
| 4922 * This method assumes that the current token matches `TokenType.LT`. |
| 4923 * |
| 4924 * typeParameterList ::= |
| 4925 * '<' typeParameter (',' typeParameter)* '>' |
| 4926 */ |
| 4927 TypeParameterList parseTypeParameterList() { |
| 4928 Token leftBracket = getAndAdvance(); |
| 4929 List<TypeParameter> typeParameters = <TypeParameter>[parseTypeParameter()]; |
| 4930 while (_optional(TokenType.COMMA)) { |
| 4931 typeParameters.add(parseTypeParameter()); |
| 4932 } |
| 4933 Token rightBracket = _expectGt(); |
| 4934 return new TypeParameterList(leftBracket, typeParameters, rightBracket); |
| 4935 } |
| 4936 |
| 4937 /** |
| 7745 * Parse a unary expression. Return the unary expression that was parsed. | 4938 * Parse a unary expression. Return the unary expression that was parsed. |
| 7746 * | 4939 * |
| 7747 * unaryExpression ::= | 4940 * unaryExpression ::= |
| 7748 * prefixOperator unaryExpression | 4941 * prefixOperator unaryExpression |
| 7749 * | awaitExpression | 4942 * | awaitExpression |
| 7750 * | postfixExpression | 4943 * | postfixExpression |
| 7751 * | unaryOperator 'super' | 4944 * | unaryOperator 'super' |
| 7752 * | '-' 'super' | 4945 * | '-' 'super' |
| 7753 * | incrementOperator assignableExpression | 4946 * | incrementOperator assignableExpression |
| 7754 */ | 4947 */ |
| 7755 Expression _parseUnaryExpression() { | 4948 Expression parseUnaryExpression() { |
| 7756 if (_matches(TokenType.MINUS) || | 4949 TokenType type = _currentToken.type; |
| 7757 _matches(TokenType.BANG) || | 4950 if (type == TokenType.MINUS || |
| 7758 _matches(TokenType.TILDE)) { | 4951 type == TokenType.BANG || |
| 4952 type == TokenType.TILDE) { |
| 7759 Token operator = getAndAdvance(); | 4953 Token operator = getAndAdvance(); |
| 7760 if (_matchesKeyword(Keyword.SUPER)) { | 4954 if (_matchesKeyword(Keyword.SUPER)) { |
| 7761 if (_tokenMatches(_peek(), TokenType.OPEN_SQUARE_BRACKET) || | 4955 TokenType nextType = _peek().type; |
| 7762 _tokenMatches(_peek(), TokenType.PERIOD)) { | 4956 if (nextType == TokenType.OPEN_SQUARE_BRACKET || |
| 4957 nextType == TokenType.PERIOD) { |
| 7763 // "prefixOperator unaryExpression" | 4958 // "prefixOperator unaryExpression" |
| 7764 // --> "prefixOperator postfixExpression" | 4959 // --> "prefixOperator postfixExpression" |
| 7765 // --> "prefixOperator primary selector*" | 4960 // --> "prefixOperator primary selector*" |
| 7766 // --> "prefixOperator 'super' assignableSelector selector*" | 4961 // --> "prefixOperator 'super' assignableSelector selector*" |
| 7767 return new PrefixExpression(operator, _parseUnaryExpression()); | 4962 return new PrefixExpression(operator, parseUnaryExpression()); |
| 7768 } | 4963 } |
| 7769 return new PrefixExpression( | 4964 return new PrefixExpression( |
| 7770 operator, new SuperExpression(getAndAdvance())); | 4965 operator, new SuperExpression(getAndAdvance())); |
| 7771 } | 4966 } |
| 7772 return new PrefixExpression(operator, _parseUnaryExpression()); | 4967 return new PrefixExpression(operator, parseUnaryExpression()); |
| 7773 } else if (_currentToken.type.isIncrementOperator) { | 4968 } else if (_currentToken.type.isIncrementOperator) { |
| 7774 Token operator = getAndAdvance(); | 4969 Token operator = getAndAdvance(); |
| 7775 if (_matchesKeyword(Keyword.SUPER)) { | 4970 if (_matchesKeyword(Keyword.SUPER)) { |
| 7776 if (_tokenMatches(_peek(), TokenType.OPEN_SQUARE_BRACKET) || | 4971 TokenType nextType = _peek().type; |
| 7777 _tokenMatches(_peek(), TokenType.PERIOD)) { | 4972 if (nextType == TokenType.OPEN_SQUARE_BRACKET || |
| 4973 nextType == TokenType.PERIOD) { |
| 7778 // --> "prefixOperator 'super' assignableSelector selector*" | 4974 // --> "prefixOperator 'super' assignableSelector selector*" |
| 7779 return new PrefixExpression(operator, _parseUnaryExpression()); | 4975 return new PrefixExpression(operator, parseUnaryExpression()); |
| 7780 } | 4976 } |
| 7781 // | 4977 // |
| 7782 // Even though it is not valid to use an incrementing operator | 4978 // Even though it is not valid to use an incrementing operator |
| 7783 // ('++' or '--') before 'super', we can (and therefore must) interpret | 4979 // ('++' or '--') before 'super', we can (and therefore must) interpret |
| 7784 // "--super" as semantically equivalent to "-(-super)". Unfortunately, | 4980 // "--super" as semantically equivalent to "-(-super)". Unfortunately, |
| 7785 // we cannot do the same for "++super" because "+super" is also not | 4981 // we cannot do the same for "++super" because "+super" is also not |
| 7786 // valid. | 4982 // valid. |
| 7787 // | 4983 // |
| 7788 if (operator.type == TokenType.MINUS_MINUS) { | 4984 if (type == TokenType.MINUS_MINUS) { |
| 7789 Token firstOperator = _createToken(operator, TokenType.MINUS); | 4985 Token firstOperator = _createToken(operator, TokenType.MINUS); |
| 7790 Token secondOperator = | 4986 Token secondOperator = |
| 7791 new Token(TokenType.MINUS, operator.offset + 1); | 4987 new Token(TokenType.MINUS, operator.offset + 1); |
| 7792 secondOperator.setNext(_currentToken); | 4988 secondOperator.setNext(_currentToken); |
| 7793 firstOperator.setNext(secondOperator); | 4989 firstOperator.setNext(secondOperator); |
| 7794 operator.previous.setNext(firstOperator); | 4990 operator.previous.setNext(firstOperator); |
| 7795 return new PrefixExpression( | 4991 return new PrefixExpression( |
| 7796 firstOperator, | 4992 firstOperator, |
| 7797 new PrefixExpression( | 4993 new PrefixExpression( |
| 7798 secondOperator, new SuperExpression(getAndAdvance()))); | 4994 secondOperator, new SuperExpression(getAndAdvance()))); |
| 7799 } else { | |
| 7800 // Invalid operator before 'super' | |
| 7801 _reportErrorForCurrentToken( | |
| 7802 ParserErrorCode.INVALID_OPERATOR_FOR_SUPER, [operator.lexeme]); | |
| 7803 return new PrefixExpression( | |
| 7804 operator, new SuperExpression(getAndAdvance())); | |
| 7805 } | 4995 } |
| 4996 // Invalid operator before 'super' |
| 4997 _reportErrorForCurrentToken( |
| 4998 ParserErrorCode.INVALID_OPERATOR_FOR_SUPER, [operator.lexeme]); |
| 4999 return new PrefixExpression( |
| 5000 operator, new SuperExpression(getAndAdvance())); |
| 7806 } | 5001 } |
| 7807 return new PrefixExpression(operator, _parseAssignableExpression(false)); | 5002 return new PrefixExpression( |
| 7808 } else if (_matches(TokenType.PLUS)) { | 5003 operator, _parseAssignableExpressionNotStartingWithSuper(false)); |
| 5004 } else if (type == TokenType.PLUS) { |
| 7809 _reportErrorForCurrentToken(ParserErrorCode.MISSING_IDENTIFIER); | 5005 _reportErrorForCurrentToken(ParserErrorCode.MISSING_IDENTIFIER); |
| 7810 return _createSyntheticIdentifier(); | 5006 return createSyntheticIdentifier(); |
| 7811 } else if (_inAsync && _matchesString(_AWAIT)) { | 5007 } else if (_inAsync && _matchesString(_AWAIT)) { |
| 7812 return _parseAwaitExpression(); | 5008 return parseAwaitExpression(); |
| 7813 } | 5009 } |
| 7814 return _parsePostfixExpression(); | 5010 return parsePostfixExpression(); |
| 7815 } | 5011 } |
| 7816 | 5012 |
| 7817 /** | 5013 /** |
| 7818 * Parse a string literal representing a URI. Return the string literal that | |
| 7819 * was parsed. | |
| 7820 */ | |
| 7821 StringLiteral _parseUri() { | |
| 7822 bool iskeywordAfterUri(Token token) => token.lexeme == Keyword.AS.syntax || | |
| 7823 token.lexeme == _HIDE || | |
| 7824 token.lexeme == _SHOW; | |
| 7825 if (!_matches(TokenType.STRING) && | |
| 7826 !_matches(TokenType.SEMICOLON) && | |
| 7827 !iskeywordAfterUri(_currentToken)) { | |
| 7828 // Attempt to recover in the case where the URI was not enclosed in | |
| 7829 // quotes. | |
| 7830 Token token = _currentToken; | |
| 7831 while ((_tokenMatchesIdentifier(token) && !iskeywordAfterUri(token)) || | |
| 7832 _tokenMatches(token, TokenType.COLON) || | |
| 7833 _tokenMatches(token, TokenType.SLASH) || | |
| 7834 _tokenMatches(token, TokenType.PERIOD) || | |
| 7835 _tokenMatches(token, TokenType.PERIOD_PERIOD) || | |
| 7836 _tokenMatches(token, TokenType.PERIOD_PERIOD_PERIOD) || | |
| 7837 _tokenMatches(token, TokenType.INT) || | |
| 7838 _tokenMatches(token, TokenType.DOUBLE)) { | |
| 7839 token = token.next; | |
| 7840 } | |
| 7841 if (_tokenMatches(token, TokenType.SEMICOLON) || | |
| 7842 iskeywordAfterUri(token)) { | |
| 7843 Token endToken = token.previous; | |
| 7844 token = _currentToken; | |
| 7845 int endOffset = token.end; | |
| 7846 StringBuffer buffer = new StringBuffer(); | |
| 7847 buffer.write(token.lexeme); | |
| 7848 while (token != endToken) { | |
| 7849 token = token.next; | |
| 7850 if (token.offset != endOffset || token.precedingComments != null) { | |
| 7851 return parseStringLiteral(); | |
| 7852 } | |
| 7853 buffer.write(token.lexeme); | |
| 7854 endOffset = token.end; | |
| 7855 } | |
| 7856 String value = buffer.toString(); | |
| 7857 Token newToken = | |
| 7858 new StringToken(TokenType.STRING, "'$value'", _currentToken.offset); | |
| 7859 _reportErrorForToken( | |
| 7860 ParserErrorCode.NON_STRING_LITERAL_AS_URI, newToken); | |
| 7861 _currentToken = endToken.next; | |
| 7862 return new SimpleStringLiteral(newToken, value); | |
| 7863 } | |
| 7864 } | |
| 7865 return parseStringLiteral(); | |
| 7866 } | |
| 7867 | |
| 7868 /** | |
| 7869 * Parse a variable declaration. Return the variable declaration that was | 5014 * Parse a variable declaration. Return the variable declaration that was |
| 7870 * parsed. | 5015 * parsed. |
| 7871 * | 5016 * |
| 7872 * variableDeclaration ::= | 5017 * variableDeclaration ::= |
| 7873 * identifier ('=' expression)? | 5018 * identifier ('=' expression)? |
| 7874 */ | 5019 */ |
| 7875 VariableDeclaration _parseVariableDeclaration() { | 5020 VariableDeclaration parseVariableDeclaration() { |
| 7876 // TODO(paulberry): prior to the fix for bug 23204, we permitted | 5021 // TODO(paulberry): prior to the fix for bug 23204, we permitted |
| 7877 // annotations before variable declarations (e.g. "String @deprecated s;"). | 5022 // annotations before variable declarations (e.g. "String @deprecated s;"). |
| 7878 // Although such constructions are prohibited by the spec, we may want to | 5023 // Although such constructions are prohibited by the spec, we may want to |
| 7879 // consider handling them anyway to allow for better parser recovery in the | 5024 // consider handling them anyway to allow for better parser recovery in the |
| 7880 // event that the user erroneously tries to use them. However, as a | 5025 // event that the user erroneously tries to use them. However, as a |
| 7881 // counterargument, this would likely degrade parser recovery in the event | 5026 // counterargument, this would likely degrade parser recovery in the event |
| 7882 // of a construct like "class C { int @deprecated foo() {} }" (i.e. the | 5027 // of a construct like "class C { int @deprecated foo() {} }" (i.e. the |
| 7883 // user is in the middle of inserting "int bar;" prior to | 5028 // user is in the middle of inserting "int bar;" prior to |
| 7884 // "@deprecated foo() {}"). | 5029 // "@deprecated foo() {}"). |
| 7885 SimpleIdentifier name = parseSimpleIdentifier(); | 5030 SimpleIdentifier name = parseSimpleIdentifier(isDeclaration: true); |
| 7886 Token equals = null; | 5031 Token equals = null; |
| 7887 Expression initializer = null; | 5032 Expression initializer = null; |
| 7888 if (_matches(TokenType.EQ)) { | 5033 if (_matches(TokenType.EQ)) { |
| 7889 equals = getAndAdvance(); | 5034 equals = getAndAdvance(); |
| 7890 initializer = parseExpression2(); | 5035 initializer = parseExpression2(); |
| 7891 } | 5036 } |
| 7892 return new VariableDeclaration(name, equals, initializer); | 5037 return new VariableDeclaration(name, equals, initializer); |
| 7893 } | 5038 } |
| 7894 | 5039 |
| 7895 /** | 5040 /** |
| 7896 * Parse a variable declaration list. The [commentAndMetadata] is the metadata | 5041 * Parse a variable declaration list. The [commentAndMetadata] is the metadata |
| 7897 * to be associated with the variable declaration list. Return the variable | 5042 * to be associated with the variable declaration list. Return the variable |
| 7898 * declaration list that was parsed. | 5043 * declaration list that was parsed. |
| 7899 * | 5044 * |
| 7900 * variableDeclarationList ::= | 5045 * variableDeclarationList ::= |
| 7901 * finalConstVarOrType variableDeclaration (',' variableDeclaration)* | 5046 * finalConstVarOrType variableDeclaration (',' variableDeclaration)* |
| 7902 */ | 5047 */ |
| 7903 VariableDeclarationList _parseVariableDeclarationListAfterMetadata( | 5048 VariableDeclarationList parseVariableDeclarationListAfterMetadata( |
| 7904 CommentAndMetadata commentAndMetadata) { | 5049 CommentAndMetadata commentAndMetadata) { |
| 7905 FinalConstVarOrType holder = _parseFinalConstVarOrType(false); | 5050 FinalConstVarOrType holder = parseFinalConstVarOrType(false); |
| 7906 return _parseVariableDeclarationListAfterType( | 5051 return parseVariableDeclarationListAfterType( |
| 7907 commentAndMetadata, holder.keyword, holder.type); | 5052 commentAndMetadata, holder.keyword, holder.type); |
| 7908 } | 5053 } |
| 7909 | 5054 |
| 7910 /** | 5055 /** |
| 7911 * Parse a variable declaration list. The [commentAndMetadata] is the metadata | 5056 * Parse a variable declaration list. The [commentAndMetadata] is the metadata |
| 7912 * to be associated with the variable declaration list, or `null` if there is | 5057 * to be associated with the variable declaration list, or `null` if there is |
| 7913 * no attempt at parsing the comment and metadata. The [keyword] is the token | 5058 * no attempt at parsing the comment and metadata. The [keyword] is the token |
| 7914 * representing the 'final', 'const' or 'var' keyword, or `null` if there is | 5059 * representing the 'final', 'const' or 'var' keyword, or `null` if there is |
| 7915 * no keyword. The [type] is the type of the variables in the list. Return the | 5060 * no keyword. The [type] is the type of the variables in the list. Return the |
| 7916 * variable declaration list that was parsed. | 5061 * variable declaration list that was parsed. |
| 7917 * | 5062 * |
| 7918 * variableDeclarationList ::= | 5063 * variableDeclarationList ::= |
| 7919 * finalConstVarOrType variableDeclaration (',' variableDeclaration)* | 5064 * finalConstVarOrType variableDeclaration (',' variableDeclaration)* |
| 7920 */ | 5065 */ |
| 7921 VariableDeclarationList _parseVariableDeclarationListAfterType( | 5066 VariableDeclarationList parseVariableDeclarationListAfterType( |
| 7922 CommentAndMetadata commentAndMetadata, Token keyword, TypeName type) { | 5067 CommentAndMetadata commentAndMetadata, Token keyword, TypeName type) { |
| 7923 if (type != null && | 5068 if (type != null && |
| 7924 keyword != null && | 5069 keyword != null && |
| 7925 _tokenMatchesKeyword(keyword, Keyword.VAR)) { | 5070 _tokenMatchesKeyword(keyword, Keyword.VAR)) { |
| 7926 _reportErrorForToken(ParserErrorCode.VAR_AND_TYPE, keyword); | 5071 _reportErrorForToken(ParserErrorCode.VAR_AND_TYPE, keyword); |
| 7927 } | 5072 } |
| 7928 List<VariableDeclaration> variables = new List<VariableDeclaration>(); | 5073 List<VariableDeclaration> variables = <VariableDeclaration>[ |
| 7929 variables.add(_parseVariableDeclaration()); | 5074 parseVariableDeclaration() |
| 7930 while (_matches(TokenType.COMMA)) { | 5075 ]; |
| 7931 _advance(); | 5076 while (_optional(TokenType.COMMA)) { |
| 7932 variables.add(_parseVariableDeclaration()); | 5077 variables.add(parseVariableDeclaration()); |
| 7933 } | 5078 } |
| 7934 return new VariableDeclarationList( | 5079 return new VariableDeclarationList(commentAndMetadata?.comment, |
| 7935 commentAndMetadata != null ? commentAndMetadata.comment : null, | 5080 commentAndMetadata?.metadata, keyword, type, variables); |
| 7936 commentAndMetadata != null ? commentAndMetadata.metadata : null, | |
| 7937 keyword, | |
| 7938 type, | |
| 7939 variables); | |
| 7940 } | 5081 } |
| 7941 | 5082 |
| 7942 /** | 5083 /** |
| 7943 * Parse a variable declaration statement. The [commentAndMetadata] is the | 5084 * Parse a variable declaration statement. The [commentAndMetadata] is the |
| 7944 * metadata to be associated with the variable declaration statement, or | 5085 * metadata to be associated with the variable declaration statement, or |
| 7945 * `null` if there is no attempt at parsing the comment and metadata. Return | 5086 * `null` if there is no attempt at parsing the comment and metadata. Return |
| 7946 * the variable declaration statement that was parsed. | 5087 * the variable declaration statement that was parsed. |
| 7947 * | 5088 * |
| 7948 * variableDeclarationStatement ::= | 5089 * variableDeclarationStatement ::= |
| 7949 * variableDeclarationList ';' | 5090 * variableDeclarationList ';' |
| 7950 */ | 5091 */ |
| 7951 VariableDeclarationStatement _parseVariableDeclarationStatementAfterMetadata( | 5092 VariableDeclarationStatement parseVariableDeclarationStatementAfterMetadata( |
| 7952 CommentAndMetadata commentAndMetadata) { | 5093 CommentAndMetadata commentAndMetadata) { |
| 7953 // Token startToken = currentToken; | 5094 // Token startToken = currentToken; |
| 7954 VariableDeclarationList variableList = | 5095 VariableDeclarationList variableList = |
| 7955 _parseVariableDeclarationListAfterMetadata(commentAndMetadata); | 5096 parseVariableDeclarationListAfterMetadata(commentAndMetadata); |
| 7956 // if (!matches(TokenType.SEMICOLON)) { | 5097 // if (!matches(TokenType.SEMICOLON)) { |
| 7957 // if (matches(startToken, Keyword.VAR) && isTypedIdentifier(startToken
.getNext())) { | 5098 // if (matches(startToken, Keyword.VAR) && isTypedIdentifier(startToken
.getNext())) { |
| 7958 // // TODO(brianwilkerson) This appears to be of the form "var type v
ariable". We should do | 5099 // // TODO(brianwilkerson) This appears to be of the form "var type v
ariable". We should do |
| 7959 // // a better job of recovering in this case. | 5100 // // a better job of recovering in this case. |
| 7960 // } | 5101 // } |
| 7961 // } | 5102 // } |
| 7962 Token semicolon = _expect(TokenType.SEMICOLON); | 5103 Token semicolon = _expect(TokenType.SEMICOLON); |
| 7963 return new VariableDeclarationStatement(variableList, semicolon); | 5104 return new VariableDeclarationStatement(variableList, semicolon); |
| 7964 } | 5105 } |
| 7965 | 5106 |
| 7966 /** | 5107 /** |
| 7967 * Parse a variable declaration statement. The [commentAndMetadata] is the | |
| 7968 * metadata to be associated with the variable declaration statement, or | |
| 7969 * `null` if there is no attempt at parsing the comment and metadata. The | |
| 7970 * [keyword] is the token representing the 'final', 'const' or 'var' keyword, | |
| 7971 * or `null` if there is no keyword. The [type] is the type of the variables | |
| 7972 * in the list. Return the variable declaration statement that was parsed. | |
| 7973 * | |
| 7974 * variableDeclarationStatement ::= | |
| 7975 * variableDeclarationList ';' | |
| 7976 */ | |
| 7977 VariableDeclarationStatement _parseVariableDeclarationStatementAfterType( | |
| 7978 CommentAndMetadata commentAndMetadata, Token keyword, TypeName type) { | |
| 7979 VariableDeclarationList variableList = | |
| 7980 _parseVariableDeclarationListAfterType( | |
| 7981 commentAndMetadata, keyword, type); | |
| 7982 Token semicolon = _expect(TokenType.SEMICOLON); | |
| 7983 return new VariableDeclarationStatement(variableList, semicolon); | |
| 7984 } | |
| 7985 | |
| 7986 /** | |
| 7987 * Parse a while statement. Return the while statement that was parsed. | 5108 * Parse a while statement. Return the while statement that was parsed. |
| 7988 * | 5109 * |
| 5110 * This method assumes that the current token matches [Keyword.WHILE]. |
| 5111 * |
| 7989 * whileStatement ::= | 5112 * whileStatement ::= |
| 7990 * 'while' '(' expression ')' statement | 5113 * 'while' '(' expression ')' statement |
| 7991 */ | 5114 */ |
| 7992 Statement _parseWhileStatement() { | 5115 Statement parseWhileStatement() { |
| 7993 bool wasInLoop = _inLoop; | 5116 bool wasInLoop = _inLoop; |
| 7994 _inLoop = true; | 5117 _inLoop = true; |
| 7995 try { | 5118 try { |
| 7996 Token keyword = _expectKeyword(Keyword.WHILE); | 5119 Token keyword = getAndAdvance(); |
| 7997 Token leftParenthesis = _expect(TokenType.OPEN_PAREN); | 5120 Token leftParenthesis = _expect(TokenType.OPEN_PAREN); |
| 7998 Expression condition = parseExpression2(); | 5121 Expression condition = parseExpression2(); |
| 7999 Token rightParenthesis = _expect(TokenType.CLOSE_PAREN); | 5122 Token rightParenthesis = _expect(TokenType.CLOSE_PAREN); |
| 8000 Statement body = parseStatement2(); | 5123 Statement body = parseStatement2(); |
| 8001 return new WhileStatement( | 5124 return new WhileStatement( |
| 8002 keyword, leftParenthesis, condition, rightParenthesis, body); | 5125 keyword, leftParenthesis, condition, rightParenthesis, body); |
| 8003 } finally { | 5126 } finally { |
| 8004 _inLoop = wasInLoop; | 5127 _inLoop = wasInLoop; |
| 8005 } | 5128 } |
| 8006 } | 5129 } |
| 8007 | 5130 |
| 8008 /** | 5131 /** |
| 5132 * Parse a with clause. Return the with clause that was parsed. |
| 5133 * |
| 5134 * This method assumes that the current token matches `Keyword.WITH`. |
| 5135 * |
| 5136 * withClause ::= |
| 5137 * 'with' typeName (',' typeName)* |
| 5138 */ |
| 5139 WithClause parseWithClause() { |
| 5140 Token withKeyword = getAndAdvance(); |
| 5141 List<TypeName> types = <TypeName>[]; |
| 5142 do { |
| 5143 TypeName typeName = parseTypeName(false); |
| 5144 _mustNotBeNullable(typeName, ParserErrorCode.NULLABLE_TYPE_IN_WITH); |
| 5145 types.add(typeName); |
| 5146 } while (_optional(TokenType.COMMA)); |
| 5147 return new WithClause(withKeyword, types); |
| 5148 } |
| 5149 |
| 5150 /** |
| 8009 * Parse a yield statement. Return the yield statement that was parsed. | 5151 * Parse a yield statement. Return the yield statement that was parsed. |
| 8010 * | 5152 * |
| 5153 * This method assumes that the current token matches [Keyword.YIELD]. |
| 5154 * |
| 8011 * yieldStatement ::= | 5155 * yieldStatement ::= |
| 8012 * 'yield' '*'? expression ';' | 5156 * 'yield' '*'? expression ';' |
| 8013 */ | 5157 */ |
| 8014 YieldStatement _parseYieldStatement() { | 5158 YieldStatement parseYieldStatement() { |
| 8015 Token yieldToken = getAndAdvance(); | 5159 Token yieldToken = getAndAdvance(); |
| 8016 Token star = null; | 5160 Token star = null; |
| 8017 if (_matches(TokenType.STAR)) { | 5161 if (_matches(TokenType.STAR)) { |
| 8018 star = getAndAdvance(); | 5162 star = getAndAdvance(); |
| 8019 } | 5163 } |
| 8020 Expression expression = parseExpression2(); | 5164 Expression expression = parseExpression2(); |
| 8021 Token semicolon = _expect(TokenType.SEMICOLON); | 5165 Token semicolon = _expect(TokenType.SEMICOLON); |
| 8022 return new YieldStatement(yieldToken, star, expression, semicolon); | 5166 return new YieldStatement(yieldToken, star, expression, semicolon); |
| 8023 } | 5167 } |
| 8024 | 5168 |
| 8025 /** | 5169 /** |
| 5170 * Parse a prefixed identifier, starting at the [startToken], without actually |
| 5171 * creating a prefixed identifier or changing the current token. Return the |
| 5172 * token following the prefixed identifier that was parsed, or `null` if the |
| 5173 * given token is not the first token in a valid prefixed identifier. |
| 5174 * |
| 5175 * This method must be kept in sync with [parsePrefixedIdentifier]. |
| 5176 * |
| 5177 * prefixedIdentifier ::= |
| 5178 * identifier ('.' identifier)? |
| 5179 */ |
| 5180 Token skipPrefixedIdentifier(Token startToken) { |
| 5181 Token token = skipSimpleIdentifier(startToken); |
| 5182 if (token == null) { |
| 5183 return null; |
| 5184 } else if (!_tokenMatches(token, TokenType.PERIOD)) { |
| 5185 return token; |
| 5186 } |
| 5187 token = token.next; |
| 5188 Token nextToken = skipSimpleIdentifier(token); |
| 5189 if (nextToken != null) { |
| 5190 return nextToken; |
| 5191 } else if (_tokenMatches(token, TokenType.CLOSE_PAREN) || |
| 5192 _tokenMatches(token, TokenType.COMMA)) { |
| 5193 // If the `id.` is followed by something that cannot produce a valid |
| 5194 // structure then assume this is a prefixed identifier but missing the |
| 5195 // trailing identifier |
| 5196 return token; |
| 5197 } |
| 5198 return null; |
| 5199 } |
| 5200 |
| 5201 /** |
| 5202 * Parse a return type, starting at the [startToken], without actually |
| 5203 * creating a return type or changing the current token. Return the token |
| 5204 * following the return type that was parsed, or `null` if the given token is |
| 5205 * not the first token in a valid return type. |
| 5206 * |
| 5207 * This method must be kept in sync with [parseReturnType]. |
| 5208 * |
| 5209 * returnType ::= |
| 5210 * 'void' |
| 5211 * | type |
| 5212 */ |
| 5213 Token skipReturnType(Token startToken) { |
| 5214 if (_tokenMatchesKeyword(startToken, Keyword.VOID)) { |
| 5215 return startToken.next; |
| 5216 } else { |
| 5217 return skipTypeName(startToken); |
| 5218 } |
| 5219 } |
| 5220 |
| 5221 /** |
| 5222 * Parse a simple identifier, starting at the [startToken], without actually |
| 5223 * creating a simple identifier or changing the current token. Return the |
| 5224 * token following the simple identifier that was parsed, or `null` if the |
| 5225 * given token is not the first token in a valid simple identifier. |
| 5226 * |
| 5227 * This method must be kept in sync with [parseSimpleIdentifier]. |
| 5228 * |
| 5229 * identifier ::= |
| 5230 * IDENTIFIER |
| 5231 */ |
| 5232 Token skipSimpleIdentifier(Token startToken) { |
| 5233 if (_tokenMatches(startToken, TokenType.IDENTIFIER) || |
| 5234 _tokenMatchesPseudoKeyword(startToken)) { |
| 5235 return startToken.next; |
| 5236 } |
| 5237 return null; |
| 5238 } |
| 5239 |
| 5240 /** |
| 5241 * Parse a string literal, starting at the [startToken], without actually |
| 5242 * creating a string literal or changing the current token. Return the token |
| 5243 * following the string literal that was parsed, or `null` if the given token |
| 5244 * is not the first token in a valid string literal. |
| 5245 * |
| 5246 * This method must be kept in sync with [parseStringLiteral]. |
| 5247 * |
| 5248 * stringLiteral ::= |
| 5249 * MULTI_LINE_STRING+ |
| 5250 * | SINGLE_LINE_STRING+ |
| 5251 */ |
| 5252 Token skipStringLiteral(Token startToken) { |
| 5253 Token token = startToken; |
| 5254 while (token != null && _tokenMatches(token, TokenType.STRING)) { |
| 5255 token = token.next; |
| 5256 TokenType type = token.type; |
| 5257 if (type == TokenType.STRING_INTERPOLATION_EXPRESSION || |
| 5258 type == TokenType.STRING_INTERPOLATION_IDENTIFIER) { |
| 5259 token = _skipStringInterpolation(token); |
| 5260 } |
| 5261 } |
| 5262 if (identical(token, startToken)) { |
| 5263 return null; |
| 5264 } |
| 5265 return token; |
| 5266 } |
| 5267 |
| 5268 /** |
| 5269 * Parse a list of type arguments, starting at the [startToken], without |
| 5270 * actually creating a type argument list or changing the current token. |
| 5271 * Return the token following the type argument list that was parsed, or |
| 5272 * `null` if the given token is not the first token in a valid type argument |
| 5273 * list. |
| 5274 * |
| 5275 * This method must be kept in sync with [parseTypeArgumentList]. |
| 5276 * |
| 5277 * typeArguments ::= |
| 5278 * '<' typeList '>' |
| 5279 * |
| 5280 * typeList ::= |
| 5281 * type (',' type)* |
| 5282 */ |
| 5283 Token skipTypeArgumentList(Token startToken) { |
| 5284 Token token = startToken; |
| 5285 if (!_tokenMatches(token, TokenType.LT) && |
| 5286 !_injectGenericCommentTypeList()) { |
| 5287 return null; |
| 5288 } |
| 5289 token = skipTypeName(token.next); |
| 5290 if (token == null) { |
| 5291 // If the start token '<' is followed by '>' |
| 5292 // then assume this should be type argument list but is missing a type |
| 5293 token = startToken.next; |
| 5294 if (_tokenMatches(token, TokenType.GT)) { |
| 5295 return token.next; |
| 5296 } |
| 5297 return null; |
| 5298 } |
| 5299 while (_tokenMatches(token, TokenType.COMMA)) { |
| 5300 token = skipTypeName(token.next); |
| 5301 if (token == null) { |
| 5302 return null; |
| 5303 } |
| 5304 } |
| 5305 if (token.type == TokenType.GT) { |
| 5306 return token.next; |
| 5307 } else if (token.type == TokenType.GT_GT) { |
| 5308 Token second = new Token(TokenType.GT, token.offset + 1); |
| 5309 second.setNextWithoutSettingPrevious(token.next); |
| 5310 return second; |
| 5311 } |
| 5312 return null; |
| 5313 } |
| 5314 |
| 5315 /** |
| 5316 * Parse a type name, starting at the [startToken], without actually creating |
| 5317 * a type name or changing the current token. Return the token following the |
| 5318 * type name that was parsed, or `null` if the given token is not the first |
| 5319 * token in a valid type name. |
| 5320 * |
| 5321 * This method must be kept in sync with [parseTypeName]. |
| 5322 * |
| 5323 * type ::= |
| 5324 * qualified typeArguments? |
| 5325 */ |
| 5326 Token skipTypeName(Token startToken) { |
| 5327 Token token = skipPrefixedIdentifier(startToken); |
| 5328 if (token == null) { |
| 5329 return null; |
| 5330 } |
| 5331 if (_tokenMatches(token, TokenType.LT)) { |
| 5332 token = skipTypeArgumentList(token); |
| 5333 } |
| 5334 return token; |
| 5335 } |
| 5336 |
| 5337 /** |
| 5338 * Advance to the next token in the token stream. |
| 5339 */ |
| 5340 void _advance() { |
| 5341 _currentToken = _currentToken.next; |
| 5342 } |
| 5343 |
| 5344 /** |
| 5345 * Append the character equivalent of the given [codePoint] to the given |
| 5346 * [builder]. Use the [startIndex] and [endIndex] to report an error, and |
| 5347 * don't append anything to the builder, if the code point is invalid. The |
| 5348 * [escapeSequence] is the escape sequence that was parsed to produce the |
| 5349 * code point (used for error reporting). |
| 5350 */ |
| 5351 void _appendCodePoint(StringBuffer buffer, String source, int codePoint, |
| 5352 int startIndex, int endIndex) { |
| 5353 if (codePoint < 0 || codePoint > Character.MAX_CODE_POINT) { |
| 5354 String escapeSequence = source.substring(startIndex, endIndex + 1); |
| 5355 _reportErrorForCurrentToken( |
| 5356 ParserErrorCode.INVALID_CODE_POINT, [escapeSequence]); |
| 5357 return; |
| 5358 } |
| 5359 if (codePoint < Character.MAX_VALUE) { |
| 5360 buffer.writeCharCode(codePoint); |
| 5361 } else { |
| 5362 buffer.write(Character.toChars(codePoint)); |
| 5363 } |
| 5364 } |
| 5365 |
| 5366 /** |
| 5367 * Clone all token starting from the given [token] up to the end of the token |
| 5368 * stream, and return the first token in the new token stream. |
| 5369 */ |
| 5370 Token _cloneTokens(Token token) { |
| 5371 if (token == null) { |
| 5372 return null; |
| 5373 } |
| 5374 token = token is CommentToken ? token.parent : token; |
| 5375 Token head = new Token(TokenType.EOF, -1); |
| 5376 head.setNext(head); |
| 5377 Token current = head; |
| 5378 while (token.type != TokenType.EOF) { |
| 5379 Token clone = token.copy(); |
| 5380 current.setNext(clone); |
| 5381 current = clone; |
| 5382 token = token.next; |
| 5383 } |
| 5384 Token tail = new Token(TokenType.EOF, 0); |
| 5385 tail.setNext(tail); |
| 5386 current.setNext(tail); |
| 5387 return head.next; |
| 5388 } |
| 5389 |
| 5390 /** |
| 5391 * Convert the given [method] declaration into the nearest valid top-level |
| 5392 * function declaration (that is, the function declaration that most closely |
| 5393 * captures the components of the given method declaration). |
| 5394 */ |
| 5395 FunctionDeclaration _convertToFunctionDeclaration(MethodDeclaration method) => |
| 5396 new FunctionDeclaration( |
| 5397 method.documentationComment, |
| 5398 method.metadata, |
| 5399 method.externalKeyword, |
| 5400 method.returnType, |
| 5401 method.propertyKeyword, |
| 5402 method.name, |
| 5403 new FunctionExpression( |
| 5404 method.typeParameters, method.parameters, method.body)); |
| 5405 |
| 5406 /** |
| 5407 * Return `true` if the current token could be the start of a compilation unit |
| 5408 * member. This method is used for recovery purposes to decide when to stop |
| 5409 * skipping tokens after finding an error while parsing a compilation unit |
| 5410 * member. |
| 5411 */ |
| 5412 bool _couldBeStartOfCompilationUnitMember() { |
| 5413 Keyword keyword = _currentToken.keyword; |
| 5414 Token next = _currentToken.next; |
| 5415 TokenType nextType = next.type; |
| 5416 if ((keyword == Keyword.IMPORT || |
| 5417 keyword == Keyword.EXPORT || |
| 5418 keyword == Keyword.LIBRARY || |
| 5419 keyword == Keyword.PART) && |
| 5420 nextType != TokenType.PERIOD && |
| 5421 nextType != TokenType.LT) { |
| 5422 // This looks like the start of a directive |
| 5423 return true; |
| 5424 } else if (keyword == Keyword.CLASS) { |
| 5425 // This looks like the start of a class definition |
| 5426 return true; |
| 5427 } else if (keyword == Keyword.TYPEDEF && |
| 5428 nextType != TokenType.PERIOD && |
| 5429 nextType != TokenType.LT) { |
| 5430 // This looks like the start of a typedef |
| 5431 return true; |
| 5432 } else if (keyword == Keyword.VOID || |
| 5433 ((keyword == Keyword.GET || keyword == Keyword.SET) && |
| 5434 _tokenMatchesIdentifier(next)) || |
| 5435 (keyword == Keyword.OPERATOR && _isOperator(next))) { |
| 5436 // This looks like the start of a function |
| 5437 return true; |
| 5438 } else if (_matchesIdentifier()) { |
| 5439 if (nextType == TokenType.OPEN_PAREN) { |
| 5440 // This looks like the start of a function |
| 5441 return true; |
| 5442 } |
| 5443 Token token = skipReturnType(_currentToken); |
| 5444 if (token == null) { |
| 5445 return false; |
| 5446 } |
| 5447 // TODO(brianwilkerson) This looks wrong; should we be checking 'token'? |
| 5448 if (keyword == Keyword.GET || |
| 5449 keyword == Keyword.SET || |
| 5450 (keyword == Keyword.OPERATOR && _isOperator(next)) || |
| 5451 _matchesIdentifier()) { |
| 5452 return true; |
| 5453 } |
| 5454 } |
| 5455 return false; |
| 5456 } |
| 5457 |
| 5458 /** |
| 5459 * Return a synthetic token representing the given [keyword]. |
| 5460 */ |
| 5461 Token _createSyntheticKeyword(Keyword keyword) => _injectToken( |
| 5462 new Parser_SyntheticKeywordToken(keyword, _currentToken.offset)); |
| 5463 |
| 5464 /** |
| 5465 * Return a synthetic token with the given [type]. |
| 5466 */ |
| 5467 Token _createSyntheticToken(TokenType type) => |
| 5468 _injectToken(new StringToken(type, "", _currentToken.offset)); |
| 5469 |
| 5470 /** |
| 5471 * Create and return a new token with the given [type]. The token will replace |
| 5472 * the first portion of the given [token], so it will have the same offset and |
| 5473 * will have any comments that might have preceeded the token. |
| 5474 */ |
| 5475 Token _createToken(Token token, TokenType type, {bool isBegin: false}) { |
| 5476 CommentToken comments = token.precedingComments; |
| 5477 if (comments == null) { |
| 5478 if (isBegin) { |
| 5479 return new BeginToken(type, token.offset); |
| 5480 } |
| 5481 return new Token(type, token.offset); |
| 5482 } else if (isBegin) { |
| 5483 return new BeginTokenWithComment(type, token.offset, comments); |
| 5484 } |
| 5485 return new TokenWithComment(type, token.offset, comments); |
| 5486 } |
| 5487 |
| 5488 /** |
| 5489 * Check that the given [expression] is assignable and report an error if it |
| 5490 * isn't. |
| 5491 * |
| 5492 * assignableExpression ::= |
| 5493 * primary (arguments* assignableSelector)+ |
| 5494 * | 'super' unconditionalAssignableSelector |
| 5495 * | identifier |
| 5496 * |
| 5497 * unconditionalAssignableSelector ::= |
| 5498 * '[' expression ']' |
| 5499 * | '.' identifier |
| 5500 * |
| 5501 * assignableSelector ::= |
| 5502 * unconditionalAssignableSelector |
| 5503 * | '?.' identifier |
| 5504 */ |
| 5505 void _ensureAssignable(Expression expression) { |
| 5506 if (expression != null && !expression.isAssignable) { |
| 5507 _reportErrorForCurrentToken( |
| 5508 ParserErrorCode.ILLEGAL_ASSIGNMENT_TO_NON_ASSIGNABLE); |
| 5509 } |
| 5510 } |
| 5511 |
| 5512 /** |
| 5513 * If the current token has the expected type, return it after advancing to |
| 5514 * the next token. Otherwise report an error and return the current token |
| 5515 * without advancing. |
| 5516 * |
| 5517 * Note that the method [_expectGt] should be used if the argument to this |
| 5518 * method would be [TokenType.GT]. |
| 5519 * |
| 5520 * The [type] is the type of token that is expected. |
| 5521 */ |
| 5522 Token _expect(TokenType type) { |
| 5523 if (_matches(type)) { |
| 5524 return getAndAdvance(); |
| 5525 } |
| 5526 // Remove uses of this method in favor of matches? |
| 5527 // Pass in the error code to use to report the error? |
| 5528 if (type == TokenType.SEMICOLON) { |
| 5529 if (_tokenMatches(_currentToken.next, TokenType.SEMICOLON)) { |
| 5530 _reportErrorForCurrentToken( |
| 5531 ParserErrorCode.UNEXPECTED_TOKEN, [_currentToken.lexeme]); |
| 5532 _advance(); |
| 5533 return getAndAdvance(); |
| 5534 } |
| 5535 _reportErrorForToken(ParserErrorCode.EXPECTED_TOKEN, |
| 5536 _currentToken.previous, [type.lexeme]); |
| 5537 return _createSyntheticToken(TokenType.SEMICOLON); |
| 5538 } |
| 5539 _reportErrorForCurrentToken(ParserErrorCode.EXPECTED_TOKEN, [type.lexeme]); |
| 5540 return _createSyntheticToken(type); |
| 5541 } |
| 5542 |
| 5543 /** |
| 5544 * If the current token has the type [TokenType.GT], return it after advancing |
| 5545 * to the next token. Otherwise report an error and create a synthetic token. |
| 5546 */ |
| 5547 Token _expectGt() { |
| 5548 if (_matchesGt()) { |
| 5549 return getAndAdvance(); |
| 5550 } |
| 5551 _reportErrorForCurrentToken( |
| 5552 ParserErrorCode.EXPECTED_TOKEN, [TokenType.GT.lexeme]); |
| 5553 return _createSyntheticToken(TokenType.GT); |
| 5554 } |
| 5555 |
| 5556 /** |
| 5557 * If the current token is a keyword matching the given [keyword], return it |
| 5558 * after advancing to the next token. Otherwise report an error and return the |
| 5559 * current token without advancing. |
| 5560 */ |
| 5561 Token _expectKeyword(Keyword keyword) { |
| 5562 if (_matchesKeyword(keyword)) { |
| 5563 return getAndAdvance(); |
| 5564 } |
| 5565 // Remove uses of this method in favor of matches? |
| 5566 // Pass in the error code to use to report the error? |
| 5567 _reportErrorForCurrentToken( |
| 5568 ParserErrorCode.EXPECTED_TOKEN, [keyword.syntax]); |
| 5569 return _currentToken; |
| 5570 } |
| 5571 |
| 5572 /** |
| 5573 * Search the given list of [ranges] for a range that contains the given |
| 5574 * [index]. Return the range that was found, or `null` if none of the ranges |
| 5575 * contain the index. |
| 5576 */ |
| 5577 List<int> _findRange(List<List<int>> ranges, int index) { |
| 5578 int rangeCount = ranges.length; |
| 5579 for (int i = 0; i < rangeCount; i++) { |
| 5580 List<int> range = ranges[i]; |
| 5581 if (range[0] <= index && index <= range[1]) { |
| 5582 return range; |
| 5583 } else if (index < range[0]) { |
| 5584 return null; |
| 5585 } |
| 5586 } |
| 5587 return null; |
| 5588 } |
| 5589 |
| 5590 /** |
| 5591 * Return a list of the ranges of characters in the given [comment] that |
| 5592 * should be treated as code blocks. |
| 5593 */ |
| 5594 List<List<int>> _getCodeBlockRanges(String comment) { |
| 5595 List<List<int>> ranges = <List<int>>[]; |
| 5596 int length = comment.length; |
| 5597 if (length < 3) { |
| 5598 return ranges; |
| 5599 } |
| 5600 int index = 0; |
| 5601 int firstChar = comment.codeUnitAt(0); |
| 5602 if (firstChar == 0x2F) { |
| 5603 int secondChar = comment.codeUnitAt(1); |
| 5604 int thirdChar = comment.codeUnitAt(2); |
| 5605 if ((secondChar == 0x2A && thirdChar == 0x2A) || |
| 5606 (secondChar == 0x2F && thirdChar == 0x2F)) { |
| 5607 index = 3; |
| 5608 } |
| 5609 } |
| 5610 if (StringUtilities.startsWith4(comment, index, 0x20, 0x20, 0x20, 0x20)) { |
| 5611 int end = index + 4; |
| 5612 while (end < length && |
| 5613 comment.codeUnitAt(end) != 0xD && |
| 5614 comment.codeUnitAt(end) != 0xA) { |
| 5615 end = end + 1; |
| 5616 } |
| 5617 ranges.add(<int>[index, end]); |
| 5618 index = end; |
| 5619 } |
| 5620 while (index < length) { |
| 5621 int currentChar = comment.codeUnitAt(index); |
| 5622 if (currentChar == 0xD || currentChar == 0xA) { |
| 5623 index = index + 1; |
| 5624 while (index < length && |
| 5625 Character.isWhitespace(comment.codeUnitAt(index))) { |
| 5626 index = index + 1; |
| 5627 } |
| 5628 if (StringUtilities.startsWith6( |
| 5629 comment, index, 0x2A, 0x20, 0x20, 0x20, 0x20, 0x20)) { |
| 5630 int end = index + 6; |
| 5631 while (end < length && |
| 5632 comment.codeUnitAt(end) != 0xD && |
| 5633 comment.codeUnitAt(end) != 0xA) { |
| 5634 end = end + 1; |
| 5635 } |
| 5636 ranges.add(<int>[index, end]); |
| 5637 index = end; |
| 5638 } |
| 5639 } else if (index + 1 < length && |
| 5640 currentChar == 0x5B && |
| 5641 comment.codeUnitAt(index + 1) == 0x3A) { |
| 5642 int end = StringUtilities.indexOf2(comment, index + 2, 0x3A, 0x5D); |
| 5643 if (end < 0) { |
| 5644 end = length; |
| 5645 } |
| 5646 ranges.add(<int>[index, end]); |
| 5647 index = end + 1; |
| 5648 } else { |
| 5649 index = index + 1; |
| 5650 } |
| 5651 } |
| 5652 return ranges; |
| 5653 } |
| 5654 |
| 5655 /** |
| 5656 * Return the end token associated with the given [beginToken], or `null` if |
| 5657 * either the given token is not a begin token or it does not have an end |
| 5658 * token associated with it. |
| 5659 */ |
| 5660 Token _getEndToken(Token beginToken) { |
| 5661 if (beginToken is BeginToken) { |
| 5662 return beginToken.endToken; |
| 5663 } |
| 5664 return null; |
| 5665 } |
| 5666 |
| 5667 bool _injectGenericComment(TokenType type, int prefixLen) { |
| 5668 if (parseGenericMethodComments) { |
| 5669 CommentToken t = _currentToken.precedingComments; |
| 5670 for (; t != null; t = t.next) { |
| 5671 if (t.type == type) { |
| 5672 String comment = t.lexeme.substring(prefixLen, t.lexeme.length - 2); |
| 5673 Token list = _scanGenericMethodComment(comment, t.offset + prefixLen); |
| 5674 if (list != null) { |
| 5675 // Remove the token from the comment stream. |
| 5676 t.remove(); |
| 5677 // Insert the tokens into the stream. |
| 5678 _injectTokenList(list); |
| 5679 return true; |
| 5680 } |
| 5681 } |
| 5682 } |
| 5683 } |
| 5684 return false; |
| 5685 } |
| 5686 |
| 5687 /** |
| 5688 * Matches a generic comment type substitution and injects it into the token |
| 5689 * stream. Returns true if a match was injected, otherwise false. |
| 5690 * |
| 5691 * These comments are of the form `/*=T*/`, in other words, a [TypeName] |
| 5692 * inside a slash-star comment, preceded by equals sign. |
| 5693 */ |
| 5694 bool _injectGenericCommentTypeAssign() { |
| 5695 return _injectGenericComment(TokenType.GENERIC_METHOD_TYPE_ASSIGN, 3); |
| 5696 } |
| 5697 |
| 5698 /** |
| 5699 * Matches a generic comment type parameters and injects them into the token |
| 5700 * stream. Returns true if a match was injected, otherwise false. |
| 5701 * |
| 5702 * These comments are of the form `/*<K, V>*/`, in other words, a |
| 5703 * [TypeParameterList] or [TypeArgumentList] inside a slash-star comment. |
| 5704 */ |
| 5705 bool _injectGenericCommentTypeList() { |
| 5706 return _injectGenericComment(TokenType.GENERIC_METHOD_TYPE_LIST, 2); |
| 5707 } |
| 5708 |
| 5709 /** |
| 5710 * Inject the given [token] into the token stream immediately before the |
| 5711 * current token. |
| 5712 */ |
| 5713 Token _injectToken(Token token) { |
| 5714 Token previous = _currentToken.previous; |
| 5715 token.setNext(_currentToken); |
| 5716 previous.setNext(token); |
| 5717 return token; |
| 5718 } |
| 5719 |
| 5720 void _injectTokenList(Token firstToken) { |
| 5721 // Scanner creates a cyclic EOF token. |
| 5722 Token lastToken = firstToken; |
| 5723 while (lastToken.next.type != TokenType.EOF) { |
| 5724 lastToken = lastToken.next; |
| 5725 } |
| 5726 // Inject these new tokens into the stream. |
| 5727 Token previous = _currentToken.previous; |
| 5728 lastToken.setNext(_currentToken); |
| 5729 previous.setNext(firstToken); |
| 5730 _currentToken = firstToken; |
| 5731 } |
| 5732 |
| 5733 /** |
| 5734 * Return `true` if the current token could be the question mark in a |
| 5735 * condition expression. The current token is assumed to be a question mark. |
| 5736 */ |
| 5737 bool _isConditionalOperator() { |
| 5738 void parseOperation(Parser parser) { |
| 5739 parser.parseExpressionWithoutCascade(); |
| 5740 } |
| 5741 |
| 5742 Token token = _skip(_currentToken.next, parseOperation); |
| 5743 if (token == null || !_tokenMatches(token, TokenType.COLON)) { |
| 5744 return false; |
| 5745 } |
| 5746 token = _skip(token.next, parseOperation); |
| 5747 return token != null; |
| 5748 } |
| 5749 |
| 5750 /** |
| 5751 * Return `true` if the given [character] is a valid hexadecimal digit. |
| 5752 */ |
| 5753 bool _isHexDigit(int character) => |
| 5754 (0x30 <= character && character <= 0x39) || |
| 5755 (0x41 <= character && character <= 0x46) || |
| 5756 (0x61 <= character && character <= 0x66); |
| 5757 |
| 5758 bool _isLikelyArgumentList() { |
| 5759 // Try to reduce the amount of lookahead required here before enabling |
| 5760 // generic methods. |
| 5761 if (_matches(TokenType.OPEN_PAREN)) { |
| 5762 return true; |
| 5763 } |
| 5764 if (!parseGenericMethods) { |
| 5765 return false; |
| 5766 } |
| 5767 Token token = skipTypeArgumentList(_currentToken); |
| 5768 return token != null && _tokenMatches(token, TokenType.OPEN_PAREN); |
| 5769 } |
| 5770 |
| 5771 /** |
| 5772 * Given that we have just found bracketed text within the given [comment], |
| 5773 * look to see whether that text is (a) followed by a parenthesized link |
| 5774 * address, (b) followed by a colon, or (c) followed by optional whitespace |
| 5775 * and another square bracket. The [rightIndex] is the index of the right |
| 5776 * bracket. Return `true` if the bracketed text is followed by a link address. |
| 5777 * |
| 5778 * This method uses the syntax described by the |
| 5779 * <a href="http://daringfireball.net/projects/markdown/syntax">markdown</a> |
| 5780 * project. |
| 5781 */ |
| 5782 bool _isLinkText(String comment, int rightIndex) { |
| 5783 int length = comment.length; |
| 5784 int index = rightIndex + 1; |
| 5785 if (index >= length) { |
| 5786 return false; |
| 5787 } |
| 5788 int nextChar = comment.codeUnitAt(index); |
| 5789 if (nextChar == 0x28 || nextChar == 0x3A) { |
| 5790 return true; |
| 5791 } |
| 5792 while (Character.isWhitespace(nextChar)) { |
| 5793 index = index + 1; |
| 5794 if (index >= length) { |
| 5795 return false; |
| 5796 } |
| 5797 nextChar = comment.codeUnitAt(index); |
| 5798 } |
| 5799 return nextChar == 0x5B; |
| 5800 } |
| 5801 |
| 5802 /** |
| 5803 * Return `true` if the given [startToken] appears to be the beginning of an |
| 5804 * operator declaration. |
| 5805 */ |
| 5806 bool _isOperator(Token startToken) { |
| 5807 // Accept any operator here, even if it is not user definable. |
| 5808 if (!startToken.isOperator) { |
| 5809 return false; |
| 5810 } |
| 5811 // Token "=" means that it is actually a field initializer. |
| 5812 if (startToken.type == TokenType.EQ) { |
| 5813 return false; |
| 5814 } |
| 5815 // Consume all operator tokens. |
| 5816 Token token = startToken.next; |
| 5817 while (token.isOperator) { |
| 5818 token = token.next; |
| 5819 } |
| 5820 // Formal parameter list is expect now. |
| 5821 return _tokenMatches(token, TokenType.OPEN_PAREN); |
| 5822 } |
| 5823 |
| 5824 bool _isPeekGenericTypeParametersAndOpenParen() { |
| 5825 if (!parseGenericMethods) { |
| 5826 return false; |
| 5827 } |
| 5828 Token token = _skipTypeParameterList(_peek()); |
| 5829 return token != null && _tokenMatches(token, TokenType.OPEN_PAREN); |
| 5830 } |
| 5831 |
| 5832 /** |
| 5833 * Return `true` if the [startToken] appears to be the first token of a type |
| 5834 * name that is followed by a variable or field formal parameter. |
| 5835 */ |
| 5836 bool _isTypedIdentifier(Token startToken) { |
| 5837 Token token = skipReturnType(startToken); |
| 5838 if (token == null) { |
| 5839 return false; |
| 5840 } else if (_tokenMatchesIdentifier(token)) { |
| 5841 return true; |
| 5842 } else if (_tokenMatchesKeyword(token, Keyword.THIS) && |
| 5843 _tokenMatches(token.next, TokenType.PERIOD) && |
| 5844 _tokenMatchesIdentifier(token.next.next)) { |
| 5845 return true; |
| 5846 } else if (_tokenMatchesKeyword(startToken, Keyword.VOID)) { |
| 5847 // The keyword 'void' isn't a valid identifier, so it should be assumed to |
| 5848 // be a type name. |
| 5849 return true; |
| 5850 } else if (startToken.next != token && |
| 5851 !_tokenMatches(token, TokenType.OPEN_PAREN)) { |
| 5852 // The type is more than a simple identifier, so it should be assumed to |
| 5853 // be a type name. |
| 5854 return true; |
| 5855 } |
| 5856 return false; |
| 5857 } |
| 5858 |
| 5859 /** |
| 5860 * Increments the error reporting lock level. If level is more than `0`, then |
| 5861 * [reportError] wont report any error. |
| 5862 */ |
| 5863 void _lockErrorListener() { |
| 5864 _errorListenerLock++; |
| 5865 } |
| 5866 |
| 5867 /** |
| 5868 * Return `true` if the current token has the given [type]. Note that the |
| 5869 * method [_matchesGt] should be used if the argument to this method would be |
| 5870 * [TokenType.GT]. |
| 5871 */ |
| 5872 bool _matches(TokenType type) => _currentToken.type == type; |
| 5873 |
| 5874 /** |
| 5875 * Return `true` if the current token has a type of [TokenType.GT]. Note that |
| 5876 * this method, unlike other variants, will modify the token stream if |
| 5877 * possible to match desired type. In particular, if the next token is either |
| 5878 * a '>>' or '>>>', the token stream will be re-written and `true` will be |
| 5879 * returned. |
| 5880 */ |
| 5881 bool _matchesGt() { |
| 5882 TokenType currentType = _currentToken.type; |
| 5883 if (currentType == TokenType.GT) { |
| 5884 return true; |
| 5885 } else if (currentType == TokenType.GT_GT) { |
| 5886 Token first = _createToken(_currentToken, TokenType.GT); |
| 5887 Token second = new Token(TokenType.GT, _currentToken.offset + 1); |
| 5888 second.setNext(_currentToken.next); |
| 5889 first.setNext(second); |
| 5890 _currentToken.previous.setNext(first); |
| 5891 _currentToken = first; |
| 5892 return true; |
| 5893 } else if (currentType == TokenType.GT_EQ) { |
| 5894 Token first = _createToken(_currentToken, TokenType.GT); |
| 5895 Token second = new Token(TokenType.EQ, _currentToken.offset + 1); |
| 5896 second.setNext(_currentToken.next); |
| 5897 first.setNext(second); |
| 5898 _currentToken.previous.setNext(first); |
| 5899 _currentToken = first; |
| 5900 return true; |
| 5901 } else if (currentType == TokenType.GT_GT_EQ) { |
| 5902 int offset = _currentToken.offset; |
| 5903 Token first = _createToken(_currentToken, TokenType.GT); |
| 5904 Token second = new Token(TokenType.GT, offset + 1); |
| 5905 Token third = new Token(TokenType.EQ, offset + 2); |
| 5906 third.setNext(_currentToken.next); |
| 5907 second.setNext(third); |
| 5908 first.setNext(second); |
| 5909 _currentToken.previous.setNext(first); |
| 5910 _currentToken = first; |
| 5911 return true; |
| 5912 } |
| 5913 return false; |
| 5914 } |
| 5915 |
| 5916 /** |
| 5917 * Return `true` if the current token is a valid identifier. Valid identifiers |
| 5918 * include built-in identifiers (pseudo-keywords). |
| 5919 */ |
| 5920 bool _matchesIdentifier() => _tokenMatchesIdentifier(_currentToken); |
| 5921 |
| 5922 /** |
| 5923 * Return `true` if the current token matches the given [keyword]. |
| 5924 */ |
| 5925 bool _matchesKeyword(Keyword keyword) => |
| 5926 _tokenMatchesKeyword(_currentToken, keyword); |
| 5927 |
| 5928 /** |
| 5929 * Return `true` if the current token matches the given [identifier]. |
| 5930 */ |
| 5931 bool _matchesString(String identifier) => |
| 5932 _currentToken.type == TokenType.IDENTIFIER && |
| 5933 _currentToken.lexeme == identifier; |
| 5934 |
| 5935 /** |
| 5936 * Report an error with the given [errorCode] if the given [typeName] has been |
| 5937 * marked as nullable. |
| 5938 */ |
| 5939 void _mustNotBeNullable(TypeName typeName, ParserErrorCode errorCode) { |
| 5940 if (typeName.question != null) { |
| 5941 _reportErrorForToken(errorCode, typeName.question); |
| 5942 } |
| 5943 } |
| 5944 |
| 5945 /** |
| 5946 * If the current token has the given [type], then advance to the next token |
| 5947 * and return `true`. Otherwise, return `false` without advancing. This method |
| 5948 * should not be invoked with an argument value of [TokenType.GT]. |
| 5949 */ |
| 5950 bool _optional(TokenType type) { |
| 5951 if (_currentToken.type == type) { |
| 5952 _advance(); |
| 5953 return true; |
| 5954 } |
| 5955 return false; |
| 5956 } |
| 5957 |
| 5958 /** |
| 5959 * Parse an argument list when we need to check for an open paren and recover |
| 5960 * when there isn't one. Return the argument list that was parsed. |
| 5961 */ |
| 5962 ArgumentList _parseArgumentListChecked() { |
| 5963 if (_matches(TokenType.OPEN_PAREN)) { |
| 5964 return parseArgumentList(); |
| 5965 } |
| 5966 _reportErrorForCurrentToken( |
| 5967 ParserErrorCode.EXPECTED_TOKEN, [TokenType.OPEN_PAREN.lexeme]); |
| 5968 // Recovery: Look to see whether there is a close paren that isn't matched |
| 5969 // to an open paren and if so parse the list of arguments as normal. |
| 5970 return new ArgumentList(_createSyntheticToken(TokenType.OPEN_PAREN), null, |
| 5971 _createSyntheticToken(TokenType.CLOSE_PAREN)); |
| 5972 } |
| 5973 |
| 5974 /** |
| 5975 * Parse an assert within a constructor's initializer list. Return the assert. |
| 5976 * |
| 5977 * This method assumes that the current token matches `Keyword.ASSERT`. |
| 5978 * |
| 5979 * assertInitializer ::= |
| 5980 * 'assert' '(' expression [',' expression] ')' |
| 5981 */ |
| 5982 void _parseAssertInitializer() { |
| 5983 // TODO(brianwilkerson) Capture the syntax in the AST using a new class, |
| 5984 // such as AssertInitializer |
| 5985 Token keyword = getAndAdvance(); |
| 5986 Token leftParen = _expect(TokenType.OPEN_PAREN); |
| 5987 Expression expression = parseExpression2(); |
| 5988 Token comma; |
| 5989 Expression message; |
| 5990 if (_matches(TokenType.COMMA)) { |
| 5991 comma = getAndAdvance(); |
| 5992 message = parseExpression2(); |
| 5993 } |
| 5994 Token rightParen = _expect(TokenType.CLOSE_PAREN); |
| 5995 // return new AssertInitializer( |
| 5996 // keyword, leftParen, expression, comma, message, rightParen); |
| 5997 } |
| 5998 |
| 5999 /** |
| 6000 * Parse an assignable expression given that the current token is not 'super'. |
| 6001 * The [primaryAllowed] is `true` if the expression is allowed to be a primary |
| 6002 * without any assignable selector. Return the assignable expression that was |
| 6003 * parsed. |
| 6004 */ |
| 6005 Expression _parseAssignableExpressionNotStartingWithSuper( |
| 6006 bool primaryAllowed) { |
| 6007 // |
| 6008 // A primary expression can start with an identifier. We resolve the |
| 6009 // ambiguity by determining whether the primary consists of anything other |
| 6010 // than an identifier and/or is followed by an assignableSelector. |
| 6011 // |
| 6012 Expression expression = parsePrimaryExpression(); |
| 6013 bool isOptional = primaryAllowed || expression is SimpleIdentifier; |
| 6014 while (true) { |
| 6015 while (_isLikelyArgumentList()) { |
| 6016 TypeArgumentList typeArguments = _parseOptionalTypeArguments(); |
| 6017 ArgumentList argumentList = parseArgumentList(); |
| 6018 Expression currentExpression = expression; |
| 6019 if (currentExpression is SimpleIdentifier) { |
| 6020 expression = new MethodInvocation( |
| 6021 null, null, currentExpression, typeArguments, argumentList); |
| 6022 } else if (currentExpression is PrefixedIdentifier) { |
| 6023 expression = new MethodInvocation( |
| 6024 currentExpression.prefix, |
| 6025 currentExpression.period, |
| 6026 currentExpression.identifier, |
| 6027 typeArguments, |
| 6028 argumentList); |
| 6029 } else if (currentExpression is PropertyAccess) { |
| 6030 expression = new MethodInvocation( |
| 6031 currentExpression.target, |
| 6032 currentExpression.operator, |
| 6033 currentExpression.propertyName, |
| 6034 typeArguments, |
| 6035 argumentList); |
| 6036 } else { |
| 6037 expression = new FunctionExpressionInvocation( |
| 6038 expression, typeArguments, argumentList); |
| 6039 } |
| 6040 if (!primaryAllowed) { |
| 6041 isOptional = false; |
| 6042 } |
| 6043 } |
| 6044 Expression selectorExpression = parseAssignableSelector( |
| 6045 expression, isOptional || (expression is PrefixedIdentifier)); |
| 6046 if (identical(selectorExpression, expression)) { |
| 6047 if (!isOptional && (expression is PrefixedIdentifier)) { |
| 6048 PrefixedIdentifier identifier = expression as PrefixedIdentifier; |
| 6049 expression = new PropertyAccess( |
| 6050 identifier.prefix, identifier.period, identifier.identifier); |
| 6051 } |
| 6052 return expression; |
| 6053 } |
| 6054 expression = selectorExpression; |
| 6055 isOptional = true; |
| 6056 } |
| 6057 } |
| 6058 |
| 6059 /** |
| 6060 * Parse a block when we need to check for an open curly brace and recover |
| 6061 * when there isn't one. Return the block that was parsed. |
| 6062 * |
| 6063 * block ::= |
| 6064 * '{' statements '}' |
| 6065 */ |
| 6066 Block _parseBlockChecked() { |
| 6067 if (_matches(TokenType.OPEN_CURLY_BRACKET)) { |
| 6068 return parseBlock(); |
| 6069 } |
| 6070 // TODO(brianwilkerson) Improve the error message. |
| 6071 _reportErrorForCurrentToken( |
| 6072 ParserErrorCode.EXPECTED_TOKEN, [TokenType.OPEN_CURLY_BRACKET.lexeme]); |
| 6073 // Recovery: Check for an unmatched closing curly bracket and parse |
| 6074 // statements until it is reached. |
| 6075 return new Block(_createSyntheticToken(TokenType.OPEN_CURLY_BRACKET), null, |
| 6076 _createSyntheticToken(TokenType.CLOSE_CURLY_BRACKET)); |
| 6077 } |
| 6078 |
| 6079 /** |
| 6080 * Parse a list of class members. The [className] is the name of the class |
| 6081 * whose members are being parsed. The [closingBracket] is the closing bracket |
| 6082 * for the class, or `null` if the closing bracket is missing. Return the list |
| 6083 * of class members that were parsed. |
| 6084 * |
| 6085 * classMembers ::= |
| 6086 * (metadata memberDefinition)* |
| 6087 */ |
| 6088 List<ClassMember> _parseClassMembers(String className, Token closingBracket) { |
| 6089 List<ClassMember> members = <ClassMember>[]; |
| 6090 Token memberStart = _currentToken; |
| 6091 TokenType type = _currentToken.type; |
| 6092 Keyword keyword = _currentToken.keyword; |
| 6093 while (type != TokenType.EOF && |
| 6094 type != TokenType.CLOSE_CURLY_BRACKET && |
| 6095 (closingBracket != null || |
| 6096 (keyword != Keyword.CLASS && keyword != Keyword.TYPEDEF))) { |
| 6097 if (type == TokenType.SEMICOLON) { |
| 6098 _reportErrorForToken(ParserErrorCode.UNEXPECTED_TOKEN, _currentToken, |
| 6099 [_currentToken.lexeme]); |
| 6100 _advance(); |
| 6101 } else { |
| 6102 ClassMember member = parseClassMember(className); |
| 6103 if (member != null) { |
| 6104 members.add(member); |
| 6105 } |
| 6106 } |
| 6107 if (identical(_currentToken, memberStart)) { |
| 6108 _reportErrorForToken(ParserErrorCode.UNEXPECTED_TOKEN, _currentToken, |
| 6109 [_currentToken.lexeme]); |
| 6110 _advance(); |
| 6111 } |
| 6112 memberStart = _currentToken; |
| 6113 type = _currentToken.type; |
| 6114 keyword = _currentToken.keyword; |
| 6115 } |
| 6116 return members; |
| 6117 } |
| 6118 |
| 6119 /** |
| 6120 * Parse a class type alias. The [commentAndMetadata] is the metadata to be |
| 6121 * associated with the member. The [abstractKeyword] is the token representing |
| 6122 * the 'abstract' keyword. The [classKeyword] is the token representing the |
| 6123 * 'class' keyword. The [className] is the name of the alias, and the |
| 6124 * [typeParameters] are the type parameters following the name. Return the |
| 6125 * class type alias that was parsed. |
| 6126 * |
| 6127 * classTypeAlias ::= |
| 6128 * identifier typeParameters? '=' 'abstract'? mixinApplication |
| 6129 * |
| 6130 * mixinApplication ::= |
| 6131 * type withClause implementsClause? ';' |
| 6132 */ |
| 6133 ClassTypeAlias _parseClassTypeAliasAfterName( |
| 6134 CommentAndMetadata commentAndMetadata, |
| 6135 Token abstractKeyword, |
| 6136 Token classKeyword, |
| 6137 SimpleIdentifier className, |
| 6138 TypeParameterList typeParameters) { |
| 6139 Token equals = _expect(TokenType.EQ); |
| 6140 TypeName superclass = parseTypeName(false); |
| 6141 WithClause withClause = null; |
| 6142 if (_matchesKeyword(Keyword.WITH)) { |
| 6143 withClause = parseWithClause(); |
| 6144 } else { |
| 6145 _reportErrorForCurrentToken( |
| 6146 ParserErrorCode.EXPECTED_TOKEN, [Keyword.WITH.syntax]); |
| 6147 } |
| 6148 ImplementsClause implementsClause = null; |
| 6149 if (_matchesKeyword(Keyword.IMPLEMENTS)) { |
| 6150 implementsClause = parseImplementsClause(); |
| 6151 } |
| 6152 Token semicolon; |
| 6153 if (_matches(TokenType.SEMICOLON)) { |
| 6154 semicolon = getAndAdvance(); |
| 6155 } else { |
| 6156 if (_matches(TokenType.OPEN_CURLY_BRACKET)) { |
| 6157 _reportErrorForCurrentToken( |
| 6158 ParserErrorCode.EXPECTED_TOKEN, [TokenType.SEMICOLON.lexeme]); |
| 6159 Token leftBracket = getAndAdvance(); |
| 6160 _parseClassMembers(className.name, _getEndToken(leftBracket)); |
| 6161 _expect(TokenType.CLOSE_CURLY_BRACKET); |
| 6162 } else { |
| 6163 _reportErrorForToken(ParserErrorCode.EXPECTED_TOKEN, |
| 6164 _currentToken.previous, [TokenType.SEMICOLON.lexeme]); |
| 6165 } |
| 6166 semicolon = _createSyntheticToken(TokenType.SEMICOLON); |
| 6167 } |
| 6168 return new ClassTypeAlias( |
| 6169 commentAndMetadata.comment, |
| 6170 commentAndMetadata.metadata, |
| 6171 classKeyword, |
| 6172 className, |
| 6173 typeParameters, |
| 6174 equals, |
| 6175 abstractKeyword, |
| 6176 superclass, |
| 6177 withClause, |
| 6178 implementsClause, |
| 6179 semicolon); |
| 6180 } |
| 6181 |
| 6182 /** |
| 6183 * Parse a list of configurations. Return the configurations that were parsed, |
| 6184 * or `null` if there are no configurations. |
| 6185 */ |
| 6186 List<Configuration> _parseConfigurations() { |
| 6187 List<Configuration> configurations = null; |
| 6188 while (_matchesKeyword(Keyword.IF)) { |
| 6189 configurations ??= <Configuration>[]; |
| 6190 configurations.add(parseConfiguration()); |
| 6191 } |
| 6192 return configurations; |
| 6193 } |
| 6194 |
| 6195 ConstructorDeclaration _parseConstructor( |
| 6196 CommentAndMetadata commentAndMetadata, |
| 6197 Token externalKeyword, |
| 6198 Token constKeyword, |
| 6199 Token factoryKeyword, |
| 6200 SimpleIdentifier returnType, |
| 6201 Token period, |
| 6202 SimpleIdentifier name, |
| 6203 FormalParameterList parameters) { |
| 6204 bool bodyAllowed = externalKeyword == null; |
| 6205 Token separator = null; |
| 6206 List<ConstructorInitializer> initializers = null; |
| 6207 if (_matches(TokenType.COLON)) { |
| 6208 separator = getAndAdvance(); |
| 6209 initializers = <ConstructorInitializer>[]; |
| 6210 do { |
| 6211 Keyword keyword = _currentToken.keyword; |
| 6212 if (keyword == Keyword.THIS) { |
| 6213 TokenType nextType = _peek().type; |
| 6214 if (nextType == TokenType.OPEN_PAREN) { |
| 6215 bodyAllowed = false; |
| 6216 initializers.add(parseRedirectingConstructorInvocation(false)); |
| 6217 } else if (nextType == TokenType.PERIOD && |
| 6218 _tokenMatches(_peekAt(3), TokenType.OPEN_PAREN)) { |
| 6219 bodyAllowed = false; |
| 6220 initializers.add(parseRedirectingConstructorInvocation(true)); |
| 6221 } else { |
| 6222 initializers.add(parseConstructorFieldInitializer(true)); |
| 6223 } |
| 6224 } else if (keyword == Keyword.SUPER) { |
| 6225 initializers.add(parseSuperConstructorInvocation()); |
| 6226 } else if (_matches(TokenType.OPEN_CURLY_BRACKET) || |
| 6227 _matches(TokenType.FUNCTION)) { |
| 6228 _reportErrorForCurrentToken(ParserErrorCode.MISSING_INITIALIZER); |
| 6229 } else if (_enableAssertInitializer && |
| 6230 _matchesKeyword(Keyword.ASSERT)) { |
| 6231 _parseAssertInitializer(); |
| 6232 } else { |
| 6233 initializers.add(parseConstructorFieldInitializer(false)); |
| 6234 } |
| 6235 } while (_optional(TokenType.COMMA)); |
| 6236 if (factoryKeyword != null) { |
| 6237 _reportErrorForToken( |
| 6238 ParserErrorCode.FACTORY_WITH_INITIALIZERS, factoryKeyword); |
| 6239 } |
| 6240 } |
| 6241 ConstructorName redirectedConstructor = null; |
| 6242 FunctionBody body; |
| 6243 if (_matches(TokenType.EQ)) { |
| 6244 separator = getAndAdvance(); |
| 6245 redirectedConstructor = parseConstructorName(); |
| 6246 body = new EmptyFunctionBody(_expect(TokenType.SEMICOLON)); |
| 6247 if (factoryKeyword == null) { |
| 6248 _reportErrorForNode( |
| 6249 ParserErrorCode.REDIRECTION_IN_NON_FACTORY_CONSTRUCTOR, |
| 6250 redirectedConstructor); |
| 6251 } |
| 6252 } else { |
| 6253 body = |
| 6254 parseFunctionBody(true, ParserErrorCode.MISSING_FUNCTION_BODY, false); |
| 6255 if (constKeyword != null && |
| 6256 factoryKeyword != null && |
| 6257 externalKeyword == null) { |
| 6258 _reportErrorForToken(ParserErrorCode.CONST_FACTORY, factoryKeyword); |
| 6259 } else if (body is EmptyFunctionBody) { |
| 6260 if (factoryKeyword != null && |
| 6261 externalKeyword == null && |
| 6262 _parseFunctionBodies) { |
| 6263 _reportErrorForToken( |
| 6264 ParserErrorCode.FACTORY_WITHOUT_BODY, factoryKeyword); |
| 6265 } |
| 6266 } else { |
| 6267 if (constKeyword != null) { |
| 6268 _reportErrorForNode( |
| 6269 ParserErrorCode.CONST_CONSTRUCTOR_WITH_BODY, body); |
| 6270 } else if (externalKeyword != null) { |
| 6271 _reportErrorForNode( |
| 6272 ParserErrorCode.EXTERNAL_CONSTRUCTOR_WITH_BODY, body); |
| 6273 } else if (!bodyAllowed) { |
| 6274 _reportErrorForNode( |
| 6275 ParserErrorCode.REDIRECTING_CONSTRUCTOR_WITH_BODY, body); |
| 6276 } |
| 6277 } |
| 6278 } |
| 6279 return new ConstructorDeclaration( |
| 6280 commentAndMetadata.comment, |
| 6281 commentAndMetadata.metadata, |
| 6282 externalKeyword, |
| 6283 constKeyword, |
| 6284 factoryKeyword, |
| 6285 returnType, |
| 6286 period, |
| 6287 name, |
| 6288 parameters, |
| 6289 separator, |
| 6290 initializers, |
| 6291 redirectedConstructor, |
| 6292 body); |
| 6293 } |
| 6294 |
| 6295 /** |
| 6296 * Parse an enum constant declaration. Return the enum constant declaration |
| 6297 * that was parsed. |
| 6298 * |
| 6299 * Specified: |
| 6300 * |
| 6301 * enumConstant ::= |
| 6302 * id |
| 6303 * |
| 6304 * Actual: |
| 6305 * |
| 6306 * enumConstant ::= |
| 6307 * metadata id |
| 6308 */ |
| 6309 EnumConstantDeclaration _parseEnumConstantDeclaration() { |
| 6310 CommentAndMetadata commentAndMetadata = parseCommentAndMetadata(); |
| 6311 SimpleIdentifier name; |
| 6312 if (_matchesIdentifier()) { |
| 6313 name = _parseSimpleIdentifierUnchecked(isDeclaration: true); |
| 6314 } else { |
| 6315 name = createSyntheticIdentifier(); |
| 6316 } |
| 6317 if (commentAndMetadata.hasMetadata) { |
| 6318 _reportErrorForNode(ParserErrorCode.ANNOTATION_ON_ENUM_CONSTANT, |
| 6319 commentAndMetadata.metadata[0]); |
| 6320 } |
| 6321 return new EnumConstantDeclaration( |
| 6322 commentAndMetadata.comment, commentAndMetadata.metadata, name); |
| 6323 } |
| 6324 |
| 6325 /** |
| 6326 * Parse a list of formal parameters given that the list starts with the given |
| 6327 * [leftParenthesis]. Return the formal parameters that were parsed. |
| 6328 */ |
| 6329 FormalParameterList _parseFormalParameterListAfterParen( |
| 6330 Token leftParenthesis) { |
| 6331 if (_matches(TokenType.CLOSE_PAREN)) { |
| 6332 return new FormalParameterList( |
| 6333 leftParenthesis, null, null, null, getAndAdvance()); |
| 6334 } |
| 6335 // |
| 6336 // Even though it is invalid to have default parameters outside of brackets, |
| 6337 // required parameters inside of brackets, or multiple groups of default and |
| 6338 // named parameters, we allow all of these cases so that we can recover |
| 6339 // better. |
| 6340 // |
| 6341 List<FormalParameter> parameters = <FormalParameter>[]; |
| 6342 Token leftSquareBracket = null; |
| 6343 Token rightSquareBracket = null; |
| 6344 Token leftCurlyBracket = null; |
| 6345 Token rightCurlyBracket = null; |
| 6346 ParameterKind kind = ParameterKind.REQUIRED; |
| 6347 bool firstParameter = true; |
| 6348 bool reportedMultiplePositionalGroups = false; |
| 6349 bool reportedMultipleNamedGroups = false; |
| 6350 bool reportedMixedGroups = false; |
| 6351 bool wasOptionalParameter = false; |
| 6352 Token initialToken = null; |
| 6353 do { |
| 6354 if (firstParameter) { |
| 6355 firstParameter = false; |
| 6356 } else if (!_optional(TokenType.COMMA)) { |
| 6357 // TODO(brianwilkerson) The token is wrong, we need to recover from this |
| 6358 // case. |
| 6359 if (_getEndToken(leftParenthesis) != null) { |
| 6360 _reportErrorForCurrentToken( |
| 6361 ParserErrorCode.EXPECTED_TOKEN, [TokenType.COMMA.lexeme]); |
| 6362 } else { |
| 6363 _reportErrorForToken(ParserErrorCode.MISSING_CLOSING_PARENTHESIS, |
| 6364 _currentToken.previous); |
| 6365 break; |
| 6366 } |
| 6367 } |
| 6368 initialToken = _currentToken; |
| 6369 // |
| 6370 // Handle the beginning of parameter groups. |
| 6371 // |
| 6372 TokenType type = _currentToken.type; |
| 6373 if (type == TokenType.OPEN_SQUARE_BRACKET) { |
| 6374 wasOptionalParameter = true; |
| 6375 if (leftSquareBracket != null && !reportedMultiplePositionalGroups) { |
| 6376 _reportErrorForCurrentToken( |
| 6377 ParserErrorCode.MULTIPLE_POSITIONAL_PARAMETER_GROUPS); |
| 6378 reportedMultiplePositionalGroups = true; |
| 6379 } |
| 6380 if (leftCurlyBracket != null && !reportedMixedGroups) { |
| 6381 _reportErrorForCurrentToken(ParserErrorCode.MIXED_PARAMETER_GROUPS); |
| 6382 reportedMixedGroups = true; |
| 6383 } |
| 6384 leftSquareBracket = getAndAdvance(); |
| 6385 kind = ParameterKind.POSITIONAL; |
| 6386 } else if (type == TokenType.OPEN_CURLY_BRACKET) { |
| 6387 wasOptionalParameter = true; |
| 6388 if (leftCurlyBracket != null && !reportedMultipleNamedGroups) { |
| 6389 _reportErrorForCurrentToken( |
| 6390 ParserErrorCode.MULTIPLE_NAMED_PARAMETER_GROUPS); |
| 6391 reportedMultipleNamedGroups = true; |
| 6392 } |
| 6393 if (leftSquareBracket != null && !reportedMixedGroups) { |
| 6394 _reportErrorForCurrentToken(ParserErrorCode.MIXED_PARAMETER_GROUPS); |
| 6395 reportedMixedGroups = true; |
| 6396 } |
| 6397 leftCurlyBracket = getAndAdvance(); |
| 6398 kind = ParameterKind.NAMED; |
| 6399 } |
| 6400 // |
| 6401 // Parse and record the parameter. |
| 6402 // |
| 6403 FormalParameter parameter = parseFormalParameter(kind); |
| 6404 parameters.add(parameter); |
| 6405 if (kind == ParameterKind.REQUIRED && wasOptionalParameter) { |
| 6406 _reportErrorForNode( |
| 6407 ParserErrorCode.NORMAL_BEFORE_OPTIONAL_PARAMETERS, parameter); |
| 6408 } |
| 6409 // |
| 6410 // Handle the end of parameter groups. |
| 6411 // |
| 6412 // TODO(brianwilkerson) Improve the detection and reporting of missing and |
| 6413 // mismatched delimiters. |
| 6414 type = _currentToken.type; |
| 6415 |
| 6416 // Advance past trailing commas as appropriate. |
| 6417 if (type == TokenType.COMMA) { |
| 6418 // Only parse commas trailing normal (non-positional/named) params. |
| 6419 if (rightSquareBracket == null && rightCurlyBracket == null) { |
| 6420 Token next = _peek(); |
| 6421 if (next.type == TokenType.CLOSE_PAREN || |
| 6422 next.type == TokenType.CLOSE_CURLY_BRACKET || |
| 6423 next.type == TokenType.CLOSE_SQUARE_BRACKET) { |
| 6424 _advance(); |
| 6425 type = _currentToken.type; |
| 6426 } |
| 6427 } |
| 6428 } |
| 6429 |
| 6430 if (type == TokenType.CLOSE_SQUARE_BRACKET) { |
| 6431 rightSquareBracket = getAndAdvance(); |
| 6432 if (leftSquareBracket == null) { |
| 6433 if (leftCurlyBracket != null) { |
| 6434 _reportErrorForCurrentToken( |
| 6435 ParserErrorCode.WRONG_TERMINATOR_FOR_PARAMETER_GROUP, ["}"]); |
| 6436 rightCurlyBracket = rightSquareBracket; |
| 6437 rightSquareBracket = null; |
| 6438 } else { |
| 6439 _reportErrorForCurrentToken( |
| 6440 ParserErrorCode.UNEXPECTED_TERMINATOR_FOR_PARAMETER_GROUP, |
| 6441 ["["]); |
| 6442 } |
| 6443 } |
| 6444 kind = ParameterKind.REQUIRED; |
| 6445 } else if (type == TokenType.CLOSE_CURLY_BRACKET) { |
| 6446 rightCurlyBracket = getAndAdvance(); |
| 6447 if (leftCurlyBracket == null) { |
| 6448 if (leftSquareBracket != null) { |
| 6449 _reportErrorForCurrentToken( |
| 6450 ParserErrorCode.WRONG_TERMINATOR_FOR_PARAMETER_GROUP, ["]"]); |
| 6451 rightSquareBracket = rightCurlyBracket; |
| 6452 rightCurlyBracket = null; |
| 6453 } else { |
| 6454 _reportErrorForCurrentToken( |
| 6455 ParserErrorCode.UNEXPECTED_TERMINATOR_FOR_PARAMETER_GROUP, |
| 6456 ["{"]); |
| 6457 } |
| 6458 } |
| 6459 kind = ParameterKind.REQUIRED; |
| 6460 } |
| 6461 } while (!_matches(TokenType.CLOSE_PAREN) && |
| 6462 !identical(initialToken, _currentToken)); |
| 6463 Token rightParenthesis = _expect(TokenType.CLOSE_PAREN); |
| 6464 // |
| 6465 // Check that the groups were closed correctly. |
| 6466 // |
| 6467 if (leftSquareBracket != null && rightSquareBracket == null) { |
| 6468 _reportErrorForCurrentToken( |
| 6469 ParserErrorCode.MISSING_TERMINATOR_FOR_PARAMETER_GROUP, ["]"]); |
| 6470 } |
| 6471 if (leftCurlyBracket != null && rightCurlyBracket == null) { |
| 6472 _reportErrorForCurrentToken( |
| 6473 ParserErrorCode.MISSING_TERMINATOR_FOR_PARAMETER_GROUP, ["}"]); |
| 6474 } |
| 6475 // |
| 6476 // Build the parameter list. |
| 6477 // |
| 6478 leftSquareBracket ??= leftCurlyBracket; |
| 6479 rightSquareBracket ??= rightCurlyBracket; |
| 6480 return new FormalParameterList(leftParenthesis, parameters, |
| 6481 leftSquareBracket, rightSquareBracket, rightParenthesis); |
| 6482 } |
| 6483 |
| 6484 /** |
| 6485 * Parse a list of formal parameters. Return the formal parameters that were |
| 6486 * parsed. |
| 6487 * |
| 6488 * This method assumes that the current token matches `TokenType.OPEN_PAREN`. |
| 6489 */ |
| 6490 FormalParameterList _parseFormalParameterListUnchecked() { |
| 6491 return _parseFormalParameterListAfterParen(getAndAdvance()); |
| 6492 } |
| 6493 |
| 6494 /** |
| 6495 * Parse a function declaration statement. The [commentAndMetadata] is the |
| 6496 * documentation comment and metadata to be associated with the declaration. |
| 6497 * The [returnType] is the return type, or `null` if there is no return type. |
| 6498 * Return the function declaration statement that was parsed. |
| 6499 * |
| 6500 * functionDeclarationStatement ::= |
| 6501 * functionSignature functionBody |
| 6502 */ |
| 6503 Statement _parseFunctionDeclarationStatementAfterReturnType( |
| 6504 CommentAndMetadata commentAndMetadata, TypeName returnType) { |
| 6505 FunctionDeclaration declaration = |
| 6506 parseFunctionDeclaration(commentAndMetadata, null, returnType); |
| 6507 Token propertyKeyword = declaration.propertyKeyword; |
| 6508 if (propertyKeyword != null) { |
| 6509 if (propertyKeyword.keyword == Keyword.GET) { |
| 6510 _reportErrorForToken( |
| 6511 ParserErrorCode.GETTER_IN_FUNCTION, propertyKeyword); |
| 6512 } else { |
| 6513 _reportErrorForToken( |
| 6514 ParserErrorCode.SETTER_IN_FUNCTION, propertyKeyword); |
| 6515 } |
| 6516 } |
| 6517 return new FunctionDeclarationStatement(declaration); |
| 6518 } |
| 6519 |
| 6520 /** |
| 6521 * Parse a function type alias. The [commentAndMetadata] is the metadata to be |
| 6522 * associated with the member. The [keyword] is the token representing the |
| 6523 * 'typedef' keyword. Return the function type alias that was parsed. |
| 6524 * |
| 6525 * functionTypeAlias ::= |
| 6526 * functionPrefix typeParameterList? formalParameterList ';' |
| 6527 * |
| 6528 * functionPrefix ::= |
| 6529 * returnType? name |
| 6530 */ |
| 6531 FunctionTypeAlias _parseFunctionTypeAlias( |
| 6532 CommentAndMetadata commentAndMetadata, Token keyword) { |
| 6533 TypeName returnType = null; |
| 6534 if (hasReturnTypeInTypeAlias) { |
| 6535 returnType = parseReturnType(); |
| 6536 } |
| 6537 SimpleIdentifier name = parseSimpleIdentifier(isDeclaration: true); |
| 6538 TypeParameterList typeParameters = null; |
| 6539 if (_matches(TokenType.LT)) { |
| 6540 typeParameters = parseTypeParameterList(); |
| 6541 } |
| 6542 TokenType type = _currentToken.type; |
| 6543 if (type == TokenType.SEMICOLON || type == TokenType.EOF) { |
| 6544 _reportErrorForCurrentToken(ParserErrorCode.MISSING_TYPEDEF_PARAMETERS); |
| 6545 FormalParameterList parameters = new FormalParameterList( |
| 6546 _createSyntheticToken(TokenType.OPEN_PAREN), |
| 6547 null, |
| 6548 null, |
| 6549 null, |
| 6550 _createSyntheticToken(TokenType.CLOSE_PAREN)); |
| 6551 Token semicolon = _expect(TokenType.SEMICOLON); |
| 6552 return new FunctionTypeAlias( |
| 6553 commentAndMetadata.comment, |
| 6554 commentAndMetadata.metadata, |
| 6555 keyword, |
| 6556 returnType, |
| 6557 name, |
| 6558 typeParameters, |
| 6559 parameters, |
| 6560 semicolon); |
| 6561 } else if (type == TokenType.OPEN_PAREN) { |
| 6562 FormalParameterList parameters = _parseFormalParameterListUnchecked(); |
| 6563 _validateFormalParameterList(parameters); |
| 6564 Token semicolon = _expect(TokenType.SEMICOLON); |
| 6565 return new FunctionTypeAlias( |
| 6566 commentAndMetadata.comment, |
| 6567 commentAndMetadata.metadata, |
| 6568 keyword, |
| 6569 returnType, |
| 6570 name, |
| 6571 typeParameters, |
| 6572 parameters, |
| 6573 semicolon); |
| 6574 } else { |
| 6575 _reportErrorForCurrentToken(ParserErrorCode.MISSING_TYPEDEF_PARAMETERS); |
| 6576 // Recovery: At the very least we should skip to the start of the next |
| 6577 // valid compilation unit member, allowing for the possibility of finding |
| 6578 // the typedef parameters before that point. |
| 6579 return new FunctionTypeAlias( |
| 6580 commentAndMetadata.comment, |
| 6581 commentAndMetadata.metadata, |
| 6582 keyword, |
| 6583 returnType, |
| 6584 name, |
| 6585 typeParameters, |
| 6586 new FormalParameterList(_createSyntheticToken(TokenType.OPEN_PAREN), |
| 6587 null, null, null, _createSyntheticToken(TokenType.CLOSE_PAREN)), |
| 6588 _createSyntheticToken(TokenType.SEMICOLON)); |
| 6589 } |
| 6590 } |
| 6591 |
| 6592 /** |
| 6593 * Parses generic type parameters from a comment. |
| 6594 * |
| 6595 * Normally this is handled by [_parseGenericMethodTypeParameters], but if the |
| 6596 * code already handles the normal generic type parameters, the comment |
| 6597 * matcher can be called directly. For example, we may have already tried |
| 6598 * matching `<` (less than sign) in a method declaration, and be currently |
| 6599 * on the `(` (open paren) because we didn't find it. In that case, this |
| 6600 * function will parse the preceding comment such as `/*<T, R>*/`. |
| 6601 */ |
| 6602 TypeParameterList _parseGenericCommentTypeParameters() { |
| 6603 if (_injectGenericCommentTypeList()) { |
| 6604 return parseTypeParameterList(); |
| 6605 } |
| 6606 return null; |
| 6607 } |
| 6608 |
| 6609 /** |
| 6610 * Parse the generic method or function's type parameters. |
| 6611 * |
| 6612 * For backwards compatibility this can optionally use comments. |
| 6613 * See [parseGenericMethodComments]. |
| 6614 */ |
| 6615 TypeParameterList _parseGenericMethodTypeParameters() { |
| 6616 if (parseGenericMethods && _matches(TokenType.LT) || |
| 6617 _injectGenericCommentTypeList()) { |
| 6618 return parseTypeParameterList(); |
| 6619 } |
| 6620 return null; |
| 6621 } |
| 6622 |
| 6623 /** |
| 6624 * Parse a library name. The [missingNameError] is the error code to be used |
| 6625 * if the library name is missing. The [missingNameToken] is the token |
| 6626 * associated with the error produced if the library name is missing. Return |
| 6627 * the library name that was parsed. |
| 6628 * |
| 6629 * libraryName ::= |
| 6630 * libraryIdentifier |
| 6631 */ |
| 6632 LibraryIdentifier _parseLibraryName( |
| 6633 ParserErrorCode missingNameError, Token missingNameToken) { |
| 6634 if (_matchesIdentifier()) { |
| 6635 return parseLibraryIdentifier(); |
| 6636 } else if (_matches(TokenType.STRING)) { |
| 6637 // Recovery: This should be extended to handle arbitrary tokens until we |
| 6638 // can find a token that can start a compilation unit member. |
| 6639 StringLiteral string = parseStringLiteral(); |
| 6640 _reportErrorForNode(ParserErrorCode.NON_IDENTIFIER_LIBRARY_NAME, string); |
| 6641 } else { |
| 6642 _reportErrorForToken(missingNameError, missingNameToken); |
| 6643 } |
| 6644 return new LibraryIdentifier( |
| 6645 <SimpleIdentifier>[createSyntheticIdentifier()]); |
| 6646 } |
| 6647 |
| 6648 /** |
| 6649 * Parse a method declaration. The [commentAndMetadata] is the documentation |
| 6650 * comment and metadata to be associated with the declaration. The |
| 6651 * [externalKeyword] is the 'external' token. The [staticKeyword] is the |
| 6652 * static keyword, or `null` if the getter is not static. The [returnType] is |
| 6653 * the return type of the method. The [name] is the name of the method. The |
| 6654 * [parameters] is the parameters to the method. Return the method declaration |
| 6655 * that was parsed. |
| 6656 * |
| 6657 * functionDeclaration ::= |
| 6658 * ('external' 'static'?)? functionSignature functionBody |
| 6659 * | 'external'? functionSignature ';' |
| 6660 */ |
| 6661 MethodDeclaration _parseMethodDeclarationAfterParameters( |
| 6662 CommentAndMetadata commentAndMetadata, |
| 6663 Token externalKeyword, |
| 6664 Token staticKeyword, |
| 6665 TypeName returnType, |
| 6666 SimpleIdentifier name, |
| 6667 TypeParameterList typeParameters, |
| 6668 FormalParameterList parameters) { |
| 6669 FunctionBody body = parseFunctionBody( |
| 6670 externalKeyword != null || staticKeyword == null, |
| 6671 ParserErrorCode.MISSING_FUNCTION_BODY, |
| 6672 false); |
| 6673 if (externalKeyword != null) { |
| 6674 if (body is! EmptyFunctionBody) { |
| 6675 _reportErrorForNode(ParserErrorCode.EXTERNAL_METHOD_WITH_BODY, body); |
| 6676 } |
| 6677 } else if (staticKeyword != null) { |
| 6678 if (body is EmptyFunctionBody && _parseFunctionBodies) { |
| 6679 _reportErrorForNode(ParserErrorCode.ABSTRACT_STATIC_METHOD, body); |
| 6680 } |
| 6681 } |
| 6682 return new MethodDeclaration( |
| 6683 commentAndMetadata.comment, |
| 6684 commentAndMetadata.metadata, |
| 6685 externalKeyword, |
| 6686 staticKeyword, |
| 6687 returnType, |
| 6688 null, |
| 6689 null, |
| 6690 name, |
| 6691 typeParameters, |
| 6692 parameters, |
| 6693 body); |
| 6694 } |
| 6695 |
| 6696 /** |
| 6697 * Parse a method declaration. The [commentAndMetadata] is the documentation |
| 6698 * comment and metadata to be associated with the declaration. The |
| 6699 * [externalKeyword] is the 'external' token. The [staticKeyword] is the |
| 6700 * static keyword, or `null` if the getter is not static. The [returnType] is |
| 6701 * the return type of the method. Return the method declaration that was |
| 6702 * parsed. |
| 6703 * |
| 6704 * functionDeclaration ::= |
| 6705 * 'external'? 'static'? functionSignature functionBody |
| 6706 * | 'external'? functionSignature ';' |
| 6707 */ |
| 6708 MethodDeclaration _parseMethodDeclarationAfterReturnType( |
| 6709 CommentAndMetadata commentAndMetadata, |
| 6710 Token externalKeyword, |
| 6711 Token staticKeyword, |
| 6712 TypeName returnType) { |
| 6713 SimpleIdentifier methodName = parseSimpleIdentifier(isDeclaration: true); |
| 6714 TypeParameterList typeParameters = _parseGenericMethodTypeParameters(); |
| 6715 FormalParameterList parameters; |
| 6716 TokenType type = _currentToken.type; |
| 6717 // TODO(brianwilkerson) Figure out why we care what the current token is if |
| 6718 // it isn't a paren. |
| 6719 if (type != TokenType.OPEN_PAREN && |
| 6720 (type == TokenType.OPEN_CURLY_BRACKET || type == TokenType.FUNCTION)) { |
| 6721 _reportErrorForToken( |
| 6722 ParserErrorCode.MISSING_METHOD_PARAMETERS, _currentToken.previous); |
| 6723 parameters = new FormalParameterList( |
| 6724 _createSyntheticToken(TokenType.OPEN_PAREN), |
| 6725 null, |
| 6726 null, |
| 6727 null, |
| 6728 _createSyntheticToken(TokenType.CLOSE_PAREN)); |
| 6729 } else { |
| 6730 parameters = parseFormalParameterList(); |
| 6731 } |
| 6732 _validateFormalParameterList(parameters); |
| 6733 return _parseMethodDeclarationAfterParameters( |
| 6734 commentAndMetadata, |
| 6735 externalKeyword, |
| 6736 staticKeyword, |
| 6737 returnType, |
| 6738 methodName, |
| 6739 typeParameters, |
| 6740 parameters); |
| 6741 } |
| 6742 |
| 6743 /** |
| 6744 * Parse a class native clause. Return the native clause that was parsed. |
| 6745 * |
| 6746 * This method assumes that the current token matches `_NATIVE`. |
| 6747 * |
| 6748 * classNativeClause ::= |
| 6749 * 'native' name |
| 6750 */ |
| 6751 NativeClause _parseNativeClause() { |
| 6752 Token keyword = getAndAdvance(); |
| 6753 StringLiteral name = parseStringLiteral(); |
| 6754 return new NativeClause(keyword, name); |
| 6755 } |
| 6756 |
| 6757 /** |
| 6758 * Parse an operator declaration starting after the 'operator' keyword. The |
| 6759 * [commentAndMetadata] is the documentation comment and metadata to be |
| 6760 * associated with the declaration. The [externalKeyword] is the 'external' |
| 6761 * token. The [returnType] is the return type that has already been parsed, or |
| 6762 * `null` if there was no return type. The [operatorKeyword] is the 'operator' |
| 6763 * keyword. Return the operator declaration that was parsed. |
| 6764 * |
| 6765 * operatorDeclaration ::= |
| 6766 * operatorSignature (';' | functionBody) |
| 6767 * |
| 6768 * operatorSignature ::= |
| 6769 * 'external'? returnType? 'operator' operator formalParameterList |
| 6770 */ |
| 6771 MethodDeclaration _parseOperatorAfterKeyword( |
| 6772 CommentAndMetadata commentAndMetadata, |
| 6773 Token externalKeyword, |
| 6774 TypeName returnType, |
| 6775 Token operatorKeyword) { |
| 6776 if (!_currentToken.isUserDefinableOperator) { |
| 6777 _reportErrorForCurrentToken( |
| 6778 ParserErrorCode.NON_USER_DEFINABLE_OPERATOR, [_currentToken.lexeme]); |
| 6779 } |
| 6780 SimpleIdentifier name = |
| 6781 new SimpleIdentifier(getAndAdvance(), isDeclaration: true); |
| 6782 if (_matches(TokenType.EQ)) { |
| 6783 Token previous = _currentToken.previous; |
| 6784 if ((_tokenMatches(previous, TokenType.EQ_EQ) || |
| 6785 _tokenMatches(previous, TokenType.BANG_EQ)) && |
| 6786 _currentToken.offset == previous.offset + 2) { |
| 6787 _reportErrorForCurrentToken(ParserErrorCode.INVALID_OPERATOR, |
| 6788 ["${previous.lexeme}${_currentToken.lexeme}"]); |
| 6789 _advance(); |
| 6790 } |
| 6791 } |
| 6792 FormalParameterList parameters = parseFormalParameterList(); |
| 6793 _validateFormalParameterList(parameters); |
| 6794 FunctionBody body = |
| 6795 parseFunctionBody(true, ParserErrorCode.MISSING_FUNCTION_BODY, false); |
| 6796 if (externalKeyword != null && body is! EmptyFunctionBody) { |
| 6797 _reportErrorForCurrentToken(ParserErrorCode.EXTERNAL_OPERATOR_WITH_BODY); |
| 6798 } |
| 6799 return new MethodDeclaration( |
| 6800 commentAndMetadata.comment, |
| 6801 commentAndMetadata.metadata, |
| 6802 externalKeyword, |
| 6803 null, |
| 6804 returnType, |
| 6805 null, |
| 6806 operatorKeyword, |
| 6807 name, |
| 6808 null, |
| 6809 parameters, |
| 6810 body); |
| 6811 } |
| 6812 |
| 6813 /** |
| 6814 * Parse a return type if one is given, otherwise return `null` without |
| 6815 * advancing. Return the return type that was parsed. |
| 6816 */ |
| 6817 TypeName _parseOptionalReturnType() { |
| 6818 TypeName typeComment = _parseOptionalTypeNameComment(); |
| 6819 if (typeComment != null) { |
| 6820 return typeComment; |
| 6821 } |
| 6822 Keyword keyword = _currentToken.keyword; |
| 6823 if (keyword == Keyword.VOID) { |
| 6824 return new TypeName(new SimpleIdentifier(getAndAdvance()), null); |
| 6825 } else if (_matchesIdentifier()) { |
| 6826 Token next = _peek(); |
| 6827 if (keyword != Keyword.GET && |
| 6828 keyword != Keyword.SET && |
| 6829 keyword != Keyword.OPERATOR && |
| 6830 (_tokenMatchesIdentifier(next) || |
| 6831 _tokenMatches(next, TokenType.LT))) { |
| 6832 return parseReturnType(); |
| 6833 } |
| 6834 Token next2 = next.next; |
| 6835 Token next3 = next2.next; |
| 6836 if (_tokenMatches(next, TokenType.PERIOD) && |
| 6837 _tokenMatchesIdentifier(next2) && |
| 6838 (_tokenMatchesIdentifier(next3) || |
| 6839 _tokenMatches(next3, TokenType.LT))) { |
| 6840 return parseReturnType(); |
| 6841 } |
| 6842 } |
| 6843 return null; |
| 6844 } |
| 6845 |
| 6846 /** |
| 6847 * Parse a [TypeArgumentList] if present, otherwise return null. |
| 6848 * This also supports the comment form, if enabled: `/*<T>*/` |
| 6849 */ |
| 6850 TypeArgumentList _parseOptionalTypeArguments() { |
| 6851 if (_matches(TokenType.LT) || _injectGenericCommentTypeList()) { |
| 6852 return parseTypeArgumentList(); |
| 6853 } |
| 6854 return null; |
| 6855 } |
| 6856 |
| 6857 TypeName _parseOptionalTypeNameComment() { |
| 6858 if (_injectGenericCommentTypeAssign()) { |
| 6859 return _parseTypeName(false); |
| 6860 } |
| 6861 return null; |
| 6862 } |
| 6863 |
| 6864 /** |
| 6865 * Parse a part directive. The [commentAndMetadata] is the metadata to be |
| 6866 * associated with the directive. Return the part or part-of directive that |
| 6867 * was parsed. |
| 6868 * |
| 6869 * This method assumes that the current token matches `Keyword.PART`. |
| 6870 * |
| 6871 * partDirective ::= |
| 6872 * metadata 'part' stringLiteral ';' |
| 6873 */ |
| 6874 Directive _parsePartDirective(CommentAndMetadata commentAndMetadata) { |
| 6875 Token partKeyword = getAndAdvance(); |
| 6876 StringLiteral partUri = _parseUri(); |
| 6877 Token semicolon = _expect(TokenType.SEMICOLON); |
| 6878 return new PartDirective(commentAndMetadata.comment, |
| 6879 commentAndMetadata.metadata, partKeyword, partUri, semicolon); |
| 6880 } |
| 6881 |
| 6882 /** |
| 6883 * Parse a part-of directive. The [commentAndMetadata] is the metadata to be |
| 6884 * associated with the directive. Return the part or part-of directive that |
| 6885 * was parsed. |
| 6886 * |
| 6887 * This method assumes that the current token matches [Keyword.PART] and that |
| 6888 * the following token matches the identifier 'of'. |
| 6889 * |
| 6890 * partOfDirective ::= |
| 6891 * metadata 'part' 'of' identifier ';' |
| 6892 */ |
| 6893 Directive _parsePartOfDirective(CommentAndMetadata commentAndMetadata) { |
| 6894 Token partKeyword = getAndAdvance(); |
| 6895 Token ofKeyword = getAndAdvance(); |
| 6896 LibraryIdentifier libraryName = _parseLibraryName( |
| 6897 ParserErrorCode.MISSING_NAME_IN_PART_OF_DIRECTIVE, ofKeyword); |
| 6898 Token semicolon = _expect(TokenType.SEMICOLON); |
| 6899 return new PartOfDirective( |
| 6900 commentAndMetadata.comment, |
| 6901 commentAndMetadata.metadata, |
| 6902 partKeyword, |
| 6903 ofKeyword, |
| 6904 libraryName, |
| 6905 semicolon); |
| 6906 } |
| 6907 |
| 6908 /** |
| 6909 * Parse a prefixed identifier given that the given [qualifier] was already |
| 6910 * parsed. Return the prefixed identifier that was parsed. |
| 6911 * |
| 6912 * prefixedIdentifier ::= |
| 6913 * identifier ('.' identifier)? |
| 6914 */ |
| 6915 Identifier _parsePrefixedIdentifierAfterIdentifier( |
| 6916 SimpleIdentifier qualifier) { |
| 6917 if (!_matches(TokenType.PERIOD) || _injectGenericCommentTypeList()) { |
| 6918 return qualifier; |
| 6919 } |
| 6920 Token period = getAndAdvance(); |
| 6921 SimpleIdentifier qualified = parseSimpleIdentifier(); |
| 6922 return new PrefixedIdentifier(qualifier, period, qualified); |
| 6923 } |
| 6924 |
| 6925 /** |
| 6926 * Parse a prefixed identifier. Return the prefixed identifier that was |
| 6927 * parsed. |
| 6928 * |
| 6929 * This method assumes that the current token matches an identifier. |
| 6930 * |
| 6931 * prefixedIdentifier ::= |
| 6932 * identifier ('.' identifier)? |
| 6933 */ |
| 6934 Identifier _parsePrefixedIdentifierUnchecked() { |
| 6935 return _parsePrefixedIdentifierAfterIdentifier( |
| 6936 _parseSimpleIdentifierUnchecked()); |
| 6937 } |
| 6938 |
| 6939 /** |
| 6940 * Parse a simple identifier. Return the simple identifier that was parsed. |
| 6941 * |
| 6942 * This method assumes that the current token matches an identifier. |
| 6943 * |
| 6944 * identifier ::= |
| 6945 * IDENTIFIER |
| 6946 */ |
| 6947 SimpleIdentifier _parseSimpleIdentifierUnchecked( |
| 6948 {bool isDeclaration: false}) { |
| 6949 String lexeme = _currentToken.lexeme; |
| 6950 if ((_inAsync || _inGenerator) && |
| 6951 (lexeme == ASYNC || lexeme == _AWAIT || lexeme == _YIELD)) { |
| 6952 _reportErrorForCurrentToken( |
| 6953 ParserErrorCode.ASYNC_KEYWORD_USED_AS_IDENTIFIER); |
| 6954 } |
| 6955 return new SimpleIdentifier(getAndAdvance(), isDeclaration: isDeclaration); |
| 6956 } |
| 6957 |
| 6958 /** |
| 6959 * Parse a list of statements within a switch statement. Return the statements |
| 6960 * that were parsed. |
| 6961 * |
| 6962 * statements ::= |
| 6963 * statement* |
| 6964 */ |
| 6965 List<Statement> _parseStatementList() { |
| 6966 List<Statement> statements = <Statement>[]; |
| 6967 Token statementStart = _currentToken; |
| 6968 TokenType type = _currentToken.type; |
| 6969 while (type != TokenType.EOF && |
| 6970 type != TokenType.CLOSE_CURLY_BRACKET && |
| 6971 !isSwitchMember()) { |
| 6972 statements.add(parseStatement2()); |
| 6973 if (identical(_currentToken, statementStart)) { |
| 6974 _reportErrorForToken(ParserErrorCode.UNEXPECTED_TOKEN, _currentToken, |
| 6975 [_currentToken.lexeme]); |
| 6976 _advance(); |
| 6977 } |
| 6978 statementStart = _currentToken; |
| 6979 type = _currentToken.type; |
| 6980 } |
| 6981 return statements; |
| 6982 } |
| 6983 |
| 6984 /** |
| 6985 * Parse a string literal that contains interpolations. Return the string |
| 6986 * literal that was parsed. |
| 6987 * |
| 6988 * This method assumes that the current token matches either |
| 6989 * [TokenType.STRING_INTERPOLATION_EXPRESSION] or |
| 6990 * [TokenType.STRING_INTERPOLATION_IDENTIFIER]. |
| 6991 */ |
| 6992 StringInterpolation _parseStringInterpolation(Token string) { |
| 6993 List<InterpolationElement> elements = <InterpolationElement>[ |
| 6994 new InterpolationString( |
| 6995 string, computeStringValue(string.lexeme, true, false)) |
| 6996 ]; |
| 6997 bool hasMore = true; |
| 6998 bool isExpression = _matches(TokenType.STRING_INTERPOLATION_EXPRESSION); |
| 6999 while (hasMore) { |
| 7000 if (isExpression) { |
| 7001 Token openToken = getAndAdvance(); |
| 7002 bool wasInInitializer = _inInitializer; |
| 7003 _inInitializer = false; |
| 7004 try { |
| 7005 Expression expression = parseExpression2(); |
| 7006 Token rightBracket = _expect(TokenType.CLOSE_CURLY_BRACKET); |
| 7007 elements.add( |
| 7008 new InterpolationExpression(openToken, expression, rightBracket)); |
| 7009 } finally { |
| 7010 _inInitializer = wasInInitializer; |
| 7011 } |
| 7012 } else { |
| 7013 Token openToken = getAndAdvance(); |
| 7014 Expression expression = null; |
| 7015 if (_matchesKeyword(Keyword.THIS)) { |
| 7016 expression = new ThisExpression(getAndAdvance()); |
| 7017 } else { |
| 7018 expression = parseSimpleIdentifier(); |
| 7019 } |
| 7020 elements.add(new InterpolationExpression(openToken, expression, null)); |
| 7021 } |
| 7022 if (_matches(TokenType.STRING)) { |
| 7023 string = getAndAdvance(); |
| 7024 isExpression = _matches(TokenType.STRING_INTERPOLATION_EXPRESSION); |
| 7025 hasMore = |
| 7026 isExpression || _matches(TokenType.STRING_INTERPOLATION_IDENTIFIER); |
| 7027 elements.add(new InterpolationString( |
| 7028 string, computeStringValue(string.lexeme, false, !hasMore))); |
| 7029 } else { |
| 7030 hasMore = false; |
| 7031 } |
| 7032 } |
| 7033 return new StringInterpolation(elements); |
| 7034 } |
| 7035 |
| 7036 /** |
| 7037 * Parse a string literal. Return the string literal that was parsed. |
| 7038 * |
| 7039 * This method assumes that the current token matches `TokenType.STRING`. |
| 7040 * |
| 7041 * stringLiteral ::= |
| 7042 * MULTI_LINE_STRING+ |
| 7043 * | SINGLE_LINE_STRING+ |
| 7044 */ |
| 7045 StringLiteral _parseStringLiteralUnchecked() { |
| 7046 List<StringLiteral> strings = <StringLiteral>[]; |
| 7047 do { |
| 7048 Token string = getAndAdvance(); |
| 7049 if (_matches(TokenType.STRING_INTERPOLATION_EXPRESSION) || |
| 7050 _matches(TokenType.STRING_INTERPOLATION_IDENTIFIER)) { |
| 7051 strings.add(_parseStringInterpolation(string)); |
| 7052 } else { |
| 7053 strings.add(new SimpleStringLiteral( |
| 7054 string, computeStringValue(string.lexeme, true, true))); |
| 7055 } |
| 7056 } while (_matches(TokenType.STRING)); |
| 7057 return strings.length == 1 ? strings[0] : new AdjacentStrings(strings); |
| 7058 } |
| 7059 |
| 7060 TypeName _parseTypeName(bool inExpression) { |
| 7061 Identifier typeName; |
| 7062 if (_matchesIdentifier()) { |
| 7063 typeName = _parsePrefixedIdentifierUnchecked(); |
| 7064 } else if (_matchesKeyword(Keyword.VAR)) { |
| 7065 _reportErrorForCurrentToken(ParserErrorCode.VAR_AS_TYPE_NAME); |
| 7066 typeName = new SimpleIdentifier(getAndAdvance()); |
| 7067 } else { |
| 7068 typeName = createSyntheticIdentifier(); |
| 7069 _reportErrorForCurrentToken(ParserErrorCode.EXPECTED_TYPE_NAME); |
| 7070 } |
| 7071 TypeArgumentList typeArguments = _parseOptionalTypeArguments(); |
| 7072 Token question = null; |
| 7073 if (enableNnbd && _matches(TokenType.QUESTION)) { |
| 7074 if (!inExpression || !_isConditionalOperator()) { |
| 7075 question = getAndAdvance(); |
| 7076 } |
| 7077 } |
| 7078 return new TypeName(typeName, typeArguments, question: question); |
| 7079 } |
| 7080 |
| 7081 /** |
| 7082 * Parse a type name. Return the type name that was parsed. |
| 7083 * |
| 7084 * This method assumes that the current token is an identifier. |
| 7085 * |
| 7086 * type ::= |
| 7087 * qualified typeArguments? |
| 7088 */ |
| 7089 TypeName _parseTypeNameAfterIdentifier() { |
| 7090 Identifier typeName = _parsePrefixedIdentifierUnchecked(); |
| 7091 TypeArgumentList typeArguments = _parseOptionalTypeArguments(); |
| 7092 // If this is followed by a generic method type comment, allow the comment |
| 7093 // type to replace the real type name. |
| 7094 // TODO(jmesserly): this feels like a big hammer. Can we restrict it to |
| 7095 // only work inside generic methods? |
| 7096 TypeName typeFromComment = _parseOptionalTypeNameComment(); |
| 7097 return typeFromComment ?? new TypeName(typeName, typeArguments); |
| 7098 } |
| 7099 |
| 7100 /** |
| 7101 * Parse a string literal representing a URI. Return the string literal that |
| 7102 * was parsed. |
| 7103 */ |
| 7104 StringLiteral _parseUri() { |
| 7105 // TODO(brianwilkerson) Should this function also return true for valid |
| 7106 // top-level keywords? |
| 7107 bool isKeywordAfterUri(Token token) => |
| 7108 token.lexeme == Keyword.AS.syntax || |
| 7109 token.lexeme == _HIDE || |
| 7110 token.lexeme == _SHOW; |
| 7111 TokenType type = _currentToken.type; |
| 7112 if (type != TokenType.STRING && |
| 7113 type != TokenType.SEMICOLON && |
| 7114 !isKeywordAfterUri(_currentToken)) { |
| 7115 // Attempt to recover in the case where the URI was not enclosed in |
| 7116 // quotes. |
| 7117 Token token = _currentToken; |
| 7118 bool isValidInUri(Token token) { |
| 7119 TokenType type = token.type; |
| 7120 return type == TokenType.COLON || |
| 7121 type == TokenType.SLASH || |
| 7122 type == TokenType.PERIOD || |
| 7123 type == TokenType.PERIOD_PERIOD || |
| 7124 type == TokenType.PERIOD_PERIOD_PERIOD || |
| 7125 type == TokenType.INT || |
| 7126 type == TokenType.DOUBLE; |
| 7127 } |
| 7128 |
| 7129 while ((_tokenMatchesIdentifier(token) && !isKeywordAfterUri(token)) || |
| 7130 isValidInUri(token)) { |
| 7131 token = token.next; |
| 7132 } |
| 7133 if (_tokenMatches(token, TokenType.SEMICOLON) || |
| 7134 isKeywordAfterUri(token)) { |
| 7135 Token endToken = token.previous; |
| 7136 token = _currentToken; |
| 7137 int endOffset = token.end; |
| 7138 StringBuffer buffer = new StringBuffer(); |
| 7139 buffer.write(token.lexeme); |
| 7140 while (token != endToken) { |
| 7141 token = token.next; |
| 7142 if (token.offset != endOffset || token.precedingComments != null) { |
| 7143 return parseStringLiteral(); |
| 7144 } |
| 7145 buffer.write(token.lexeme); |
| 7146 endOffset = token.end; |
| 7147 } |
| 7148 String value = buffer.toString(); |
| 7149 Token newToken = |
| 7150 new StringToken(TokenType.STRING, "'$value'", _currentToken.offset); |
| 7151 _reportErrorForToken( |
| 7152 ParserErrorCode.NON_STRING_LITERAL_AS_URI, newToken); |
| 7153 _currentToken = endToken.next; |
| 7154 return new SimpleStringLiteral(newToken, value); |
| 7155 } |
| 7156 } |
| 7157 return parseStringLiteral(); |
| 7158 } |
| 7159 |
| 7160 /** |
| 7161 * Parse a variable declaration statement. The [commentAndMetadata] is the |
| 7162 * metadata to be associated with the variable declaration statement, or |
| 7163 * `null` if there is no attempt at parsing the comment and metadata. The |
| 7164 * [keyword] is the token representing the 'final', 'const' or 'var' keyword, |
| 7165 * or `null` if there is no keyword. The [type] is the type of the variables |
| 7166 * in the list. Return the variable declaration statement that was parsed. |
| 7167 * |
| 7168 * variableDeclarationStatement ::= |
| 7169 * variableDeclarationList ';' |
| 7170 */ |
| 7171 VariableDeclarationStatement _parseVariableDeclarationStatementAfterType( |
| 7172 CommentAndMetadata commentAndMetadata, Token keyword, TypeName type) { |
| 7173 VariableDeclarationList variableList = |
| 7174 parseVariableDeclarationListAfterType( |
| 7175 commentAndMetadata, keyword, type); |
| 7176 Token semicolon = _expect(TokenType.SEMICOLON); |
| 7177 return new VariableDeclarationStatement(variableList, semicolon); |
| 7178 } |
| 7179 |
| 7180 /** |
| 8026 * Return the token that is immediately after the current token. This is | 7181 * Return the token that is immediately after the current token. This is |
| 8027 * equivalent to [_peekAt](1). | 7182 * equivalent to [_peekAt](1). |
| 8028 */ | 7183 */ |
| 8029 Token _peek() => _currentToken.next; | 7184 Token _peek() => _currentToken.next; |
| 8030 | 7185 |
| 8031 /** | 7186 /** |
| 8032 * Return the token that is the given [distance] after the current token, | 7187 * Return the token that is the given [distance] after the current token, |
| 8033 * where the distance is the number of tokens to look ahead. A distance of `0` | 7188 * where the distance is the number of tokens to look ahead. A distance of `0` |
| 8034 * is the current token, `1` is the next token, etc. | 7189 * is the current token, `1` is the next token, etc. |
| 8035 */ | 7190 */ |
| 8036 Token _peekAt(int distance) { | 7191 Token _peekAt(int distance) { |
| 8037 Token token = _currentToken; | 7192 Token token = _currentToken; |
| 8038 for (int i = 0; i < distance; i++) { | 7193 for (int i = 0; i < distance; i++) { |
| 8039 token = token.next; | 7194 token = token.next; |
| 8040 } | 7195 } |
| 8041 return token; | 7196 return token; |
| 8042 } | 7197 } |
| 8043 | 7198 |
| 7199 String _removeGitHubInlineCode(String comment) { |
| 7200 int index = 0; |
| 7201 while (true) { |
| 7202 int beginIndex = comment.indexOf('`', index); |
| 7203 if (beginIndex == -1) { |
| 7204 break; |
| 7205 } |
| 7206 int endIndex = comment.indexOf('`', beginIndex + 1); |
| 7207 if (endIndex == -1) { |
| 7208 break; |
| 7209 } |
| 7210 comment = comment.substring(0, beginIndex + 1) + |
| 7211 ' ' * (endIndex - beginIndex - 1) + |
| 7212 comment.substring(endIndex); |
| 7213 index = endIndex + 1; |
| 7214 } |
| 7215 return comment; |
| 7216 } |
| 7217 |
| 8044 /** | 7218 /** |
| 8045 * Report the given [error]. | 7219 * Report the given [error]. |
| 8046 */ | 7220 */ |
| 8047 void _reportError(AnalysisError error) { | 7221 void _reportError(AnalysisError error) { |
| 8048 if (_errorListenerLock != 0) { | 7222 if (_errorListenerLock != 0) { |
| 8049 return; | 7223 return; |
| 8050 } | 7224 } |
| 8051 _errorListener.onError(error); | 7225 _errorListener.onError(error); |
| 8052 } | 7226 } |
| 8053 | 7227 |
| (...skipping 23 matching lines...) Expand all Loading... |
| 8077 void _reportErrorForToken(ErrorCode errorCode, Token token, | 7251 void _reportErrorForToken(ErrorCode errorCode, Token token, |
| 8078 [List<Object> arguments]) { | 7252 [List<Object> arguments]) { |
| 8079 if (token.type == TokenType.EOF) { | 7253 if (token.type == TokenType.EOF) { |
| 8080 token = token.previous; | 7254 token = token.previous; |
| 8081 } | 7255 } |
| 8082 _reportError(new AnalysisError(_source, token.offset, | 7256 _reportError(new AnalysisError(_source, token.offset, |
| 8083 math.max(token.length, 1), errorCode, arguments)); | 7257 math.max(token.length, 1), errorCode, arguments)); |
| 8084 } | 7258 } |
| 8085 | 7259 |
| 8086 /** | 7260 /** |
| 7261 * Scans the generic method comment, and returns the tokens, otherwise |
| 7262 * returns null. |
| 7263 */ |
| 7264 Token _scanGenericMethodComment(String code, int offset) { |
| 7265 BooleanErrorListener listener = new BooleanErrorListener(); |
| 7266 Scanner scanner = |
| 7267 new Scanner(null, new SubSequenceReader(code, offset), listener); |
| 7268 scanner.setSourceStart(1, 1); |
| 7269 Token firstToken = scanner.tokenize(); |
| 7270 if (listener.errorReported) { |
| 7271 return null; |
| 7272 } |
| 7273 return firstToken; |
| 7274 } |
| 7275 |
| 7276 /** |
| 7277 * Execute the given [parseOperation] in a temporary parser whose current |
| 7278 * token has been set to the given [startToken]. If the parse does not |
| 7279 * generate any errors or exceptions, then return the token following the |
| 7280 * matching portion of the token stream. Otherwise, return `null`. |
| 7281 * |
| 7282 * Note: This is an extremely inefficient way of testing whether the tokens in |
| 7283 * the token stream match a given production. It should not be used for |
| 7284 * production code. |
| 7285 */ |
| 7286 Token _skip(Token startToken, parseOperation(Parser parser)) { |
| 7287 BooleanErrorListener listener = new BooleanErrorListener(); |
| 7288 Parser parser = new Parser(_source, listener); |
| 7289 parser._currentToken = _cloneTokens(startToken); |
| 7290 parser._enableAssertInitializer = _enableAssertInitializer; |
| 7291 parser._enableNnbd = _enableNnbd; |
| 7292 parser._inAsync = _inAsync; |
| 7293 parser._inGenerator = _inGenerator; |
| 7294 parser._inInitializer = _inInitializer; |
| 7295 parser._inLoop = _inLoop; |
| 7296 parser._inSwitch = _inSwitch; |
| 7297 parser._parseFunctionBodies = _parseFunctionBodies; |
| 7298 try { |
| 7299 parseOperation(parser); |
| 7300 } catch (exception) { |
| 7301 return null; |
| 7302 } |
| 7303 if (listener.errorReported) { |
| 7304 return null; |
| 7305 } |
| 7306 return parser._currentToken; |
| 7307 } |
| 7308 |
| 7309 /** |
| 8087 * Skips a block with all containing blocks. | 7310 * Skips a block with all containing blocks. |
| 8088 */ | 7311 */ |
| 8089 void _skipBlock() { | 7312 void _skipBlock() { |
| 8090 Token endToken = (_currentToken as BeginToken).endToken; | 7313 Token endToken = (_currentToken as BeginToken).endToken; |
| 8091 if (endToken == null) { | 7314 if (endToken == null) { |
| 8092 endToken = _currentToken.next; | 7315 endToken = _currentToken.next; |
| 8093 while (!identical(endToken, _currentToken)) { | 7316 while (!identical(endToken, _currentToken)) { |
| 8094 _currentToken = endToken; | 7317 _currentToken = endToken; |
| 8095 endToken = _currentToken.next; | 7318 endToken = _currentToken.next; |
| 8096 } | 7319 } |
| (...skipping 12 matching lines...) Expand all Loading... |
| 8109 * [startToken] is the token at which parsing is to begin. Return the token | 7332 * [startToken] is the token at which parsing is to begin. Return the token |
| 8110 * following the type that was parsed. | 7333 * following the type that was parsed. |
| 8111 * | 7334 * |
| 8112 * finalConstVarOrType ::= | 7335 * finalConstVarOrType ::= |
| 8113 * | 'final' type? | 7336 * | 'final' type? |
| 8114 * | 'const' type? | 7337 * | 'const' type? |
| 8115 * | 'var' | 7338 * | 'var' |
| 8116 * | type | 7339 * | type |
| 8117 */ | 7340 */ |
| 8118 Token _skipFinalConstVarOrType(Token startToken) { | 7341 Token _skipFinalConstVarOrType(Token startToken) { |
| 8119 if (_tokenMatchesKeyword(startToken, Keyword.FINAL) || | 7342 Keyword keyword = startToken.keyword; |
| 8120 _tokenMatchesKeyword(startToken, Keyword.CONST)) { | 7343 if (keyword == Keyword.FINAL || keyword == Keyword.CONST) { |
| 8121 Token next = startToken.next; | 7344 Token next = startToken.next; |
| 8122 if (_tokenMatchesIdentifier(next)) { | 7345 if (_tokenMatchesIdentifier(next)) { |
| 8123 Token next2 = next.next; | 7346 Token next2 = next.next; |
| 8124 // "Type parameter" or "Type<" or "prefix.Type" | 7347 // "Type parameter" or "Type<" or "prefix.Type" |
| 8125 if (_tokenMatchesIdentifier(next2) || | 7348 if (_tokenMatchesIdentifier(next2) || |
| 8126 _tokenMatches(next2, TokenType.LT) || | 7349 _tokenMatches(next2, TokenType.LT) || |
| 8127 _tokenMatches(next2, TokenType.PERIOD)) { | 7350 _tokenMatches(next2, TokenType.PERIOD)) { |
| 8128 return _skipTypeName(next); | 7351 return skipTypeName(next); |
| 8129 } | 7352 } |
| 8130 // "parameter" | 7353 // "parameter" |
| 8131 return next; | 7354 return next; |
| 8132 } | 7355 } |
| 8133 } else if (_tokenMatchesKeyword(startToken, Keyword.VAR)) { | 7356 } else if (keyword == Keyword.VAR) { |
| 8134 return startToken.next; | 7357 return startToken.next; |
| 8135 } else if (_tokenMatchesIdentifier(startToken)) { | 7358 } else if (_tokenMatchesIdentifier(startToken)) { |
| 8136 Token next = startToken.next; | 7359 Token next = startToken.next; |
| 8137 if (_tokenMatchesIdentifier(next) || | 7360 if (_tokenMatchesIdentifier(next) || |
| 8138 _tokenMatches(next, TokenType.LT) || | 7361 _tokenMatches(next, TokenType.LT) || |
| 8139 _tokenMatchesKeyword(next, Keyword.THIS) || | 7362 _tokenMatchesKeyword(next, Keyword.THIS) || |
| 8140 (_tokenMatches(next, TokenType.PERIOD) && | 7363 (_tokenMatches(next, TokenType.PERIOD) && |
| 8141 _tokenMatchesIdentifier(next.next) && | 7364 _tokenMatchesIdentifier(next.next) && |
| 8142 (_tokenMatchesIdentifier(next.next.next) || | 7365 (_tokenMatchesIdentifier(next.next.next) || |
| 8143 _tokenMatches(next.next.next, TokenType.LT) || | 7366 _tokenMatches(next.next.next, TokenType.LT) || |
| 8144 _tokenMatchesKeyword(next.next.next, Keyword.THIS)))) { | 7367 _tokenMatchesKeyword(next.next.next, Keyword.THIS)))) { |
| 8145 return _skipReturnType(startToken); | 7368 return skipReturnType(startToken); |
| 8146 } | 7369 } |
| 8147 } | 7370 } |
| 8148 return null; | 7371 return null; |
| 8149 } | 7372 } |
| 8150 | 7373 |
| 8151 /** | 7374 /** |
| 8152 * Parse a list of formal parameters, starting at the [startToken], without | 7375 * Parse a list of formal parameters, starting at the [startToken], without |
| 8153 * actually creating a formal parameter list or changing the current token. | 7376 * actually creating a formal parameter list or changing the current token. |
| 8154 * Return the token following the formal parameter list that was parsed, or | 7377 * Return the token following the formal parameter list that was parsed, or |
| 8155 * `null` if the given token is not the first token in a valid list of formal | 7378 * `null` if the given token is not the first token in a valid list of formal |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 8187 return null; | 7410 return null; |
| 8188 } | 7411 } |
| 8189 Token next = startToken.next; | 7412 Token next = startToken.next; |
| 8190 if (_tokenMatches(next, TokenType.CLOSE_PAREN)) { | 7413 if (_tokenMatches(next, TokenType.CLOSE_PAREN)) { |
| 8191 return next.next; | 7414 return next.next; |
| 8192 } | 7415 } |
| 8193 // | 7416 // |
| 8194 // Look to see whether the token after the open parenthesis is something | 7417 // Look to see whether the token after the open parenthesis is something |
| 8195 // that should only occur at the beginning of a parameter list. | 7418 // that should only occur at the beginning of a parameter list. |
| 8196 // | 7419 // |
| 8197 if (next.matchesAny([ | 7420 if (next.matchesAny(const <TokenType>[ |
| 8198 TokenType.AT, | 7421 TokenType.AT, |
| 8199 TokenType.OPEN_SQUARE_BRACKET, | 7422 TokenType.OPEN_SQUARE_BRACKET, |
| 8200 TokenType.OPEN_CURLY_BRACKET | 7423 TokenType.OPEN_CURLY_BRACKET |
| 8201 ]) || | 7424 ]) || |
| 8202 _tokenMatchesKeyword(next, Keyword.VOID) || | 7425 _tokenMatchesKeyword(next, Keyword.VOID) || |
| 8203 (_tokenMatchesIdentifier(next) && | 7426 (_tokenMatchesIdentifier(next) && |
| 8204 (next.next.matchesAny([TokenType.COMMA, TokenType.CLOSE_PAREN])))) { | 7427 (next.next.matchesAny( |
| 7428 const <TokenType>[TokenType.COMMA, TokenType.CLOSE_PAREN])))) { |
| 8205 return _skipPastMatchingToken(startToken); | 7429 return _skipPastMatchingToken(startToken); |
| 8206 } | 7430 } |
| 8207 // | 7431 // |
| 8208 // Look to see whether the first parameter is a function typed parameter | 7432 // Look to see whether the first parameter is a function typed parameter |
| 8209 // without a return type. | 7433 // without a return type. |
| 8210 // | 7434 // |
| 8211 if (_tokenMatchesIdentifier(next) && | 7435 if (_tokenMatchesIdentifier(next) && |
| 8212 _tokenMatches(next.next, TokenType.OPEN_PAREN)) { | 7436 _tokenMatches(next.next, TokenType.OPEN_PAREN)) { |
| 8213 Token afterParameters = _skipFormalParameterList(next.next); | 7437 Token afterParameters = _skipFormalParameterList(next.next); |
| 8214 if (afterParameters != null && | 7438 if (afterParameters != null && |
| 8215 (afterParameters | 7439 afterParameters.matchesAny( |
| 8216 .matchesAny([TokenType.COMMA, TokenType.CLOSE_PAREN]))) { | 7440 const <TokenType>[TokenType.COMMA, TokenType.CLOSE_PAREN])) { |
| 8217 return _skipPastMatchingToken(startToken); | 7441 return _skipPastMatchingToken(startToken); |
| 8218 } | 7442 } |
| 8219 } | 7443 } |
| 8220 // | 7444 // |
| 8221 // Look to see whether the first parameter has a type or is a function typed | 7445 // Look to see whether the first parameter has a type or is a function typed |
| 8222 // parameter with a return type. | 7446 // parameter with a return type. |
| 8223 // | 7447 // |
| 8224 Token afterType = _skipFinalConstVarOrType(next); | 7448 Token afterType = _skipFinalConstVarOrType(next); |
| 8225 if (afterType == null) { | 7449 if (afterType == null) { |
| 8226 return null; | 7450 return null; |
| 8227 } | 7451 } |
| 8228 if (_skipSimpleIdentifier(afterType) == null) { | 7452 if (skipSimpleIdentifier(afterType) == null) { |
| 8229 return null; | 7453 return null; |
| 8230 } | 7454 } |
| 8231 return _skipPastMatchingToken(startToken); | 7455 return _skipPastMatchingToken(startToken); |
| 8232 } | 7456 } |
| 8233 | 7457 |
| 8234 /** | 7458 /** |
| 8235 * If the [startToken] is a begin token with an associated end token, then | 7459 * If the [startToken] is a begin token with an associated end token, then |
| 8236 * return the token following the end token. Otherwise, return `null`. | 7460 * return the token following the end token. Otherwise, return `null`. |
| 8237 */ | 7461 */ |
| 8238 Token _skipPastMatchingToken(Token startToken) { | 7462 Token _skipPastMatchingToken(Token startToken) { |
| 8239 if (startToken is! BeginToken) { | 7463 if (startToken is! BeginToken) { |
| 8240 return null; | 7464 return null; |
| 8241 } | 7465 } |
| 8242 Token closeParen = (startToken as BeginToken).endToken; | 7466 Token closeParen = (startToken as BeginToken).endToken; |
| 8243 if (closeParen == null) { | 7467 if (closeParen == null) { |
| 8244 return null; | 7468 return null; |
| 8245 } | 7469 } |
| 8246 return closeParen.next; | 7470 return closeParen.next; |
| 8247 } | 7471 } |
| 8248 | 7472 |
| 8249 /** | 7473 /** |
| 8250 * Parse a prefixed identifier, starting at the [startToken], without actually | |
| 8251 * creating a prefixed identifier or changing the current token. Return the | |
| 8252 * token following the prefixed identifier that was parsed, or `null` if the | |
| 8253 * given token is not the first token in a valid prefixed identifier. | |
| 8254 * | |
| 8255 * This method must be kept in sync with [parsePrefixedIdentifier]. | |
| 8256 * | |
| 8257 * prefixedIdentifier ::= | |
| 8258 * identifier ('.' identifier)? | |
| 8259 */ | |
| 8260 Token _skipPrefixedIdentifier(Token startToken) { | |
| 8261 Token token = _skipSimpleIdentifier(startToken); | |
| 8262 if (token == null) { | |
| 8263 return null; | |
| 8264 } else if (!_tokenMatches(token, TokenType.PERIOD)) { | |
| 8265 return token; | |
| 8266 } | |
| 8267 token = token.next; | |
| 8268 Token nextToken = _skipSimpleIdentifier(token); | |
| 8269 if (nextToken != null) { | |
| 8270 return nextToken; | |
| 8271 } else if (_tokenMatches(token, TokenType.CLOSE_PAREN) || | |
| 8272 _tokenMatches(token, TokenType.COMMA)) { | |
| 8273 // If the `id.` is followed by something that cannot produce a valid | |
| 8274 // structure then assume this is a prefixed identifier but missing the | |
| 8275 // trailing identifier | |
| 8276 return token; | |
| 8277 } | |
| 8278 return null; | |
| 8279 } | |
| 8280 | |
| 8281 /** | |
| 8282 * Parse a return type, starting at the [startToken], without actually | |
| 8283 * creating a return type or changing the current token. Return the token | |
| 8284 * following the return type that was parsed, or `null` if the given token is | |
| 8285 * not the first token in a valid return type. | |
| 8286 * | |
| 8287 * This method must be kept in sync with [parseReturnType]. | |
| 8288 * | |
| 8289 * returnType ::= | |
| 8290 * 'void' | |
| 8291 * | type | |
| 8292 */ | |
| 8293 Token _skipReturnType(Token startToken) { | |
| 8294 if (_tokenMatchesKeyword(startToken, Keyword.VOID)) { | |
| 8295 return startToken.next; | |
| 8296 } else { | |
| 8297 return _skipTypeName(startToken); | |
| 8298 } | |
| 8299 } | |
| 8300 | |
| 8301 /** | |
| 8302 * Parse a simple identifier, starting at the [startToken], without actually | |
| 8303 * creating a simple identifier or changing the current token. Return the | |
| 8304 * token following the simple identifier that was parsed, or `null` if the | |
| 8305 * given token is not the first token in a valid simple identifier. | |
| 8306 * | |
| 8307 * This method must be kept in sync with [parseSimpleIdentifier]. | |
| 8308 * | |
| 8309 * identifier ::= | |
| 8310 * IDENTIFIER | |
| 8311 */ | |
| 8312 Token _skipSimpleIdentifier(Token startToken) { | |
| 8313 if (_tokenMatches(startToken, TokenType.IDENTIFIER) || | |
| 8314 _tokenMatchesPseudoKeyword(startToken)) { | |
| 8315 return startToken.next; | |
| 8316 } | |
| 8317 return null; | |
| 8318 } | |
| 8319 | |
| 8320 /** | |
| 8321 * Parse a string literal that contains interpolations, starting at the | 7474 * Parse a string literal that contains interpolations, starting at the |
| 8322 * [startToken], without actually creating a string literal or changing the | 7475 * [startToken], without actually creating a string literal or changing the |
| 8323 * current token. Return the token following the string literal that was | 7476 * current token. Return the token following the string literal that was |
| 8324 * parsed, or `null` if the given token is not the first token in a valid | 7477 * parsed, or `null` if the given token is not the first token in a valid |
| 8325 * string literal. | 7478 * string literal. |
| 8326 * | 7479 * |
| 8327 * This method must be kept in sync with [parseStringInterpolation]. | 7480 * This method must be kept in sync with [parseStringInterpolation]. |
| 8328 */ | 7481 */ |
| 8329 Token _skipStringInterpolation(Token startToken) { | 7482 Token _skipStringInterpolation(Token startToken) { |
| 8330 Token token = startToken; | 7483 Token token = startToken; |
| 8331 TokenType type = token.type; | 7484 TokenType type = token.type; |
| 8332 while (type == TokenType.STRING_INTERPOLATION_EXPRESSION || | 7485 while (type == TokenType.STRING_INTERPOLATION_EXPRESSION || |
| 8333 type == TokenType.STRING_INTERPOLATION_IDENTIFIER) { | 7486 type == TokenType.STRING_INTERPOLATION_IDENTIFIER) { |
| 8334 if (type == TokenType.STRING_INTERPOLATION_EXPRESSION) { | 7487 if (type == TokenType.STRING_INTERPOLATION_EXPRESSION) { |
| 8335 token = token.next; | 7488 token = token.next; |
| 8336 type = token.type; | 7489 type = token.type; |
| 8337 // | 7490 // |
| 8338 // Rather than verify that the following tokens represent a valid | 7491 // Rather than verify that the following tokens represent a valid |
| 8339 // expression, we simply skip tokens until we reach the end of the | 7492 // expression, we simply skip tokens until we reach the end of the |
| 8340 // interpolation, being careful to handle nested string literals. | 7493 // interpolation, being careful to handle nested string literals. |
| 8341 // | 7494 // |
| 8342 int bracketNestingLevel = 1; | 7495 int bracketNestingLevel = 1; |
| 8343 while (bracketNestingLevel > 0) { | 7496 while (bracketNestingLevel > 0) { |
| 8344 if (type == TokenType.EOF) { | 7497 if (type == TokenType.EOF) { |
| 8345 return null; | 7498 return null; |
| 8346 } else if (type == TokenType.OPEN_CURLY_BRACKET) { | 7499 } else if (type == TokenType.OPEN_CURLY_BRACKET) { |
| 8347 bracketNestingLevel++; | 7500 bracketNestingLevel++; |
| 7501 token = token.next; |
| 8348 } else if (type == TokenType.CLOSE_CURLY_BRACKET) { | 7502 } else if (type == TokenType.CLOSE_CURLY_BRACKET) { |
| 8349 bracketNestingLevel--; | 7503 bracketNestingLevel--; |
| 7504 token = token.next; |
| 8350 } else if (type == TokenType.STRING) { | 7505 } else if (type == TokenType.STRING) { |
| 8351 token = _skipStringLiteral(token); | 7506 token = skipStringLiteral(token); |
| 8352 if (token == null) { | 7507 if (token == null) { |
| 8353 return null; | 7508 return null; |
| 8354 } | 7509 } |
| 8355 } else { | 7510 } else { |
| 8356 token = token.next; | 7511 token = token.next; |
| 8357 } | 7512 } |
| 8358 type = token.type; | 7513 type = token.type; |
| 8359 } | 7514 } |
| 8360 token = token.next; | 7515 token = token.next; |
| 8361 type = token.type; | 7516 type = token.type; |
| 8362 } else { | 7517 } else { |
| 8363 token = token.next; | 7518 token = token.next; |
| 8364 if (token.type != TokenType.IDENTIFIER) { | 7519 if (token.type != TokenType.IDENTIFIER) { |
| 8365 return null; | 7520 return null; |
| 8366 } | 7521 } |
| 8367 token = token.next; | 7522 token = token.next; |
| 8368 } | 7523 } |
| 8369 type = token.type; | 7524 type = token.type; |
| 8370 if (type == TokenType.STRING) { | 7525 if (type == TokenType.STRING) { |
| 8371 token = token.next; | 7526 token = token.next; |
| 8372 type = token.type; | 7527 type = token.type; |
| 8373 } | 7528 } |
| 8374 } | 7529 } |
| 8375 return token; | 7530 return token; |
| 8376 } | 7531 } |
| 8377 | 7532 |
| 8378 /** | 7533 /** |
| 8379 * Parse a string literal, starting at the [startToken], without actually | |
| 8380 * creating a string literal or changing the current token. Return the token | |
| 8381 * following the string literal that was parsed, or `null` if the given token | |
| 8382 * is not the first token in a valid string literal. | |
| 8383 * | |
| 8384 * This method must be kept in sync with [parseStringLiteral]. | |
| 8385 * | |
| 8386 * stringLiteral ::= | |
| 8387 * MULTI_LINE_STRING+ | |
| 8388 * | SINGLE_LINE_STRING+ | |
| 8389 */ | |
| 8390 Token _skipStringLiteral(Token startToken) { | |
| 8391 Token token = startToken; | |
| 8392 while (token != null && _tokenMatches(token, TokenType.STRING)) { | |
| 8393 token = token.next; | |
| 8394 TokenType type = token.type; | |
| 8395 if (type == TokenType.STRING_INTERPOLATION_EXPRESSION || | |
| 8396 type == TokenType.STRING_INTERPOLATION_IDENTIFIER) { | |
| 8397 token = _skipStringInterpolation(token); | |
| 8398 } | |
| 8399 } | |
| 8400 if (identical(token, startToken)) { | |
| 8401 return null; | |
| 8402 } | |
| 8403 return token; | |
| 8404 } | |
| 8405 | |
| 8406 /** | |
| 8407 * Parse a list of type arguments, starting at the [startToken], without | |
| 8408 * actually creating a type argument list or changing the current token. | |
| 8409 * Return the token following the type argument list that was parsed, or | |
| 8410 * `null` if the given token is not the first token in a valid type argument | |
| 8411 * list. | |
| 8412 * | |
| 8413 * This method must be kept in sync with [parseTypeArgumentList]. | |
| 8414 * | |
| 8415 * typeArguments ::= | |
| 8416 * '<' typeList '>' | |
| 8417 * | |
| 8418 * typeList ::= | |
| 8419 * type (',' type)* | |
| 8420 */ | |
| 8421 Token _skipTypeArgumentList(Token startToken) { | |
| 8422 Token token = startToken; | |
| 8423 if (!_tokenMatches(token, TokenType.LT)) { | |
| 8424 return null; | |
| 8425 } | |
| 8426 token = _skipTypeName(token.next); | |
| 8427 if (token == null) { | |
| 8428 // If the start token '<' is followed by '>' | |
| 8429 // then assume this should be type argument list but is missing a type | |
| 8430 token = startToken.next; | |
| 8431 if (_tokenMatches(token, TokenType.GT)) { | |
| 8432 return token.next; | |
| 8433 } | |
| 8434 return null; | |
| 8435 } | |
| 8436 while (_tokenMatches(token, TokenType.COMMA)) { | |
| 8437 token = _skipTypeName(token.next); | |
| 8438 if (token == null) { | |
| 8439 return null; | |
| 8440 } | |
| 8441 } | |
| 8442 if (token.type == TokenType.GT) { | |
| 8443 return token.next; | |
| 8444 } else if (token.type == TokenType.GT_GT) { | |
| 8445 Token second = new Token(TokenType.GT, token.offset + 1); | |
| 8446 second.setNextWithoutSettingPrevious(token.next); | |
| 8447 return second; | |
| 8448 } | |
| 8449 return null; | |
| 8450 } | |
| 8451 | |
| 8452 /** | |
| 8453 * Parse a type name, starting at the [startToken], without actually creating | |
| 8454 * a type name or changing the current token. Return the token following the | |
| 8455 * type name that was parsed, or `null` if the given token is not the first | |
| 8456 * token in a valid type name. | |
| 8457 * | |
| 8458 * This method must be kept in sync with [parseTypeName]. | |
| 8459 * | |
| 8460 * type ::= | |
| 8461 * qualified typeArguments? | |
| 8462 */ | |
| 8463 Token _skipTypeName(Token startToken) { | |
| 8464 Token token = _skipPrefixedIdentifier(startToken); | |
| 8465 if (token == null) { | |
| 8466 return null; | |
| 8467 } | |
| 8468 if (_tokenMatches(token, TokenType.LT)) { | |
| 8469 token = _skipTypeArgumentList(token); | |
| 8470 } | |
| 8471 return token; | |
| 8472 } | |
| 8473 | |
| 8474 /** | |
| 8475 * Parse a list of type parameters, starting at the [startToken], without | 7534 * Parse a list of type parameters, starting at the [startToken], without |
| 8476 * actually creating a type parameter list or changing the current token. | 7535 * actually creating a type parameter list or changing the current token. |
| 8477 * Return the token following the type parameter list that was parsed, or | 7536 * Return the token following the type parameter list that was parsed, or |
| 8478 * `null` if the given token is not the first token in a valid type parameter | 7537 * `null` if the given token is not the first token in a valid type parameter |
| 8479 * list. | 7538 * list. |
| 8480 * | 7539 * |
| 8481 * This method must be kept in sync with [parseTypeParameterList]. | 7540 * This method must be kept in sync with [parseTypeParameterList]. |
| 8482 * | 7541 * |
| 8483 * typeParameterList ::= | 7542 * typeParameterList ::= |
| 8484 * '<' typeParameter (',' typeParameter)* '>' | 7543 * '<' typeParameter (',' typeParameter)* '>' |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 8528 * Return `true` if the given [token] has the given [type]. | 7587 * Return `true` if the given [token] has the given [type]. |
| 8529 */ | 7588 */ |
| 8530 bool _tokenMatches(Token token, TokenType type) => token.type == type; | 7589 bool _tokenMatches(Token token, TokenType type) => token.type == type; |
| 8531 | 7590 |
| 8532 /** | 7591 /** |
| 8533 * Return `true` if the given [token] is a valid identifier. Valid identifiers | 7592 * Return `true` if the given [token] is a valid identifier. Valid identifiers |
| 8534 * include built-in identifiers (pseudo-keywords). | 7593 * include built-in identifiers (pseudo-keywords). |
| 8535 */ | 7594 */ |
| 8536 bool _tokenMatchesIdentifier(Token token) => | 7595 bool _tokenMatchesIdentifier(Token token) => |
| 8537 _tokenMatches(token, TokenType.IDENTIFIER) || | 7596 _tokenMatches(token, TokenType.IDENTIFIER) || |
| 8538 _tokenMatchesPseudoKeyword(token); | 7597 _tokenMatchesPseudoKeyword(token); |
| 8539 | 7598 |
| 8540 /** | 7599 /** |
| 8541 * Return `true` if the given [token] matches the given [keyword]. | 7600 * Return `true` if the given [token] matches the given [keyword]. |
| 8542 */ | 7601 */ |
| 8543 bool _tokenMatchesKeyword(Token token, Keyword keyword) => | 7602 bool _tokenMatchesKeyword(Token token, Keyword keyword) => |
| 8544 token.type == TokenType.KEYWORD && | 7603 token.keyword == keyword; |
| 8545 (token as KeywordToken).keyword == keyword; | |
| 8546 | 7604 |
| 8547 /** | 7605 /** |
| 8548 * Return `true` if the given [token] matches a pseudo keyword. | 7606 * Return `true` if the given [token] matches a pseudo keyword. |
| 8549 */ | 7607 */ |
| 8550 bool _tokenMatchesPseudoKeyword(Token token) => | 7608 bool _tokenMatchesPseudoKeyword(Token token) => |
| 8551 _tokenMatches(token, TokenType.KEYWORD) && | 7609 token.keyword?.isPseudoKeyword ?? false; |
| 8552 (token as KeywordToken).keyword.isPseudoKeyword; | |
| 8553 | 7610 |
| 8554 /** | 7611 /** |
| 8555 * Return `true` if the given [token] matches the given [identifier]. | 7612 * Return `true` if the given [token] matches the given [identifier]. |
| 8556 */ | 7613 */ |
| 8557 bool _tokenMatchesString(Token token, String identifier) => | 7614 bool _tokenMatchesString(Token token, String identifier) => |
| 8558 token.type == TokenType.IDENTIFIER && token.lexeme == identifier; | 7615 token.type == TokenType.IDENTIFIER && token.lexeme == identifier; |
| 8559 | 7616 |
| 8560 /** | 7617 /** |
| 8561 * Translate the characters at the given [index] in the given [lexeme], | 7618 * Translate the characters at the given [index] in the given [lexeme], |
| 8562 * appending the translated character to the given [buffer]. The index is | 7619 * appending the translated character to the given [buffer]. The index is |
| (...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 8654 // Illegal escape sequence: incomplete escape | 7711 // Illegal escape sequence: incomplete escape |
| 8655 _reportErrorForCurrentToken(ParserErrorCode.INVALID_UNICODE_ESCAPE); | 7712 _reportErrorForCurrentToken(ParserErrorCode.INVALID_UNICODE_ESCAPE); |
| 8656 return length; | 7713 return length; |
| 8657 } | 7714 } |
| 8658 currentChar = lexeme.codeUnitAt(currentIndex); | 7715 currentChar = lexeme.codeUnitAt(currentIndex); |
| 8659 } | 7716 } |
| 8660 if (digitCount < 1 || digitCount > 6) { | 7717 if (digitCount < 1 || digitCount > 6) { |
| 8661 // Illegal escape sequence: not enough or too many hex digits | 7718 // Illegal escape sequence: not enough or too many hex digits |
| 8662 _reportErrorForCurrentToken(ParserErrorCode.INVALID_UNICODE_ESCAPE); | 7719 _reportErrorForCurrentToken(ParserErrorCode.INVALID_UNICODE_ESCAPE); |
| 8663 } | 7720 } |
| 8664 _appendScalarValue(buffer, lexeme.substring(index, currentIndex + 1), | 7721 _appendCodePoint(buffer, lexeme, value, index, currentIndex); |
| 8665 value, index, currentIndex); | |
| 8666 return currentIndex + 1; | 7722 return currentIndex + 1; |
| 8667 } else { | 7723 } else { |
| 8668 if (currentIndex + 3 >= length) { | 7724 if (currentIndex + 3 >= length) { |
| 8669 // Illegal escape sequence: not enough hex digits | 7725 // Illegal escape sequence: not enough hex digits |
| 8670 _reportErrorForCurrentToken(ParserErrorCode.INVALID_UNICODE_ESCAPE); | 7726 _reportErrorForCurrentToken(ParserErrorCode.INVALID_UNICODE_ESCAPE); |
| 8671 return length; | 7727 return length; |
| 8672 } | 7728 } |
| 8673 int firstDigit = currentChar; | 7729 int firstDigit = currentChar; |
| 8674 int secondDigit = lexeme.codeUnitAt(currentIndex + 1); | 7730 int secondDigit = lexeme.codeUnitAt(currentIndex + 1); |
| 8675 int thirdDigit = lexeme.codeUnitAt(currentIndex + 2); | 7731 int thirdDigit = lexeme.codeUnitAt(currentIndex + 2); |
| 8676 int fourthDigit = lexeme.codeUnitAt(currentIndex + 3); | 7732 int fourthDigit = lexeme.codeUnitAt(currentIndex + 3); |
| 8677 if (!_isHexDigit(firstDigit) || | 7733 if (!_isHexDigit(firstDigit) || |
| 8678 !_isHexDigit(secondDigit) || | 7734 !_isHexDigit(secondDigit) || |
| 8679 !_isHexDigit(thirdDigit) || | 7735 !_isHexDigit(thirdDigit) || |
| 8680 !_isHexDigit(fourthDigit)) { | 7736 !_isHexDigit(fourthDigit)) { |
| 8681 // Illegal escape sequence: invalid hex digits | 7737 // Illegal escape sequence: invalid hex digits |
| 8682 _reportErrorForCurrentToken(ParserErrorCode.INVALID_UNICODE_ESCAPE); | 7738 _reportErrorForCurrentToken(ParserErrorCode.INVALID_UNICODE_ESCAPE); |
| 8683 } else { | 7739 } else { |
| 8684 _appendScalarValue( | 7740 _appendCodePoint( |
| 8685 buffer, | 7741 buffer, |
| 8686 lexeme.substring(index, currentIndex + 1), | 7742 lexeme, |
| 8687 (((((Character.digit(firstDigit, 16) << 4) + | 7743 (((((Character.digit(firstDigit, 16) << 4) + |
| 8688 Character.digit(secondDigit, 16)) << | 7744 Character.digit(secondDigit, 16)) << |
| 8689 4) + | 7745 4) + |
| 8690 Character.digit(thirdDigit, 16)) << | 7746 Character.digit(thirdDigit, 16)) << |
| 8691 4) + | 7747 4) + |
| 8692 Character.digit(fourthDigit, 16), | 7748 Character.digit(fourthDigit, 16), |
| 8693 index, | 7749 index, |
| 8694 currentIndex + 3); | 7750 currentIndex + 3); |
| 8695 } | 7751 } |
| 8696 return currentIndex + 4; | 7752 return currentIndex + 4; |
| 8697 } | 7753 } |
| 8698 } else { | 7754 } else { |
| 8699 buffer.writeCharCode(currentChar); | 7755 buffer.writeCharCode(currentChar); |
| 8700 } | 7756 } |
| 8701 return currentIndex + 1; | 7757 return currentIndex + 1; |
| 8702 } | 7758 } |
| 8703 | 7759 |
| 8704 /** | 7760 /** |
| 8705 * Decrements the error reporting lock level. If level is more than `0`, then | 7761 * Decrements the error reporting lock level. If level is more than `0`, then |
| 8706 * [reportError] wont report any error. | 7762 * [reportError] wont report any error. |
| 8707 */ | 7763 */ |
| 8708 void _unlockErrorListener() { | 7764 void _unlockErrorListener() { |
| 8709 if (_errorListenerLock == 0) { | 7765 if (_errorListenerLock == 0) { |
| 8710 throw new IllegalStateException( | 7766 throw new StateError("Attempt to unlock not locked error listener."); |
| 8711 "Attempt to unlock not locked error listener."); | |
| 8712 } | 7767 } |
| 8713 _errorListenerLock--; | 7768 _errorListenerLock--; |
| 8714 } | 7769 } |
| 8715 | 7770 |
| 8716 /** | 7771 /** |
| 8717 * Validate that the given [parameterList] does not contain any field | 7772 * Validate that the given [parameterList] does not contain any field |
| 8718 * initializers. | 7773 * initializers. |
| 8719 */ | 7774 */ |
| 8720 void _validateFormalParameterList(FormalParameterList parameterList) { | 7775 void _validateFormalParameterList(FormalParameterList parameterList) { |
| 8721 for (FormalParameter parameter in parameterList.parameters) { | 7776 for (FormalParameter parameter in parameterList.parameters) { |
| (...skipping 322 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 9044 */ | 8099 */ |
| 9045 Parser_SyntheticKeywordToken(Keyword keyword, int offset) | 8100 Parser_SyntheticKeywordToken(Keyword keyword, int offset) |
| 9046 : super(keyword, offset); | 8101 : super(keyword, offset); |
| 9047 | 8102 |
| 9048 @override | 8103 @override |
| 9049 int get length => 0; | 8104 int get length => 0; |
| 9050 | 8105 |
| 9051 @override | 8106 @override |
| 9052 Token copy() => new Parser_SyntheticKeywordToken(keyword, offset); | 8107 Token copy() => new Parser_SyntheticKeywordToken(keyword, offset); |
| 9053 } | 8108 } |
| 9054 | |
| 9055 /** | |
| 9056 * The error codes used for errors detected by the parser. The convention for | |
| 9057 * this class is for the name of the error code to indicate the problem that | |
| 9058 * caused the error to be generated and for the error message to explain what | |
| 9059 * is wrong and, when appropriate, how the problem can be corrected. | |
| 9060 */ | |
| 9061 class ParserErrorCode extends ErrorCode { | |
| 9062 static const ParserErrorCode ABSTRACT_CLASS_MEMBER = const ParserErrorCode( | |
| 9063 'ABSTRACT_CLASS_MEMBER', | |
| 9064 "Members of classes cannot be declared to be 'abstract'"); | |
| 9065 | |
| 9066 static const ParserErrorCode ABSTRACT_ENUM = const ParserErrorCode( | |
| 9067 'ABSTRACT_ENUM', "Enums cannot be declared to be 'abstract'"); | |
| 9068 | |
| 9069 static const ParserErrorCode ABSTRACT_STATIC_METHOD = const ParserErrorCode( | |
| 9070 'ABSTRACT_STATIC_METHOD', | |
| 9071 "Static methods cannot be declared to be 'abstract'"); | |
| 9072 | |
| 9073 static const ParserErrorCode ABSTRACT_TOP_LEVEL_FUNCTION = | |
| 9074 const ParserErrorCode('ABSTRACT_TOP_LEVEL_FUNCTION', | |
| 9075 "Top-level functions cannot be declared to be 'abstract'"); | |
| 9076 | |
| 9077 static const ParserErrorCode ABSTRACT_TOP_LEVEL_VARIABLE = | |
| 9078 const ParserErrorCode('ABSTRACT_TOP_LEVEL_VARIABLE', | |
| 9079 "Top-level variables cannot be declared to be 'abstract'"); | |
| 9080 | |
| 9081 static const ParserErrorCode ABSTRACT_TYPEDEF = const ParserErrorCode( | |
| 9082 'ABSTRACT_TYPEDEF', "Type aliases cannot be declared to be 'abstract'"); | |
| 9083 | |
| 9084 static const ParserErrorCode ANNOTATION_ON_ENUM_CONSTANT = | |
| 9085 const ParserErrorCode('ANNOTATION_ON_ENUM_CONSTANT', | |
| 9086 "Enum constants cannot have annotations"); | |
| 9087 | |
| 9088 static const ParserErrorCode ASSERT_DOES_NOT_TAKE_ASSIGNMENT = | |
| 9089 const ParserErrorCode('ASSERT_DOES_NOT_TAKE_ASSIGNMENT', | |
| 9090 "Assert cannot be called on an assignment"); | |
| 9091 | |
| 9092 static const ParserErrorCode ASSERT_DOES_NOT_TAKE_CASCADE = | |
| 9093 const ParserErrorCode( | |
| 9094 'ASSERT_DOES_NOT_TAKE_CASCADE', "Assert cannot be called on cascade"); | |
| 9095 | |
| 9096 static const ParserErrorCode ASSERT_DOES_NOT_TAKE_THROW = | |
| 9097 const ParserErrorCode( | |
| 9098 'ASSERT_DOES_NOT_TAKE_THROW', "Assert cannot be called on throws"); | |
| 9099 | |
| 9100 static const ParserErrorCode ASSERT_DOES_NOT_TAKE_RETHROW = | |
| 9101 const ParserErrorCode('ASSERT_DOES_NOT_TAKE_RETHROW', | |
| 9102 "Assert cannot be called on rethrows"); | |
| 9103 | |
| 9104 /** | |
| 9105 * 16.32 Identifier Reference: It is a compile-time error if any of the | |
| 9106 * identifiers async, await, or yield is used as an identifier in a function | |
| 9107 * body marked with either async, async*, or sync*. | |
| 9108 */ | |
| 9109 static const ParserErrorCode ASYNC_KEYWORD_USED_AS_IDENTIFIER = | |
| 9110 const ParserErrorCode('ASYNC_KEYWORD_USED_AS_IDENTIFIER', | |
| 9111 "The keywords 'async', 'await', and 'yield' may not be used as identif
iers in an asynchronous or generator function."); | |
| 9112 | |
| 9113 static const ParserErrorCode BREAK_OUTSIDE_OF_LOOP = const ParserErrorCode( | |
| 9114 'BREAK_OUTSIDE_OF_LOOP', | |
| 9115 "A break statement cannot be used outside of a loop or switch statement"); | |
| 9116 | |
| 9117 static const ParserErrorCode CLASS_IN_CLASS = const ParserErrorCode( | |
| 9118 'CLASS_IN_CLASS', "Classes cannot be declared inside other classes"); | |
| 9119 | |
| 9120 static const ParserErrorCode COLON_IN_PLACE_OF_IN = const ParserErrorCode( | |
| 9121 'COLON_IN_PLACE_OF_IN', "For-in loops use 'in' rather than a colon"); | |
| 9122 | |
| 9123 static const ParserErrorCode CONST_AND_FINAL = const ParserErrorCode( | |
| 9124 'CONST_AND_FINAL', | |
| 9125 "Members cannot be declared to be both 'const' and 'final'"); | |
| 9126 | |
| 9127 static const ParserErrorCode CONST_AND_VAR = const ParserErrorCode( | |
| 9128 'CONST_AND_VAR', | |
| 9129 "Members cannot be declared to be both 'const' and 'var'"); | |
| 9130 | |
| 9131 static const ParserErrorCode CONST_CLASS = const ParserErrorCode( | |
| 9132 'CONST_CLASS', "Classes cannot be declared to be 'const'"); | |
| 9133 | |
| 9134 static const ParserErrorCode CONST_CONSTRUCTOR_WITH_BODY = | |
| 9135 const ParserErrorCode('CONST_CONSTRUCTOR_WITH_BODY', | |
| 9136 "'const' constructors cannot have a body"); | |
| 9137 | |
| 9138 static const ParserErrorCode CONST_ENUM = const ParserErrorCode( | |
| 9139 'CONST_ENUM', "Enums cannot be declared to be 'const'"); | |
| 9140 | |
| 9141 static const ParserErrorCode CONST_FACTORY = const ParserErrorCode( | |
| 9142 'CONST_FACTORY', | |
| 9143 "Only redirecting factory constructors can be declared to be 'const'"); | |
| 9144 | |
| 9145 static const ParserErrorCode CONST_METHOD = const ParserErrorCode( | |
| 9146 'CONST_METHOD', | |
| 9147 "Getters, setters and methods cannot be declared to be 'const'"); | |
| 9148 | |
| 9149 static const ParserErrorCode CONST_TYPEDEF = const ParserErrorCode( | |
| 9150 'CONST_TYPEDEF', "Type aliases cannot be declared to be 'const'"); | |
| 9151 | |
| 9152 static const ParserErrorCode CONSTRUCTOR_WITH_RETURN_TYPE = | |
| 9153 const ParserErrorCode('CONSTRUCTOR_WITH_RETURN_TYPE', | |
| 9154 "Constructors cannot have a return type"); | |
| 9155 | |
| 9156 static const ParserErrorCode CONTINUE_OUTSIDE_OF_LOOP = const ParserErrorCode( | |
| 9157 'CONTINUE_OUTSIDE_OF_LOOP', | |
| 9158 "A continue statement cannot be used outside of a loop or switch statement
"); | |
| 9159 | |
| 9160 static const ParserErrorCode CONTINUE_WITHOUT_LABEL_IN_CASE = | |
| 9161 const ParserErrorCode('CONTINUE_WITHOUT_LABEL_IN_CASE', | |
| 9162 "A continue statement in a switch statement must have a label as a tar
get"); | |
| 9163 | |
| 9164 static const ParserErrorCode DEPRECATED_CLASS_TYPE_ALIAS = | |
| 9165 const ParserErrorCode('DEPRECATED_CLASS_TYPE_ALIAS', | |
| 9166 "The 'typedef' mixin application was replaced with 'class'"); | |
| 9167 | |
| 9168 static const ParserErrorCode DIRECTIVE_AFTER_DECLARATION = | |
| 9169 const ParserErrorCode('DIRECTIVE_AFTER_DECLARATION', | |
| 9170 "Directives must appear before any declarations"); | |
| 9171 | |
| 9172 static const ParserErrorCode DUPLICATE_LABEL_IN_SWITCH_STATEMENT = | |
| 9173 const ParserErrorCode('DUPLICATE_LABEL_IN_SWITCH_STATEMENT', | |
| 9174 "The label {0} was already used in this switch statement"); | |
| 9175 | |
| 9176 static const ParserErrorCode DUPLICATED_MODIFIER = const ParserErrorCode( | |
| 9177 'DUPLICATED_MODIFIER', "The modifier '{0}' was already specified."); | |
| 9178 | |
| 9179 static const ParserErrorCode EMPTY_ENUM_BODY = const ParserErrorCode( | |
| 9180 'EMPTY_ENUM_BODY', "An enum must declare at least one constant name"); | |
| 9181 | |
| 9182 static const ParserErrorCode ENUM_IN_CLASS = const ParserErrorCode( | |
| 9183 'ENUM_IN_CLASS', "Enums cannot be declared inside classes"); | |
| 9184 | |
| 9185 static const ParserErrorCode EQUALITY_CANNOT_BE_EQUALITY_OPERAND = | |
| 9186 const ParserErrorCode('EQUALITY_CANNOT_BE_EQUALITY_OPERAND', | |
| 9187 "Equality expression cannot be operand of another equality expression.
"); | |
| 9188 | |
| 9189 static const ParserErrorCode EXPECTED_CASE_OR_DEFAULT = const ParserErrorCode( | |
| 9190 'EXPECTED_CASE_OR_DEFAULT', "Expected 'case' or 'default'"); | |
| 9191 | |
| 9192 static const ParserErrorCode EXPECTED_CLASS_MEMBER = | |
| 9193 const ParserErrorCode('EXPECTED_CLASS_MEMBER', "Expected a class member"); | |
| 9194 | |
| 9195 static const ParserErrorCode EXPECTED_EXECUTABLE = const ParserErrorCode( | |
| 9196 'EXPECTED_EXECUTABLE', | |
| 9197 "Expected a method, getter, setter or operator declaration"); | |
| 9198 | |
| 9199 static const ParserErrorCode EXPECTED_LIST_OR_MAP_LITERAL = | |
| 9200 const ParserErrorCode( | |
| 9201 'EXPECTED_LIST_OR_MAP_LITERAL', "Expected a list or map literal"); | |
| 9202 | |
| 9203 static const ParserErrorCode EXPECTED_STRING_LITERAL = const ParserErrorCode( | |
| 9204 'EXPECTED_STRING_LITERAL', "Expected a string literal"); | |
| 9205 | |
| 9206 static const ParserErrorCode EXPECTED_TOKEN = | |
| 9207 const ParserErrorCode('EXPECTED_TOKEN', "Expected to find '{0}'"); | |
| 9208 | |
| 9209 static const ParserErrorCode EXPECTED_TYPE_NAME = | |
| 9210 const ParserErrorCode('EXPECTED_TYPE_NAME', "Expected a type name"); | |
| 9211 | |
| 9212 static const ParserErrorCode EXPORT_DIRECTIVE_AFTER_PART_DIRECTIVE = | |
| 9213 const ParserErrorCode('EXPORT_DIRECTIVE_AFTER_PART_DIRECTIVE', | |
| 9214 "Export directives must preceed part directives"); | |
| 9215 | |
| 9216 static const ParserErrorCode EXTERNAL_AFTER_CONST = const ParserErrorCode( | |
| 9217 'EXTERNAL_AFTER_CONST', | |
| 9218 "The modifier 'external' should be before the modifier 'const'"); | |
| 9219 | |
| 9220 static const ParserErrorCode EXTERNAL_AFTER_FACTORY = const ParserErrorCode( | |
| 9221 'EXTERNAL_AFTER_FACTORY', | |
| 9222 "The modifier 'external' should be before the modifier 'factory'"); | |
| 9223 | |
| 9224 static const ParserErrorCode EXTERNAL_AFTER_STATIC = const ParserErrorCode( | |
| 9225 'EXTERNAL_AFTER_STATIC', | |
| 9226 "The modifier 'external' should be before the modifier 'static'"); | |
| 9227 | |
| 9228 static const ParserErrorCode EXTERNAL_CLASS = const ParserErrorCode( | |
| 9229 'EXTERNAL_CLASS', "Classes cannot be declared to be 'external'"); | |
| 9230 | |
| 9231 static const ParserErrorCode EXTERNAL_CONSTRUCTOR_WITH_BODY = | |
| 9232 const ParserErrorCode('EXTERNAL_CONSTRUCTOR_WITH_BODY', | |
| 9233 "External constructors cannot have a body"); | |
| 9234 | |
| 9235 static const ParserErrorCode EXTERNAL_ENUM = const ParserErrorCode( | |
| 9236 'EXTERNAL_ENUM', "Enums cannot be declared to be 'external'"); | |
| 9237 | |
| 9238 static const ParserErrorCode EXTERNAL_FIELD = const ParserErrorCode( | |
| 9239 'EXTERNAL_FIELD', "Fields cannot be declared to be 'external'"); | |
| 9240 | |
| 9241 static const ParserErrorCode EXTERNAL_GETTER_WITH_BODY = | |
| 9242 const ParserErrorCode( | |
| 9243 'EXTERNAL_GETTER_WITH_BODY', "External getters cannot have a body"); | |
| 9244 | |
| 9245 static const ParserErrorCode EXTERNAL_METHOD_WITH_BODY = | |
| 9246 const ParserErrorCode( | |
| 9247 'EXTERNAL_METHOD_WITH_BODY', "External methods cannot have a body"); | |
| 9248 | |
| 9249 static const ParserErrorCode EXTERNAL_OPERATOR_WITH_BODY = | |
| 9250 const ParserErrorCode('EXTERNAL_OPERATOR_WITH_BODY', | |
| 9251 "External operators cannot have a body"); | |
| 9252 | |
| 9253 static const ParserErrorCode EXTERNAL_SETTER_WITH_BODY = | |
| 9254 const ParserErrorCode( | |
| 9255 'EXTERNAL_SETTER_WITH_BODY', "External setters cannot have a body"); | |
| 9256 | |
| 9257 static const ParserErrorCode EXTERNAL_TYPEDEF = const ParserErrorCode( | |
| 9258 'EXTERNAL_TYPEDEF', "Type aliases cannot be declared to be 'external'"); | |
| 9259 | |
| 9260 static const ParserErrorCode FACTORY_TOP_LEVEL_DECLARATION = | |
| 9261 const ParserErrorCode('FACTORY_TOP_LEVEL_DECLARATION', | |
| 9262 "Top-level declarations cannot be declared to be 'factory'"); | |
| 9263 | |
| 9264 static const ParserErrorCode FACTORY_WITH_INITIALIZERS = | |
| 9265 const ParserErrorCode( | |
| 9266 'FACTORY_WITH_INITIALIZERS', | |
| 9267 "A 'factory' constructor cannot have initializers", | |
| 9268 "Either remove the 'factory' keyword to make this a generative " | |
| 9269 "constructor or remove the initializers."); | |
| 9270 | |
| 9271 static const ParserErrorCode FACTORY_WITHOUT_BODY = const ParserErrorCode( | |
| 9272 'FACTORY_WITHOUT_BODY', | |
| 9273 "A non-redirecting 'factory' constructor must have a body"); | |
| 9274 | |
| 9275 static const ParserErrorCode FIELD_INITIALIZER_OUTSIDE_CONSTRUCTOR = | |
| 9276 const ParserErrorCode('FIELD_INITIALIZER_OUTSIDE_CONSTRUCTOR', | |
| 9277 "Field initializers can only be used in a constructor"); | |
| 9278 | |
| 9279 static const ParserErrorCode FINAL_AND_VAR = const ParserErrorCode( | |
| 9280 'FINAL_AND_VAR', | |
| 9281 "Members cannot be declared to be both 'final' and 'var'"); | |
| 9282 | |
| 9283 static const ParserErrorCode FINAL_CLASS = const ParserErrorCode( | |
| 9284 'FINAL_CLASS', "Classes cannot be declared to be 'final'"); | |
| 9285 | |
| 9286 static const ParserErrorCode FINAL_CONSTRUCTOR = const ParserErrorCode( | |
| 9287 'FINAL_CONSTRUCTOR', "A constructor cannot be declared to be 'final'"); | |
| 9288 | |
| 9289 static const ParserErrorCode FINAL_ENUM = const ParserErrorCode( | |
| 9290 'FINAL_ENUM', "Enums cannot be declared to be 'final'"); | |
| 9291 | |
| 9292 static const ParserErrorCode FINAL_METHOD = const ParserErrorCode( | |
| 9293 'FINAL_METHOD', | |
| 9294 "Getters, setters and methods cannot be declared to be 'final'"); | |
| 9295 | |
| 9296 static const ParserErrorCode FINAL_TYPEDEF = const ParserErrorCode( | |
| 9297 'FINAL_TYPEDEF', "Type aliases cannot be declared to be 'final'"); | |
| 9298 | |
| 9299 static const ParserErrorCode FUNCTION_TYPED_PARAMETER_VAR = const ParserErrorC
ode( | |
| 9300 'FUNCTION_TYPED_PARAMETER_VAR', | |
| 9301 "Function typed parameters cannot specify 'const', 'final' or 'var' instea
d of return type"); | |
| 9302 | |
| 9303 static const ParserErrorCode GETTER_IN_FUNCTION = const ParserErrorCode( | |
| 9304 'GETTER_IN_FUNCTION', | |
| 9305 "Getters cannot be defined within methods or functions"); | |
| 9306 | |
| 9307 static const ParserErrorCode GETTER_WITH_PARAMETERS = const ParserErrorCode( | |
| 9308 'GETTER_WITH_PARAMETERS', | |
| 9309 "Getter should be declared without a parameter list"); | |
| 9310 | |
| 9311 static const ParserErrorCode ILLEGAL_ASSIGNMENT_TO_NON_ASSIGNABLE = | |
| 9312 const ParserErrorCode('ILLEGAL_ASSIGNMENT_TO_NON_ASSIGNABLE', | |
| 9313 "Illegal assignment to non-assignable expression"); | |
| 9314 | |
| 9315 static const ParserErrorCode IMPLEMENTS_BEFORE_EXTENDS = | |
| 9316 const ParserErrorCode('IMPLEMENTS_BEFORE_EXTENDS', | |
| 9317 "The extends clause must be before the implements clause"); | |
| 9318 | |
| 9319 static const ParserErrorCode IMPLEMENTS_BEFORE_WITH = const ParserErrorCode( | |
| 9320 'IMPLEMENTS_BEFORE_WITH', | |
| 9321 "The with clause must be before the implements clause"); | |
| 9322 | |
| 9323 static const ParserErrorCode IMPORT_DIRECTIVE_AFTER_PART_DIRECTIVE = | |
| 9324 const ParserErrorCode('IMPORT_DIRECTIVE_AFTER_PART_DIRECTIVE', | |
| 9325 "Import directives must preceed part directives"); | |
| 9326 | |
| 9327 static const ParserErrorCode INITIALIZED_VARIABLE_IN_FOR_EACH = | |
| 9328 const ParserErrorCode('INITIALIZED_VARIABLE_IN_FOR_EACH', | |
| 9329 "The loop variable in a for-each loop cannot be initialized"); | |
| 9330 | |
| 9331 static const ParserErrorCode INVALID_AWAIT_IN_FOR = const ParserErrorCode( | |
| 9332 'INVALID_AWAIT_IN_FOR', | |
| 9333 "The modifier 'await' is not allowed for a normal 'for' statement", | |
| 9334 "Remove the keyword or use a for-each statement."); | |
| 9335 | |
| 9336 static const ParserErrorCode INVALID_CODE_POINT = const ParserErrorCode( | |
| 9337 'INVALID_CODE_POINT', | |
| 9338 "The escape sequence '{0}' is not a valid code point"); | |
| 9339 | |
| 9340 static const ParserErrorCode INVALID_COMMENT_REFERENCE = const ParserErrorCode
( | |
| 9341 'INVALID_COMMENT_REFERENCE', | |
| 9342 "Comment references should contain a possibly prefixed identifier and can
start with 'new', but should not contain anything else"); | |
| 9343 | |
| 9344 static const ParserErrorCode INVALID_HEX_ESCAPE = const ParserErrorCode( | |
| 9345 'INVALID_HEX_ESCAPE', | |
| 9346 "An escape sequence starting with '\\x' must be followed by 2 hexidecimal
digits"); | |
| 9347 | |
| 9348 static const ParserErrorCode INVALID_OPERATOR = const ParserErrorCode( | |
| 9349 'INVALID_OPERATOR', "The string '{0}' is not a valid operator"); | |
| 9350 | |
| 9351 static const ParserErrorCode INVALID_OPERATOR_FOR_SUPER = | |
| 9352 const ParserErrorCode('INVALID_OPERATOR_FOR_SUPER', | |
| 9353 "The operator '{0}' cannot be used with 'super'"); | |
| 9354 | |
| 9355 static const ParserErrorCode INVALID_STAR_AFTER_ASYNC = const ParserErrorCode( | |
| 9356 'INVALID_STAR_AFTER_ASYNC', | |
| 9357 "The modifier 'async*' is not allowed for an expression function body", | |
| 9358 "Convert the body to a block."); | |
| 9359 | |
| 9360 static const ParserErrorCode INVALID_SYNC = const ParserErrorCode( | |
| 9361 'INVALID_SYNC', | |
| 9362 "The modifier 'sync' is not allowed for an exrpression function body", | |
| 9363 "Convert the body to a block."); | |
| 9364 | |
| 9365 static const ParserErrorCode INVALID_UNICODE_ESCAPE = const ParserErrorCode( | |
| 9366 'INVALID_UNICODE_ESCAPE', | |
| 9367 "An escape sequence starting with '\\u' must be followed by 4 hexidecimal
digits or from 1 to 6 digits between '{' and '}'"); | |
| 9368 | |
| 9369 static const ParserErrorCode LIBRARY_DIRECTIVE_NOT_FIRST = | |
| 9370 const ParserErrorCode('LIBRARY_DIRECTIVE_NOT_FIRST', | |
| 9371 "The library directive must appear before all other directives"); | |
| 9372 | |
| 9373 static const ParserErrorCode LOCAL_FUNCTION_DECLARATION_MODIFIER = | |
| 9374 const ParserErrorCode('LOCAL_FUNCTION_DECLARATION_MODIFIER', | |
| 9375 "Local function declarations cannot specify any modifier"); | |
| 9376 | |
| 9377 static const ParserErrorCode MISSING_ASSIGNABLE_SELECTOR = | |
| 9378 const ParserErrorCode('MISSING_ASSIGNABLE_SELECTOR', | |
| 9379 "Missing selector such as \".<identifier>\" or \"[0]\""); | |
| 9380 | |
| 9381 static const ParserErrorCode MISSING_ASSIGNMENT_IN_INITIALIZER = | |
| 9382 const ParserErrorCode('MISSING_ASSIGNMENT_IN_INITIALIZER', | |
| 9383 "Expected an assignment after the field name"); | |
| 9384 | |
| 9385 static const ParserErrorCode MISSING_CATCH_OR_FINALLY = const ParserErrorCode( | |
| 9386 'MISSING_CATCH_OR_FINALLY', | |
| 9387 "A try statement must have either a catch or finally clause"); | |
| 9388 | |
| 9389 static const ParserErrorCode MISSING_CLASS_BODY = const ParserErrorCode( | |
| 9390 'MISSING_CLASS_BODY', | |
| 9391 "A class definition must have a body, even if it is empty"); | |
| 9392 | |
| 9393 static const ParserErrorCode MISSING_CLOSING_PARENTHESIS = | |
| 9394 const ParserErrorCode( | |
| 9395 'MISSING_CLOSING_PARENTHESIS', "The closing parenthesis is missing"); | |
| 9396 | |
| 9397 static const ParserErrorCode MISSING_CONST_FINAL_VAR_OR_TYPE = | |
| 9398 const ParserErrorCode('MISSING_CONST_FINAL_VAR_OR_TYPE', | |
| 9399 "Variables must be declared using the keywords 'const', 'final', 'var'
or a type name"); | |
| 9400 | |
| 9401 static const ParserErrorCode MISSING_ENUM_BODY = const ParserErrorCode( | |
| 9402 'MISSING_ENUM_BODY', | |
| 9403 "An enum definition must have a body with at least one constant name"); | |
| 9404 | |
| 9405 static const ParserErrorCode MISSING_EXPRESSION_IN_INITIALIZER = | |
| 9406 const ParserErrorCode('MISSING_EXPRESSION_IN_INITIALIZER', | |
| 9407 "Expected an expression after the assignment operator"); | |
| 9408 | |
| 9409 static const ParserErrorCode MISSING_EXPRESSION_IN_THROW = | |
| 9410 const ParserErrorCode('MISSING_EXPRESSION_IN_THROW', | |
| 9411 "Throw expressions must compute the object to be thrown"); | |
| 9412 | |
| 9413 static const ParserErrorCode MISSING_FUNCTION_BODY = const ParserErrorCode( | |
| 9414 'MISSING_FUNCTION_BODY', "A function body must be provided"); | |
| 9415 | |
| 9416 static const ParserErrorCode MISSING_FUNCTION_PARAMETERS = | |
| 9417 const ParserErrorCode('MISSING_FUNCTION_PARAMETERS', | |
| 9418 "Functions must have an explicit list of parameters"); | |
| 9419 | |
| 9420 static const ParserErrorCode MISSING_METHOD_PARAMETERS = | |
| 9421 const ParserErrorCode('MISSING_METHOD_PARAMETERS', | |
| 9422 "Methods must have an explicit list of parameters"); | |
| 9423 | |
| 9424 static const ParserErrorCode MISSING_GET = const ParserErrorCode( | |
| 9425 'MISSING_GET', | |
| 9426 "Getters must have the keyword 'get' before the getter name"); | |
| 9427 | |
| 9428 static const ParserErrorCode MISSING_IDENTIFIER = | |
| 9429 const ParserErrorCode('MISSING_IDENTIFIER', "Expected an identifier"); | |
| 9430 | |
| 9431 static const ParserErrorCode MISSING_INITIALIZER = | |
| 9432 const ParserErrorCode('MISSING_INITIALIZER', "Expected an initializer"); | |
| 9433 | |
| 9434 static const ParserErrorCode MISSING_KEYWORD_OPERATOR = const ParserErrorCode( | |
| 9435 'MISSING_KEYWORD_OPERATOR', | |
| 9436 "Operator declarations must be preceeded by the keyword 'operator'"); | |
| 9437 | |
| 9438 static const ParserErrorCode MISSING_NAME_IN_LIBRARY_DIRECTIVE = | |
| 9439 const ParserErrorCode('MISSING_NAME_IN_LIBRARY_DIRECTIVE', | |
| 9440 "Library directives must include a library name"); | |
| 9441 | |
| 9442 static const ParserErrorCode MISSING_NAME_IN_PART_OF_DIRECTIVE = | |
| 9443 const ParserErrorCode('MISSING_NAME_IN_PART_OF_DIRECTIVE', | |
| 9444 "Library directives must include a library name"); | |
| 9445 | |
| 9446 static const ParserErrorCode MISSING_PREFIX_IN_DEFERRED_IMPORT = | |
| 9447 const ParserErrorCode('MISSING_PREFIX_IN_DEFERRED_IMPORT', | |
| 9448 "Deferred imports must have a prefix"); | |
| 9449 | |
| 9450 static const ParserErrorCode MISSING_STAR_AFTER_SYNC = const ParserErrorCode( | |
| 9451 'MISSING_STAR_AFTER_SYNC', | |
| 9452 "The modifier 'sync' must be followed by a star ('*')", | |
| 9453 "Remove the modifier or add a star."); | |
| 9454 | |
| 9455 static const ParserErrorCode MISSING_STATEMENT = | |
| 9456 const ParserErrorCode('MISSING_STATEMENT', "Expected a statement"); | |
| 9457 | |
| 9458 static const ParserErrorCode MISSING_TERMINATOR_FOR_PARAMETER_GROUP = | |
| 9459 const ParserErrorCode('MISSING_TERMINATOR_FOR_PARAMETER_GROUP', | |
| 9460 "There is no '{0}' to close the parameter group"); | |
| 9461 | |
| 9462 static const ParserErrorCode MISSING_TYPEDEF_PARAMETERS = | |
| 9463 const ParserErrorCode('MISSING_TYPEDEF_PARAMETERS', | |
| 9464 "Type aliases for functions must have an explicit list of parameters")
; | |
| 9465 | |
| 9466 static const ParserErrorCode MISSING_VARIABLE_IN_FOR_EACH = const ParserErrorC
ode( | |
| 9467 'MISSING_VARIABLE_IN_FOR_EACH', | |
| 9468 "A loop variable must be declared in a for-each loop before the 'in', but
none were found"); | |
| 9469 | |
| 9470 static const ParserErrorCode MIXED_PARAMETER_GROUPS = const ParserErrorCode( | |
| 9471 'MIXED_PARAMETER_GROUPS', | |
| 9472 "Cannot have both positional and named parameters in a single parameter li
st"); | |
| 9473 | |
| 9474 static const ParserErrorCode MULTIPLE_EXTENDS_CLAUSES = const ParserErrorCode( | |
| 9475 'MULTIPLE_EXTENDS_CLAUSES', | |
| 9476 "Each class definition can have at most one extends clause"); | |
| 9477 | |
| 9478 static const ParserErrorCode MULTIPLE_IMPLEMENTS_CLAUSES = | |
| 9479 const ParserErrorCode('MULTIPLE_IMPLEMENTS_CLAUSES', | |
| 9480 "Each class definition can have at most one implements clause"); | |
| 9481 | |
| 9482 static const ParserErrorCode MULTIPLE_LIBRARY_DIRECTIVES = | |
| 9483 const ParserErrorCode('MULTIPLE_LIBRARY_DIRECTIVES', | |
| 9484 "Only one library directive may be declared in a file"); | |
| 9485 | |
| 9486 static const ParserErrorCode MULTIPLE_NAMED_PARAMETER_GROUPS = | |
| 9487 const ParserErrorCode('MULTIPLE_NAMED_PARAMETER_GROUPS', | |
| 9488 "Cannot have multiple groups of named parameters in a single parameter
list"); | |
| 9489 | |
| 9490 static const ParserErrorCode MULTIPLE_PART_OF_DIRECTIVES = | |
| 9491 const ParserErrorCode('MULTIPLE_PART_OF_DIRECTIVES', | |
| 9492 "Only one part-of directive may be declared in a file"); | |
| 9493 | |
| 9494 static const ParserErrorCode MULTIPLE_POSITIONAL_PARAMETER_GROUPS = | |
| 9495 const ParserErrorCode('MULTIPLE_POSITIONAL_PARAMETER_GROUPS', | |
| 9496 "Cannot have multiple groups of positional parameters in a single para
meter list"); | |
| 9497 | |
| 9498 static const ParserErrorCode MULTIPLE_VARIABLES_IN_FOR_EACH = | |
| 9499 const ParserErrorCode('MULTIPLE_VARIABLES_IN_FOR_EACH', | |
| 9500 "A single loop variable must be declared in a for-each loop before the
'in', but {0} were found"); | |
| 9501 | |
| 9502 static const ParserErrorCode MULTIPLE_WITH_CLAUSES = const ParserErrorCode( | |
| 9503 'MULTIPLE_WITH_CLAUSES', | |
| 9504 "Each class definition can have at most one with clause"); | |
| 9505 | |
| 9506 static const ParserErrorCode NAMED_FUNCTION_EXPRESSION = | |
| 9507 const ParserErrorCode( | |
| 9508 'NAMED_FUNCTION_EXPRESSION', "Function expressions cannot be named"); | |
| 9509 | |
| 9510 static const ParserErrorCode NAMED_PARAMETER_OUTSIDE_GROUP = | |
| 9511 const ParserErrorCode('NAMED_PARAMETER_OUTSIDE_GROUP', | |
| 9512 "Named parameters must be enclosed in curly braces ('{' and '}')"); | |
| 9513 | |
| 9514 static const ParserErrorCode NATIVE_CLAUSE_IN_NON_SDK_CODE = | |
| 9515 const ParserErrorCode('NATIVE_CLAUSE_IN_NON_SDK_CODE', | |
| 9516 "Native clause can only be used in the SDK and code that is loaded thr
ough native extensions"); | |
| 9517 | |
| 9518 static const ParserErrorCode NATIVE_FUNCTION_BODY_IN_NON_SDK_CODE = | |
| 9519 const ParserErrorCode('NATIVE_FUNCTION_BODY_IN_NON_SDK_CODE', | |
| 9520 "Native functions can only be declared in the SDK and code that is loa
ded through native extensions"); | |
| 9521 | |
| 9522 static const ParserErrorCode NON_CONSTRUCTOR_FACTORY = const ParserErrorCode( | |
| 9523 'NON_CONSTRUCTOR_FACTORY', | |
| 9524 "Only constructors can be declared to be a 'factory'"); | |
| 9525 | |
| 9526 static const ParserErrorCode NON_IDENTIFIER_LIBRARY_NAME = | |
| 9527 const ParserErrorCode('NON_IDENTIFIER_LIBRARY_NAME', | |
| 9528 "The name of a library must be an identifier"); | |
| 9529 | |
| 9530 static const ParserErrorCode NON_PART_OF_DIRECTIVE_IN_PART = | |
| 9531 const ParserErrorCode('NON_PART_OF_DIRECTIVE_IN_PART', | |
| 9532 "The part-of directive must be the only directive in a part"); | |
| 9533 | |
| 9534 static const ParserErrorCode NON_STRING_LITERAL_AS_URI = | |
| 9535 const ParserErrorCode( | |
| 9536 'NON_STRING_LITERAL_AS_URI', | |
| 9537 "The URI must be a string literal", | |
| 9538 "Enclose the URI in either single or double quotes."); | |
| 9539 | |
| 9540 static const ParserErrorCode NON_USER_DEFINABLE_OPERATOR = | |
| 9541 const ParserErrorCode('NON_USER_DEFINABLE_OPERATOR', | |
| 9542 "The operator '{0}' is not user definable"); | |
| 9543 | |
| 9544 static const ParserErrorCode NORMAL_BEFORE_OPTIONAL_PARAMETERS = | |
| 9545 const ParserErrorCode('NORMAL_BEFORE_OPTIONAL_PARAMETERS', | |
| 9546 "Normal parameters must occur before optional parameters"); | |
| 9547 | |
| 9548 static const ParserErrorCode POSITIONAL_AFTER_NAMED_ARGUMENT = | |
| 9549 const ParserErrorCode('POSITIONAL_AFTER_NAMED_ARGUMENT', | |
| 9550 "Positional arguments must occur before named arguments"); | |
| 9551 | |
| 9552 static const ParserErrorCode POSITIONAL_PARAMETER_OUTSIDE_GROUP = | |
| 9553 const ParserErrorCode('POSITIONAL_PARAMETER_OUTSIDE_GROUP', | |
| 9554 "Positional parameters must be enclosed in square brackets ('[' and ']
')"); | |
| 9555 | |
| 9556 static const ParserErrorCode REDIRECTION_IN_NON_FACTORY_CONSTRUCTOR = | |
| 9557 const ParserErrorCode('REDIRECTION_IN_NON_FACTORY_CONSTRUCTOR', | |
| 9558 "Only factory constructor can specify '=' redirection."); | |
| 9559 | |
| 9560 static const ParserErrorCode SETTER_IN_FUNCTION = const ParserErrorCode( | |
| 9561 'SETTER_IN_FUNCTION', | |
| 9562 "Setters cannot be defined within methods or functions"); | |
| 9563 | |
| 9564 static const ParserErrorCode STATIC_AFTER_CONST = const ParserErrorCode( | |
| 9565 'STATIC_AFTER_CONST', | |
| 9566 "The modifier 'static' should be before the modifier 'const'"); | |
| 9567 | |
| 9568 static const ParserErrorCode STATIC_AFTER_FINAL = const ParserErrorCode( | |
| 9569 'STATIC_AFTER_FINAL', | |
| 9570 "The modifier 'static' should be before the modifier 'final'"); | |
| 9571 | |
| 9572 static const ParserErrorCode STATIC_AFTER_VAR = const ParserErrorCode( | |
| 9573 'STATIC_AFTER_VAR', | |
| 9574 "The modifier 'static' should be before the modifier 'var'"); | |
| 9575 | |
| 9576 static const ParserErrorCode STATIC_CONSTRUCTOR = const ParserErrorCode( | |
| 9577 'STATIC_CONSTRUCTOR', "Constructors cannot be static"); | |
| 9578 | |
| 9579 static const ParserErrorCode STATIC_GETTER_WITHOUT_BODY = | |
| 9580 const ParserErrorCode( | |
| 9581 'STATIC_GETTER_WITHOUT_BODY', "A 'static' getter must have a body"); | |
| 9582 | |
| 9583 static const ParserErrorCode STATIC_OPERATOR = | |
| 9584 const ParserErrorCode('STATIC_OPERATOR', "Operators cannot be static"); | |
| 9585 | |
| 9586 static const ParserErrorCode STATIC_SETTER_WITHOUT_BODY = | |
| 9587 const ParserErrorCode( | |
| 9588 'STATIC_SETTER_WITHOUT_BODY', "A 'static' setter must have a body"); | |
| 9589 | |
| 9590 static const ParserErrorCode STATIC_TOP_LEVEL_DECLARATION = | |
| 9591 const ParserErrorCode('STATIC_TOP_LEVEL_DECLARATION', | |
| 9592 "Top-level declarations cannot be declared to be 'static'"); | |
| 9593 | |
| 9594 static const ParserErrorCode SWITCH_HAS_CASE_AFTER_DEFAULT_CASE = | |
| 9595 const ParserErrorCode('SWITCH_HAS_CASE_AFTER_DEFAULT_CASE', | |
| 9596 "The 'default' case should be the last case in a switch statement"); | |
| 9597 | |
| 9598 static const ParserErrorCode SWITCH_HAS_MULTIPLE_DEFAULT_CASES = | |
| 9599 const ParserErrorCode('SWITCH_HAS_MULTIPLE_DEFAULT_CASES', | |
| 9600 "The 'default' case can only be declared once"); | |
| 9601 | |
| 9602 static const ParserErrorCode TOP_LEVEL_OPERATOR = const ParserErrorCode( | |
| 9603 'TOP_LEVEL_OPERATOR', "Operators must be declared within a class"); | |
| 9604 | |
| 9605 static const ParserErrorCode TYPEDEF_IN_CLASS = const ParserErrorCode( | |
| 9606 'TYPEDEF_IN_CLASS', | |
| 9607 "Function type aliases cannot be declared inside classes"); | |
| 9608 | |
| 9609 static const ParserErrorCode UNEXPECTED_TERMINATOR_FOR_PARAMETER_GROUP = | |
| 9610 const ParserErrorCode('UNEXPECTED_TERMINATOR_FOR_PARAMETER_GROUP', | |
| 9611 "There is no '{0}' to open a parameter group"); | |
| 9612 | |
| 9613 static const ParserErrorCode UNEXPECTED_TOKEN = | |
| 9614 const ParserErrorCode('UNEXPECTED_TOKEN', "Unexpected token '{0}'"); | |
| 9615 | |
| 9616 static const ParserErrorCode WITH_BEFORE_EXTENDS = const ParserErrorCode( | |
| 9617 'WITH_BEFORE_EXTENDS', | |
| 9618 "The extends clause must be before the with clause"); | |
| 9619 | |
| 9620 static const ParserErrorCode WITH_WITHOUT_EXTENDS = const ParserErrorCode( | |
| 9621 'WITH_WITHOUT_EXTENDS', | |
| 9622 "The with clause cannot be used without an extends clause"); | |
| 9623 | |
| 9624 static const ParserErrorCode WRONG_SEPARATOR_FOR_NAMED_PARAMETER = | |
| 9625 const ParserErrorCode('WRONG_SEPARATOR_FOR_NAMED_PARAMETER', | |
| 9626 "The default value of a named parameter should be preceeded by ':'"); | |
| 9627 | |
| 9628 static const ParserErrorCode WRONG_SEPARATOR_FOR_POSITIONAL_PARAMETER = | |
| 9629 const ParserErrorCode('WRONG_SEPARATOR_FOR_POSITIONAL_PARAMETER', | |
| 9630 "The default value of a positional parameter should be preceeded by '=
'"); | |
| 9631 | |
| 9632 static const ParserErrorCode WRONG_TERMINATOR_FOR_PARAMETER_GROUP = | |
| 9633 const ParserErrorCode('WRONG_TERMINATOR_FOR_PARAMETER_GROUP', | |
| 9634 "Expected '{0}' to close parameter group"); | |
| 9635 | |
| 9636 static const ParserErrorCode VAR_AND_TYPE = const ParserErrorCode( | |
| 9637 'VAR_AND_TYPE', | |
| 9638 "Variables cannot be declared using both 'var' and a type name; remove the
'var'"); | |
| 9639 | |
| 9640 static const ParserErrorCode VAR_AS_TYPE_NAME = const ParserErrorCode( | |
| 9641 'VAR_AS_TYPE_NAME', "The keyword 'var' cannot be used as a type name"); | |
| 9642 | |
| 9643 static const ParserErrorCode VAR_CLASS = const ParserErrorCode( | |
| 9644 'VAR_CLASS', "Classes cannot be declared to be 'var'"); | |
| 9645 | |
| 9646 static const ParserErrorCode VAR_ENUM = | |
| 9647 const ParserErrorCode('VAR_ENUM', "Enums cannot be declared to be 'var'"); | |
| 9648 | |
| 9649 static const ParserErrorCode VAR_RETURN_TYPE = const ParserErrorCode( | |
| 9650 'VAR_RETURN_TYPE', "The return type cannot be 'var'"); | |
| 9651 | |
| 9652 static const ParserErrorCode VAR_TYPEDEF = const ParserErrorCode( | |
| 9653 'VAR_TYPEDEF', "Type aliases cannot be declared to be 'var'"); | |
| 9654 | |
| 9655 static const ParserErrorCode VOID_PARAMETER = const ParserErrorCode( | |
| 9656 'VOID_PARAMETER', "Parameters cannot have a type of 'void'"); | |
| 9657 | |
| 9658 static const ParserErrorCode VOID_VARIABLE = const ParserErrorCode( | |
| 9659 'VOID_VARIABLE', "Variables cannot have a type of 'void'"); | |
| 9660 | |
| 9661 /** | |
| 9662 * Initialize a newly created error code to have the given [name]. The message | |
| 9663 * associated with the error will be created from the given [message] | |
| 9664 * template. The correction associated with the error will be created from the | |
| 9665 * given [correction] template. | |
| 9666 */ | |
| 9667 const ParserErrorCode(String name, String message, [String correction]) | |
| 9668 : super(name, message, correction); | |
| 9669 | |
| 9670 @override | |
| 9671 ErrorSeverity get errorSeverity => ErrorSeverity.ERROR; | |
| 9672 | |
| 9673 @override | |
| 9674 ErrorType get type => ErrorType.SYNTACTIC_ERROR; | |
| 9675 } | |
| 9676 | |
| 9677 /** | |
| 9678 * An object that copies resolution information from one AST structure to | |
| 9679 * another as long as the structures of the corresponding children of a pair of | |
| 9680 * nodes are the same. | |
| 9681 */ | |
| 9682 class ResolutionCopier implements AstVisitor<bool> { | |
| 9683 /** | |
| 9684 * The AST node with which the node being visited is to be compared. This is | |
| 9685 * only valid at the beginning of each visit method (until [isEqualNodes] is | |
| 9686 * invoked). | |
| 9687 */ | |
| 9688 AstNode _toNode; | |
| 9689 | |
| 9690 @override | |
| 9691 bool visitAdjacentStrings(AdjacentStrings node) { | |
| 9692 AdjacentStrings toNode = this._toNode as AdjacentStrings; | |
| 9693 return _isEqualNodeLists(node.strings, toNode.strings); | |
| 9694 } | |
| 9695 | |
| 9696 @override | |
| 9697 bool visitAnnotation(Annotation node) { | |
| 9698 Annotation toNode = this._toNode as Annotation; | |
| 9699 if (_and( | |
| 9700 _isEqualTokens(node.atSign, toNode.atSign), | |
| 9701 _isEqualNodes(node.name, toNode.name), | |
| 9702 _isEqualTokens(node.period, toNode.period), | |
| 9703 _isEqualNodes(node.constructorName, toNode.constructorName), | |
| 9704 _isEqualNodes(node.arguments, toNode.arguments))) { | |
| 9705 toNode.element = node.element; | |
| 9706 return true; | |
| 9707 } | |
| 9708 return false; | |
| 9709 } | |
| 9710 | |
| 9711 @override | |
| 9712 bool visitArgumentList(ArgumentList node) { | |
| 9713 ArgumentList toNode = this._toNode as ArgumentList; | |
| 9714 return _and( | |
| 9715 _isEqualTokens(node.leftParenthesis, toNode.leftParenthesis), | |
| 9716 _isEqualNodeLists(node.arguments, toNode.arguments), | |
| 9717 _isEqualTokens(node.rightParenthesis, toNode.rightParenthesis)); | |
| 9718 } | |
| 9719 | |
| 9720 @override | |
| 9721 bool visitAsExpression(AsExpression node) { | |
| 9722 AsExpression toNode = this._toNode as AsExpression; | |
| 9723 if (_and( | |
| 9724 _isEqualNodes(node.expression, toNode.expression), | |
| 9725 _isEqualTokens(node.asOperator, toNode.asOperator), | |
| 9726 _isEqualNodes(node.type, toNode.type))) { | |
| 9727 toNode.propagatedType = node.propagatedType; | |
| 9728 toNode.staticType = node.staticType; | |
| 9729 return true; | |
| 9730 } | |
| 9731 return false; | |
| 9732 } | |
| 9733 | |
| 9734 @override | |
| 9735 bool visitAssertStatement(AssertStatement node) { | |
| 9736 AssertStatement toNode = this._toNode as AssertStatement; | |
| 9737 return _and( | |
| 9738 _isEqualTokens(node.assertKeyword, toNode.assertKeyword), | |
| 9739 _isEqualTokens(node.leftParenthesis, toNode.leftParenthesis), | |
| 9740 _isEqualNodes(node.condition, toNode.condition), | |
| 9741 _isEqualTokens(node.rightParenthesis, toNode.rightParenthesis), | |
| 9742 _isEqualTokens(node.semicolon, toNode.semicolon)); | |
| 9743 } | |
| 9744 | |
| 9745 @override | |
| 9746 bool visitAssignmentExpression(AssignmentExpression node) { | |
| 9747 AssignmentExpression toNode = this._toNode as AssignmentExpression; | |
| 9748 if (_and( | |
| 9749 _isEqualNodes(node.leftHandSide, toNode.leftHandSide), | |
| 9750 _isEqualTokens(node.operator, toNode.operator), | |
| 9751 _isEqualNodes(node.rightHandSide, toNode.rightHandSide))) { | |
| 9752 toNode.propagatedElement = node.propagatedElement; | |
| 9753 toNode.propagatedType = node.propagatedType; | |
| 9754 toNode.staticElement = node.staticElement; | |
| 9755 toNode.staticType = node.staticType; | |
| 9756 return true; | |
| 9757 } | |
| 9758 return false; | |
| 9759 } | |
| 9760 | |
| 9761 @override | |
| 9762 bool visitAwaitExpression(AwaitExpression node) { | |
| 9763 AwaitExpression toNode = this._toNode as AwaitExpression; | |
| 9764 if (_and(_isEqualTokens(node.awaitKeyword, toNode.awaitKeyword), | |
| 9765 _isEqualNodes(node.expression, toNode.expression))) { | |
| 9766 toNode.propagatedType = node.propagatedType; | |
| 9767 toNode.staticType = node.staticType; | |
| 9768 return true; | |
| 9769 } | |
| 9770 return false; | |
| 9771 } | |
| 9772 | |
| 9773 @override | |
| 9774 bool visitBinaryExpression(BinaryExpression node) { | |
| 9775 BinaryExpression toNode = this._toNode as BinaryExpression; | |
| 9776 if (_and( | |
| 9777 _isEqualNodes(node.leftOperand, toNode.leftOperand), | |
| 9778 _isEqualTokens(node.operator, toNode.operator), | |
| 9779 _isEqualNodes(node.rightOperand, toNode.rightOperand))) { | |
| 9780 toNode.propagatedElement = node.propagatedElement; | |
| 9781 toNode.propagatedType = node.propagatedType; | |
| 9782 toNode.staticElement = node.staticElement; | |
| 9783 toNode.staticType = node.staticType; | |
| 9784 return true; | |
| 9785 } | |
| 9786 return false; | |
| 9787 } | |
| 9788 | |
| 9789 @override | |
| 9790 bool visitBlock(Block node) { | |
| 9791 Block toNode = this._toNode as Block; | |
| 9792 return _and( | |
| 9793 _isEqualTokens(node.leftBracket, toNode.leftBracket), | |
| 9794 _isEqualNodeLists(node.statements, toNode.statements), | |
| 9795 _isEqualTokens(node.rightBracket, toNode.rightBracket)); | |
| 9796 } | |
| 9797 | |
| 9798 @override | |
| 9799 bool visitBlockFunctionBody(BlockFunctionBody node) { | |
| 9800 BlockFunctionBody toNode = this._toNode as BlockFunctionBody; | |
| 9801 return _isEqualNodes(node.block, toNode.block); | |
| 9802 } | |
| 9803 | |
| 9804 @override | |
| 9805 bool visitBooleanLiteral(BooleanLiteral node) { | |
| 9806 BooleanLiteral toNode = this._toNode as BooleanLiteral; | |
| 9807 if (_and(_isEqualTokens(node.literal, toNode.literal), | |
| 9808 node.value == toNode.value)) { | |
| 9809 toNode.propagatedType = node.propagatedType; | |
| 9810 toNode.staticType = node.staticType; | |
| 9811 return true; | |
| 9812 } | |
| 9813 return false; | |
| 9814 } | |
| 9815 | |
| 9816 @override | |
| 9817 bool visitBreakStatement(BreakStatement node) { | |
| 9818 BreakStatement toNode = this._toNode as BreakStatement; | |
| 9819 if (_and( | |
| 9820 _isEqualTokens(node.breakKeyword, toNode.breakKeyword), | |
| 9821 _isEqualNodes(node.label, toNode.label), | |
| 9822 _isEqualTokens(node.semicolon, toNode.semicolon))) { | |
| 9823 // TODO(paulberry): map node.target to toNode.target. | |
| 9824 return true; | |
| 9825 } | |
| 9826 return false; | |
| 9827 } | |
| 9828 | |
| 9829 @override | |
| 9830 bool visitCascadeExpression(CascadeExpression node) { | |
| 9831 CascadeExpression toNode = this._toNode as CascadeExpression; | |
| 9832 if (_and(_isEqualNodes(node.target, toNode.target), | |
| 9833 _isEqualNodeLists(node.cascadeSections, toNode.cascadeSections))) { | |
| 9834 toNode.propagatedType = node.propagatedType; | |
| 9835 toNode.staticType = node.staticType; | |
| 9836 return true; | |
| 9837 } | |
| 9838 return false; | |
| 9839 } | |
| 9840 | |
| 9841 @override | |
| 9842 bool visitCatchClause(CatchClause node) { | |
| 9843 CatchClause toNode = this._toNode as CatchClause; | |
| 9844 return _and( | |
| 9845 _isEqualTokens(node.onKeyword, toNode.onKeyword), | |
| 9846 _isEqualNodes(node.exceptionType, toNode.exceptionType), | |
| 9847 _isEqualTokens(node.catchKeyword, toNode.catchKeyword), | |
| 9848 _isEqualTokens(node.leftParenthesis, toNode.leftParenthesis), | |
| 9849 _isEqualNodes(node.exceptionParameter, toNode.exceptionParameter), | |
| 9850 _isEqualTokens(node.comma, toNode.comma), | |
| 9851 _isEqualNodes(node.stackTraceParameter, toNode.stackTraceParameter), | |
| 9852 _isEqualTokens(node.rightParenthesis, toNode.rightParenthesis), | |
| 9853 _isEqualNodes(node.body, toNode.body)); | |
| 9854 } | |
| 9855 | |
| 9856 @override | |
| 9857 bool visitClassDeclaration(ClassDeclaration node) { | |
| 9858 ClassDeclaration toNode = this._toNode as ClassDeclaration; | |
| 9859 return _and( | |
| 9860 _isEqualNodes(node.documentationComment, toNode.documentationComment), | |
| 9861 _isEqualNodeLists(node.metadata, toNode.metadata), | |
| 9862 _isEqualTokens(node.abstractKeyword, toNode.abstractKeyword), | |
| 9863 _isEqualTokens(node.classKeyword, toNode.classKeyword), | |
| 9864 _isEqualNodes(node.name, toNode.name), | |
| 9865 _isEqualNodes(node.typeParameters, toNode.typeParameters), | |
| 9866 _isEqualNodes(node.extendsClause, toNode.extendsClause), | |
| 9867 _isEqualNodes(node.withClause, toNode.withClause), | |
| 9868 _isEqualNodes(node.implementsClause, toNode.implementsClause), | |
| 9869 _isEqualTokens(node.leftBracket, toNode.leftBracket), | |
| 9870 _isEqualNodeLists(node.members, toNode.members), | |
| 9871 _isEqualTokens(node.rightBracket, toNode.rightBracket)); | |
| 9872 } | |
| 9873 | |
| 9874 @override | |
| 9875 bool visitClassTypeAlias(ClassTypeAlias node) { | |
| 9876 ClassTypeAlias toNode = this._toNode as ClassTypeAlias; | |
| 9877 return _and( | |
| 9878 _isEqualNodes(node.documentationComment, toNode.documentationComment), | |
| 9879 _isEqualNodeLists(node.metadata, toNode.metadata), | |
| 9880 _isEqualTokens(node.typedefKeyword, toNode.typedefKeyword), | |
| 9881 _isEqualNodes(node.name, toNode.name), | |
| 9882 _isEqualNodes(node.typeParameters, toNode.typeParameters), | |
| 9883 _isEqualTokens(node.equals, toNode.equals), | |
| 9884 _isEqualTokens(node.abstractKeyword, toNode.abstractKeyword), | |
| 9885 _isEqualNodes(node.superclass, toNode.superclass), | |
| 9886 _isEqualNodes(node.withClause, toNode.withClause), | |
| 9887 _isEqualNodes(node.implementsClause, toNode.implementsClause), | |
| 9888 _isEqualTokens(node.semicolon, toNode.semicolon)); | |
| 9889 } | |
| 9890 | |
| 9891 @override | |
| 9892 bool visitComment(Comment node) { | |
| 9893 Comment toNode = this._toNode as Comment; | |
| 9894 return _isEqualNodeLists(node.references, toNode.references); | |
| 9895 } | |
| 9896 | |
| 9897 @override | |
| 9898 bool visitCommentReference(CommentReference node) { | |
| 9899 CommentReference toNode = this._toNode as CommentReference; | |
| 9900 return _and(_isEqualTokens(node.newKeyword, toNode.newKeyword), | |
| 9901 _isEqualNodes(node.identifier, toNode.identifier)); | |
| 9902 } | |
| 9903 | |
| 9904 @override | |
| 9905 bool visitCompilationUnit(CompilationUnit node) { | |
| 9906 CompilationUnit toNode = this._toNode as CompilationUnit; | |
| 9907 if (_and( | |
| 9908 _isEqualTokens(node.beginToken, toNode.beginToken), | |
| 9909 _isEqualNodes(node.scriptTag, toNode.scriptTag), | |
| 9910 _isEqualNodeLists(node.directives, toNode.directives), | |
| 9911 _isEqualNodeLists(node.declarations, toNode.declarations), | |
| 9912 _isEqualTokens(node.endToken, toNode.endToken))) { | |
| 9913 toNode.element = node.element; | |
| 9914 return true; | |
| 9915 } | |
| 9916 return false; | |
| 9917 } | |
| 9918 | |
| 9919 @override | |
| 9920 bool visitConditionalExpression(ConditionalExpression node) { | |
| 9921 ConditionalExpression toNode = this._toNode as ConditionalExpression; | |
| 9922 if (_and( | |
| 9923 _isEqualNodes(node.condition, toNode.condition), | |
| 9924 _isEqualTokens(node.question, toNode.question), | |
| 9925 _isEqualNodes(node.thenExpression, toNode.thenExpression), | |
| 9926 _isEqualTokens(node.colon, toNode.colon), | |
| 9927 _isEqualNodes(node.elseExpression, toNode.elseExpression))) { | |
| 9928 toNode.propagatedType = node.propagatedType; | |
| 9929 toNode.staticType = node.staticType; | |
| 9930 return true; | |
| 9931 } | |
| 9932 return false; | |
| 9933 } | |
| 9934 | |
| 9935 @override | |
| 9936 bool visitConstructorDeclaration(ConstructorDeclaration node) { | |
| 9937 ConstructorDeclaration toNode = this._toNode as ConstructorDeclaration; | |
| 9938 if (_and( | |
| 9939 _isEqualNodes(node.documentationComment, toNode.documentationComment), | |
| 9940 _isEqualNodeLists(node.metadata, toNode.metadata), | |
| 9941 _isEqualTokens(node.externalKeyword, toNode.externalKeyword), | |
| 9942 _isEqualTokens(node.constKeyword, toNode.constKeyword), | |
| 9943 _isEqualTokens(node.factoryKeyword, toNode.factoryKeyword), | |
| 9944 _isEqualNodes(node.returnType, toNode.returnType), | |
| 9945 _isEqualTokens(node.period, toNode.period), | |
| 9946 _isEqualNodes(node.name, toNode.name), | |
| 9947 _isEqualNodes(node.parameters, toNode.parameters), | |
| 9948 _isEqualTokens(node.separator, toNode.separator), | |
| 9949 _isEqualNodeLists(node.initializers, toNode.initializers), | |
| 9950 _isEqualNodes(node.redirectedConstructor, toNode.redirectedConstructor), | |
| 9951 _isEqualNodes(node.body, toNode.body))) { | |
| 9952 toNode.element = node.element; | |
| 9953 return true; | |
| 9954 } | |
| 9955 return false; | |
| 9956 } | |
| 9957 | |
| 9958 @override | |
| 9959 bool visitConstructorFieldInitializer(ConstructorFieldInitializer node) { | |
| 9960 ConstructorFieldInitializer toNode = | |
| 9961 this._toNode as ConstructorFieldInitializer; | |
| 9962 return _and( | |
| 9963 _isEqualTokens(node.thisKeyword, toNode.thisKeyword), | |
| 9964 _isEqualTokens(node.period, toNode.period), | |
| 9965 _isEqualNodes(node.fieldName, toNode.fieldName), | |
| 9966 _isEqualTokens(node.equals, toNode.equals), | |
| 9967 _isEqualNodes(node.expression, toNode.expression)); | |
| 9968 } | |
| 9969 | |
| 9970 @override | |
| 9971 bool visitConstructorName(ConstructorName node) { | |
| 9972 ConstructorName toNode = this._toNode as ConstructorName; | |
| 9973 if (_and( | |
| 9974 _isEqualNodes(node.type, toNode.type), | |
| 9975 _isEqualTokens(node.period, toNode.period), | |
| 9976 _isEqualNodes(node.name, toNode.name))) { | |
| 9977 toNode.staticElement = node.staticElement; | |
| 9978 return true; | |
| 9979 } | |
| 9980 return false; | |
| 9981 } | |
| 9982 | |
| 9983 @override | |
| 9984 bool visitContinueStatement(ContinueStatement node) { | |
| 9985 ContinueStatement toNode = this._toNode as ContinueStatement; | |
| 9986 if (_and( | |
| 9987 _isEqualTokens(node.continueKeyword, toNode.continueKeyword), | |
| 9988 _isEqualNodes(node.label, toNode.label), | |
| 9989 _isEqualTokens(node.semicolon, toNode.semicolon))) { | |
| 9990 // TODO(paulberry): map node.target to toNode.target. | |
| 9991 return true; | |
| 9992 } | |
| 9993 return false; | |
| 9994 } | |
| 9995 | |
| 9996 @override | |
| 9997 bool visitDeclaredIdentifier(DeclaredIdentifier node) { | |
| 9998 DeclaredIdentifier toNode = this._toNode as DeclaredIdentifier; | |
| 9999 return _and( | |
| 10000 _isEqualNodes(node.documentationComment, toNode.documentationComment), | |
| 10001 _isEqualNodeLists(node.metadata, toNode.metadata), | |
| 10002 _isEqualTokens(node.keyword, toNode.keyword), | |
| 10003 _isEqualNodes(node.type, toNode.type), | |
| 10004 _isEqualNodes(node.identifier, toNode.identifier)); | |
| 10005 } | |
| 10006 | |
| 10007 @override | |
| 10008 bool visitDefaultFormalParameter(DefaultFormalParameter node) { | |
| 10009 DefaultFormalParameter toNode = this._toNode as DefaultFormalParameter; | |
| 10010 return _and( | |
| 10011 _isEqualNodes(node.parameter, toNode.parameter), | |
| 10012 node.kind == toNode.kind, | |
| 10013 _isEqualTokens(node.separator, toNode.separator), | |
| 10014 _isEqualNodes(node.defaultValue, toNode.defaultValue)); | |
| 10015 } | |
| 10016 | |
| 10017 @override | |
| 10018 bool visitDoStatement(DoStatement node) { | |
| 10019 DoStatement toNode = this._toNode as DoStatement; | |
| 10020 return _and( | |
| 10021 _isEqualTokens(node.doKeyword, toNode.doKeyword), | |
| 10022 _isEqualNodes(node.body, toNode.body), | |
| 10023 _isEqualTokens(node.whileKeyword, toNode.whileKeyword), | |
| 10024 _isEqualTokens(node.leftParenthesis, toNode.leftParenthesis), | |
| 10025 _isEqualNodes(node.condition, toNode.condition), | |
| 10026 _isEqualTokens(node.rightParenthesis, toNode.rightParenthesis), | |
| 10027 _isEqualTokens(node.semicolon, toNode.semicolon)); | |
| 10028 } | |
| 10029 | |
| 10030 @override | |
| 10031 bool visitDoubleLiteral(DoubleLiteral node) { | |
| 10032 DoubleLiteral toNode = this._toNode as DoubleLiteral; | |
| 10033 if (_and(_isEqualTokens(node.literal, toNode.literal), | |
| 10034 node.value == toNode.value)) { | |
| 10035 toNode.propagatedType = node.propagatedType; | |
| 10036 toNode.staticType = node.staticType; | |
| 10037 return true; | |
| 10038 } | |
| 10039 return false; | |
| 10040 } | |
| 10041 | |
| 10042 @override | |
| 10043 bool visitEmptyFunctionBody(EmptyFunctionBody node) { | |
| 10044 EmptyFunctionBody toNode = this._toNode as EmptyFunctionBody; | |
| 10045 return _isEqualTokens(node.semicolon, toNode.semicolon); | |
| 10046 } | |
| 10047 | |
| 10048 @override | |
| 10049 bool visitEmptyStatement(EmptyStatement node) { | |
| 10050 EmptyStatement toNode = this._toNode as EmptyStatement; | |
| 10051 return _isEqualTokens(node.semicolon, toNode.semicolon); | |
| 10052 } | |
| 10053 | |
| 10054 @override | |
| 10055 bool visitEnumConstantDeclaration(EnumConstantDeclaration node) { | |
| 10056 EnumConstantDeclaration toNode = this._toNode as EnumConstantDeclaration; | |
| 10057 return _and( | |
| 10058 _isEqualNodes(node.documentationComment, toNode.documentationComment), | |
| 10059 _isEqualNodeLists(node.metadata, toNode.metadata), | |
| 10060 _isEqualNodes(node.name, toNode.name)); | |
| 10061 } | |
| 10062 | |
| 10063 @override | |
| 10064 bool visitEnumDeclaration(EnumDeclaration node) { | |
| 10065 EnumDeclaration toNode = this._toNode as EnumDeclaration; | |
| 10066 return _and( | |
| 10067 _isEqualNodes(node.documentationComment, toNode.documentationComment), | |
| 10068 _isEqualNodeLists(node.metadata, toNode.metadata), | |
| 10069 _isEqualTokens(node.enumKeyword, toNode.enumKeyword), | |
| 10070 _isEqualNodes(node.name, toNode.name), | |
| 10071 _isEqualTokens(node.leftBracket, toNode.leftBracket), | |
| 10072 _isEqualNodeLists(node.constants, toNode.constants), | |
| 10073 _isEqualTokens(node.rightBracket, toNode.rightBracket)); | |
| 10074 } | |
| 10075 | |
| 10076 @override | |
| 10077 bool visitExportDirective(ExportDirective node) { | |
| 10078 ExportDirective toNode = this._toNode as ExportDirective; | |
| 10079 if (_and( | |
| 10080 _isEqualNodes(node.documentationComment, toNode.documentationComment), | |
| 10081 _isEqualNodeLists(node.metadata, toNode.metadata), | |
| 10082 _isEqualTokens(node.keyword, toNode.keyword), | |
| 10083 _isEqualNodes(node.uri, toNode.uri), | |
| 10084 _isEqualNodeLists(node.combinators, toNode.combinators), | |
| 10085 _isEqualTokens(node.semicolon, toNode.semicolon))) { | |
| 10086 toNode.element = node.element; | |
| 10087 return true; | |
| 10088 } | |
| 10089 return false; | |
| 10090 } | |
| 10091 | |
| 10092 @override | |
| 10093 bool visitExpressionFunctionBody(ExpressionFunctionBody node) { | |
| 10094 ExpressionFunctionBody toNode = this._toNode as ExpressionFunctionBody; | |
| 10095 return _and( | |
| 10096 _isEqualTokens(node.functionDefinition, toNode.functionDefinition), | |
| 10097 _isEqualNodes(node.expression, toNode.expression), | |
| 10098 _isEqualTokens(node.semicolon, toNode.semicolon)); | |
| 10099 } | |
| 10100 | |
| 10101 @override | |
| 10102 bool visitExpressionStatement(ExpressionStatement node) { | |
| 10103 ExpressionStatement toNode = this._toNode as ExpressionStatement; | |
| 10104 return _and(_isEqualNodes(node.expression, toNode.expression), | |
| 10105 _isEqualTokens(node.semicolon, toNode.semicolon)); | |
| 10106 } | |
| 10107 | |
| 10108 @override | |
| 10109 bool visitExtendsClause(ExtendsClause node) { | |
| 10110 ExtendsClause toNode = this._toNode as ExtendsClause; | |
| 10111 return _and(_isEqualTokens(node.extendsKeyword, toNode.extendsKeyword), | |
| 10112 _isEqualNodes(node.superclass, toNode.superclass)); | |
| 10113 } | |
| 10114 | |
| 10115 @override | |
| 10116 bool visitFieldDeclaration(FieldDeclaration node) { | |
| 10117 FieldDeclaration toNode = this._toNode as FieldDeclaration; | |
| 10118 return _and( | |
| 10119 _isEqualNodes(node.documentationComment, toNode.documentationComment), | |
| 10120 _isEqualNodeLists(node.metadata, toNode.metadata), | |
| 10121 _isEqualTokens(node.staticKeyword, toNode.staticKeyword), | |
| 10122 _isEqualNodes(node.fields, toNode.fields), | |
| 10123 _isEqualTokens(node.semicolon, toNode.semicolon)); | |
| 10124 } | |
| 10125 | |
| 10126 @override | |
| 10127 bool visitFieldFormalParameter(FieldFormalParameter node) { | |
| 10128 FieldFormalParameter toNode = this._toNode as FieldFormalParameter; | |
| 10129 return _and( | |
| 10130 _isEqualNodes(node.documentationComment, toNode.documentationComment), | |
| 10131 _isEqualNodeLists(node.metadata, toNode.metadata), | |
| 10132 _isEqualTokens(node.keyword, toNode.keyword), | |
| 10133 _isEqualNodes(node.type, toNode.type), | |
| 10134 _isEqualTokens(node.thisKeyword, toNode.thisKeyword), | |
| 10135 _isEqualTokens(node.period, toNode.period), | |
| 10136 _isEqualNodes(node.identifier, toNode.identifier)); | |
| 10137 } | |
| 10138 | |
| 10139 @override | |
| 10140 bool visitForEachStatement(ForEachStatement node) { | |
| 10141 ForEachStatement toNode = this._toNode as ForEachStatement; | |
| 10142 return _and( | |
| 10143 _isEqualTokens(node.forKeyword, toNode.forKeyword), | |
| 10144 _isEqualTokens(node.leftParenthesis, toNode.leftParenthesis), | |
| 10145 _isEqualNodes(node.loopVariable, toNode.loopVariable), | |
| 10146 _isEqualTokens(node.inKeyword, toNode.inKeyword), | |
| 10147 _isEqualNodes(node.iterable, toNode.iterable), | |
| 10148 _isEqualTokens(node.rightParenthesis, toNode.rightParenthesis), | |
| 10149 _isEqualNodes(node.body, toNode.body)); | |
| 10150 } | |
| 10151 | |
| 10152 @override | |
| 10153 bool visitFormalParameterList(FormalParameterList node) { | |
| 10154 FormalParameterList toNode = this._toNode as FormalParameterList; | |
| 10155 return _and( | |
| 10156 _isEqualTokens(node.leftParenthesis, toNode.leftParenthesis), | |
| 10157 _isEqualNodeLists(node.parameters, toNode.parameters), | |
| 10158 _isEqualTokens(node.leftDelimiter, toNode.leftDelimiter), | |
| 10159 _isEqualTokens(node.rightDelimiter, toNode.rightDelimiter), | |
| 10160 _isEqualTokens(node.rightParenthesis, toNode.rightParenthesis)); | |
| 10161 } | |
| 10162 | |
| 10163 @override | |
| 10164 bool visitForStatement(ForStatement node) { | |
| 10165 ForStatement toNode = this._toNode as ForStatement; | |
| 10166 return _and( | |
| 10167 _isEqualTokens(node.forKeyword, toNode.forKeyword), | |
| 10168 _isEqualTokens(node.leftParenthesis, toNode.leftParenthesis), | |
| 10169 _isEqualNodes(node.variables, toNode.variables), | |
| 10170 _isEqualNodes(node.initialization, toNode.initialization), | |
| 10171 _isEqualTokens(node.leftSeparator, toNode.leftSeparator), | |
| 10172 _isEqualNodes(node.condition, toNode.condition), | |
| 10173 _isEqualTokens(node.rightSeparator, toNode.rightSeparator), | |
| 10174 _isEqualNodeLists(node.updaters, toNode.updaters), | |
| 10175 _isEqualTokens(node.rightParenthesis, toNode.rightParenthesis), | |
| 10176 _isEqualNodes(node.body, toNode.body)); | |
| 10177 } | |
| 10178 | |
| 10179 @override | |
| 10180 bool visitFunctionDeclaration(FunctionDeclaration node) { | |
| 10181 FunctionDeclaration toNode = this._toNode as FunctionDeclaration; | |
| 10182 return _and( | |
| 10183 _isEqualNodes(node.documentationComment, toNode.documentationComment), | |
| 10184 _isEqualNodeLists(node.metadata, toNode.metadata), | |
| 10185 _isEqualTokens(node.externalKeyword, toNode.externalKeyword), | |
| 10186 _isEqualNodes(node.returnType, toNode.returnType), | |
| 10187 _isEqualTokens(node.propertyKeyword, toNode.propertyKeyword), | |
| 10188 _isEqualNodes(node.name, toNode.name), | |
| 10189 _isEqualNodes(node.functionExpression, toNode.functionExpression)); | |
| 10190 } | |
| 10191 | |
| 10192 @override | |
| 10193 bool visitFunctionDeclarationStatement(FunctionDeclarationStatement node) { | |
| 10194 FunctionDeclarationStatement toNode = | |
| 10195 this._toNode as FunctionDeclarationStatement; | |
| 10196 return _isEqualNodes(node.functionDeclaration, toNode.functionDeclaration); | |
| 10197 } | |
| 10198 | |
| 10199 @override | |
| 10200 bool visitFunctionExpression(FunctionExpression node) { | |
| 10201 FunctionExpression toNode = this._toNode as FunctionExpression; | |
| 10202 if (_and(_isEqualNodes(node.parameters, toNode.parameters), | |
| 10203 _isEqualNodes(node.body, toNode.body))) { | |
| 10204 toNode.element = node.element; | |
| 10205 toNode.propagatedType = node.propagatedType; | |
| 10206 toNode.staticType = node.staticType; | |
| 10207 return true; | |
| 10208 } | |
| 10209 return false; | |
| 10210 } | |
| 10211 | |
| 10212 @override | |
| 10213 bool visitFunctionExpressionInvocation(FunctionExpressionInvocation node) { | |
| 10214 FunctionExpressionInvocation toNode = | |
| 10215 this._toNode as FunctionExpressionInvocation; | |
| 10216 if (_and(_isEqualNodes(node.function, toNode.function), | |
| 10217 _isEqualNodes(node.argumentList, toNode.argumentList))) { | |
| 10218 toNode.propagatedElement = node.propagatedElement; | |
| 10219 toNode.propagatedType = node.propagatedType; | |
| 10220 toNode.staticElement = node.staticElement; | |
| 10221 toNode.staticType = node.staticType; | |
| 10222 return true; | |
| 10223 } | |
| 10224 return false; | |
| 10225 } | |
| 10226 | |
| 10227 @override | |
| 10228 bool visitFunctionTypeAlias(FunctionTypeAlias node) { | |
| 10229 FunctionTypeAlias toNode = this._toNode as FunctionTypeAlias; | |
| 10230 return _and( | |
| 10231 _isEqualNodes(node.documentationComment, toNode.documentationComment), | |
| 10232 _isEqualNodeLists(node.metadata, toNode.metadata), | |
| 10233 _isEqualTokens(node.typedefKeyword, toNode.typedefKeyword), | |
| 10234 _isEqualNodes(node.returnType, toNode.returnType), | |
| 10235 _isEqualNodes(node.name, toNode.name), | |
| 10236 _isEqualNodes(node.typeParameters, toNode.typeParameters), | |
| 10237 _isEqualNodes(node.parameters, toNode.parameters), | |
| 10238 _isEqualTokens(node.semicolon, toNode.semicolon)); | |
| 10239 } | |
| 10240 | |
| 10241 @override | |
| 10242 bool visitFunctionTypedFormalParameter(FunctionTypedFormalParameter node) { | |
| 10243 FunctionTypedFormalParameter toNode = | |
| 10244 this._toNode as FunctionTypedFormalParameter; | |
| 10245 return _and( | |
| 10246 _isEqualNodes(node.documentationComment, toNode.documentationComment), | |
| 10247 _isEqualNodeLists(node.metadata, toNode.metadata), | |
| 10248 _isEqualNodes(node.returnType, toNode.returnType), | |
| 10249 _isEqualNodes(node.identifier, toNode.identifier), | |
| 10250 _isEqualNodes(node.parameters, toNode.parameters)); | |
| 10251 } | |
| 10252 | |
| 10253 @override | |
| 10254 bool visitHideCombinator(HideCombinator node) { | |
| 10255 HideCombinator toNode = this._toNode as HideCombinator; | |
| 10256 return _and(_isEqualTokens(node.keyword, toNode.keyword), | |
| 10257 _isEqualNodeLists(node.hiddenNames, toNode.hiddenNames)); | |
| 10258 } | |
| 10259 | |
| 10260 @override | |
| 10261 bool visitIfStatement(IfStatement node) { | |
| 10262 IfStatement toNode = this._toNode as IfStatement; | |
| 10263 return _and( | |
| 10264 _isEqualTokens(node.ifKeyword, toNode.ifKeyword), | |
| 10265 _isEqualTokens(node.leftParenthesis, toNode.leftParenthesis), | |
| 10266 _isEqualNodes(node.condition, toNode.condition), | |
| 10267 _isEqualTokens(node.rightParenthesis, toNode.rightParenthesis), | |
| 10268 _isEqualNodes(node.thenStatement, toNode.thenStatement), | |
| 10269 _isEqualTokens(node.elseKeyword, toNode.elseKeyword), | |
| 10270 _isEqualNodes(node.elseStatement, toNode.elseStatement)); | |
| 10271 } | |
| 10272 | |
| 10273 @override | |
| 10274 bool visitImplementsClause(ImplementsClause node) { | |
| 10275 ImplementsClause toNode = this._toNode as ImplementsClause; | |
| 10276 return _and( | |
| 10277 _isEqualTokens(node.implementsKeyword, toNode.implementsKeyword), | |
| 10278 _isEqualNodeLists(node.interfaces, toNode.interfaces)); | |
| 10279 } | |
| 10280 | |
| 10281 @override | |
| 10282 bool visitImportDirective(ImportDirective node) { | |
| 10283 ImportDirective toNode = this._toNode as ImportDirective; | |
| 10284 if (_and( | |
| 10285 _isEqualNodes(node.documentationComment, toNode.documentationComment), | |
| 10286 _isEqualNodeLists(node.metadata, toNode.metadata), | |
| 10287 _isEqualTokens(node.keyword, toNode.keyword), | |
| 10288 _isEqualNodes(node.uri, toNode.uri), | |
| 10289 _isEqualTokens(node.asKeyword, toNode.asKeyword), | |
| 10290 _isEqualNodes(node.prefix, toNode.prefix), | |
| 10291 _isEqualNodeLists(node.combinators, toNode.combinators), | |
| 10292 _isEqualTokens(node.semicolon, toNode.semicolon))) { | |
| 10293 toNode.element = node.element; | |
| 10294 return true; | |
| 10295 } | |
| 10296 return false; | |
| 10297 } | |
| 10298 | |
| 10299 @override | |
| 10300 bool visitIndexExpression(IndexExpression node) { | |
| 10301 IndexExpression toNode = this._toNode as IndexExpression; | |
| 10302 if (_and( | |
| 10303 _isEqualNodes(node.target, toNode.target), | |
| 10304 _isEqualTokens(node.leftBracket, toNode.leftBracket), | |
| 10305 _isEqualNodes(node.index, toNode.index), | |
| 10306 _isEqualTokens(node.rightBracket, toNode.rightBracket))) { | |
| 10307 toNode.auxiliaryElements = node.auxiliaryElements; | |
| 10308 toNode.propagatedElement = node.propagatedElement; | |
| 10309 toNode.propagatedType = node.propagatedType; | |
| 10310 toNode.staticElement = node.staticElement; | |
| 10311 toNode.staticType = node.staticType; | |
| 10312 return true; | |
| 10313 } | |
| 10314 return false; | |
| 10315 } | |
| 10316 | |
| 10317 @override | |
| 10318 bool visitInstanceCreationExpression(InstanceCreationExpression node) { | |
| 10319 InstanceCreationExpression toNode = | |
| 10320 this._toNode as InstanceCreationExpression; | |
| 10321 if (_and( | |
| 10322 _isEqualTokens(node.keyword, toNode.keyword), | |
| 10323 _isEqualNodes(node.constructorName, toNode.constructorName), | |
| 10324 _isEqualNodes(node.argumentList, toNode.argumentList))) { | |
| 10325 toNode.propagatedType = node.propagatedType; | |
| 10326 toNode.staticElement = node.staticElement; | |
| 10327 toNode.staticType = node.staticType; | |
| 10328 return true; | |
| 10329 } | |
| 10330 return false; | |
| 10331 } | |
| 10332 | |
| 10333 @override | |
| 10334 bool visitIntegerLiteral(IntegerLiteral node) { | |
| 10335 IntegerLiteral toNode = this._toNode as IntegerLiteral; | |
| 10336 if (_and(_isEqualTokens(node.literal, toNode.literal), | |
| 10337 node.value == toNode.value)) { | |
| 10338 toNode.propagatedType = node.propagatedType; | |
| 10339 toNode.staticType = node.staticType; | |
| 10340 return true; | |
| 10341 } | |
| 10342 return false; | |
| 10343 } | |
| 10344 | |
| 10345 @override | |
| 10346 bool visitInterpolationExpression(InterpolationExpression node) { | |
| 10347 InterpolationExpression toNode = this._toNode as InterpolationExpression; | |
| 10348 return _and( | |
| 10349 _isEqualTokens(node.leftBracket, toNode.leftBracket), | |
| 10350 _isEqualNodes(node.expression, toNode.expression), | |
| 10351 _isEqualTokens(node.rightBracket, toNode.rightBracket)); | |
| 10352 } | |
| 10353 | |
| 10354 @override | |
| 10355 bool visitInterpolationString(InterpolationString node) { | |
| 10356 InterpolationString toNode = this._toNode as InterpolationString; | |
| 10357 return _and(_isEqualTokens(node.contents, toNode.contents), | |
| 10358 node.value == toNode.value); | |
| 10359 } | |
| 10360 | |
| 10361 @override | |
| 10362 bool visitIsExpression(IsExpression node) { | |
| 10363 IsExpression toNode = this._toNode as IsExpression; | |
| 10364 if (_and( | |
| 10365 _isEqualNodes(node.expression, toNode.expression), | |
| 10366 _isEqualTokens(node.isOperator, toNode.isOperator), | |
| 10367 _isEqualTokens(node.notOperator, toNode.notOperator), | |
| 10368 _isEqualNodes(node.type, toNode.type))) { | |
| 10369 toNode.propagatedType = node.propagatedType; | |
| 10370 toNode.staticType = node.staticType; | |
| 10371 return true; | |
| 10372 } | |
| 10373 return false; | |
| 10374 } | |
| 10375 | |
| 10376 @override | |
| 10377 bool visitLabel(Label node) { | |
| 10378 Label toNode = this._toNode as Label; | |
| 10379 return _and(_isEqualNodes(node.label, toNode.label), | |
| 10380 _isEqualTokens(node.colon, toNode.colon)); | |
| 10381 } | |
| 10382 | |
| 10383 @override | |
| 10384 bool visitLabeledStatement(LabeledStatement node) { | |
| 10385 LabeledStatement toNode = this._toNode as LabeledStatement; | |
| 10386 return _and(_isEqualNodeLists(node.labels, toNode.labels), | |
| 10387 _isEqualNodes(node.statement, toNode.statement)); | |
| 10388 } | |
| 10389 | |
| 10390 @override | |
| 10391 bool visitLibraryDirective(LibraryDirective node) { | |
| 10392 LibraryDirective toNode = this._toNode as LibraryDirective; | |
| 10393 if (_and( | |
| 10394 _isEqualNodes(node.documentationComment, toNode.documentationComment), | |
| 10395 _isEqualNodeLists(node.metadata, toNode.metadata), | |
| 10396 _isEqualTokens(node.libraryKeyword, toNode.libraryKeyword), | |
| 10397 _isEqualNodes(node.name, toNode.name), | |
| 10398 _isEqualTokens(node.semicolon, toNode.semicolon))) { | |
| 10399 toNode.element = node.element; | |
| 10400 return true; | |
| 10401 } | |
| 10402 return false; | |
| 10403 } | |
| 10404 | |
| 10405 @override | |
| 10406 bool visitLibraryIdentifier(LibraryIdentifier node) { | |
| 10407 LibraryIdentifier toNode = this._toNode as LibraryIdentifier; | |
| 10408 if (_isEqualNodeLists(node.components, toNode.components)) { | |
| 10409 toNode.propagatedType = node.propagatedType; | |
| 10410 toNode.staticType = node.staticType; | |
| 10411 return true; | |
| 10412 } | |
| 10413 return false; | |
| 10414 } | |
| 10415 | |
| 10416 @override | |
| 10417 bool visitListLiteral(ListLiteral node) { | |
| 10418 ListLiteral toNode = this._toNode as ListLiteral; | |
| 10419 if (_and( | |
| 10420 _isEqualTokens(node.constKeyword, toNode.constKeyword), | |
| 10421 _isEqualNodes(node.typeArguments, toNode.typeArguments), | |
| 10422 _isEqualTokens(node.leftBracket, toNode.leftBracket), | |
| 10423 _isEqualNodeLists(node.elements, toNode.elements), | |
| 10424 _isEqualTokens(node.rightBracket, toNode.rightBracket))) { | |
| 10425 toNode.propagatedType = node.propagatedType; | |
| 10426 toNode.staticType = node.staticType; | |
| 10427 return true; | |
| 10428 } | |
| 10429 return false; | |
| 10430 } | |
| 10431 | |
| 10432 @override | |
| 10433 bool visitMapLiteral(MapLiteral node) { | |
| 10434 MapLiteral toNode = this._toNode as MapLiteral; | |
| 10435 if (_and( | |
| 10436 _isEqualTokens(node.constKeyword, toNode.constKeyword), | |
| 10437 _isEqualNodes(node.typeArguments, toNode.typeArguments), | |
| 10438 _isEqualTokens(node.leftBracket, toNode.leftBracket), | |
| 10439 _isEqualNodeLists(node.entries, toNode.entries), | |
| 10440 _isEqualTokens(node.rightBracket, toNode.rightBracket))) { | |
| 10441 toNode.propagatedType = node.propagatedType; | |
| 10442 toNode.staticType = node.staticType; | |
| 10443 return true; | |
| 10444 } | |
| 10445 return false; | |
| 10446 } | |
| 10447 | |
| 10448 @override | |
| 10449 bool visitMapLiteralEntry(MapLiteralEntry node) { | |
| 10450 MapLiteralEntry toNode = this._toNode as MapLiteralEntry; | |
| 10451 return _and( | |
| 10452 _isEqualNodes(node.key, toNode.key), | |
| 10453 _isEqualTokens(node.separator, toNode.separator), | |
| 10454 _isEqualNodes(node.value, toNode.value)); | |
| 10455 } | |
| 10456 | |
| 10457 @override | |
| 10458 bool visitMethodDeclaration(MethodDeclaration node) { | |
| 10459 MethodDeclaration toNode = this._toNode as MethodDeclaration; | |
| 10460 return _and( | |
| 10461 _isEqualNodes(node.documentationComment, toNode.documentationComment), | |
| 10462 _isEqualNodeLists(node.metadata, toNode.metadata), | |
| 10463 _isEqualTokens(node.externalKeyword, toNode.externalKeyword), | |
| 10464 _isEqualTokens(node.modifierKeyword, toNode.modifierKeyword), | |
| 10465 _isEqualNodes(node.returnType, toNode.returnType), | |
| 10466 _isEqualTokens(node.propertyKeyword, toNode.propertyKeyword), | |
| 10467 _isEqualTokens(node.propertyKeyword, toNode.propertyKeyword), | |
| 10468 _isEqualNodes(node.name, toNode.name), | |
| 10469 _isEqualNodes(node.parameters, toNode.parameters), | |
| 10470 _isEqualNodes(node.body, toNode.body)); | |
| 10471 } | |
| 10472 | |
| 10473 @override | |
| 10474 bool visitMethodInvocation(MethodInvocation node) { | |
| 10475 MethodInvocation toNode = this._toNode as MethodInvocation; | |
| 10476 if (_and( | |
| 10477 _isEqualNodes(node.target, toNode.target), | |
| 10478 _isEqualTokens(node.operator, toNode.operator), | |
| 10479 _isEqualNodes(node.methodName, toNode.methodName), | |
| 10480 _isEqualNodes(node.argumentList, toNode.argumentList))) { | |
| 10481 toNode.propagatedType = node.propagatedType; | |
| 10482 toNode.staticType = node.staticType; | |
| 10483 return true; | |
| 10484 } | |
| 10485 return false; | |
| 10486 } | |
| 10487 | |
| 10488 @override | |
| 10489 bool visitNamedExpression(NamedExpression node) { | |
| 10490 NamedExpression toNode = this._toNode as NamedExpression; | |
| 10491 if (_and(_isEqualNodes(node.name, toNode.name), | |
| 10492 _isEqualNodes(node.expression, toNode.expression))) { | |
| 10493 toNode.propagatedType = node.propagatedType; | |
| 10494 toNode.staticType = node.staticType; | |
| 10495 return true; | |
| 10496 } | |
| 10497 return false; | |
| 10498 } | |
| 10499 | |
| 10500 @override | |
| 10501 bool visitNativeClause(NativeClause node) { | |
| 10502 NativeClause toNode = this._toNode as NativeClause; | |
| 10503 return _and(_isEqualTokens(node.nativeKeyword, toNode.nativeKeyword), | |
| 10504 _isEqualNodes(node.name, toNode.name)); | |
| 10505 } | |
| 10506 | |
| 10507 @override | |
| 10508 bool visitNativeFunctionBody(NativeFunctionBody node) { | |
| 10509 NativeFunctionBody toNode = this._toNode as NativeFunctionBody; | |
| 10510 return _and( | |
| 10511 _isEqualTokens(node.nativeKeyword, toNode.nativeKeyword), | |
| 10512 _isEqualNodes(node.stringLiteral, toNode.stringLiteral), | |
| 10513 _isEqualTokens(node.semicolon, toNode.semicolon)); | |
| 10514 } | |
| 10515 | |
| 10516 @override | |
| 10517 bool visitNullLiteral(NullLiteral node) { | |
| 10518 NullLiteral toNode = this._toNode as NullLiteral; | |
| 10519 if (_isEqualTokens(node.literal, toNode.literal)) { | |
| 10520 toNode.propagatedType = node.propagatedType; | |
| 10521 toNode.staticType = node.staticType; | |
| 10522 return true; | |
| 10523 } | |
| 10524 return false; | |
| 10525 } | |
| 10526 | |
| 10527 @override | |
| 10528 bool visitParenthesizedExpression(ParenthesizedExpression node) { | |
| 10529 ParenthesizedExpression toNode = this._toNode as ParenthesizedExpression; | |
| 10530 if (_and( | |
| 10531 _isEqualTokens(node.leftParenthesis, toNode.leftParenthesis), | |
| 10532 _isEqualNodes(node.expression, toNode.expression), | |
| 10533 _isEqualTokens(node.rightParenthesis, toNode.rightParenthesis))) { | |
| 10534 toNode.propagatedType = node.propagatedType; | |
| 10535 toNode.staticType = node.staticType; | |
| 10536 return true; | |
| 10537 } | |
| 10538 return false; | |
| 10539 } | |
| 10540 | |
| 10541 @override | |
| 10542 bool visitPartDirective(PartDirective node) { | |
| 10543 PartDirective toNode = this._toNode as PartDirective; | |
| 10544 if (_and( | |
| 10545 _isEqualNodes(node.documentationComment, toNode.documentationComment), | |
| 10546 _isEqualNodeLists(node.metadata, toNode.metadata), | |
| 10547 _isEqualTokens(node.partKeyword, toNode.partKeyword), | |
| 10548 _isEqualNodes(node.uri, toNode.uri), | |
| 10549 _isEqualTokens(node.semicolon, toNode.semicolon))) { | |
| 10550 toNode.element = node.element; | |
| 10551 return true; | |
| 10552 } | |
| 10553 return false; | |
| 10554 } | |
| 10555 | |
| 10556 @override | |
| 10557 bool visitPartOfDirective(PartOfDirective node) { | |
| 10558 PartOfDirective toNode = this._toNode as PartOfDirective; | |
| 10559 if (_and( | |
| 10560 _isEqualNodes(node.documentationComment, toNode.documentationComment), | |
| 10561 _isEqualNodeLists(node.metadata, toNode.metadata), | |
| 10562 _isEqualTokens(node.partKeyword, toNode.partKeyword), | |
| 10563 _isEqualTokens(node.ofKeyword, toNode.ofKeyword), | |
| 10564 _isEqualNodes(node.libraryName, toNode.libraryName), | |
| 10565 _isEqualTokens(node.semicolon, toNode.semicolon))) { | |
| 10566 toNode.element = node.element; | |
| 10567 return true; | |
| 10568 } | |
| 10569 return false; | |
| 10570 } | |
| 10571 | |
| 10572 @override | |
| 10573 bool visitPostfixExpression(PostfixExpression node) { | |
| 10574 PostfixExpression toNode = this._toNode as PostfixExpression; | |
| 10575 if (_and(_isEqualNodes(node.operand, toNode.operand), | |
| 10576 _isEqualTokens(node.operator, toNode.operator))) { | |
| 10577 toNode.propagatedElement = node.propagatedElement; | |
| 10578 toNode.propagatedType = node.propagatedType; | |
| 10579 toNode.staticElement = node.staticElement; | |
| 10580 toNode.staticType = node.staticType; | |
| 10581 return true; | |
| 10582 } | |
| 10583 return false; | |
| 10584 } | |
| 10585 | |
| 10586 @override | |
| 10587 bool visitPrefixedIdentifier(PrefixedIdentifier node) { | |
| 10588 PrefixedIdentifier toNode = this._toNode as PrefixedIdentifier; | |
| 10589 if (_and( | |
| 10590 _isEqualNodes(node.prefix, toNode.prefix), | |
| 10591 _isEqualTokens(node.period, toNode.period), | |
| 10592 _isEqualNodes(node.identifier, toNode.identifier))) { | |
| 10593 toNode.propagatedType = node.propagatedType; | |
| 10594 toNode.staticType = node.staticType; | |
| 10595 return true; | |
| 10596 } | |
| 10597 return false; | |
| 10598 } | |
| 10599 | |
| 10600 @override | |
| 10601 bool visitPrefixExpression(PrefixExpression node) { | |
| 10602 PrefixExpression toNode = this._toNode as PrefixExpression; | |
| 10603 if (_and(_isEqualTokens(node.operator, toNode.operator), | |
| 10604 _isEqualNodes(node.operand, toNode.operand))) { | |
| 10605 toNode.propagatedElement = node.propagatedElement; | |
| 10606 toNode.propagatedType = node.propagatedType; | |
| 10607 toNode.staticElement = node.staticElement; | |
| 10608 toNode.staticType = node.staticType; | |
| 10609 return true; | |
| 10610 } | |
| 10611 return false; | |
| 10612 } | |
| 10613 | |
| 10614 @override | |
| 10615 bool visitPropertyAccess(PropertyAccess node) { | |
| 10616 PropertyAccess toNode = this._toNode as PropertyAccess; | |
| 10617 if (_and( | |
| 10618 _isEqualNodes(node.target, toNode.target), | |
| 10619 _isEqualTokens(node.operator, toNode.operator), | |
| 10620 _isEqualNodes(node.propertyName, toNode.propertyName))) { | |
| 10621 toNode.propagatedType = node.propagatedType; | |
| 10622 toNode.staticType = node.staticType; | |
| 10623 return true; | |
| 10624 } | |
| 10625 return false; | |
| 10626 } | |
| 10627 | |
| 10628 @override | |
| 10629 bool visitRedirectingConstructorInvocation( | |
| 10630 RedirectingConstructorInvocation node) { | |
| 10631 RedirectingConstructorInvocation toNode = | |
| 10632 this._toNode as RedirectingConstructorInvocation; | |
| 10633 if (_and( | |
| 10634 _isEqualTokens(node.thisKeyword, toNode.thisKeyword), | |
| 10635 _isEqualTokens(node.period, toNode.period), | |
| 10636 _isEqualNodes(node.constructorName, toNode.constructorName), | |
| 10637 _isEqualNodes(node.argumentList, toNode.argumentList))) { | |
| 10638 toNode.staticElement = node.staticElement; | |
| 10639 return true; | |
| 10640 } | |
| 10641 return false; | |
| 10642 } | |
| 10643 | |
| 10644 @override | |
| 10645 bool visitRethrowExpression(RethrowExpression node) { | |
| 10646 RethrowExpression toNode = this._toNode as RethrowExpression; | |
| 10647 if (_isEqualTokens(node.rethrowKeyword, toNode.rethrowKeyword)) { | |
| 10648 toNode.propagatedType = node.propagatedType; | |
| 10649 toNode.staticType = node.staticType; | |
| 10650 return true; | |
| 10651 } | |
| 10652 return false; | |
| 10653 } | |
| 10654 | |
| 10655 @override | |
| 10656 bool visitReturnStatement(ReturnStatement node) { | |
| 10657 ReturnStatement toNode = this._toNode as ReturnStatement; | |
| 10658 return _and( | |
| 10659 _isEqualTokens(node.returnKeyword, toNode.returnKeyword), | |
| 10660 _isEqualNodes(node.expression, toNode.expression), | |
| 10661 _isEqualTokens(node.semicolon, toNode.semicolon)); | |
| 10662 } | |
| 10663 | |
| 10664 @override | |
| 10665 bool visitScriptTag(ScriptTag node) { | |
| 10666 ScriptTag toNode = this._toNode as ScriptTag; | |
| 10667 return _isEqualTokens(node.scriptTag, toNode.scriptTag); | |
| 10668 } | |
| 10669 | |
| 10670 @override | |
| 10671 bool visitShowCombinator(ShowCombinator node) { | |
| 10672 ShowCombinator toNode = this._toNode as ShowCombinator; | |
| 10673 return _and(_isEqualTokens(node.keyword, toNode.keyword), | |
| 10674 _isEqualNodeLists(node.shownNames, toNode.shownNames)); | |
| 10675 } | |
| 10676 | |
| 10677 @override | |
| 10678 bool visitSimpleFormalParameter(SimpleFormalParameter node) { | |
| 10679 SimpleFormalParameter toNode = this._toNode as SimpleFormalParameter; | |
| 10680 return _and( | |
| 10681 _isEqualNodes(node.documentationComment, toNode.documentationComment), | |
| 10682 _isEqualNodeLists(node.metadata, toNode.metadata), | |
| 10683 _isEqualTokens(node.keyword, toNode.keyword), | |
| 10684 _isEqualNodes(node.type, toNode.type), | |
| 10685 _isEqualNodes(node.identifier, toNode.identifier)); | |
| 10686 } | |
| 10687 | |
| 10688 @override | |
| 10689 bool visitSimpleIdentifier(SimpleIdentifier node) { | |
| 10690 SimpleIdentifier toNode = this._toNode as SimpleIdentifier; | |
| 10691 if (_isEqualTokens(node.token, toNode.token)) { | |
| 10692 toNode.staticElement = node.staticElement; | |
| 10693 toNode.staticType = node.staticType; | |
| 10694 toNode.propagatedElement = node.propagatedElement; | |
| 10695 toNode.propagatedType = node.propagatedType; | |
| 10696 toNode.auxiliaryElements = node.auxiliaryElements; | |
| 10697 return true; | |
| 10698 } | |
| 10699 return false; | |
| 10700 } | |
| 10701 | |
| 10702 @override | |
| 10703 bool visitSimpleStringLiteral(SimpleStringLiteral node) { | |
| 10704 SimpleStringLiteral toNode = this._toNode as SimpleStringLiteral; | |
| 10705 if (_and(_isEqualTokens(node.literal, toNode.literal), | |
| 10706 node.value == toNode.value)) { | |
| 10707 toNode.propagatedType = node.propagatedType; | |
| 10708 toNode.staticType = node.staticType; | |
| 10709 return true; | |
| 10710 } | |
| 10711 return false; | |
| 10712 } | |
| 10713 | |
| 10714 @override | |
| 10715 bool visitStringInterpolation(StringInterpolation node) { | |
| 10716 StringInterpolation toNode = this._toNode as StringInterpolation; | |
| 10717 if (_isEqualNodeLists(node.elements, toNode.elements)) { | |
| 10718 toNode.propagatedType = node.propagatedType; | |
| 10719 toNode.staticType = node.staticType; | |
| 10720 return true; | |
| 10721 } | |
| 10722 return false; | |
| 10723 } | |
| 10724 | |
| 10725 @override | |
| 10726 bool visitSuperConstructorInvocation(SuperConstructorInvocation node) { | |
| 10727 SuperConstructorInvocation toNode = | |
| 10728 this._toNode as SuperConstructorInvocation; | |
| 10729 if (_and( | |
| 10730 _isEqualTokens(node.superKeyword, toNode.superKeyword), | |
| 10731 _isEqualTokens(node.period, toNode.period), | |
| 10732 _isEqualNodes(node.constructorName, toNode.constructorName), | |
| 10733 _isEqualNodes(node.argumentList, toNode.argumentList))) { | |
| 10734 toNode.staticElement = node.staticElement; | |
| 10735 return true; | |
| 10736 } | |
| 10737 return false; | |
| 10738 } | |
| 10739 | |
| 10740 @override | |
| 10741 bool visitSuperExpression(SuperExpression node) { | |
| 10742 SuperExpression toNode = this._toNode as SuperExpression; | |
| 10743 if (_isEqualTokens(node.superKeyword, toNode.superKeyword)) { | |
| 10744 toNode.propagatedType = node.propagatedType; | |
| 10745 toNode.staticType = node.staticType; | |
| 10746 return true; | |
| 10747 } | |
| 10748 return false; | |
| 10749 } | |
| 10750 | |
| 10751 @override | |
| 10752 bool visitSwitchCase(SwitchCase node) { | |
| 10753 SwitchCase toNode = this._toNode as SwitchCase; | |
| 10754 return _and( | |
| 10755 _isEqualNodeLists(node.labels, toNode.labels), | |
| 10756 _isEqualTokens(node.keyword, toNode.keyword), | |
| 10757 _isEqualNodes(node.expression, toNode.expression), | |
| 10758 _isEqualTokens(node.colon, toNode.colon), | |
| 10759 _isEqualNodeLists(node.statements, toNode.statements)); | |
| 10760 } | |
| 10761 | |
| 10762 @override | |
| 10763 bool visitSwitchDefault(SwitchDefault node) { | |
| 10764 SwitchDefault toNode = this._toNode as SwitchDefault; | |
| 10765 return _and( | |
| 10766 _isEqualNodeLists(node.labels, toNode.labels), | |
| 10767 _isEqualTokens(node.keyword, toNode.keyword), | |
| 10768 _isEqualTokens(node.colon, toNode.colon), | |
| 10769 _isEqualNodeLists(node.statements, toNode.statements)); | |
| 10770 } | |
| 10771 | |
| 10772 @override | |
| 10773 bool visitSwitchStatement(SwitchStatement node) { | |
| 10774 SwitchStatement toNode = this._toNode as SwitchStatement; | |
| 10775 return _and( | |
| 10776 _isEqualTokens(node.switchKeyword, toNode.switchKeyword), | |
| 10777 _isEqualTokens(node.leftParenthesis, toNode.leftParenthesis), | |
| 10778 _isEqualNodes(node.expression, toNode.expression), | |
| 10779 _isEqualTokens(node.rightParenthesis, toNode.rightParenthesis), | |
| 10780 _isEqualTokens(node.leftBracket, toNode.leftBracket), | |
| 10781 _isEqualNodeLists(node.members, toNode.members), | |
| 10782 _isEqualTokens(node.rightBracket, toNode.rightBracket)); | |
| 10783 } | |
| 10784 | |
| 10785 @override | |
| 10786 bool visitSymbolLiteral(SymbolLiteral node) { | |
| 10787 SymbolLiteral toNode = this._toNode as SymbolLiteral; | |
| 10788 if (_and(_isEqualTokens(node.poundSign, toNode.poundSign), | |
| 10789 _isEqualTokenLists(node.components, toNode.components))) { | |
| 10790 toNode.propagatedType = node.propagatedType; | |
| 10791 toNode.staticType = node.staticType; | |
| 10792 return true; | |
| 10793 } | |
| 10794 return false; | |
| 10795 } | |
| 10796 | |
| 10797 @override | |
| 10798 bool visitThisExpression(ThisExpression node) { | |
| 10799 ThisExpression toNode = this._toNode as ThisExpression; | |
| 10800 if (_isEqualTokens(node.thisKeyword, toNode.thisKeyword)) { | |
| 10801 toNode.propagatedType = node.propagatedType; | |
| 10802 toNode.staticType = node.staticType; | |
| 10803 return true; | |
| 10804 } | |
| 10805 return false; | |
| 10806 } | |
| 10807 | |
| 10808 @override | |
| 10809 bool visitThrowExpression(ThrowExpression node) { | |
| 10810 ThrowExpression toNode = this._toNode as ThrowExpression; | |
| 10811 if (_and(_isEqualTokens(node.throwKeyword, toNode.throwKeyword), | |
| 10812 _isEqualNodes(node.expression, toNode.expression))) { | |
| 10813 toNode.propagatedType = node.propagatedType; | |
| 10814 toNode.staticType = node.staticType; | |
| 10815 return true; | |
| 10816 } | |
| 10817 return false; | |
| 10818 } | |
| 10819 | |
| 10820 @override | |
| 10821 bool visitTopLevelVariableDeclaration(TopLevelVariableDeclaration node) { | |
| 10822 TopLevelVariableDeclaration toNode = | |
| 10823 this._toNode as TopLevelVariableDeclaration; | |
| 10824 return _and( | |
| 10825 _isEqualNodes(node.documentationComment, toNode.documentationComment), | |
| 10826 _isEqualNodeLists(node.metadata, toNode.metadata), | |
| 10827 _isEqualNodes(node.variables, toNode.variables), | |
| 10828 _isEqualTokens(node.semicolon, toNode.semicolon)); | |
| 10829 } | |
| 10830 | |
| 10831 @override | |
| 10832 bool visitTryStatement(TryStatement node) { | |
| 10833 TryStatement toNode = this._toNode as TryStatement; | |
| 10834 return _and( | |
| 10835 _isEqualTokens(node.tryKeyword, toNode.tryKeyword), | |
| 10836 _isEqualNodes(node.body, toNode.body), | |
| 10837 _isEqualNodeLists(node.catchClauses, toNode.catchClauses), | |
| 10838 _isEqualTokens(node.finallyKeyword, toNode.finallyKeyword), | |
| 10839 _isEqualNodes(node.finallyBlock, toNode.finallyBlock)); | |
| 10840 } | |
| 10841 | |
| 10842 @override | |
| 10843 bool visitTypeArgumentList(TypeArgumentList node) { | |
| 10844 TypeArgumentList toNode = this._toNode as TypeArgumentList; | |
| 10845 return _and( | |
| 10846 _isEqualTokens(node.leftBracket, toNode.leftBracket), | |
| 10847 _isEqualNodeLists(node.arguments, toNode.arguments), | |
| 10848 _isEqualTokens(node.rightBracket, toNode.rightBracket)); | |
| 10849 } | |
| 10850 | |
| 10851 @override | |
| 10852 bool visitTypeName(TypeName node) { | |
| 10853 TypeName toNode = this._toNode as TypeName; | |
| 10854 if (_and(_isEqualNodes(node.name, toNode.name), | |
| 10855 _isEqualNodes(node.typeArguments, toNode.typeArguments))) { | |
| 10856 toNode.type = node.type; | |
| 10857 return true; | |
| 10858 } | |
| 10859 return false; | |
| 10860 } | |
| 10861 | |
| 10862 @override | |
| 10863 bool visitTypeParameter(TypeParameter node) { | |
| 10864 TypeParameter toNode = this._toNode as TypeParameter; | |
| 10865 return _and( | |
| 10866 _isEqualNodes(node.documentationComment, toNode.documentationComment), | |
| 10867 _isEqualNodeLists(node.metadata, toNode.metadata), | |
| 10868 _isEqualNodes(node.name, toNode.name), | |
| 10869 _isEqualTokens(node.extendsKeyword, toNode.extendsKeyword), | |
| 10870 _isEqualNodes(node.bound, toNode.bound)); | |
| 10871 } | |
| 10872 | |
| 10873 @override | |
| 10874 bool visitTypeParameterList(TypeParameterList node) { | |
| 10875 TypeParameterList toNode = this._toNode as TypeParameterList; | |
| 10876 return _and( | |
| 10877 _isEqualTokens(node.leftBracket, toNode.leftBracket), | |
| 10878 _isEqualNodeLists(node.typeParameters, toNode.typeParameters), | |
| 10879 _isEqualTokens(node.rightBracket, toNode.rightBracket)); | |
| 10880 } | |
| 10881 | |
| 10882 @override | |
| 10883 bool visitVariableDeclaration(VariableDeclaration node) { | |
| 10884 VariableDeclaration toNode = this._toNode as VariableDeclaration; | |
| 10885 return _and( | |
| 10886 _isEqualNodes(node.documentationComment, toNode.documentationComment), | |
| 10887 _isEqualNodeLists(node.metadata, toNode.metadata), | |
| 10888 _isEqualNodes(node.name, toNode.name), | |
| 10889 _isEqualTokens(node.equals, toNode.equals), | |
| 10890 _isEqualNodes(node.initializer, toNode.initializer)); | |
| 10891 } | |
| 10892 | |
| 10893 @override | |
| 10894 bool visitVariableDeclarationList(VariableDeclarationList node) { | |
| 10895 VariableDeclarationList toNode = this._toNode as VariableDeclarationList; | |
| 10896 return _and( | |
| 10897 _isEqualNodes(node.documentationComment, toNode.documentationComment), | |
| 10898 _isEqualNodeLists(node.metadata, toNode.metadata), | |
| 10899 _isEqualTokens(node.keyword, toNode.keyword), | |
| 10900 _isEqualNodes(node.type, toNode.type), | |
| 10901 _isEqualNodeLists(node.variables, toNode.variables)); | |
| 10902 } | |
| 10903 | |
| 10904 @override | |
| 10905 bool visitVariableDeclarationStatement(VariableDeclarationStatement node) { | |
| 10906 VariableDeclarationStatement toNode = | |
| 10907 this._toNode as VariableDeclarationStatement; | |
| 10908 return _and(_isEqualNodes(node.variables, toNode.variables), | |
| 10909 _isEqualTokens(node.semicolon, toNode.semicolon)); | |
| 10910 } | |
| 10911 | |
| 10912 @override | |
| 10913 bool visitWhileStatement(WhileStatement node) { | |
| 10914 WhileStatement toNode = this._toNode as WhileStatement; | |
| 10915 return _and( | |
| 10916 _isEqualTokens(node.whileKeyword, toNode.whileKeyword), | |
| 10917 _isEqualTokens(node.leftParenthesis, toNode.leftParenthesis), | |
| 10918 _isEqualNodes(node.condition, toNode.condition), | |
| 10919 _isEqualTokens(node.rightParenthesis, toNode.rightParenthesis), | |
| 10920 _isEqualNodes(node.body, toNode.body)); | |
| 10921 } | |
| 10922 | |
| 10923 @override | |
| 10924 bool visitWithClause(WithClause node) { | |
| 10925 WithClause toNode = this._toNode as WithClause; | |
| 10926 return _and(_isEqualTokens(node.withKeyword, toNode.withKeyword), | |
| 10927 _isEqualNodeLists(node.mixinTypes, toNode.mixinTypes)); | |
| 10928 } | |
| 10929 | |
| 10930 @override | |
| 10931 bool visitYieldStatement(YieldStatement node) { | |
| 10932 YieldStatement toNode = this._toNode as YieldStatement; | |
| 10933 return _and( | |
| 10934 _isEqualTokens(node.yieldKeyword, toNode.yieldKeyword), | |
| 10935 _isEqualNodes(node.expression, toNode.expression), | |
| 10936 _isEqualTokens(node.semicolon, toNode.semicolon)); | |
| 10937 } | |
| 10938 | |
| 10939 /** | |
| 10940 * Return `true` if all of the parameters are `true`. | |
| 10941 */ | |
| 10942 bool _and(bool b1, bool b2, | |
| 10943 [bool b3 = true, | |
| 10944 bool b4 = true, | |
| 10945 bool b5 = true, | |
| 10946 bool b6 = true, | |
| 10947 bool b7 = true, | |
| 10948 bool b8 = true, | |
| 10949 bool b9 = true, | |
| 10950 bool b10 = true, | |
| 10951 bool b11 = true, | |
| 10952 bool b12 = true, | |
| 10953 bool b13 = true]) { | |
| 10954 // TODO(brianwilkerson) Inline this method. | |
| 10955 return b1 && | |
| 10956 b2 && | |
| 10957 b3 && | |
| 10958 b4 && | |
| 10959 b5 && | |
| 10960 b6 && | |
| 10961 b7 && | |
| 10962 b8 && | |
| 10963 b9 && | |
| 10964 b10 && | |
| 10965 b11 && | |
| 10966 b12 && | |
| 10967 b13; | |
| 10968 } | |
| 10969 | |
| 10970 /** | |
| 10971 * Return `true` if the [first] and [second] lists of AST nodes have the same | |
| 10972 * size and corresponding elements are equal. | |
| 10973 */ | |
| 10974 bool _isEqualNodeLists(NodeList first, NodeList second) { | |
| 10975 if (first == null) { | |
| 10976 return second == null; | |
| 10977 } else if (second == null) { | |
| 10978 return false; | |
| 10979 } | |
| 10980 int size = first.length; | |
| 10981 if (second.length != size) { | |
| 10982 return false; | |
| 10983 } | |
| 10984 bool equal = true; | |
| 10985 for (int i = 0; i < size; i++) { | |
| 10986 if (!_isEqualNodes(first[i], second[i])) { | |
| 10987 equal = false; | |
| 10988 } | |
| 10989 } | |
| 10990 return equal; | |
| 10991 } | |
| 10992 | |
| 10993 /** | |
| 10994 * Return `true` if the [fromNode] and [toNode] have the same structure. As a | |
| 10995 * side-effect, if the nodes do have the same structure, any resolution data | |
| 10996 * from the first node will be copied to the second node. | |
| 10997 */ | |
| 10998 bool _isEqualNodes(AstNode fromNode, AstNode toNode) { | |
| 10999 if (fromNode == null) { | |
| 11000 return toNode == null; | |
| 11001 } else if (toNode == null) { | |
| 11002 return false; | |
| 11003 } else if (fromNode.runtimeType == toNode.runtimeType) { | |
| 11004 this._toNode = toNode; | |
| 11005 return fromNode.accept(this); | |
| 11006 } | |
| 11007 // | |
| 11008 // Check for a simple transformation caused by entering a period. | |
| 11009 // | |
| 11010 if (toNode is PrefixedIdentifier) { | |
| 11011 SimpleIdentifier prefix = toNode.prefix; | |
| 11012 if (fromNode.runtimeType == prefix.runtimeType) { | |
| 11013 this._toNode = prefix; | |
| 11014 return fromNode.accept(this); | |
| 11015 } | |
| 11016 } else if (toNode is PropertyAccess) { | |
| 11017 Expression target = toNode.target; | |
| 11018 if (fromNode.runtimeType == target.runtimeType) { | |
| 11019 this._toNode = target; | |
| 11020 return fromNode.accept(this); | |
| 11021 } | |
| 11022 } | |
| 11023 return false; | |
| 11024 } | |
| 11025 | |
| 11026 /** | |
| 11027 * Return `true` if the [first] and [second] arrays of tokens have the same | |
| 11028 * length and corresponding elements are equal. | |
| 11029 */ | |
| 11030 bool _isEqualTokenLists(List<Token> first, List<Token> second) { | |
| 11031 int length = first.length; | |
| 11032 if (second.length != length) { | |
| 11033 return false; | |
| 11034 } | |
| 11035 for (int i = 0; i < length; i++) { | |
| 11036 if (!_isEqualTokens(first[i], second[i])) { | |
| 11037 return false; | |
| 11038 } | |
| 11039 } | |
| 11040 return true; | |
| 11041 } | |
| 11042 | |
| 11043 /** | |
| 11044 * Return `true` if the [first] and [second] tokens have the same structure. | |
| 11045 */ | |
| 11046 bool _isEqualTokens(Token first, Token second) { | |
| 11047 if (first == null) { | |
| 11048 return second == null; | |
| 11049 } else if (second == null) { | |
| 11050 return false; | |
| 11051 } | |
| 11052 return first.lexeme == second.lexeme; | |
| 11053 } | |
| 11054 | |
| 11055 /** | |
| 11056 * Copy resolution data from the [fromNode] to the [toNode]. | |
| 11057 */ | |
| 11058 static void copyResolutionData(AstNode fromNode, AstNode toNode) { | |
| 11059 ResolutionCopier copier = new ResolutionCopier(); | |
| 11060 copier._isEqualNodes(fromNode, toNode); | |
| 11061 } | |
| 11062 } | |
| OLD | NEW |