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