| OLD | NEW |
| (Empty) |
| 1 // This code was auto-generated, is not intended to be edited, and is subject to | |
| 2 // significant change. Please see the README file for more information. | |
| 3 library engine.parser; | |
| 4 import 'dart:collection'; | |
| 5 import 'java_core.dart'; | |
| 6 import 'instrumentation.dart'; | |
| 7 import 'error.dart'; | |
| 8 import 'source.dart'; | |
| 9 import 'scanner.dart'; | |
| 10 import 'ast.dart'; | |
| 11 import 'utilities_dart.dart'; | |
| 12 import 'engine.dart' show AnalysisEngine; | |
| 13 /** | |
| 14 * Instances of the class `CommentAndMetadata` implement a simple data-holder fo
r a method | |
| 15 * that needs to return multiple values. | |
| 16 * | |
| 17 * @coverage dart.engine.parser | |
| 18 */ | |
| 19 class CommentAndMetadata { | |
| 20 | |
| 21 /** | |
| 22 * The documentation comment that was parsed, or `null` if none was given. | |
| 23 */ | |
| 24 Comment comment; | |
| 25 | |
| 26 /** | |
| 27 * The metadata that was parsed. | |
| 28 */ | |
| 29 List<Annotation> metadata; | |
| 30 | |
| 31 /** | |
| 32 * Initialize a newly created holder with the given data. | |
| 33 * | |
| 34 * @param comment the documentation comment that was parsed | |
| 35 * @param metadata the metadata that was parsed | |
| 36 */ | |
| 37 CommentAndMetadata(Comment comment, List<Annotation> metadata) { | |
| 38 this.comment = comment; | |
| 39 this.metadata = metadata; | |
| 40 } | |
| 41 } | |
| 42 /** | |
| 43 * Instances of the class `FinalConstVarOrType` implement a simple data-holder f
or a method | |
| 44 * that needs to return multiple values. | |
| 45 * | |
| 46 * @coverage dart.engine.parser | |
| 47 */ | |
| 48 class FinalConstVarOrType { | |
| 49 | |
| 50 /** | |
| 51 * The 'final', 'const' or 'var' keyword, or `null` if none was given. | |
| 52 */ | |
| 53 Token keyword; | |
| 54 | |
| 55 /** | |
| 56 * The type, of `null` if no type was specified. | |
| 57 */ | |
| 58 TypeName type; | |
| 59 | |
| 60 /** | |
| 61 * Initialize a newly created holder with the given data. | |
| 62 * | |
| 63 * @param keyword the 'final', 'const' or 'var' keyword | |
| 64 * @param type the type | |
| 65 */ | |
| 66 FinalConstVarOrType(Token keyword, TypeName type) { | |
| 67 this.keyword = keyword; | |
| 68 this.type = type; | |
| 69 } | |
| 70 } | |
| 71 /** | |
| 72 * Instances of the class `Modifiers` implement a simple data-holder for a metho
d that needs | |
| 73 * to return multiple values. | |
| 74 * | |
| 75 * @coverage dart.engine.parser | |
| 76 */ | |
| 77 class Modifiers { | |
| 78 | |
| 79 /** | |
| 80 * The token representing the keyword 'abstract', or `null` if the keyword was
not found. | |
| 81 */ | |
| 82 Token abstractKeyword; | |
| 83 | |
| 84 /** | |
| 85 * The token representing the keyword 'const', or `null` if the keyword was no
t found. | |
| 86 */ | |
| 87 Token constKeyword; | |
| 88 | |
| 89 /** | |
| 90 * The token representing the keyword 'external', or `null` if the keyword was
not found. | |
| 91 */ | |
| 92 Token externalKeyword; | |
| 93 | |
| 94 /** | |
| 95 * The token representing the keyword 'factory', or `null` if the keyword was
not found. | |
| 96 */ | |
| 97 Token factoryKeyword; | |
| 98 | |
| 99 /** | |
| 100 * The token representing the keyword 'final', or `null` if the keyword was no
t found. | |
| 101 */ | |
| 102 Token finalKeyword; | |
| 103 | |
| 104 /** | |
| 105 * The token representing the keyword 'static', or `null` if the keyword was n
ot found. | |
| 106 */ | |
| 107 Token staticKeyword; | |
| 108 | |
| 109 /** | |
| 110 * The token representing the keyword 'var', or `null` if the keyword was not
found. | |
| 111 */ | |
| 112 Token varKeyword; | |
| 113 String toString() { | |
| 114 JavaStringBuilder builder = new JavaStringBuilder(); | |
| 115 bool needsSpace = appendKeyword(builder, false, abstractKeyword); | |
| 116 needsSpace = appendKeyword(builder, needsSpace, constKeyword); | |
| 117 needsSpace = appendKeyword(builder, needsSpace, externalKeyword); | |
| 118 needsSpace = appendKeyword(builder, needsSpace, factoryKeyword); | |
| 119 needsSpace = appendKeyword(builder, needsSpace, finalKeyword); | |
| 120 needsSpace = appendKeyword(builder, needsSpace, staticKeyword); | |
| 121 appendKeyword(builder, needsSpace, varKeyword); | |
| 122 return builder.toString(); | |
| 123 } | |
| 124 | |
| 125 /** | |
| 126 * If the given keyword is not `null`, append it to the given builder, prefixi
ng it with a | |
| 127 * space if needed. | |
| 128 * | |
| 129 * @param builder the builder to which the keyword will be appended | |
| 130 * @param needsSpace `true` if the keyword needs to be prefixed with a space | |
| 131 * @param keyword the keyword to be appended | |
| 132 * @return `true` if subsequent keywords need to be prefixed with a space | |
| 133 */ | |
| 134 bool appendKeyword(JavaStringBuilder builder, bool needsSpace, Token keyword)
{ | |
| 135 if (keyword != null) { | |
| 136 if (needsSpace) { | |
| 137 builder.appendChar(0x20); | |
| 138 } | |
| 139 builder.append(keyword.lexeme); | |
| 140 return true; | |
| 141 } | |
| 142 return needsSpace; | |
| 143 } | |
| 144 } | |
| 145 /** | |
| 146 * Instances of the class `Parser` are used to parse tokens into an AST structur
e. | |
| 147 * | |
| 148 * @coverage dart.engine.parser | |
| 149 */ | |
| 150 class Parser { | |
| 151 | |
| 152 /** | |
| 153 * The source being parsed. | |
| 154 */ | |
| 155 Source _source; | |
| 156 | |
| 157 /** | |
| 158 * The error listener that will be informed of any errors that are found durin
g the parse. | |
| 159 */ | |
| 160 AnalysisErrorListener _errorListener; | |
| 161 | |
| 162 /** | |
| 163 * The next token to be parsed. | |
| 164 */ | |
| 165 Token _currentToken; | |
| 166 | |
| 167 /** | |
| 168 * A flag indicating whether the parser is currently in the body of a loop. | |
| 169 */ | |
| 170 bool _inLoop = false; | |
| 171 | |
| 172 /** | |
| 173 * A flag indicating whether the parser is currently in a switch statement. | |
| 174 */ | |
| 175 bool _inSwitch = false; | |
| 176 static String _HIDE = "hide"; | |
| 177 static String _OF = "of"; | |
| 178 static String _ON = "on"; | |
| 179 static String _SHOW = "show"; | |
| 180 static String _NATIVE = "native"; | |
| 181 | |
| 182 /** | |
| 183 * Initialize a newly created parser. | |
| 184 * | |
| 185 * @param source the source being parsed | |
| 186 * @param errorListener the error listener that will be informed of any errors
that are found | |
| 187 * during the parse | |
| 188 */ | |
| 189 Parser(Source source, AnalysisErrorListener errorListener) { | |
| 190 this._source = source; | |
| 191 this._errorListener = errorListener; | |
| 192 } | |
| 193 | |
| 194 /** | |
| 195 * Parse a compilation unit, starting with the given token. | |
| 196 * | |
| 197 * @param token the first token of the compilation unit | |
| 198 * @return the compilation unit that was parsed | |
| 199 */ | |
| 200 CompilationUnit parseCompilationUnit(Token token) { | |
| 201 InstrumentationBuilder instrumentation = Instrumentation.builder2("dart.engi
ne.Parser.parseCompilationUnit"); | |
| 202 try { | |
| 203 _currentToken = token; | |
| 204 CompilationUnit compilationUnit = parseCompilationUnit2(); | |
| 205 gatherTodoComments(token); | |
| 206 return compilationUnit; | |
| 207 } finally { | |
| 208 instrumentation.log2(2); | |
| 209 } | |
| 210 } | |
| 211 | |
| 212 /** | |
| 213 * Parse an expression, starting with the given token. | |
| 214 * | |
| 215 * @param token the first token of the expression | |
| 216 * @return the expression that was parsed, or `null` if the tokens do not repr
esent a | |
| 217 * recognizable expression | |
| 218 */ | |
| 219 Expression parseExpression(Token token) { | |
| 220 InstrumentationBuilder instrumentation = Instrumentation.builder2("dart.engi
ne.Parser.parseExpression"); | |
| 221 try { | |
| 222 _currentToken = token; | |
| 223 return parseExpression2(); | |
| 224 } finally { | |
| 225 instrumentation.log(); | |
| 226 } | |
| 227 } | |
| 228 | |
| 229 /** | |
| 230 * Parse a statement, starting with the given token. | |
| 231 * | |
| 232 * @param token the first token of the statement | |
| 233 * @return the statement that was parsed, or `null` if the tokens do not repre
sent a | |
| 234 * recognizable statement | |
| 235 */ | |
| 236 Statement parseStatement(Token token) { | |
| 237 InstrumentationBuilder instrumentation = Instrumentation.builder2("dart.engi
ne.Parser.parseStatement"); | |
| 238 try { | |
| 239 _currentToken = token; | |
| 240 return parseStatement2(); | |
| 241 } finally { | |
| 242 instrumentation.log(); | |
| 243 } | |
| 244 } | |
| 245 | |
| 246 /** | |
| 247 * Parse a sequence of statements, starting with the given token. | |
| 248 * | |
| 249 * @param token the first token of the sequence of statement | |
| 250 * @return the statements that were parsed, or `null` if the tokens do not rep
resent a | |
| 251 * recognizable sequence of statements | |
| 252 */ | |
| 253 List<Statement> parseStatements(Token token) { | |
| 254 InstrumentationBuilder instrumentation = Instrumentation.builder2("dart.engi
ne.Parser.parseStatements"); | |
| 255 try { | |
| 256 _currentToken = token; | |
| 257 return parseStatements2(); | |
| 258 } finally { | |
| 259 instrumentation.log(); | |
| 260 } | |
| 261 } | |
| 262 void set currentToken(Token currentToken) { | |
| 263 this._currentToken = currentToken; | |
| 264 } | |
| 265 | |
| 266 /** | |
| 267 * Advance to the next token in the token stream. | |
| 268 */ | |
| 269 void advance() { | |
| 270 _currentToken = _currentToken.next; | |
| 271 } | |
| 272 | |
| 273 /** | |
| 274 * Append the character equivalent of the given scalar value to the given buil
der. Use the start | |
| 275 * and end indices to report an error, and don't append anything to the builde
r, if the scalar | |
| 276 * value is invalid. | |
| 277 * | |
| 278 * @param builder the builder to which the scalar value is to be appended | |
| 279 * @param escapeSequence the escape sequence that was parsed to produce the sc
alar value | |
| 280 * @param scalarValue the value to be appended | |
| 281 * @param startIndex the index of the first character representing the scalar
value | |
| 282 * @param endIndex the index of the last character representing the scalar val
ue | |
| 283 */ | |
| 284 void appendScalarValue(JavaStringBuilder builder, String escapeSequence, int s
calarValue, int startIndex, int endIndex) { | |
| 285 if (scalarValue < 0 || scalarValue > Character.MAX_CODE_POINT || (scalarValu
e >= 0xD800 && scalarValue <= 0xDFFF)) { | |
| 286 reportError8(ParserErrorCode.INVALID_CODE_POINT, [escapeSequence]); | |
| 287 return; | |
| 288 } | |
| 289 if (scalarValue < Character.MAX_VALUE) { | |
| 290 builder.appendChar(scalarValue as int); | |
| 291 } else { | |
| 292 builder.append(Character.toChars(scalarValue)); | |
| 293 } | |
| 294 } | |
| 295 | |
| 296 /** | |
| 297 * Compute the content of a string with the given literal representation. | |
| 298 * | |
| 299 * @param lexeme the literal representation of the string | |
| 300 * @param first `true` if this is the first token in a string literal | |
| 301 * @param last `true` if this is the last token in a string literal | |
| 302 * @return the actual value of the string | |
| 303 */ | |
| 304 String computeStringValue(String lexeme, bool first, bool last) { | |
| 305 bool isRaw = false; | |
| 306 int start = 0; | |
| 307 if (first) { | |
| 308 if (lexeme.startsWith("r\"\"\"") || lexeme.startsWith("r'''")) { | |
| 309 isRaw = true; | |
| 310 start += 4; | |
| 311 } else if (lexeme.startsWith("r\"") || lexeme.startsWith("r'")) { | |
| 312 isRaw = true; | |
| 313 start += 2; | |
| 314 } else if (lexeme.startsWith("\"\"\"") || lexeme.startsWith("'''")) { | |
| 315 start += 3; | |
| 316 } else if (lexeme.startsWith("\"") || lexeme.startsWith("'")) { | |
| 317 start += 1; | |
| 318 } | |
| 319 } | |
| 320 int end = lexeme.length; | |
| 321 if (last) { | |
| 322 if (lexeme.endsWith("\"\"\"") || lexeme.endsWith("'''")) { | |
| 323 end -= 3; | |
| 324 } else if (lexeme.endsWith("\"") || lexeme.endsWith("'")) { | |
| 325 end -= 1; | |
| 326 } | |
| 327 } | |
| 328 if (end - start + 1 < 0) { | |
| 329 AnalysisEngine.instance.logger.logError("Internal error: computeStringValu
e(${lexeme}, ${first}, ${last})"); | |
| 330 return ""; | |
| 331 } | |
| 332 if (isRaw) { | |
| 333 return lexeme.substring(start, end); | |
| 334 } | |
| 335 JavaStringBuilder builder = new JavaStringBuilder(); | |
| 336 int index = start; | |
| 337 while (index < end) { | |
| 338 index = translateCharacter(builder, lexeme, index); | |
| 339 } | |
| 340 return builder.toString(); | |
| 341 } | |
| 342 | |
| 343 /** | |
| 344 * Convert the given method declaration into the nearest valid top-level funct
ion declaration. | |
| 345 * | |
| 346 * @param method the method to be converted | |
| 347 * @return the function declaration that most closely captures the components
of the given method | |
| 348 * declaration | |
| 349 */ | |
| 350 FunctionDeclaration convertToFunctionDeclaration(MethodDeclaration method) =>
new FunctionDeclaration.full(method.documentationComment, method.metadata, metho
d.externalKeyword, method.returnType, method.propertyKeyword, method.name, new F
unctionExpression.full(method.parameters, method.body)); | |
| 351 | |
| 352 /** | |
| 353 * Return `true` if the current token could be the start of a compilation unit
member. This | |
| 354 * method is used for recovery purposes to decide when to stop skipping tokens
after finding an | |
| 355 * error while parsing a compilation unit member. | |
| 356 * | |
| 357 * @return `true` if the current token could be the start of a compilation uni
t member | |
| 358 */ | |
| 359 bool couldBeStartOfCompilationUnitMember() { | |
| 360 if ((matches(Keyword.IMPORT) || matches(Keyword.EXPORT) || matches(Keyword.L
IBRARY) || matches(Keyword.PART)) && !matches4(peek(), TokenType.PERIOD) && !mat
ches4(peek(), TokenType.LT)) { | |
| 361 return true; | |
| 362 } else if (matches(Keyword.CLASS)) { | |
| 363 return true; | |
| 364 } else if (matches(Keyword.TYPEDEF) && !matches4(peek(), TokenType.PERIOD) &
& !matches4(peek(), TokenType.LT)) { | |
| 365 return true; | |
| 366 } else if (matches(Keyword.VOID) || ((matches(Keyword.GET) || matches(Keywor
d.SET)) && matchesIdentifier2(peek())) || (matches(Keyword.OPERATOR) && isOperat
or(peek()))) { | |
| 367 return true; | |
| 368 } else if (matchesIdentifier()) { | |
| 369 if (matches4(peek(), TokenType.OPEN_PAREN)) { | |
| 370 return true; | |
| 371 } | |
| 372 Token token = skipReturnType(_currentToken); | |
| 373 if (token == null) { | |
| 374 return false; | |
| 375 } | |
| 376 if (matches(Keyword.GET) || matches(Keyword.SET) || (matches(Keyword.OPERA
TOR) && isOperator(peek())) || matchesIdentifier()) { | |
| 377 return true; | |
| 378 } | |
| 379 } | |
| 380 return false; | |
| 381 } | |
| 382 | |
| 383 /** | |
| 384 * Create a synthetic identifier. | |
| 385 * | |
| 386 * @return the synthetic identifier that was created | |
| 387 */ | |
| 388 SimpleIdentifier createSyntheticIdentifier() => new SimpleIdentifier.full(crea
teSyntheticToken2(TokenType.IDENTIFIER)); | |
| 389 | |
| 390 /** | |
| 391 * Create a synthetic string literal. | |
| 392 * | |
| 393 * @return the synthetic string literal that was created | |
| 394 */ | |
| 395 SimpleStringLiteral createSyntheticStringLiteral() => new SimpleStringLiteral.
full(createSyntheticToken2(TokenType.STRING), ""); | |
| 396 | |
| 397 /** | |
| 398 * Create a synthetic token representing the given keyword. | |
| 399 * | |
| 400 * @return the synthetic token that was created | |
| 401 */ | |
| 402 Token createSyntheticToken(Keyword keyword) => new Parser_SyntheticKeywordToke
n(keyword, _currentToken.offset); | |
| 403 | |
| 404 /** | |
| 405 * Create a synthetic token with the given type. | |
| 406 * | |
| 407 * @return the synthetic token that was created | |
| 408 */ | |
| 409 Token createSyntheticToken2(TokenType type) => new StringToken(type, "", _curr
entToken.offset); | |
| 410 | |
| 411 /** | |
| 412 * Check that the given expression is assignable and report an error if it isn
't. | |
| 413 * | |
| 414 * <pre> | |
| 415 * assignableExpression ::= | |
| 416 * primary (arguments* assignableSelector)+ | |
| 417 * | 'super' assignableSelector | |
| 418 * | identifier | |
| 419 * | |
| 420 * assignableSelector ::= | |
| 421 * '[' expression ']' | |
| 422 * | '.' identifier | |
| 423 * </pre> | |
| 424 * | |
| 425 * @param expression the expression being checked | |
| 426 */ | |
| 427 void ensureAssignable(Expression expression) { | |
| 428 if (expression != null && !expression.isAssignable) { | |
| 429 reportError8(ParserErrorCode.ILLEGAL_ASSIGNMENT_TO_NON_ASSIGNABLE, []); | |
| 430 } | |
| 431 } | |
| 432 | |
| 433 /** | |
| 434 * If the current token is a keyword matching the given string, return it afte
r advancing to the | |
| 435 * next token. Otherwise report an error and return the current token without
advancing. | |
| 436 * | |
| 437 * @param keyword the keyword that is expected | |
| 438 * @return the token that matched the given type | |
| 439 */ | |
| 440 Token expect(Keyword keyword) { | |
| 441 if (matches(keyword)) { | |
| 442 return andAdvance; | |
| 443 } | |
| 444 reportError8(ParserErrorCode.EXPECTED_TOKEN, [keyword.syntax]); | |
| 445 return _currentToken; | |
| 446 } | |
| 447 | |
| 448 /** | |
| 449 * If the current token has the expected type, return it after advancing to th
e next token. | |
| 450 * Otherwise report an error and return the current token without advancing. | |
| 451 * | |
| 452 * @param type the type of token that is expected | |
| 453 * @return the token that matched the given type | |
| 454 */ | |
| 455 Token expect2(TokenType type) { | |
| 456 if (matches5(type)) { | |
| 457 return andAdvance; | |
| 458 } | |
| 459 if (identical(type, TokenType.SEMICOLON)) { | |
| 460 reportError9(ParserErrorCode.EXPECTED_TOKEN, _currentToken.previous, [type
.lexeme]); | |
| 461 } else { | |
| 462 reportError8(ParserErrorCode.EXPECTED_TOKEN, [type.lexeme]); | |
| 463 } | |
| 464 return _currentToken; | |
| 465 } | |
| 466 | |
| 467 /** | |
| 468 * Search the given list of ranges for a range that contains the given index.
Return the range | |
| 469 * that was found, or `null` if none of the ranges contain the index. | |
| 470 * | |
| 471 * @param ranges the ranges to be searched | |
| 472 * @param index the index contained in the returned range | |
| 473 * @return the range that was found | |
| 474 */ | |
| 475 List<int> findRange(List<List<int>> ranges, int index) { | |
| 476 for (List<int> range in ranges) { | |
| 477 if (range[0] <= index && index <= range[1]) { | |
| 478 return range; | |
| 479 } else if (index < range[0]) { | |
| 480 return null; | |
| 481 } | |
| 482 } | |
| 483 return null; | |
| 484 } | |
| 485 void gatherTodoComments(Token token) { | |
| 486 while (token != null && token.type != TokenType.EOF) { | |
| 487 Token commentToken = token.precedingComments; | |
| 488 while (commentToken != null) { | |
| 489 if (identical(commentToken.type, TokenType.SINGLE_LINE_COMMENT) || ident
ical(commentToken.type, TokenType.MULTI_LINE_COMMENT)) { | |
| 490 scrapeTodoComment(commentToken); | |
| 491 } | |
| 492 commentToken = commentToken.next; | |
| 493 } | |
| 494 token = token.next; | |
| 495 } | |
| 496 } | |
| 497 | |
| 498 /** | |
| 499 * Advance to the next token in the token stream, making it the new current to
ken. | |
| 500 * | |
| 501 * @return the token that was current before this method was invoked | |
| 502 */ | |
| 503 Token get andAdvance { | |
| 504 Token token = _currentToken; | |
| 505 advance(); | |
| 506 return token; | |
| 507 } | |
| 508 | |
| 509 /** | |
| 510 * Return a list of the ranges of characters in the given comment string that
should be treated as | |
| 511 * code blocks. | |
| 512 * | |
| 513 * @param comment the comment being processed | |
| 514 * @return the ranges of characters that should be treated as code blocks | |
| 515 */ | |
| 516 List<List<int>> getCodeBlockRanges(String comment) { | |
| 517 List<List<int>> ranges = new List<List<int>>(); | |
| 518 int length = comment.length; | |
| 519 int index = 0; | |
| 520 if (comment.startsWith("/**") || comment.startsWith("///")) { | |
| 521 index = 3; | |
| 522 } | |
| 523 while (index < length) { | |
| 524 int currentChar = comment.codeUnitAt(index); | |
| 525 if (currentChar == 0xD || currentChar == 0xA) { | |
| 526 index = index + 1; | |
| 527 while (index < length && Character.isWhitespace(comment.codeUnitAt(index
))) { | |
| 528 index = index + 1; | |
| 529 } | |
| 530 if (JavaString.startsWithBefore(comment, "* ", index)) { | |
| 531 int end = index + 6; | |
| 532 while (end < length && comment.codeUnitAt(end) != 0xD && comment.codeU
nitAt(end) != 0xA) { | |
| 533 end = end + 1; | |
| 534 } | |
| 535 ranges.add(<int> [index, end]); | |
| 536 index = end; | |
| 537 } | |
| 538 } else if (JavaString.startsWithBefore(comment, "[:", index)) { | |
| 539 int end = JavaString.indexOf(comment, ":]", index + 2); | |
| 540 if (end < 0) { | |
| 541 end = length; | |
| 542 } | |
| 543 ranges.add(<int> [index, end]); | |
| 544 index = end + 1; | |
| 545 } else { | |
| 546 index = index + 1; | |
| 547 } | |
| 548 } | |
| 549 return ranges; | |
| 550 } | |
| 551 | |
| 552 /** | |
| 553 * Return the end token associated with the given begin token, or `null` if ei
ther the given | |
| 554 * token is not a begin token or it does not have an end token associated with
it. | |
| 555 * | |
| 556 * @param beginToken the token that is expected to have an end token associate
d with it | |
| 557 * @return the end token associated with the begin token | |
| 558 */ | |
| 559 Token getEndToken(Token beginToken) { | |
| 560 if (beginToken is BeginToken) { | |
| 561 return ((beginToken as BeginToken)).endToken; | |
| 562 } | |
| 563 return null; | |
| 564 } | |
| 565 | |
| 566 /** | |
| 567 * Return `true` if the current token is the first token of a return type that
is followed | |
| 568 * by an identifier, possibly followed by a list of type parameters, followed
by a | |
| 569 * left-parenthesis. This is used by parseTypeAlias to determine whether or no
t to parse a return | |
| 570 * type. | |
| 571 * | |
| 572 * @return `true` if we can successfully parse the rest of a type alias if we
first parse a | |
| 573 * return type. | |
| 574 */ | |
| 575 bool hasReturnTypeInTypeAlias() { | |
| 576 Token next = skipReturnType(_currentToken); | |
| 577 if (next == null) { | |
| 578 return false; | |
| 579 } | |
| 580 return matchesIdentifier2(next); | |
| 581 } | |
| 582 | |
| 583 /** | |
| 584 * Return `true` if the current token appears to be the beginning of a functio
n declaration. | |
| 585 * | |
| 586 * @return `true` if the current token appears to be the beginning of a functi
on declaration | |
| 587 */ | |
| 588 bool isFunctionDeclaration() { | |
| 589 if (matches(Keyword.VOID)) { | |
| 590 return true; | |
| 591 } | |
| 592 Token afterReturnType = skipTypeName(_currentToken); | |
| 593 if (afterReturnType == null) { | |
| 594 afterReturnType = _currentToken; | |
| 595 } | |
| 596 Token afterIdentifier = skipSimpleIdentifier(afterReturnType); | |
| 597 if (afterIdentifier == null) { | |
| 598 afterIdentifier = skipSimpleIdentifier(_currentToken); | |
| 599 } | |
| 600 if (afterIdentifier == null) { | |
| 601 return false; | |
| 602 } | |
| 603 if (isFunctionExpression(afterIdentifier)) { | |
| 604 return true; | |
| 605 } | |
| 606 if (matches(Keyword.GET)) { | |
| 607 Token afterName = skipSimpleIdentifier(_currentToken.next); | |
| 608 if (afterName == null) { | |
| 609 return false; | |
| 610 } | |
| 611 return matches4(afterName, TokenType.FUNCTION) || matches4(afterName, Toke
nType.OPEN_CURLY_BRACKET); | |
| 612 } | |
| 613 return false; | |
| 614 } | |
| 615 | |
| 616 /** | |
| 617 * Return `true` if the given token appears to be the beginning of a function
expression. | |
| 618 * | |
| 619 * @param startToken the token that might be the start of a function expressio
n | |
| 620 * @return `true` if the given token appears to be the beginning of a function
expression | |
| 621 */ | |
| 622 bool isFunctionExpression(Token startToken) { | |
| 623 Token afterParameters = skipFormalParameterList(startToken); | |
| 624 if (afterParameters == null) { | |
| 625 return false; | |
| 626 } | |
| 627 return matchesAny(afterParameters, [TokenType.OPEN_CURLY_BRACKET, TokenType.
FUNCTION]); | |
| 628 } | |
| 629 | |
| 630 /** | |
| 631 * Return `true` if the given character is a valid hexadecimal digit. | |
| 632 * | |
| 633 * @param character the character being tested | |
| 634 * @return `true` if the character is a valid hexadecimal digit | |
| 635 */ | |
| 636 bool isHexDigit(int character) => (0x30 <= character && character <= 0x39) ||
(0x41 <= character && character <= 0x46) || (0x61 <= character && character <= 0
x66); | |
| 637 | |
| 638 /** | |
| 639 * Return `true` if the current token is the first token in an initialized var
iable | |
| 640 * declaration rather than an expression. This method assumes that we have alr
eady skipped past | |
| 641 * any metadata that might be associated with the declaration. | |
| 642 * | |
| 643 * <pre> | |
| 644 * initializedVariableDeclaration ::= | |
| 645 * declaredIdentifier ('=' expression)? (',' initializedIdentifier)* | |
| 646 * | |
| 647 * declaredIdentifier ::= | |
| 648 * metadata finalConstVarOrType identifier | |
| 649 * | |
| 650 * finalConstVarOrType ::= | |
| 651 * 'final' type? | |
| 652 * | 'const' type? | |
| 653 * | 'var' | |
| 654 * | type | |
| 655 * | |
| 656 * type ::= | |
| 657 * qualified typeArguments? | |
| 658 * | |
| 659 * initializedIdentifier ::= | |
| 660 * identifier ('=' expression)? | |
| 661 * </pre> | |
| 662 * | |
| 663 * @return `true` if the current token is the first token in an initialized va
riable | |
| 664 * declaration | |
| 665 */ | |
| 666 bool isInitializedVariableDeclaration() { | |
| 667 if (matches(Keyword.FINAL) || matches(Keyword.VAR)) { | |
| 668 return true; | |
| 669 } | |
| 670 if (matches(Keyword.CONST)) { | |
| 671 return !matchesAny(peek(), [ | |
| 672 TokenType.LT, | |
| 673 TokenType.OPEN_CURLY_BRACKET, | |
| 674 TokenType.OPEN_SQUARE_BRACKET, | |
| 675 TokenType.INDEX]); | |
| 676 } | |
| 677 Token token = skipTypeName(_currentToken); | |
| 678 if (token == null) { | |
| 679 return false; | |
| 680 } | |
| 681 token = skipSimpleIdentifier(token); | |
| 682 if (token == null) { | |
| 683 return false; | |
| 684 } | |
| 685 TokenType type = token.type; | |
| 686 return identical(type, TokenType.EQ) || identical(type, TokenType.COMMA) ||
identical(type, TokenType.SEMICOLON) || matches3(token, Keyword.IN); | |
| 687 } | |
| 688 | |
| 689 /** | |
| 690 * Given that we have just found bracketed text within a comment, look to see
whether that text is | |
| 691 * (a) followed by a parenthesized link address, (b) followed by a colon, or (
c) followed by | |
| 692 * optional whitespace and another square bracket. | |
| 693 * | |
| 694 * This method uses the syntax described by the <a | |
| 695 * href="http://daringfireball.net/projects/markdown/syntax">markdown</a> proj
ect. | |
| 696 * | |
| 697 * @param comment the comment text in which the bracketed text was found | |
| 698 * @param rightIndex the index of the right bracket | |
| 699 * @return `true` if the bracketed text is followed by a link address | |
| 700 */ | |
| 701 bool isLinkText(String comment, int rightIndex) { | |
| 702 int length = comment.length; | |
| 703 int index = rightIndex + 1; | |
| 704 if (index >= length) { | |
| 705 return false; | |
| 706 } | |
| 707 int nextChar = comment.codeUnitAt(index); | |
| 708 if (nextChar == 0x28 || nextChar == 0x3A) { | |
| 709 return true; | |
| 710 } | |
| 711 while (Character.isWhitespace(nextChar)) { | |
| 712 index = index + 1; | |
| 713 if (index >= length) { | |
| 714 return false; | |
| 715 } | |
| 716 nextChar = comment.codeUnitAt(index); | |
| 717 } | |
| 718 return nextChar == 0x5B; | |
| 719 } | |
| 720 | |
| 721 /** | |
| 722 * Return `true` if the given token appears to be the beginning of an operator
declaration. | |
| 723 * | |
| 724 * @param startToken the token that might be the start of an operator declarat
ion | |
| 725 * @return `true` if the given token appears to be the beginning of an operato
r declaration | |
| 726 */ | |
| 727 bool isOperator(Token startToken) { | |
| 728 if (startToken.isOperator) { | |
| 729 Token token = startToken.next; | |
| 730 while (token.isOperator) { | |
| 731 token = token.next; | |
| 732 } | |
| 733 return matches4(token, TokenType.OPEN_PAREN); | |
| 734 } | |
| 735 return false; | |
| 736 } | |
| 737 | |
| 738 /** | |
| 739 * Return `true` if the current token appears to be the beginning of a switch
member. | |
| 740 * | |
| 741 * @return `true` if the current token appears to be the beginning of a switch
member | |
| 742 */ | |
| 743 bool isSwitchMember() { | |
| 744 Token token = _currentToken; | |
| 745 while (matches4(token, TokenType.IDENTIFIER) && matches4(token.next, TokenTy
pe.COLON)) { | |
| 746 token = token.next.next; | |
| 747 } | |
| 748 if (identical(token.type, TokenType.KEYWORD)) { | |
| 749 Keyword keyword = ((token as KeywordToken)).keyword; | |
| 750 return identical(keyword, Keyword.CASE) || identical(keyword, Keyword.DEFA
ULT); | |
| 751 } | |
| 752 return false; | |
| 753 } | |
| 754 | |
| 755 /** | |
| 756 * Return `true` if the given token appears to be the first token of a type na
me that is | |
| 757 * followed by a variable or field formal parameter. | |
| 758 * | |
| 759 * @param startToken the first token of the sequence being checked | |
| 760 * @return `true` if there is a type name and variable starting at the given t
oken | |
| 761 */ | |
| 762 bool isTypedIdentifier(Token startToken) { | |
| 763 Token token = skipReturnType(startToken); | |
| 764 if (token == null) { | |
| 765 return false; | |
| 766 } else if (matchesIdentifier2(token)) { | |
| 767 return true; | |
| 768 } else if (matches3(token, Keyword.THIS) && matches4(token.next, TokenType.P
ERIOD) && matchesIdentifier2(token.next.next)) { | |
| 769 return true; | |
| 770 } | |
| 771 return false; | |
| 772 } | |
| 773 | |
| 774 /** | |
| 775 * Compare the given tokens to find the token that appears first in the source
being parsed. That | |
| 776 * is, return the left-most of all of the tokens. The arguments are allowed to
be `null`. | |
| 777 * Return the token with the smallest offset, or `null` if there are no argume
nts or if all | |
| 778 * of the arguments are `null`. | |
| 779 * | |
| 780 * @param tokens the tokens being compared | |
| 781 * @return the token with the smallest offset | |
| 782 */ | |
| 783 Token lexicallyFirst(List<Token> tokens) { | |
| 784 Token first = null; | |
| 785 int firstOffset = 2147483647; | |
| 786 for (Token token in tokens) { | |
| 787 if (token != null) { | |
| 788 int offset = token.offset; | |
| 789 if (offset < firstOffset) { | |
| 790 first = token; | |
| 791 firstOffset = offset; | |
| 792 } | |
| 793 } | |
| 794 } | |
| 795 return first; | |
| 796 } | |
| 797 | |
| 798 /** | |
| 799 * Return `true` if the current token matches the given keyword. | |
| 800 * | |
| 801 * @param keyword the keyword that can optionally appear in the current locati
on | |
| 802 * @return `true` if the current token matches the given keyword | |
| 803 */ | |
| 804 bool matches(Keyword keyword) => matches3(_currentToken, keyword); | |
| 805 | |
| 806 /** | |
| 807 * Return `true` if the current token matches the given identifier. | |
| 808 * | |
| 809 * @param identifier the identifier that can optionally appear in the current
location | |
| 810 * @return `true` if the current token matches the given identifier | |
| 811 */ | |
| 812 bool matches2(String identifier) => identical(_currentToken.type, TokenType.ID
ENTIFIER) && _currentToken.lexeme == identifier; | |
| 813 | |
| 814 /** | |
| 815 * Return `true` if the given token matches the given keyword. | |
| 816 * | |
| 817 * @param token the token being tested | |
| 818 * @param keyword the keyword that is being tested for | |
| 819 * @return `true` if the given token matches the given keyword | |
| 820 */ | |
| 821 bool matches3(Token token, Keyword keyword) => identical(token.type, TokenType
.KEYWORD) && identical(((token as KeywordToken)).keyword, keyword); | |
| 822 | |
| 823 /** | |
| 824 * Return `true` if the given token has the given type. | |
| 825 * | |
| 826 * @param token the token being tested | |
| 827 * @param type the type of token that is being tested for | |
| 828 * @return `true` if the given token has the given type | |
| 829 */ | |
| 830 bool matches4(Token token, TokenType type) => identical(token.type, type); | |
| 831 | |
| 832 /** | |
| 833 * Return `true` if the current token has the given type. Note that this metho
d, unlike | |
| 834 * other variants, will modify the token stream if possible to match a wider r
ange of tokens. In | |
| 835 * particular, if we are attempting to match a '>' and the next token is eithe
r a '>>' or '>>>', | |
| 836 * the token stream will be re-written and `true` will be returned. | |
| 837 * | |
| 838 * @param type the type of token that can optionally appear in the current loc
ation | |
| 839 * @return `true` if the current token has the given type | |
| 840 */ | |
| 841 bool matches5(TokenType type) { | |
| 842 TokenType currentType = _currentToken.type; | |
| 843 if (currentType != type) { | |
| 844 if (identical(type, TokenType.GT)) { | |
| 845 if (identical(currentType, TokenType.GT_GT)) { | |
| 846 int offset = _currentToken.offset; | |
| 847 Token first = new Token(TokenType.GT, offset); | |
| 848 Token second = new Token(TokenType.GT, offset + 1); | |
| 849 second.setNext(_currentToken.next); | |
| 850 first.setNext(second); | |
| 851 _currentToken.previous.setNext(first); | |
| 852 _currentToken = first; | |
| 853 return true; | |
| 854 } else if (identical(currentType, TokenType.GT_EQ)) { | |
| 855 int offset = _currentToken.offset; | |
| 856 Token first = new Token(TokenType.GT, offset); | |
| 857 Token second = new Token(TokenType.EQ, offset + 1); | |
| 858 second.setNext(_currentToken.next); | |
| 859 first.setNext(second); | |
| 860 _currentToken.previous.setNext(first); | |
| 861 _currentToken = first; | |
| 862 return true; | |
| 863 } else if (identical(currentType, TokenType.GT_GT_EQ)) { | |
| 864 int offset = _currentToken.offset; | |
| 865 Token first = new Token(TokenType.GT, offset); | |
| 866 Token second = new Token(TokenType.GT, offset + 1); | |
| 867 Token third = new Token(TokenType.EQ, offset + 2); | |
| 868 third.setNext(_currentToken.next); | |
| 869 second.setNext(third); | |
| 870 first.setNext(second); | |
| 871 _currentToken.previous.setNext(first); | |
| 872 _currentToken = first; | |
| 873 return true; | |
| 874 } | |
| 875 } | |
| 876 return false; | |
| 877 } | |
| 878 return true; | |
| 879 } | |
| 880 | |
| 881 /** | |
| 882 * Return `true` if the given token has any one of the given types. | |
| 883 * | |
| 884 * @param token the token being tested | |
| 885 * @param types the types of token that are being tested for | |
| 886 * @return `true` if the given token has any of the given types | |
| 887 */ | |
| 888 bool matchesAny(Token token, List<TokenType> types) { | |
| 889 TokenType actualType = token.type; | |
| 890 for (TokenType type in types) { | |
| 891 if (identical(actualType, type)) { | |
| 892 return true; | |
| 893 } | |
| 894 } | |
| 895 return false; | |
| 896 } | |
| 897 | |
| 898 /** | |
| 899 * Return `true` if the current token is a valid identifier. Valid identifiers
include | |
| 900 * built-in identifiers (pseudo-keywords). | |
| 901 * | |
| 902 * @return `true` if the current token is a valid identifier | |
| 903 */ | |
| 904 bool matchesIdentifier() => matchesIdentifier2(_currentToken); | |
| 905 | |
| 906 /** | |
| 907 * Return `true` if the given token is a valid identifier. Valid identifiers i
nclude | |
| 908 * built-in identifiers (pseudo-keywords). | |
| 909 * | |
| 910 * @return `true` if the given token is a valid identifier | |
| 911 */ | |
| 912 bool matchesIdentifier2(Token token) => matches4(token, TokenType.IDENTIFIER)
|| (matches4(token, TokenType.KEYWORD) && ((token as KeywordToken)).keyword.isPs
eudoKeyword); | |
| 913 | |
| 914 /** | |
| 915 * If the current token has the given type, then advance to the next token and
return `true` | |
| 916 * . Otherwise, return `false` without advancing. | |
| 917 * | |
| 918 * @param type the type of token that can optionally appear in the current loc
ation | |
| 919 * @return `true` if the current token has the given type | |
| 920 */ | |
| 921 bool optional(TokenType type) { | |
| 922 if (matches5(type)) { | |
| 923 advance(); | |
| 924 return true; | |
| 925 } | |
| 926 return false; | |
| 927 } | |
| 928 | |
| 929 /** | |
| 930 * Parse an additive expression. | |
| 931 * | |
| 932 * <pre> | |
| 933 * additiveExpression ::= | |
| 934 * multiplicativeExpression (additiveOperator multiplicativeExpression)* | |
| 935 * | 'super' (additiveOperator multiplicativeExpression)+ | |
| 936 * </pre> | |
| 937 * | |
| 938 * @return the additive expression that was parsed | |
| 939 */ | |
| 940 Expression parseAdditiveExpression() { | |
| 941 Expression expression; | |
| 942 if (matches(Keyword.SUPER) && _currentToken.next.type.isAdditiveOperator) { | |
| 943 expression = new SuperExpression.full(andAdvance); | |
| 944 } else { | |
| 945 expression = parseMultiplicativeExpression(); | |
| 946 } | |
| 947 while (_currentToken.type.isAdditiveOperator) { | |
| 948 Token operator = andAdvance; | |
| 949 expression = new BinaryExpression.full(expression, operator, parseMultipli
cativeExpression()); | |
| 950 } | |
| 951 return expression; | |
| 952 } | |
| 953 | |
| 954 /** | |
| 955 * Parse an annotation. | |
| 956 * | |
| 957 * <pre> | |
| 958 * annotation ::= | |
| 959 * '@' qualified ('.' identifier)? arguments? | |
| 960 * </pre> | |
| 961 * | |
| 962 * @return the annotation that was parsed | |
| 963 */ | |
| 964 Annotation parseAnnotation() { | |
| 965 Token atSign = expect2(TokenType.AT); | |
| 966 Identifier name = parsePrefixedIdentifier(); | |
| 967 Token period = null; | |
| 968 SimpleIdentifier constructorName = null; | |
| 969 if (matches5(TokenType.PERIOD)) { | |
| 970 period = andAdvance; | |
| 971 constructorName = parseSimpleIdentifier(); | |
| 972 } | |
| 973 ArgumentList arguments = null; | |
| 974 if (matches5(TokenType.OPEN_PAREN)) { | |
| 975 arguments = parseArgumentList(); | |
| 976 } | |
| 977 return new Annotation.full(atSign, name, period, constructorName, arguments)
; | |
| 978 } | |
| 979 | |
| 980 /** | |
| 981 * Parse an argument. | |
| 982 * | |
| 983 * <pre> | |
| 984 * argument ::= | |
| 985 * namedArgument | |
| 986 * | expression | |
| 987 * | |
| 988 * namedArgument ::= | |
| 989 * label expression | |
| 990 * </pre> | |
| 991 * | |
| 992 * @return the argument that was parsed | |
| 993 */ | |
| 994 Expression parseArgument() { | |
| 995 if (matchesIdentifier() && matches4(peek(), TokenType.COLON)) { | |
| 996 SimpleIdentifier label = new SimpleIdentifier.full(andAdvance); | |
| 997 Label name = new Label.full(label, andAdvance); | |
| 998 return new NamedExpression.full(name, parseExpression2()); | |
| 999 } else { | |
| 1000 return parseExpression2(); | |
| 1001 } | |
| 1002 } | |
| 1003 | |
| 1004 /** | |
| 1005 * Parse an argument definition test. | |
| 1006 * | |
| 1007 * <pre> | |
| 1008 * argumentDefinitionTest ::= | |
| 1009 * '?' identifier | |
| 1010 * </pre> | |
| 1011 * | |
| 1012 * @return the argument definition test that was parsed | |
| 1013 */ | |
| 1014 ArgumentDefinitionTest parseArgumentDefinitionTest() { | |
| 1015 Token question = expect2(TokenType.QUESTION); | |
| 1016 SimpleIdentifier identifier = parseSimpleIdentifier(); | |
| 1017 reportError9(ParserErrorCode.DEPRECATED_ARGUMENT_DEFINITION_TEST, question,
[]); | |
| 1018 return new ArgumentDefinitionTest.full(question, identifier); | |
| 1019 } | |
| 1020 | |
| 1021 /** | |
| 1022 * Parse a list of arguments. | |
| 1023 * | |
| 1024 * <pre> | |
| 1025 * arguments ::= | |
| 1026 * '(' argumentList? ')' | |
| 1027 * | |
| 1028 * argumentList ::= | |
| 1029 * namedArgument (',' namedArgument)* | |
| 1030 * | expressionList (',' namedArgument)* | |
| 1031 * </pre> | |
| 1032 * | |
| 1033 * @return the argument list that was parsed | |
| 1034 */ | |
| 1035 ArgumentList parseArgumentList() { | |
| 1036 Token leftParenthesis = expect2(TokenType.OPEN_PAREN); | |
| 1037 List<Expression> arguments = new List<Expression>(); | |
| 1038 if (matches5(TokenType.CLOSE_PAREN)) { | |
| 1039 return new ArgumentList.full(leftParenthesis, arguments, andAdvance); | |
| 1040 } | |
| 1041 Expression argument = parseArgument(); | |
| 1042 arguments.add(argument); | |
| 1043 bool foundNamedArgument = argument is NamedExpression; | |
| 1044 bool generatedError = false; | |
| 1045 while (optional(TokenType.COMMA)) { | |
| 1046 argument = parseArgument(); | |
| 1047 arguments.add(argument); | |
| 1048 if (foundNamedArgument) { | |
| 1049 if (!generatedError && argument is! NamedExpression) { | |
| 1050 reportError8(ParserErrorCode.POSITIONAL_AFTER_NAMED_ARGUMENT, []); | |
| 1051 generatedError = true; | |
| 1052 } | |
| 1053 } else if (argument is NamedExpression) { | |
| 1054 foundNamedArgument = true; | |
| 1055 } | |
| 1056 } | |
| 1057 Token rightParenthesis = expect2(TokenType.CLOSE_PAREN); | |
| 1058 return new ArgumentList.full(leftParenthesis, arguments, rightParenthesis); | |
| 1059 } | |
| 1060 | |
| 1061 /** | |
| 1062 * Parse an assert statement. | |
| 1063 * | |
| 1064 * <pre> | |
| 1065 * assertStatement ::= | |
| 1066 * 'assert' '(' conditionalExpression ')' ';' | |
| 1067 * </pre> | |
| 1068 * | |
| 1069 * @return the assert statement | |
| 1070 */ | |
| 1071 AssertStatement parseAssertStatement() { | |
| 1072 Token keyword = expect(Keyword.ASSERT); | |
| 1073 Token leftParen = expect2(TokenType.OPEN_PAREN); | |
| 1074 Expression expression = parseExpression2(); | |
| 1075 if (expression is AssignmentExpression) { | |
| 1076 reportError(ParserErrorCode.ASSERT_DOES_NOT_TAKE_ASSIGNMENT, expression, [
]); | |
| 1077 } else if (expression is CascadeExpression) { | |
| 1078 reportError(ParserErrorCode.ASSERT_DOES_NOT_TAKE_CASCADE, expression, []); | |
| 1079 } else if (expression is ThrowExpression) { | |
| 1080 reportError(ParserErrorCode.ASSERT_DOES_NOT_TAKE_THROW, expression, []); | |
| 1081 } else if (expression is RethrowExpression) { | |
| 1082 reportError(ParserErrorCode.ASSERT_DOES_NOT_TAKE_RETHROW, expression, []); | |
| 1083 } | |
| 1084 Token rightParen = expect2(TokenType.CLOSE_PAREN); | |
| 1085 Token semicolon = expect2(TokenType.SEMICOLON); | |
| 1086 return new AssertStatement.full(keyword, leftParen, expression, rightParen,
semicolon); | |
| 1087 } | |
| 1088 | |
| 1089 /** | |
| 1090 * Parse an assignable expression. | |
| 1091 * | |
| 1092 * <pre> | |
| 1093 * assignableExpression ::= | |
| 1094 * primary (arguments* assignableSelector)+ | |
| 1095 * | 'super' assignableSelector | |
| 1096 * | identifier | |
| 1097 * </pre> | |
| 1098 * | |
| 1099 * @param primaryAllowed `true` if the expression is allowed to be a primary w
ithout any | |
| 1100 * assignable selector | |
| 1101 * @return the assignable expression that was parsed | |
| 1102 */ | |
| 1103 Expression parseAssignableExpression(bool primaryAllowed) { | |
| 1104 if (matches(Keyword.SUPER)) { | |
| 1105 return parseAssignableSelector(new SuperExpression.full(andAdvance), false
); | |
| 1106 } | |
| 1107 Expression expression = parsePrimaryExpression(); | |
| 1108 bool isOptional = primaryAllowed || expression is SimpleIdentifier; | |
| 1109 while (true) { | |
| 1110 while (matches5(TokenType.OPEN_PAREN)) { | |
| 1111 ArgumentList argumentList = parseArgumentList(); | |
| 1112 if (expression is SimpleIdentifier) { | |
| 1113 expression = new MethodInvocation.full(null, null, expression as Simpl
eIdentifier, argumentList); | |
| 1114 } else if (expression is PrefixedIdentifier) { | |
| 1115 PrefixedIdentifier identifier = expression as PrefixedIdentifier; | |
| 1116 expression = new MethodInvocation.full(identifier.prefix, identifier.p
eriod, identifier.identifier, argumentList); | |
| 1117 } else if (expression is PropertyAccess) { | |
| 1118 PropertyAccess access = expression as PropertyAccess; | |
| 1119 expression = new MethodInvocation.full(access.target, access.operator,
access.propertyName, argumentList); | |
| 1120 } else { | |
| 1121 expression = new FunctionExpressionInvocation.full(expression, argumen
tList); | |
| 1122 } | |
| 1123 if (!primaryAllowed) { | |
| 1124 isOptional = false; | |
| 1125 } | |
| 1126 } | |
| 1127 Expression selectorExpression = parseAssignableSelector(expression, isOpti
onal || (expression is PrefixedIdentifier)); | |
| 1128 if (identical(selectorExpression, expression)) { | |
| 1129 if (!isOptional && (expression is PrefixedIdentifier)) { | |
| 1130 PrefixedIdentifier identifier = expression as PrefixedIdentifier; | |
| 1131 expression = new PropertyAccess.full(identifier.prefix, identifier.per
iod, identifier.identifier); | |
| 1132 } | |
| 1133 return expression; | |
| 1134 } | |
| 1135 expression = selectorExpression; | |
| 1136 isOptional = true; | |
| 1137 } | |
| 1138 } | |
| 1139 | |
| 1140 /** | |
| 1141 * Parse an assignable selector. | |
| 1142 * | |
| 1143 * <pre> | |
| 1144 * assignableSelector ::= | |
| 1145 * '[' expression ']' | |
| 1146 * | '.' identifier | |
| 1147 * </pre> | |
| 1148 * | |
| 1149 * @param prefix the expression preceding the selector | |
| 1150 * @param optional `true` if the selector is optional | |
| 1151 * @return the assignable selector that was parsed | |
| 1152 */ | |
| 1153 Expression parseAssignableSelector(Expression prefix, bool optional) { | |
| 1154 if (matches5(TokenType.OPEN_SQUARE_BRACKET)) { | |
| 1155 Token leftBracket = andAdvance; | |
| 1156 Expression index = parseExpression2(); | |
| 1157 Token rightBracket = expect2(TokenType.CLOSE_SQUARE_BRACKET); | |
| 1158 return new IndexExpression.forTarget_full(prefix, leftBracket, index, righ
tBracket); | |
| 1159 } else if (matches5(TokenType.PERIOD)) { | |
| 1160 Token period = andAdvance; | |
| 1161 return new PropertyAccess.full(prefix, period, parseSimpleIdentifier()); | |
| 1162 } else { | |
| 1163 if (!optional) { | |
| 1164 reportError8(ParserErrorCode.MISSING_ASSIGNABLE_SELECTOR, []); | |
| 1165 } | |
| 1166 return prefix; | |
| 1167 } | |
| 1168 } | |
| 1169 | |
| 1170 /** | |
| 1171 * Parse a bitwise and expression. | |
| 1172 * | |
| 1173 * <pre> | |
| 1174 * bitwiseAndExpression ::= | |
| 1175 * shiftExpression ('&' shiftExpression)* | |
| 1176 * | 'super' ('&' shiftExpression)+ | |
| 1177 * </pre> | |
| 1178 * | |
| 1179 * @return the bitwise and expression that was parsed | |
| 1180 */ | |
| 1181 Expression parseBitwiseAndExpression() { | |
| 1182 Expression expression; | |
| 1183 if (matches(Keyword.SUPER) && matches4(peek(), TokenType.AMPERSAND)) { | |
| 1184 expression = new SuperExpression.full(andAdvance); | |
| 1185 } else { | |
| 1186 expression = parseShiftExpression(); | |
| 1187 } | |
| 1188 while (matches5(TokenType.AMPERSAND)) { | |
| 1189 Token operator = andAdvance; | |
| 1190 expression = new BinaryExpression.full(expression, operator, parseShiftExp
ression()); | |
| 1191 } | |
| 1192 return expression; | |
| 1193 } | |
| 1194 | |
| 1195 /** | |
| 1196 * Parse a bitwise or expression. | |
| 1197 * | |
| 1198 * <pre> | |
| 1199 * bitwiseOrExpression ::= | |
| 1200 * bitwiseXorExpression ('|' bitwiseXorExpression)* | |
| 1201 * | 'super' ('|' bitwiseXorExpression)+ | |
| 1202 * </pre> | |
| 1203 * | |
| 1204 * @return the bitwise or expression that was parsed | |
| 1205 */ | |
| 1206 Expression parseBitwiseOrExpression() { | |
| 1207 Expression expression; | |
| 1208 if (matches(Keyword.SUPER) && matches4(peek(), TokenType.BAR)) { | |
| 1209 expression = new SuperExpression.full(andAdvance); | |
| 1210 } else { | |
| 1211 expression = parseBitwiseXorExpression(); | |
| 1212 } | |
| 1213 while (matches5(TokenType.BAR)) { | |
| 1214 Token operator = andAdvance; | |
| 1215 expression = new BinaryExpression.full(expression, operator, parseBitwiseX
orExpression()); | |
| 1216 } | |
| 1217 return expression; | |
| 1218 } | |
| 1219 | |
| 1220 /** | |
| 1221 * Parse a bitwise exclusive-or expression. | |
| 1222 * | |
| 1223 * <pre> | |
| 1224 * bitwiseXorExpression ::= | |
| 1225 * bitwiseAndExpression ('^' bitwiseAndExpression)* | |
| 1226 * | 'super' ('^' bitwiseAndExpression)+ | |
| 1227 * </pre> | |
| 1228 * | |
| 1229 * @return the bitwise exclusive-or expression that was parsed | |
| 1230 */ | |
| 1231 Expression parseBitwiseXorExpression() { | |
| 1232 Expression expression; | |
| 1233 if (matches(Keyword.SUPER) && matches4(peek(), TokenType.CARET)) { | |
| 1234 expression = new SuperExpression.full(andAdvance); | |
| 1235 } else { | |
| 1236 expression = parseBitwiseAndExpression(); | |
| 1237 } | |
| 1238 while (matches5(TokenType.CARET)) { | |
| 1239 Token operator = andAdvance; | |
| 1240 expression = new BinaryExpression.full(expression, operator, parseBitwiseA
ndExpression()); | |
| 1241 } | |
| 1242 return expression; | |
| 1243 } | |
| 1244 | |
| 1245 /** | |
| 1246 * Parse a block. | |
| 1247 * | |
| 1248 * <pre> | |
| 1249 * block ::= | |
| 1250 * '{' statements '}' | |
| 1251 * </pre> | |
| 1252 * | |
| 1253 * @return the block that was parsed | |
| 1254 */ | |
| 1255 Block parseBlock() { | |
| 1256 Token leftBracket = expect2(TokenType.OPEN_CURLY_BRACKET); | |
| 1257 List<Statement> statements = new List<Statement>(); | |
| 1258 Token statementStart = _currentToken; | |
| 1259 while (!matches5(TokenType.EOF) && !matches5(TokenType.CLOSE_CURLY_BRACKET))
{ | |
| 1260 Statement statement = parseStatement2(); | |
| 1261 if (statement != null) { | |
| 1262 statements.add(statement); | |
| 1263 } | |
| 1264 if (identical(_currentToken, statementStart)) { | |
| 1265 reportError9(ParserErrorCode.UNEXPECTED_TOKEN, _currentToken, [_currentT
oken.lexeme]); | |
| 1266 advance(); | |
| 1267 } | |
| 1268 statementStart = _currentToken; | |
| 1269 } | |
| 1270 Token rightBracket = expect2(TokenType.CLOSE_CURLY_BRACKET); | |
| 1271 return new Block.full(leftBracket, statements, rightBracket); | |
| 1272 } | |
| 1273 | |
| 1274 /** | |
| 1275 * Parse a break statement. | |
| 1276 * | |
| 1277 * <pre> | |
| 1278 * breakStatement ::= | |
| 1279 * 'break' identifier? ';' | |
| 1280 * </pre> | |
| 1281 * | |
| 1282 * @return the break statement that was parsed | |
| 1283 */ | |
| 1284 Statement parseBreakStatement() { | |
| 1285 Token breakKeyword = expect(Keyword.BREAK); | |
| 1286 SimpleIdentifier label = null; | |
| 1287 if (matchesIdentifier()) { | |
| 1288 label = parseSimpleIdentifier(); | |
| 1289 } | |
| 1290 if (!_inLoop && !_inSwitch && label == null) { | |
| 1291 reportError9(ParserErrorCode.BREAK_OUTSIDE_OF_LOOP, breakKeyword, []); | |
| 1292 } | |
| 1293 Token semicolon = expect2(TokenType.SEMICOLON); | |
| 1294 return new BreakStatement.full(breakKeyword, label, semicolon); | |
| 1295 } | |
| 1296 | |
| 1297 /** | |
| 1298 * Parse a cascade section. | |
| 1299 * | |
| 1300 * <pre> | |
| 1301 * cascadeSection ::= | |
| 1302 * '..' (cascadeSelector arguments*) (assignableSelector arguments*)* casc
adeAssignment? | |
| 1303 * | |
| 1304 * cascadeSelector ::= | |
| 1305 * '[' expression ']' | |
| 1306 * | identifier | |
| 1307 * | |
| 1308 * cascadeAssignment ::= | |
| 1309 * assignmentOperator expressionWithoutCascade | |
| 1310 * </pre> | |
| 1311 * | |
| 1312 * @return the expression representing the cascaded method invocation | |
| 1313 */ | |
| 1314 Expression parseCascadeSection() { | |
| 1315 Token period = expect2(TokenType.PERIOD_PERIOD); | |
| 1316 Expression expression = null; | |
| 1317 SimpleIdentifier functionName = null; | |
| 1318 if (matchesIdentifier()) { | |
| 1319 functionName = parseSimpleIdentifier(); | |
| 1320 } else if (identical(_currentToken.type, TokenType.OPEN_SQUARE_BRACKET)) { | |
| 1321 Token leftBracket = andAdvance; | |
| 1322 Expression index = parseExpression2(); | |
| 1323 Token rightBracket = expect2(TokenType.CLOSE_SQUARE_BRACKET); | |
| 1324 expression = new IndexExpression.forCascade_full(period, leftBracket, inde
x, rightBracket); | |
| 1325 period = null; | |
| 1326 } else { | |
| 1327 reportError9(ParserErrorCode.MISSING_IDENTIFIER, _currentToken, [_currentT
oken.lexeme]); | |
| 1328 functionName = createSyntheticIdentifier(); | |
| 1329 } | |
| 1330 if (identical(_currentToken.type, TokenType.OPEN_PAREN)) { | |
| 1331 while (identical(_currentToken.type, TokenType.OPEN_PAREN)) { | |
| 1332 if (functionName != null) { | |
| 1333 expression = new MethodInvocation.full(expression, period, functionNam
e, parseArgumentList()); | |
| 1334 period = null; | |
| 1335 functionName = null; | |
| 1336 } else if (expression == null) { | |
| 1337 expression = new MethodInvocation.full(expression, period, createSynth
eticIdentifier(), parseArgumentList()); | |
| 1338 } else { | |
| 1339 expression = new FunctionExpressionInvocation.full(expression, parseAr
gumentList()); | |
| 1340 } | |
| 1341 } | |
| 1342 } else if (functionName != null) { | |
| 1343 expression = new PropertyAccess.full(expression, period, functionName); | |
| 1344 period = null; | |
| 1345 } | |
| 1346 bool progress = true; | |
| 1347 while (progress) { | |
| 1348 progress = false; | |
| 1349 Expression selector = parseAssignableSelector(expression, true); | |
| 1350 if (selector != expression) { | |
| 1351 expression = selector; | |
| 1352 progress = true; | |
| 1353 while (identical(_currentToken.type, TokenType.OPEN_PAREN)) { | |
| 1354 expression = new FunctionExpressionInvocation.full(expression, parseAr
gumentList()); | |
| 1355 } | |
| 1356 } | |
| 1357 } | |
| 1358 if (_currentToken.type.isAssignmentOperator) { | |
| 1359 Token operator = andAdvance; | |
| 1360 ensureAssignable(expression); | |
| 1361 expression = new AssignmentExpression.full(expression, operator, parseExpr
essionWithoutCascade()); | |
| 1362 } | |
| 1363 return expression; | |
| 1364 } | |
| 1365 | |
| 1366 /** | |
| 1367 * Parse a class declaration. | |
| 1368 * | |
| 1369 * <pre> | |
| 1370 * classDeclaration ::= | |
| 1371 * metadata 'abstract'? 'class' name typeParameterList? (extendsClause wit
hClause?)? implementsClause? '{' classMembers '}' | | |
| 1372 * metadata 'abstract'? 'class' mixinApplicationClass | |
| 1373 * </pre> | |
| 1374 * | |
| 1375 * @param commentAndMetadata the metadata to be associated with the member | |
| 1376 * @param abstractKeyword the token for the keyword 'abstract', or `null` if t
he keyword was | |
| 1377 * not given | |
| 1378 * @return the class declaration that was parsed | |
| 1379 */ | |
| 1380 CompilationUnitMember parseClassDeclaration(CommentAndMetadata commentAndMetad
ata, Token abstractKeyword) { | |
| 1381 Token keyword = expect(Keyword.CLASS); | |
| 1382 if (matchesIdentifier()) { | |
| 1383 Token next = peek(); | |
| 1384 if (matches4(next, TokenType.LT)) { | |
| 1385 next = skipTypeParameterList(next); | |
| 1386 if (next != null && matches4(next, TokenType.EQ)) { | |
| 1387 return parseClassTypeAlias(commentAndMetadata, keyword); | |
| 1388 } | |
| 1389 } else if (matches4(next, TokenType.EQ)) { | |
| 1390 return parseClassTypeAlias(commentAndMetadata, keyword); | |
| 1391 } | |
| 1392 } | |
| 1393 SimpleIdentifier name = parseSimpleIdentifier(); | |
| 1394 String className = name.name; | |
| 1395 TypeParameterList typeParameters = null; | |
| 1396 if (matches5(TokenType.LT)) { | |
| 1397 typeParameters = parseTypeParameterList(); | |
| 1398 } | |
| 1399 ExtendsClause extendsClause = null; | |
| 1400 WithClause withClause = null; | |
| 1401 ImplementsClause implementsClause = null; | |
| 1402 bool foundClause = true; | |
| 1403 while (foundClause) { | |
| 1404 if (matches(Keyword.EXTENDS)) { | |
| 1405 if (extendsClause == null) { | |
| 1406 extendsClause = parseExtendsClause(); | |
| 1407 if (withClause != null) { | |
| 1408 reportError9(ParserErrorCode.WITH_BEFORE_EXTENDS, withClause.withKey
word, []); | |
| 1409 } else if (implementsClause != null) { | |
| 1410 reportError9(ParserErrorCode.IMPLEMENTS_BEFORE_EXTENDS, implementsCl
ause.keyword, []); | |
| 1411 } | |
| 1412 } else { | |
| 1413 reportError9(ParserErrorCode.MULTIPLE_EXTENDS_CLAUSES, extendsClause.k
eyword, []); | |
| 1414 parseExtendsClause(); | |
| 1415 } | |
| 1416 } else if (matches(Keyword.WITH)) { | |
| 1417 if (withClause == null) { | |
| 1418 withClause = parseWithClause(); | |
| 1419 if (implementsClause != null) { | |
| 1420 reportError9(ParserErrorCode.IMPLEMENTS_BEFORE_WITH, implementsClaus
e.keyword, []); | |
| 1421 } | |
| 1422 } else { | |
| 1423 reportError9(ParserErrorCode.MULTIPLE_WITH_CLAUSES, withClause.withKey
word, []); | |
| 1424 parseWithClause(); | |
| 1425 } | |
| 1426 } else if (matches(Keyword.IMPLEMENTS)) { | |
| 1427 if (implementsClause == null) { | |
| 1428 implementsClause = parseImplementsClause(); | |
| 1429 } else { | |
| 1430 reportError9(ParserErrorCode.MULTIPLE_IMPLEMENTS_CLAUSES, implementsCl
ause.keyword, []); | |
| 1431 parseImplementsClause(); | |
| 1432 } | |
| 1433 } else { | |
| 1434 foundClause = false; | |
| 1435 } | |
| 1436 } | |
| 1437 if (withClause != null && extendsClause == null) { | |
| 1438 reportError9(ParserErrorCode.WITH_WITHOUT_EXTENDS, withClause.withKeyword,
[]); | |
| 1439 } | |
| 1440 NativeClause nativeClause = null; | |
| 1441 if (matches2(_NATIVE) && matches4(peek(), TokenType.STRING)) { | |
| 1442 nativeClause = parseNativeClause(); | |
| 1443 } | |
| 1444 Token leftBracket = null; | |
| 1445 List<ClassMember> members = null; | |
| 1446 Token rightBracket = null; | |
| 1447 if (matches5(TokenType.OPEN_CURLY_BRACKET)) { | |
| 1448 leftBracket = expect2(TokenType.OPEN_CURLY_BRACKET); | |
| 1449 members = parseClassMembers(className, getEndToken(leftBracket)); | |
| 1450 rightBracket = expect2(TokenType.CLOSE_CURLY_BRACKET); | |
| 1451 } else { | |
| 1452 leftBracket = createSyntheticToken2(TokenType.OPEN_CURLY_BRACKET); | |
| 1453 rightBracket = createSyntheticToken2(TokenType.CLOSE_CURLY_BRACKET); | |
| 1454 reportError8(ParserErrorCode.MISSING_CLASS_BODY, []); | |
| 1455 } | |
| 1456 ClassDeclaration classDeclaration = new ClassDeclaration.full(commentAndMeta
data.comment, commentAndMetadata.metadata, abstractKeyword, keyword, name, typeP
arameters, extendsClause, withClause, implementsClause, leftBracket, members, ri
ghtBracket); | |
| 1457 classDeclaration.nativeClause = nativeClause; | |
| 1458 return classDeclaration; | |
| 1459 } | |
| 1460 | |
| 1461 /** | |
| 1462 * Parse a class member. | |
| 1463 * | |
| 1464 * <pre> | |
| 1465 * classMemberDefinition ::= | |
| 1466 * declaration ';' | |
| 1467 * | methodSignature functionBody | |
| 1468 * </pre> | |
| 1469 * | |
| 1470 * @param className the name of the class containing the member being parsed | |
| 1471 * @return the class member that was parsed, or `null` if what was found was n
ot a valid | |
| 1472 * class member | |
| 1473 */ | |
| 1474 ClassMember parseClassMember(String className) { | |
| 1475 CommentAndMetadata commentAndMetadata = parseCommentAndMetadata(); | |
| 1476 Modifiers modifiers = parseModifiers(); | |
| 1477 if (matches(Keyword.VOID)) { | |
| 1478 TypeName returnType = parseReturnType(); | |
| 1479 if (matches(Keyword.GET) && matchesIdentifier2(peek())) { | |
| 1480 validateModifiersForGetterOrSetterOrMethod(modifiers); | |
| 1481 return parseGetter(commentAndMetadata, modifiers.externalKeyword, modifi
ers.staticKeyword, returnType); | |
| 1482 } else if (matches(Keyword.SET) && matchesIdentifier2(peek())) { | |
| 1483 validateModifiersForGetterOrSetterOrMethod(modifiers); | |
| 1484 return parseSetter(commentAndMetadata, modifiers.externalKeyword, modifi
ers.staticKeyword, returnType); | |
| 1485 } else if (matches(Keyword.OPERATOR) && isOperator(peek())) { | |
| 1486 validateModifiersForOperator(modifiers); | |
| 1487 return parseOperator(commentAndMetadata, modifiers.externalKeyword, retu
rnType); | |
| 1488 } else if (matchesIdentifier() && matchesAny(peek(), [ | |
| 1489 TokenType.OPEN_PAREN, | |
| 1490 TokenType.OPEN_CURLY_BRACKET, | |
| 1491 TokenType.FUNCTION])) { | |
| 1492 validateModifiersForGetterOrSetterOrMethod(modifiers); | |
| 1493 return parseMethodDeclaration(commentAndMetadata, modifiers.externalKeyw
ord, modifiers.staticKeyword, returnType); | |
| 1494 } else { | |
| 1495 if (matchesIdentifier()) { | |
| 1496 if (matchesAny(peek(), [TokenType.EQ, TokenType.COMMA, TokenType.SEMIC
OLON])) { | |
| 1497 reportError(ParserErrorCode.VOID_VARIABLE, returnType, []); | |
| 1498 return parseInitializedIdentifierList(commentAndMetadata, modifiers.
staticKeyword, validateModifiersForField(modifiers), returnType); | |
| 1499 } | |
| 1500 } | |
| 1501 if (isOperator(_currentToken)) { | |
| 1502 validateModifiersForOperator(modifiers); | |
| 1503 return parseOperator(commentAndMetadata, modifiers.externalKeyword, re
turnType); | |
| 1504 } | |
| 1505 reportError9(ParserErrorCode.EXPECTED_EXECUTABLE, _currentToken, []); | |
| 1506 return null; | |
| 1507 } | |
| 1508 } else if (matches(Keyword.GET) && matchesIdentifier2(peek())) { | |
| 1509 validateModifiersForGetterOrSetterOrMethod(modifiers); | |
| 1510 return parseGetter(commentAndMetadata, modifiers.externalKeyword, modifier
s.staticKeyword, null); | |
| 1511 } else if (matches(Keyword.SET) && matchesIdentifier2(peek())) { | |
| 1512 validateModifiersForGetterOrSetterOrMethod(modifiers); | |
| 1513 return parseSetter(commentAndMetadata, modifiers.externalKeyword, modifier
s.staticKeyword, null); | |
| 1514 } else if (matches(Keyword.OPERATOR) && isOperator(peek())) { | |
| 1515 validateModifiersForOperator(modifiers); | |
| 1516 return parseOperator(commentAndMetadata, modifiers.externalKeyword, null); | |
| 1517 } else if (!matchesIdentifier()) { | |
| 1518 if (isOperator(_currentToken)) { | |
| 1519 validateModifiersForOperator(modifiers); | |
| 1520 return parseOperator(commentAndMetadata, modifiers.externalKeyword, null
); | |
| 1521 } | |
| 1522 reportError9(ParserErrorCode.EXPECTED_CLASS_MEMBER, _currentToken, []); | |
| 1523 return null; | |
| 1524 } else if (matches4(peek(), TokenType.PERIOD) && matchesIdentifier2(peek2(2)
) && matches4(peek2(3), TokenType.OPEN_PAREN)) { | |
| 1525 return parseConstructor(commentAndMetadata, modifiers.externalKeyword, val
idateModifiersForConstructor(modifiers), modifiers.factoryKeyword, parseSimpleId
entifier(), andAdvance, parseSimpleIdentifier(), parseFormalParameterList()); | |
| 1526 } else if (matches4(peek(), TokenType.OPEN_PAREN)) { | |
| 1527 SimpleIdentifier methodName = parseSimpleIdentifier(); | |
| 1528 FormalParameterList parameters = parseFormalParameterList(); | |
| 1529 if (matches5(TokenType.COLON) || modifiers.factoryKeyword != null || metho
dName.name == className) { | |
| 1530 return parseConstructor(commentAndMetadata, modifiers.externalKeyword, v
alidateModifiersForConstructor(modifiers), modifiers.factoryKeyword, methodName,
null, null, parameters); | |
| 1531 } | |
| 1532 validateModifiersForGetterOrSetterOrMethod(modifiers); | |
| 1533 validateFormalParameterList(parameters); | |
| 1534 return parseMethodDeclaration2(commentAndMetadata, modifiers.externalKeywo
rd, modifiers.staticKeyword, null, methodName, parameters); | |
| 1535 } else if (matchesAny(peek(), [TokenType.EQ, TokenType.COMMA, TokenType.SEMI
COLON])) { | |
| 1536 if (modifiers.constKeyword == null && modifiers.finalKeyword == null && mo
difiers.varKeyword == null) { | |
| 1537 reportError8(ParserErrorCode.MISSING_CONST_FINAL_VAR_OR_TYPE, []); | |
| 1538 } | |
| 1539 return parseInitializedIdentifierList(commentAndMetadata, modifiers.static
Keyword, validateModifiersForField(modifiers), null); | |
| 1540 } | |
| 1541 TypeName type = parseTypeName(); | |
| 1542 if (matches(Keyword.GET) && matchesIdentifier2(peek())) { | |
| 1543 validateModifiersForGetterOrSetterOrMethod(modifiers); | |
| 1544 return parseGetter(commentAndMetadata, modifiers.externalKeyword, modifier
s.staticKeyword, type); | |
| 1545 } else if (matches(Keyword.SET) && matchesIdentifier2(peek())) { | |
| 1546 validateModifiersForGetterOrSetterOrMethod(modifiers); | |
| 1547 return parseSetter(commentAndMetadata, modifiers.externalKeyword, modifier
s.staticKeyword, type); | |
| 1548 } else if (matches(Keyword.OPERATOR) && isOperator(peek())) { | |
| 1549 validateModifiersForOperator(modifiers); | |
| 1550 return parseOperator(commentAndMetadata, modifiers.externalKeyword, type); | |
| 1551 } else if (!matchesIdentifier()) { | |
| 1552 if (matches5(TokenType.CLOSE_CURLY_BRACKET)) { | |
| 1553 return parseInitializedIdentifierList(commentAndMetadata, modifiers.stat
icKeyword, validateModifiersForField(modifiers), type); | |
| 1554 } | |
| 1555 if (isOperator(_currentToken)) { | |
| 1556 validateModifiersForOperator(modifiers); | |
| 1557 return parseOperator(commentAndMetadata, modifiers.externalKeyword, type
); | |
| 1558 } | |
| 1559 reportError9(ParserErrorCode.EXPECTED_CLASS_MEMBER, _currentToken, []); | |
| 1560 return null; | |
| 1561 } else if (matches4(peek(), TokenType.OPEN_PAREN)) { | |
| 1562 SimpleIdentifier methodName = parseSimpleIdentifier(); | |
| 1563 FormalParameterList parameters = parseFormalParameterList(); | |
| 1564 if (methodName.name == className) { | |
| 1565 reportError(ParserErrorCode.CONSTRUCTOR_WITH_RETURN_TYPE, type, []); | |
| 1566 return parseConstructor(commentAndMetadata, modifiers.externalKeyword, v
alidateModifiersForConstructor(modifiers), modifiers.factoryKeyword, methodName,
null, null, parameters); | |
| 1567 } | |
| 1568 validateModifiersForGetterOrSetterOrMethod(modifiers); | |
| 1569 validateFormalParameterList(parameters); | |
| 1570 return parseMethodDeclaration2(commentAndMetadata, modifiers.externalKeywo
rd, modifiers.staticKeyword, type, methodName, parameters); | |
| 1571 } | |
| 1572 return parseInitializedIdentifierList(commentAndMetadata, modifiers.staticKe
yword, validateModifiersForField(modifiers), type); | |
| 1573 } | |
| 1574 | |
| 1575 /** | |
| 1576 * Parse a list of class members. | |
| 1577 * | |
| 1578 * <pre> | |
| 1579 * classMembers ::= | |
| 1580 * (metadata memberDefinition)* | |
| 1581 * </pre> | |
| 1582 * | |
| 1583 * @param className the name of the class whose members are being parsed | |
| 1584 * @param closingBracket the closing bracket for the class, or `null` if the c
losing bracket | |
| 1585 * is missing | |
| 1586 * @return the list of class members that were parsed | |
| 1587 */ | |
| 1588 List<ClassMember> parseClassMembers(String className, Token closingBracket) { | |
| 1589 List<ClassMember> members = new List<ClassMember>(); | |
| 1590 Token memberStart = _currentToken; | |
| 1591 while (!matches5(TokenType.EOF) && !matches5(TokenType.CLOSE_CURLY_BRACKET)
&& (closingBracket != null || (!matches(Keyword.CLASS) && !matches(Keyword.TYPED
EF)))) { | |
| 1592 if (matches5(TokenType.SEMICOLON)) { | |
| 1593 reportError9(ParserErrorCode.UNEXPECTED_TOKEN, _currentToken, [_currentT
oken.lexeme]); | |
| 1594 advance(); | |
| 1595 } else { | |
| 1596 ClassMember member = parseClassMember(className); | |
| 1597 if (member != null) { | |
| 1598 members.add(member); | |
| 1599 } | |
| 1600 } | |
| 1601 if (identical(_currentToken, memberStart)) { | |
| 1602 reportError9(ParserErrorCode.UNEXPECTED_TOKEN, _currentToken, [_currentT
oken.lexeme]); | |
| 1603 advance(); | |
| 1604 } | |
| 1605 memberStart = _currentToken; | |
| 1606 } | |
| 1607 return members; | |
| 1608 } | |
| 1609 | |
| 1610 /** | |
| 1611 * Parse a class type alias. | |
| 1612 * | |
| 1613 * <pre> | |
| 1614 * classTypeAlias ::= | |
| 1615 * identifier typeParameters? '=' 'abstract'? mixinApplication | |
| 1616 * | |
| 1617 * mixinApplication ::= | |
| 1618 * type withClause implementsClause? ';' | |
| 1619 * </pre> | |
| 1620 * | |
| 1621 * @param commentAndMetadata the metadata to be associated with the member | |
| 1622 * @param keyword the token representing the 'typedef' keyword | |
| 1623 * @return the class type alias that was parsed | |
| 1624 */ | |
| 1625 ClassTypeAlias parseClassTypeAlias(CommentAndMetadata commentAndMetadata, Toke
n keyword) { | |
| 1626 SimpleIdentifier className = parseSimpleIdentifier(); | |
| 1627 TypeParameterList typeParameters = null; | |
| 1628 if (matches5(TokenType.LT)) { | |
| 1629 typeParameters = parseTypeParameterList(); | |
| 1630 } | |
| 1631 Token equals = expect2(TokenType.EQ); | |
| 1632 Token abstractKeyword = null; | |
| 1633 if (matches(Keyword.ABSTRACT)) { | |
| 1634 abstractKeyword = andAdvance; | |
| 1635 } | |
| 1636 TypeName superclass = parseTypeName(); | |
| 1637 WithClause withClause = null; | |
| 1638 if (matches(Keyword.WITH)) { | |
| 1639 withClause = parseWithClause(); | |
| 1640 } | |
| 1641 ImplementsClause implementsClause = null; | |
| 1642 if (matches(Keyword.IMPLEMENTS)) { | |
| 1643 implementsClause = parseImplementsClause(); | |
| 1644 } | |
| 1645 Token semicolon; | |
| 1646 if (matches5(TokenType.SEMICOLON)) { | |
| 1647 semicolon = andAdvance; | |
| 1648 } else { | |
| 1649 if (matches5(TokenType.OPEN_CURLY_BRACKET)) { | |
| 1650 reportError8(ParserErrorCode.EXPECTED_TOKEN, [TokenType.SEMICOLON.lexeme
]); | |
| 1651 Token leftBracket = andAdvance; | |
| 1652 parseClassMembers(className.name, getEndToken(leftBracket)); | |
| 1653 expect2(TokenType.CLOSE_CURLY_BRACKET); | |
| 1654 } else { | |
| 1655 reportError9(ParserErrorCode.EXPECTED_TOKEN, _currentToken.previous, [To
kenType.SEMICOLON.lexeme]); | |
| 1656 } | |
| 1657 semicolon = createSyntheticToken2(TokenType.SEMICOLON); | |
| 1658 } | |
| 1659 return new ClassTypeAlias.full(commentAndMetadata.comment, commentAndMetadat
a.metadata, keyword, className, typeParameters, equals, abstractKeyword, supercl
ass, withClause, implementsClause, semicolon); | |
| 1660 } | |
| 1661 | |
| 1662 /** | |
| 1663 * Parse a list of combinators in a directive. | |
| 1664 * | |
| 1665 * <pre> | |
| 1666 * combinator ::= | |
| 1667 * 'show' identifier (',' identifier)* | |
| 1668 * | 'hide' identifier (',' identifier)* | |
| 1669 * </pre> | |
| 1670 * | |
| 1671 * @return the combinators that were parsed | |
| 1672 */ | |
| 1673 List<Combinator> parseCombinators() { | |
| 1674 List<Combinator> combinators = new List<Combinator>(); | |
| 1675 while (matches2(_SHOW) || matches2(_HIDE)) { | |
| 1676 Token keyword = expect2(TokenType.IDENTIFIER); | |
| 1677 if (keyword.lexeme == _SHOW) { | |
| 1678 List<SimpleIdentifier> shownNames = parseIdentifierList(); | |
| 1679 combinators.add(new ShowCombinator.full(keyword, shownNames)); | |
| 1680 } else { | |
| 1681 List<SimpleIdentifier> hiddenNames = parseIdentifierList(); | |
| 1682 combinators.add(new HideCombinator.full(keyword, hiddenNames)); | |
| 1683 } | |
| 1684 } | |
| 1685 return combinators; | |
| 1686 } | |
| 1687 | |
| 1688 /** | |
| 1689 * Parse the documentation comment and metadata preceding a declaration. This
method allows any | |
| 1690 * number of documentation comments to occur before, after or between the meta
data, but only | |
| 1691 * returns the last (right-most) documentation comment that is found. | |
| 1692 * | |
| 1693 * <pre> | |
| 1694 * metadata ::= | |
| 1695 * annotation* | |
| 1696 * </pre> | |
| 1697 * | |
| 1698 * @return the documentation comment and metadata that were parsed | |
| 1699 */ | |
| 1700 CommentAndMetadata parseCommentAndMetadata() { | |
| 1701 Comment comment = parseDocumentationComment(); | |
| 1702 List<Annotation> metadata = new List<Annotation>(); | |
| 1703 while (matches5(TokenType.AT)) { | |
| 1704 metadata.add(parseAnnotation()); | |
| 1705 Comment optionalComment = parseDocumentationComment(); | |
| 1706 if (optionalComment != null) { | |
| 1707 comment = optionalComment; | |
| 1708 } | |
| 1709 } | |
| 1710 return new CommentAndMetadata(comment, metadata); | |
| 1711 } | |
| 1712 | |
| 1713 /** | |
| 1714 * Parse a comment reference from the source between square brackets. | |
| 1715 * | |
| 1716 * <pre> | |
| 1717 * commentReference ::= | |
| 1718 * 'new'? prefixedIdentifier | |
| 1719 * </pre> | |
| 1720 * | |
| 1721 * @param referenceSource the source occurring between the square brackets wit
hin a documentation | |
| 1722 * comment | |
| 1723 * @param sourceOffset the offset of the first character of the reference sour
ce | |
| 1724 * @return the comment reference that was parsed, or `null` if no reference co
uld be found | |
| 1725 */ | |
| 1726 CommentReference parseCommentReference(String referenceSource, int sourceOffse
t) { | |
| 1727 if (referenceSource.length == 0) { | |
| 1728 return null; | |
| 1729 } | |
| 1730 try { | |
| 1731 List<bool> errorFound = [false]; | |
| 1732 AnalysisErrorListener listener = new AnalysisErrorListener_15(errorFound); | |
| 1733 Scanner scanner = new Scanner(null, new SubSequenceReader(new CharSequence
(referenceSource), sourceOffset), listener); | |
| 1734 scanner.setSourceStart(1, 1); | |
| 1735 Token firstToken = scanner.tokenize(); | |
| 1736 if (errorFound[0]) { | |
| 1737 return null; | |
| 1738 } | |
| 1739 Token newKeyword = null; | |
| 1740 if (matches3(firstToken, Keyword.NEW)) { | |
| 1741 newKeyword = firstToken; | |
| 1742 firstToken = firstToken.next; | |
| 1743 } | |
| 1744 if (matchesIdentifier2(firstToken)) { | |
| 1745 Token secondToken = firstToken.next; | |
| 1746 Token thirdToken = secondToken.next; | |
| 1747 Token nextToken; | |
| 1748 Identifier identifier; | |
| 1749 if (matches4(secondToken, TokenType.PERIOD) && matchesIdentifier2(thirdT
oken)) { | |
| 1750 identifier = new PrefixedIdentifier.full(new SimpleIdentifier.full(fir
stToken), secondToken, new SimpleIdentifier.full(thirdToken)); | |
| 1751 nextToken = thirdToken.next; | |
| 1752 } else { | |
| 1753 identifier = new SimpleIdentifier.full(firstToken); | |
| 1754 nextToken = firstToken.next; | |
| 1755 } | |
| 1756 if (nextToken.type != TokenType.EOF) { | |
| 1757 return null; | |
| 1758 } | |
| 1759 return new CommentReference.full(newKeyword, identifier); | |
| 1760 } else if (matches3(firstToken, Keyword.THIS) || matches3(firstToken, Keyw
ord.NULL) || matches3(firstToken, Keyword.TRUE) || matches3(firstToken, Keyword.
FALSE)) { | |
| 1761 return null; | |
| 1762 } | |
| 1763 } on JavaException catch (exception) { | |
| 1764 } | |
| 1765 return null; | |
| 1766 } | |
| 1767 | |
| 1768 /** | |
| 1769 * Parse all of the comment references occurring in the given array of documen
tation comments. | |
| 1770 * | |
| 1771 * <pre> | |
| 1772 * commentReference ::= | |
| 1773 * '[' 'new'? qualified ']' libraryReference? | |
| 1774 * | |
| 1775 * libraryReference ::= | |
| 1776 * '(' stringLiteral ')' | |
| 1777 * </pre> | |
| 1778 * | |
| 1779 * @param tokens the comment tokens representing the documentation comments to
be parsed | |
| 1780 * @return the comment references that were parsed | |
| 1781 */ | |
| 1782 List<CommentReference> parseCommentReferences(List<Token> tokens) { | |
| 1783 List<CommentReference> references = new List<CommentReference>(); | |
| 1784 for (Token token in tokens) { | |
| 1785 String comment = token.lexeme; | |
| 1786 int length = comment.length; | |
| 1787 List<List<int>> codeBlockRanges = getCodeBlockRanges(comment); | |
| 1788 int leftIndex = comment.indexOf('['); | |
| 1789 while (leftIndex >= 0 && leftIndex + 1 < length) { | |
| 1790 List<int> range = findRange(codeBlockRanges, leftIndex); | |
| 1791 if (range == null) { | |
| 1792 int rightIndex = JavaString.indexOf(comment, ']', leftIndex); | |
| 1793 if (rightIndex >= 0) { | |
| 1794 int firstChar = comment.codeUnitAt(leftIndex + 1); | |
| 1795 if (firstChar != 0x27 && firstChar != 0x22) { | |
| 1796 if (isLinkText(comment, rightIndex)) { | |
| 1797 } else { | |
| 1798 CommentReference reference = parseCommentReference(comment.subst
ring(leftIndex + 1, rightIndex), token.offset + leftIndex + 1); | |
| 1799 if (reference != null) { | |
| 1800 references.add(reference); | |
| 1801 } | |
| 1802 } | |
| 1803 } | |
| 1804 } else { | |
| 1805 rightIndex = leftIndex + 1; | |
| 1806 } | |
| 1807 leftIndex = JavaString.indexOf(comment, '[', rightIndex); | |
| 1808 } else { | |
| 1809 leftIndex = JavaString.indexOf(comment, '[', range[1] + 1); | |
| 1810 } | |
| 1811 } | |
| 1812 } | |
| 1813 return references; | |
| 1814 } | |
| 1815 | |
| 1816 /** | |
| 1817 * Parse a compilation unit. | |
| 1818 * | |
| 1819 * Specified: | |
| 1820 * | |
| 1821 * <pre> | |
| 1822 * compilationUnit ::= | |
| 1823 * scriptTag? directive* topLevelDeclaration* | |
| 1824 * </pre> | |
| 1825 * Actual: | |
| 1826 * | |
| 1827 * <pre> | |
| 1828 * compilationUnit ::= | |
| 1829 * scriptTag? topLevelElement* | |
| 1830 * | |
| 1831 * topLevelElement ::= | |
| 1832 * directive | |
| 1833 * | topLevelDeclaration | |
| 1834 * </pre> | |
| 1835 * | |
| 1836 * @return the compilation unit that was parsed | |
| 1837 */ | |
| 1838 CompilationUnit parseCompilationUnit2() { | |
| 1839 Token firstToken = _currentToken; | |
| 1840 ScriptTag scriptTag = null; | |
| 1841 if (matches5(TokenType.SCRIPT_TAG)) { | |
| 1842 scriptTag = new ScriptTag.full(andAdvance); | |
| 1843 } | |
| 1844 bool libraryDirectiveFound = false; | |
| 1845 bool partOfDirectiveFound = false; | |
| 1846 bool partDirectiveFound = false; | |
| 1847 bool directiveFoundAfterDeclaration = false; | |
| 1848 List<Directive> directives = new List<Directive>(); | |
| 1849 List<CompilationUnitMember> declarations = new List<CompilationUnitMember>()
; | |
| 1850 Token memberStart = _currentToken; | |
| 1851 while (!matches5(TokenType.EOF)) { | |
| 1852 CommentAndMetadata commentAndMetadata = parseCommentAndMetadata(); | |
| 1853 if ((matches(Keyword.IMPORT) || matches(Keyword.EXPORT) || matches(Keyword
.LIBRARY) || matches(Keyword.PART)) && !matches4(peek(), TokenType.PERIOD) && !m
atches4(peek(), TokenType.LT)) { | |
| 1854 Directive directive = parseDirective(commentAndMetadata); | |
| 1855 if (declarations.length > 0 && !directiveFoundAfterDeclaration) { | |
| 1856 reportError8(ParserErrorCode.DIRECTIVE_AFTER_DECLARATION, []); | |
| 1857 directiveFoundAfterDeclaration = true; | |
| 1858 } | |
| 1859 if (directive is LibraryDirective) { | |
| 1860 if (libraryDirectiveFound) { | |
| 1861 reportError8(ParserErrorCode.MULTIPLE_LIBRARY_DIRECTIVES, []); | |
| 1862 } else { | |
| 1863 if (directives.length > 0) { | |
| 1864 reportError8(ParserErrorCode.LIBRARY_DIRECTIVE_NOT_FIRST, []); | |
| 1865 } | |
| 1866 libraryDirectiveFound = true; | |
| 1867 } | |
| 1868 } else if (directive is PartDirective) { | |
| 1869 partDirectiveFound = true; | |
| 1870 } else if (partDirectiveFound) { | |
| 1871 if (directive is ExportDirective) { | |
| 1872 reportError9(ParserErrorCode.EXPORT_DIRECTIVE_AFTER_PART_DIRECTIVE,
((directive as NamespaceDirective)).keyword, []); | |
| 1873 } else if (directive is ImportDirective) { | |
| 1874 reportError9(ParserErrorCode.IMPORT_DIRECTIVE_AFTER_PART_DIRECTIVE,
((directive as NamespaceDirective)).keyword, []); | |
| 1875 } | |
| 1876 } | |
| 1877 if (directive is PartOfDirective) { | |
| 1878 if (partOfDirectiveFound) { | |
| 1879 reportError8(ParserErrorCode.MULTIPLE_PART_OF_DIRECTIVES, []); | |
| 1880 } else { | |
| 1881 for (Directive precedingDirective in directives) { | |
| 1882 reportError9(ParserErrorCode.NON_PART_OF_DIRECTIVE_IN_PART, preced
ingDirective.keyword, []); | |
| 1883 } | |
| 1884 partOfDirectiveFound = true; | |
| 1885 } | |
| 1886 } else { | |
| 1887 if (partOfDirectiveFound) { | |
| 1888 reportError9(ParserErrorCode.NON_PART_OF_DIRECTIVE_IN_PART, directiv
e.keyword, []); | |
| 1889 } | |
| 1890 } | |
| 1891 directives.add(directive); | |
| 1892 } else if (matches5(TokenType.SEMICOLON)) { | |
| 1893 reportError9(ParserErrorCode.UNEXPECTED_TOKEN, _currentToken, [_currentT
oken.lexeme]); | |
| 1894 advance(); | |
| 1895 } else { | |
| 1896 CompilationUnitMember member = parseCompilationUnitMember(commentAndMeta
data); | |
| 1897 if (member != null) { | |
| 1898 declarations.add(member); | |
| 1899 } | |
| 1900 } | |
| 1901 if (identical(_currentToken, memberStart)) { | |
| 1902 reportError9(ParserErrorCode.UNEXPECTED_TOKEN, _currentToken, [_currentT
oken.lexeme]); | |
| 1903 advance(); | |
| 1904 while (!matches5(TokenType.EOF) && !couldBeStartOfCompilationUnitMember(
)) { | |
| 1905 advance(); | |
| 1906 } | |
| 1907 } | |
| 1908 memberStart = _currentToken; | |
| 1909 } | |
| 1910 return new CompilationUnit.full(firstToken, scriptTag, directives, declarati
ons, _currentToken); | |
| 1911 } | |
| 1912 | |
| 1913 /** | |
| 1914 * Parse a compilation unit member. | |
| 1915 * | |
| 1916 * <pre> | |
| 1917 * compilationUnitMember ::= | |
| 1918 * classDefinition | |
| 1919 * | functionTypeAlias | |
| 1920 * | external functionSignature | |
| 1921 * | external getterSignature | |
| 1922 * | external setterSignature | |
| 1923 * | functionSignature functionBody | |
| 1924 * | returnType? getOrSet identifier formalParameterList functionBody | |
| 1925 * | (final | const) type? staticFinalDeclarationList ';' | |
| 1926 * | variableDeclaration ';' | |
| 1927 * </pre> | |
| 1928 * | |
| 1929 * @param commentAndMetadata the metadata to be associated with the member | |
| 1930 * @return the compilation unit member that was parsed, or `null` if what was
parsed could | |
| 1931 * not be represented as a compilation unit member | |
| 1932 */ | |
| 1933 CompilationUnitMember parseCompilationUnitMember(CommentAndMetadata commentAnd
Metadata) { | |
| 1934 Modifiers modifiers = parseModifiers(); | |
| 1935 if (matches(Keyword.CLASS)) { | |
| 1936 return parseClassDeclaration(commentAndMetadata, validateModifiersForClass
(modifiers)); | |
| 1937 } else if (matches(Keyword.TYPEDEF) && !matches4(peek(), TokenType.PERIOD) &
& !matches4(peek(), TokenType.LT)) { | |
| 1938 validateModifiersForTypedef(modifiers); | |
| 1939 return parseTypeAlias(commentAndMetadata); | |
| 1940 } | |
| 1941 if (matches(Keyword.VOID)) { | |
| 1942 TypeName returnType = parseReturnType(); | |
| 1943 if ((matches(Keyword.GET) || matches(Keyword.SET)) && matchesIdentifier2(p
eek())) { | |
| 1944 validateModifiersForTopLevelFunction(modifiers); | |
| 1945 return parseFunctionDeclaration(commentAndMetadata, modifiers.externalKe
yword, null); | |
| 1946 } else if (matches(Keyword.OPERATOR) && isOperator(peek())) { | |
| 1947 reportError9(ParserErrorCode.TOP_LEVEL_OPERATOR, _currentToken, []); | |
| 1948 return convertToFunctionDeclaration(parseOperator(commentAndMetadata, mo
difiers.externalKeyword, returnType)); | |
| 1949 } else if (matchesIdentifier() && matchesAny(peek(), [ | |
| 1950 TokenType.OPEN_PAREN, | |
| 1951 TokenType.OPEN_CURLY_BRACKET, | |
| 1952 TokenType.FUNCTION])) { | |
| 1953 validateModifiersForTopLevelFunction(modifiers); | |
| 1954 return parseFunctionDeclaration(commentAndMetadata, modifiers.externalKe
yword, returnType); | |
| 1955 } else { | |
| 1956 if (matchesIdentifier()) { | |
| 1957 if (matchesAny(peek(), [TokenType.EQ, TokenType.COMMA, TokenType.SEMIC
OLON])) { | |
| 1958 reportError(ParserErrorCode.VOID_VARIABLE, returnType, []); | |
| 1959 return new TopLevelVariableDeclaration.full(commentAndMetadata.comme
nt, commentAndMetadata.metadata, parseVariableDeclarationList2(null, validateMod
ifiersForTopLevelVariable(modifiers), null), expect2(TokenType.SEMICOLON)); | |
| 1960 } | |
| 1961 } | |
| 1962 reportError9(ParserErrorCode.EXPECTED_EXECUTABLE, _currentToken, []); | |
| 1963 return null; | |
| 1964 } | |
| 1965 } else if ((matches(Keyword.GET) || matches(Keyword.SET)) && matchesIdentifi
er2(peek())) { | |
| 1966 validateModifiersForTopLevelFunction(modifiers); | |
| 1967 return parseFunctionDeclaration(commentAndMetadata, modifiers.externalKeyw
ord, null); | |
| 1968 } else if (matches(Keyword.OPERATOR) && isOperator(peek())) { | |
| 1969 reportError9(ParserErrorCode.TOP_LEVEL_OPERATOR, _currentToken, []); | |
| 1970 return convertToFunctionDeclaration(parseOperator(commentAndMetadata, modi
fiers.externalKeyword, null)); | |
| 1971 } else if (!matchesIdentifier()) { | |
| 1972 reportError9(ParserErrorCode.EXPECTED_EXECUTABLE, _currentToken, []); | |
| 1973 return null; | |
| 1974 } else if (matches4(peek(), TokenType.OPEN_PAREN)) { | |
| 1975 validateModifiersForTopLevelFunction(modifiers); | |
| 1976 return parseFunctionDeclaration(commentAndMetadata, modifiers.externalKeyw
ord, null); | |
| 1977 } else if (matchesAny(peek(), [TokenType.EQ, TokenType.COMMA, TokenType.SEMI
COLON])) { | |
| 1978 if (modifiers.constKeyword == null && modifiers.finalKeyword == null && mo
difiers.varKeyword == null) { | |
| 1979 reportError8(ParserErrorCode.MISSING_CONST_FINAL_VAR_OR_TYPE, []); | |
| 1980 } | |
| 1981 return new TopLevelVariableDeclaration.full(commentAndMetadata.comment, co
mmentAndMetadata.metadata, parseVariableDeclarationList2(null, validateModifiers
ForTopLevelVariable(modifiers), null), expect2(TokenType.SEMICOLON)); | |
| 1982 } | |
| 1983 TypeName returnType = parseReturnType(); | |
| 1984 if ((matches(Keyword.GET) || matches(Keyword.SET)) && matchesIdentifier2(pee
k())) { | |
| 1985 validateModifiersForTopLevelFunction(modifiers); | |
| 1986 return parseFunctionDeclaration(commentAndMetadata, modifiers.externalKeyw
ord, returnType); | |
| 1987 } else if (matches(Keyword.OPERATOR) && isOperator(peek())) { | |
| 1988 reportError9(ParserErrorCode.TOP_LEVEL_OPERATOR, _currentToken, []); | |
| 1989 return convertToFunctionDeclaration(parseOperator(commentAndMetadata, modi
fiers.externalKeyword, returnType)); | |
| 1990 } else if (matches5(TokenType.AT)) { | |
| 1991 return new TopLevelVariableDeclaration.full(commentAndMetadata.comment, co
mmentAndMetadata.metadata, parseVariableDeclarationList2(null, validateModifiers
ForTopLevelVariable(modifiers), returnType), expect2(TokenType.SEMICOLON)); | |
| 1992 } else if (!matchesIdentifier()) { | |
| 1993 reportError9(ParserErrorCode.EXPECTED_EXECUTABLE, _currentToken, []); | |
| 1994 Token semicolon; | |
| 1995 if (matches5(TokenType.SEMICOLON)) { | |
| 1996 semicolon = andAdvance; | |
| 1997 } else { | |
| 1998 semicolon = createSyntheticToken2(TokenType.SEMICOLON); | |
| 1999 } | |
| 2000 List<VariableDeclaration> variables = new List<VariableDeclaration>(); | |
| 2001 variables.add(new VariableDeclaration.full(null, null, createSyntheticIden
tifier(), null, null)); | |
| 2002 return new TopLevelVariableDeclaration.full(commentAndMetadata.comment, co
mmentAndMetadata.metadata, new VariableDeclarationList.full(null, null, null, re
turnType, variables), semicolon); | |
| 2003 } | |
| 2004 if (matchesAny(peek(), [ | |
| 2005 TokenType.OPEN_PAREN, | |
| 2006 TokenType.FUNCTION, | |
| 2007 TokenType.OPEN_CURLY_BRACKET])) { | |
| 2008 validateModifiersForTopLevelFunction(modifiers); | |
| 2009 return parseFunctionDeclaration(commentAndMetadata, modifiers.externalKeyw
ord, returnType); | |
| 2010 } | |
| 2011 return new TopLevelVariableDeclaration.full(commentAndMetadata.comment, comm
entAndMetadata.metadata, parseVariableDeclarationList2(null, validateModifiersFo
rTopLevelVariable(modifiers), returnType), expect2(TokenType.SEMICOLON)); | |
| 2012 } | |
| 2013 | |
| 2014 /** | |
| 2015 * Parse a conditional expression. | |
| 2016 * | |
| 2017 * <pre> | |
| 2018 * conditionalExpression ::= | |
| 2019 * logicalOrExpression ('?' expressionWithoutCascade ':' expressionWithout
Cascade)? | |
| 2020 * </pre> | |
| 2021 * | |
| 2022 * @return the conditional expression that was parsed | |
| 2023 */ | |
| 2024 Expression parseConditionalExpression() { | |
| 2025 Expression condition = parseLogicalOrExpression(); | |
| 2026 if (!matches5(TokenType.QUESTION)) { | |
| 2027 return condition; | |
| 2028 } | |
| 2029 Token question = andAdvance; | |
| 2030 Expression thenExpression = parseExpressionWithoutCascade(); | |
| 2031 Token colon = expect2(TokenType.COLON); | |
| 2032 Expression elseExpression = parseExpressionWithoutCascade(); | |
| 2033 return new ConditionalExpression.full(condition, question, thenExpression, c
olon, elseExpression); | |
| 2034 } | |
| 2035 | |
| 2036 /** | |
| 2037 * Parse a const expression. | |
| 2038 * | |
| 2039 * <pre> | |
| 2040 * constExpression ::= | |
| 2041 * instanceCreationExpression | |
| 2042 * | listLiteral | |
| 2043 * | mapLiteral | |
| 2044 * </pre> | |
| 2045 * | |
| 2046 * @return the const expression that was parsed | |
| 2047 */ | |
| 2048 Expression parseConstExpression() { | |
| 2049 Token keyword = expect(Keyword.CONST); | |
| 2050 if (matches5(TokenType.OPEN_SQUARE_BRACKET) || matches5(TokenType.INDEX)) { | |
| 2051 return parseListLiteral(keyword, null); | |
| 2052 } else if (matches5(TokenType.OPEN_CURLY_BRACKET)) { | |
| 2053 return parseMapLiteral(keyword, null); | |
| 2054 } else if (matches5(TokenType.LT)) { | |
| 2055 return parseListOrMapLiteral(keyword); | |
| 2056 } | |
| 2057 return parseInstanceCreationExpression(keyword); | |
| 2058 } | |
| 2059 ConstructorDeclaration parseConstructor(CommentAndMetadata commentAndMetadata,
Token externalKeyword, Token constKeyword, Token factoryKeyword, SimpleIdentifi
er returnType, Token period, SimpleIdentifier name, FormalParameterList paramete
rs) { | |
| 2060 bool bodyAllowed = externalKeyword == null; | |
| 2061 Token separator = null; | |
| 2062 List<ConstructorInitializer> initializers = null; | |
| 2063 if (matches5(TokenType.COLON)) { | |
| 2064 separator = andAdvance; | |
| 2065 initializers = new List<ConstructorInitializer>(); | |
| 2066 do { | |
| 2067 if (matches(Keyword.THIS)) { | |
| 2068 if (matches4(peek(), TokenType.OPEN_PAREN)) { | |
| 2069 bodyAllowed = false; | |
| 2070 initializers.add(parseRedirectingConstructorInvocation()); | |
| 2071 } else if (matches4(peek(), TokenType.PERIOD) && matches4(peek2(3), To
kenType.OPEN_PAREN)) { | |
| 2072 bodyAllowed = false; | |
| 2073 initializers.add(parseRedirectingConstructorInvocation()); | |
| 2074 } else { | |
| 2075 initializers.add(parseConstructorFieldInitializer()); | |
| 2076 } | |
| 2077 } else if (matches(Keyword.SUPER)) { | |
| 2078 initializers.add(parseSuperConstructorInvocation()); | |
| 2079 } else { | |
| 2080 initializers.add(parseConstructorFieldInitializer()); | |
| 2081 } | |
| 2082 } while (optional(TokenType.COMMA)); | |
| 2083 } | |
| 2084 ConstructorName redirectedConstructor = null; | |
| 2085 FunctionBody body; | |
| 2086 if (matches5(TokenType.EQ)) { | |
| 2087 separator = andAdvance; | |
| 2088 redirectedConstructor = parseConstructorName(); | |
| 2089 body = new EmptyFunctionBody.full(expect2(TokenType.SEMICOLON)); | |
| 2090 if (factoryKeyword == null) { | |
| 2091 reportError(ParserErrorCode.REDIRECTION_IN_NON_FACTORY_CONSTRUCTOR, redi
rectedConstructor, []); | |
| 2092 } | |
| 2093 } else { | |
| 2094 body = parseFunctionBody(true, ParserErrorCode.MISSING_FUNCTION_BODY, fals
e); | |
| 2095 if (constKeyword != null && factoryKeyword != null) { | |
| 2096 reportError9(ParserErrorCode.CONST_FACTORY, factoryKeyword, []); | |
| 2097 } else if (body is EmptyFunctionBody) { | |
| 2098 if (factoryKeyword != null && externalKeyword == null) { | |
| 2099 reportError9(ParserErrorCode.FACTORY_WITHOUT_BODY, factoryKeyword, [])
; | |
| 2100 } | |
| 2101 } else { | |
| 2102 if (constKeyword != null) { | |
| 2103 reportError(ParserErrorCode.CONST_CONSTRUCTOR_WITH_BODY, body, []); | |
| 2104 } else if (!bodyAllowed) { | |
| 2105 reportError(ParserErrorCode.EXTERNAL_CONSTRUCTOR_WITH_BODY, body, []); | |
| 2106 } | |
| 2107 } | |
| 2108 } | |
| 2109 return new ConstructorDeclaration.full(commentAndMetadata.comment, commentAn
dMetadata.metadata, externalKeyword, constKeyword, factoryKeyword, returnType, p
eriod, name, parameters, separator, initializers, redirectedConstructor, body); | |
| 2110 } | |
| 2111 | |
| 2112 /** | |
| 2113 * Parse a field initializer within a constructor. | |
| 2114 * | |
| 2115 * <pre> | |
| 2116 * fieldInitializer: | |
| 2117 * ('this' '.')? identifier '=' conditionalExpression cascadeSection* | |
| 2118 * </pre> | |
| 2119 * | |
| 2120 * @return the field initializer that was parsed | |
| 2121 */ | |
| 2122 ConstructorFieldInitializer parseConstructorFieldInitializer() { | |
| 2123 Token keyword = null; | |
| 2124 Token period = null; | |
| 2125 if (matches(Keyword.THIS)) { | |
| 2126 keyword = andAdvance; | |
| 2127 period = expect2(TokenType.PERIOD); | |
| 2128 } | |
| 2129 SimpleIdentifier fieldName = parseSimpleIdentifier(); | |
| 2130 Token equals = expect2(TokenType.EQ); | |
| 2131 Expression expression = parseConditionalExpression(); | |
| 2132 TokenType tokenType = _currentToken.type; | |
| 2133 if (identical(tokenType, TokenType.PERIOD_PERIOD)) { | |
| 2134 List<Expression> cascadeSections = new List<Expression>(); | |
| 2135 while (identical(tokenType, TokenType.PERIOD_PERIOD)) { | |
| 2136 Expression section = parseCascadeSection(); | |
| 2137 if (section != null) { | |
| 2138 cascadeSections.add(section); | |
| 2139 } | |
| 2140 tokenType = _currentToken.type; | |
| 2141 } | |
| 2142 expression = new CascadeExpression.full(expression, cascadeSections); | |
| 2143 } | |
| 2144 return new ConstructorFieldInitializer.full(keyword, period, fieldName, equa
ls, expression); | |
| 2145 } | |
| 2146 | |
| 2147 /** | |
| 2148 * Parse the name of a constructor. | |
| 2149 * | |
| 2150 * <pre> | |
| 2151 * constructorName: | |
| 2152 * type ('.' identifier)? | |
| 2153 * </pre> | |
| 2154 * | |
| 2155 * @return the constructor name that was parsed | |
| 2156 */ | |
| 2157 ConstructorName parseConstructorName() { | |
| 2158 TypeName type = parseTypeName(); | |
| 2159 Token period = null; | |
| 2160 SimpleIdentifier name = null; | |
| 2161 if (matches5(TokenType.PERIOD)) { | |
| 2162 period = andAdvance; | |
| 2163 name = parseSimpleIdentifier(); | |
| 2164 } | |
| 2165 return new ConstructorName.full(type, period, name); | |
| 2166 } | |
| 2167 | |
| 2168 /** | |
| 2169 * Parse a continue statement. | |
| 2170 * | |
| 2171 * <pre> | |
| 2172 * continueStatement ::= | |
| 2173 * 'continue' identifier? ';' | |
| 2174 * </pre> | |
| 2175 * | |
| 2176 * @return the continue statement that was parsed | |
| 2177 */ | |
| 2178 Statement parseContinueStatement() { | |
| 2179 Token continueKeyword = expect(Keyword.CONTINUE); | |
| 2180 if (!_inLoop && !_inSwitch) { | |
| 2181 reportError9(ParserErrorCode.CONTINUE_OUTSIDE_OF_LOOP, continueKeyword, []
); | |
| 2182 } | |
| 2183 SimpleIdentifier label = null; | |
| 2184 if (matchesIdentifier()) { | |
| 2185 label = parseSimpleIdentifier(); | |
| 2186 } | |
| 2187 if (_inSwitch && !_inLoop && label == null) { | |
| 2188 reportError9(ParserErrorCode.CONTINUE_WITHOUT_LABEL_IN_CASE, continueKeywo
rd, []); | |
| 2189 } | |
| 2190 Token semicolon = expect2(TokenType.SEMICOLON); | |
| 2191 return new ContinueStatement.full(continueKeyword, label, semicolon); | |
| 2192 } | |
| 2193 | |
| 2194 /** | |
| 2195 * Parse a directive. | |
| 2196 * | |
| 2197 * <pre> | |
| 2198 * directive ::= | |
| 2199 * exportDirective | |
| 2200 * | libraryDirective | |
| 2201 * | importDirective | |
| 2202 * | partDirective | |
| 2203 * </pre> | |
| 2204 * | |
| 2205 * @param commentAndMetadata the metadata to be associated with the directive | |
| 2206 * @return the directive that was parsed | |
| 2207 */ | |
| 2208 Directive parseDirective(CommentAndMetadata commentAndMetadata) { | |
| 2209 if (matches(Keyword.IMPORT)) { | |
| 2210 return parseImportDirective(commentAndMetadata); | |
| 2211 } else if (matches(Keyword.EXPORT)) { | |
| 2212 return parseExportDirective(commentAndMetadata); | |
| 2213 } else if (matches(Keyword.LIBRARY)) { | |
| 2214 return parseLibraryDirective(commentAndMetadata); | |
| 2215 } else if (matches(Keyword.PART)) { | |
| 2216 return parsePartDirective(commentAndMetadata); | |
| 2217 } else { | |
| 2218 throw new IllegalStateException("parseDirective invoked in an invalid stat
e; currentToken = ${_currentToken}"); | |
| 2219 } | |
| 2220 } | |
| 2221 | |
| 2222 /** | |
| 2223 * Parse a documentation comment. | |
| 2224 * | |
| 2225 * <pre> | |
| 2226 * documentationComment ::= | |
| 2227 * multiLineComment? | |
| 2228 * | singleLineComment* | |
| 2229 * </pre> | |
| 2230 * | |
| 2231 * @return the documentation comment that was parsed, or `null` if there was n
o comment | |
| 2232 */ | |
| 2233 Comment parseDocumentationComment() { | |
| 2234 List<Token> commentTokens = new List<Token>(); | |
| 2235 Token commentToken = _currentToken.precedingComments; | |
| 2236 while (commentToken != null) { | |
| 2237 if (identical(commentToken.type, TokenType.SINGLE_LINE_COMMENT)) { | |
| 2238 if (commentToken.lexeme.startsWith("///")) { | |
| 2239 if (commentTokens.length == 1 && commentTokens[0].lexeme.startsWith("/
**")) { | |
| 2240 commentTokens.clear(); | |
| 2241 } | |
| 2242 commentTokens.add(commentToken); | |
| 2243 } | |
| 2244 } else { | |
| 2245 if (commentToken.lexeme.startsWith("/**")) { | |
| 2246 commentTokens.clear(); | |
| 2247 commentTokens.add(commentToken); | |
| 2248 } | |
| 2249 } | |
| 2250 commentToken = commentToken.next; | |
| 2251 } | |
| 2252 if (commentTokens.isEmpty) { | |
| 2253 return null; | |
| 2254 } | |
| 2255 List<Token> tokens = new List.from(commentTokens); | |
| 2256 List<CommentReference> references = parseCommentReferences(tokens); | |
| 2257 return Comment.createDocumentationComment2(tokens, references); | |
| 2258 } | |
| 2259 | |
| 2260 /** | |
| 2261 * Parse a do statement. | |
| 2262 * | |
| 2263 * <pre> | |
| 2264 * doStatement ::= | |
| 2265 * 'do' statement 'while' '(' expression ')' ';' | |
| 2266 * </pre> | |
| 2267 * | |
| 2268 * @return the do statement that was parsed | |
| 2269 */ | |
| 2270 Statement parseDoStatement() { | |
| 2271 bool wasInLoop = _inLoop; | |
| 2272 _inLoop = true; | |
| 2273 try { | |
| 2274 Token doKeyword = expect(Keyword.DO); | |
| 2275 Statement body = parseStatement2(); | |
| 2276 Token whileKeyword = expect(Keyword.WHILE); | |
| 2277 Token leftParenthesis = expect2(TokenType.OPEN_PAREN); | |
| 2278 Expression condition = parseExpression2(); | |
| 2279 Token rightParenthesis = expect2(TokenType.CLOSE_PAREN); | |
| 2280 Token semicolon = expect2(TokenType.SEMICOLON); | |
| 2281 return new DoStatement.full(doKeyword, body, whileKeyword, leftParenthesis
, condition, rightParenthesis, semicolon); | |
| 2282 } finally { | |
| 2283 _inLoop = wasInLoop; | |
| 2284 } | |
| 2285 } | |
| 2286 | |
| 2287 /** | |
| 2288 * Parse an empty statement. | |
| 2289 * | |
| 2290 * <pre> | |
| 2291 * emptyStatement ::= | |
| 2292 * ';' | |
| 2293 * </pre> | |
| 2294 * | |
| 2295 * @return the empty statement that was parsed | |
| 2296 */ | |
| 2297 Statement parseEmptyStatement() => new EmptyStatement.full(andAdvance); | |
| 2298 | |
| 2299 /** | |
| 2300 * Parse an equality expression. | |
| 2301 * | |
| 2302 * <pre> | |
| 2303 * equalityExpression ::= | |
| 2304 * relationalExpression (equalityOperator relationalExpression)? | |
| 2305 * | 'super' equalityOperator relationalExpression | |
| 2306 * </pre> | |
| 2307 * | |
| 2308 * @return the equality expression that was parsed | |
| 2309 */ | |
| 2310 Expression parseEqualityExpression() { | |
| 2311 Expression expression; | |
| 2312 if (matches(Keyword.SUPER) && _currentToken.next.type.isEqualityOperator) { | |
| 2313 expression = new SuperExpression.full(andAdvance); | |
| 2314 } else { | |
| 2315 expression = parseRelationalExpression(); | |
| 2316 } | |
| 2317 bool leftEqualityExpression = false; | |
| 2318 while (_currentToken.type.isEqualityOperator) { | |
| 2319 Token operator = andAdvance; | |
| 2320 if (leftEqualityExpression) { | |
| 2321 reportError(ParserErrorCode.EQUALITY_CANNOT_BE_EQUALITY_OPERAND, express
ion, []); | |
| 2322 } | |
| 2323 expression = new BinaryExpression.full(expression, operator, parseRelation
alExpression()); | |
| 2324 leftEqualityExpression = true; | |
| 2325 } | |
| 2326 return expression; | |
| 2327 } | |
| 2328 | |
| 2329 /** | |
| 2330 * Parse an export directive. | |
| 2331 * | |
| 2332 * <pre> | |
| 2333 * exportDirective ::= | |
| 2334 * metadata 'export' stringLiteral combinator*';' | |
| 2335 * </pre> | |
| 2336 * | |
| 2337 * @param commentAndMetadata the metadata to be associated with the directive | |
| 2338 * @return the export directive that was parsed | |
| 2339 */ | |
| 2340 ExportDirective parseExportDirective(CommentAndMetadata commentAndMetadata) { | |
| 2341 Token exportKeyword = expect(Keyword.EXPORT); | |
| 2342 StringLiteral libraryUri = parseStringLiteral(); | |
| 2343 List<Combinator> combinators = parseCombinators(); | |
| 2344 Token semicolon = expect2(TokenType.SEMICOLON); | |
| 2345 return new ExportDirective.full(commentAndMetadata.comment, commentAndMetada
ta.metadata, exportKeyword, libraryUri, combinators, semicolon); | |
| 2346 } | |
| 2347 | |
| 2348 /** | |
| 2349 * Parse an expression that does not contain any cascades. | |
| 2350 * | |
| 2351 * <pre> | |
| 2352 * expression ::= | |
| 2353 * assignableExpression assignmentOperator expression | |
| 2354 * | conditionalExpression cascadeSection* | |
| 2355 * | throwExpression | |
| 2356 * </pre> | |
| 2357 * | |
| 2358 * @return the expression that was parsed | |
| 2359 */ | |
| 2360 Expression parseExpression2() { | |
| 2361 if (matches(Keyword.THROW)) { | |
| 2362 return parseThrowExpression(); | |
| 2363 } else if (matches(Keyword.RETHROW)) { | |
| 2364 return parseRethrowExpression(); | |
| 2365 } | |
| 2366 Expression expression = parseConditionalExpression(); | |
| 2367 TokenType tokenType = _currentToken.type; | |
| 2368 if (identical(tokenType, TokenType.PERIOD_PERIOD)) { | |
| 2369 List<Expression> cascadeSections = new List<Expression>(); | |
| 2370 while (identical(tokenType, TokenType.PERIOD_PERIOD)) { | |
| 2371 Expression section = parseCascadeSection(); | |
| 2372 if (section != null) { | |
| 2373 cascadeSections.add(section); | |
| 2374 } | |
| 2375 tokenType = _currentToken.type; | |
| 2376 } | |
| 2377 return new CascadeExpression.full(expression, cascadeSections); | |
| 2378 } else if (tokenType.isAssignmentOperator) { | |
| 2379 Token operator = andAdvance; | |
| 2380 ensureAssignable(expression); | |
| 2381 return new AssignmentExpression.full(expression, operator, parseExpression
2()); | |
| 2382 } | |
| 2383 return expression; | |
| 2384 } | |
| 2385 | |
| 2386 /** | |
| 2387 * Parse a list of expressions. | |
| 2388 * | |
| 2389 * <pre> | |
| 2390 * expressionList ::= | |
| 2391 * expression (',' expression)* | |
| 2392 * </pre> | |
| 2393 * | |
| 2394 * @return the expression that was parsed | |
| 2395 */ | |
| 2396 List<Expression> parseExpressionList() { | |
| 2397 List<Expression> expressions = new List<Expression>(); | |
| 2398 expressions.add(parseExpression2()); | |
| 2399 while (optional(TokenType.COMMA)) { | |
| 2400 expressions.add(parseExpression2()); | |
| 2401 } | |
| 2402 return expressions; | |
| 2403 } | |
| 2404 | |
| 2405 /** | |
| 2406 * Parse an expression that does not contain any cascades. | |
| 2407 * | |
| 2408 * <pre> | |
| 2409 * expressionWithoutCascade ::= | |
| 2410 * assignableExpression assignmentOperator expressionWithoutCascade | |
| 2411 * | conditionalExpression | |
| 2412 * | throwExpressionWithoutCascade | |
| 2413 * </pre> | |
| 2414 * | |
| 2415 * @return the expression that was parsed | |
| 2416 */ | |
| 2417 Expression parseExpressionWithoutCascade() { | |
| 2418 if (matches(Keyword.THROW)) { | |
| 2419 return parseThrowExpressionWithoutCascade(); | |
| 2420 } else if (matches(Keyword.RETHROW)) { | |
| 2421 return parseRethrowExpression(); | |
| 2422 } | |
| 2423 Expression expression = parseConditionalExpression(); | |
| 2424 if (_currentToken.type.isAssignmentOperator) { | |
| 2425 Token operator = andAdvance; | |
| 2426 ensureAssignable(expression); | |
| 2427 expression = new AssignmentExpression.full(expression, operator, parseExpr
essionWithoutCascade()); | |
| 2428 } | |
| 2429 return expression; | |
| 2430 } | |
| 2431 | |
| 2432 /** | |
| 2433 * Parse a class extends clause. | |
| 2434 * | |
| 2435 * <pre> | |
| 2436 * classExtendsClause ::= | |
| 2437 * 'extends' type | |
| 2438 * </pre> | |
| 2439 * | |
| 2440 * @return the class extends clause that was parsed | |
| 2441 */ | |
| 2442 ExtendsClause parseExtendsClause() { | |
| 2443 Token keyword = expect(Keyword.EXTENDS); | |
| 2444 TypeName superclass = parseTypeName(); | |
| 2445 return new ExtendsClause.full(keyword, superclass); | |
| 2446 } | |
| 2447 | |
| 2448 /** | |
| 2449 * Parse the 'final', 'const', 'var' or type preceding a variable declaration. | |
| 2450 * | |
| 2451 * <pre> | |
| 2452 * finalConstVarOrType ::= | |
| 2453 * | 'final' type? | |
| 2454 * | 'const' type? | |
| 2455 * | 'var' | |
| 2456 * | type | |
| 2457 * </pre> | |
| 2458 * | |
| 2459 * @param optional `true` if the keyword and type are optional | |
| 2460 * @return the 'final', 'const', 'var' or type that was parsed | |
| 2461 */ | |
| 2462 FinalConstVarOrType parseFinalConstVarOrType(bool optional) { | |
| 2463 Token keyword = null; | |
| 2464 TypeName type = null; | |
| 2465 if (matches(Keyword.FINAL) || matches(Keyword.CONST)) { | |
| 2466 keyword = andAdvance; | |
| 2467 if (isTypedIdentifier(_currentToken)) { | |
| 2468 type = parseTypeName(); | |
| 2469 } | |
| 2470 } else if (matches(Keyword.VAR)) { | |
| 2471 keyword = andAdvance; | |
| 2472 } else { | |
| 2473 if (isTypedIdentifier(_currentToken)) { | |
| 2474 type = parseReturnType(); | |
| 2475 } else if (!optional) { | |
| 2476 reportError8(ParserErrorCode.MISSING_CONST_FINAL_VAR_OR_TYPE, []); | |
| 2477 } | |
| 2478 } | |
| 2479 return new FinalConstVarOrType(keyword, type); | |
| 2480 } | |
| 2481 | |
| 2482 /** | |
| 2483 * Parse a formal parameter. At most one of `isOptional` and `isNamed` can be | |
| 2484 * `true`. | |
| 2485 * | |
| 2486 * <pre> | |
| 2487 * defaultFormalParameter ::= | |
| 2488 * normalFormalParameter ('=' expression)? | |
| 2489 * | |
| 2490 * defaultNamedParameter ::= | |
| 2491 * normalFormalParameter (':' expression)? | |
| 2492 * </pre> | |
| 2493 * | |
| 2494 * @param kind the kind of parameter being expected based on the presence or a
bsence of group | |
| 2495 * delimiters | |
| 2496 * @return the formal parameter that was parsed | |
| 2497 */ | |
| 2498 FormalParameter parseFormalParameter(ParameterKind kind) { | |
| 2499 NormalFormalParameter parameter = parseNormalFormalParameter(); | |
| 2500 if (matches5(TokenType.EQ)) { | |
| 2501 Token seperator = andAdvance; | |
| 2502 Expression defaultValue = parseExpression2(); | |
| 2503 if (identical(kind, ParameterKind.NAMED)) { | |
| 2504 reportError9(ParserErrorCode.WRONG_SEPARATOR_FOR_NAMED_PARAMETER, sepera
tor, []); | |
| 2505 } else if (identical(kind, ParameterKind.REQUIRED)) { | |
| 2506 reportError(ParserErrorCode.POSITIONAL_PARAMETER_OUTSIDE_GROUP, paramete
r, []); | |
| 2507 } | |
| 2508 return new DefaultFormalParameter.full(parameter, kind, seperator, default
Value); | |
| 2509 } else if (matches5(TokenType.COLON)) { | |
| 2510 Token seperator = andAdvance; | |
| 2511 Expression defaultValue = parseExpression2(); | |
| 2512 if (identical(kind, ParameterKind.POSITIONAL)) { | |
| 2513 reportError9(ParserErrorCode.WRONG_SEPARATOR_FOR_POSITIONAL_PARAMETER, s
eperator, []); | |
| 2514 } else if (identical(kind, ParameterKind.REQUIRED)) { | |
| 2515 reportError(ParserErrorCode.NAMED_PARAMETER_OUTSIDE_GROUP, parameter, []
); | |
| 2516 } | |
| 2517 return new DefaultFormalParameter.full(parameter, kind, seperator, default
Value); | |
| 2518 } else if (kind != ParameterKind.REQUIRED) { | |
| 2519 return new DefaultFormalParameter.full(parameter, kind, null, null); | |
| 2520 } | |
| 2521 return parameter; | |
| 2522 } | |
| 2523 | |
| 2524 /** | |
| 2525 * Parse a list of formal parameters. | |
| 2526 * | |
| 2527 * <pre> | |
| 2528 * formalParameterList ::= | |
| 2529 * '(' ')' | |
| 2530 * | '(' normalFormalParameters (',' optionalFormalParameters)? ')' | |
| 2531 * | '(' optionalFormalParameters ')' | |
| 2532 * | |
| 2533 * normalFormalParameters ::= | |
| 2534 * normalFormalParameter (',' normalFormalParameter)* | |
| 2535 * | |
| 2536 * optionalFormalParameters ::= | |
| 2537 * optionalPositionalFormalParameters | |
| 2538 * | namedFormalParameters | |
| 2539 * | |
| 2540 * optionalPositionalFormalParameters ::= | |
| 2541 * '[' defaultFormalParameter (',' defaultFormalParameter)* ']' | |
| 2542 * | |
| 2543 * namedFormalParameters ::= | |
| 2544 * '{' defaultNamedParameter (',' defaultNamedParameter)* '}' | |
| 2545 * </pre> | |
| 2546 * | |
| 2547 * @return the formal parameters that were parsed | |
| 2548 */ | |
| 2549 FormalParameterList parseFormalParameterList() { | |
| 2550 Token leftParenthesis = expect2(TokenType.OPEN_PAREN); | |
| 2551 if (matches5(TokenType.CLOSE_PAREN)) { | |
| 2552 return new FormalParameterList.full(leftParenthesis, null, null, null, and
Advance); | |
| 2553 } | |
| 2554 List<FormalParameter> parameters = new List<FormalParameter>(); | |
| 2555 List<FormalParameter> normalParameters = new List<FormalParameter>(); | |
| 2556 List<FormalParameter> positionalParameters = new List<FormalParameter>(); | |
| 2557 List<FormalParameter> namedParameters = new List<FormalParameter>(); | |
| 2558 List<FormalParameter> currentParameters = normalParameters; | |
| 2559 Token leftSquareBracket = null; | |
| 2560 Token rightSquareBracket = null; | |
| 2561 Token leftCurlyBracket = null; | |
| 2562 Token rightCurlyBracket = null; | |
| 2563 ParameterKind kind = ParameterKind.REQUIRED; | |
| 2564 bool firstParameter = true; | |
| 2565 bool reportedMuliplePositionalGroups = false; | |
| 2566 bool reportedMulipleNamedGroups = false; | |
| 2567 bool reportedMixedGroups = false; | |
| 2568 bool wasOptionalParameter = false; | |
| 2569 Token initialToken = null; | |
| 2570 do { | |
| 2571 if (firstParameter) { | |
| 2572 firstParameter = false; | |
| 2573 } else if (!optional(TokenType.COMMA)) { | |
| 2574 if (getEndToken(leftParenthesis) != null) { | |
| 2575 reportError8(ParserErrorCode.EXPECTED_TOKEN, [TokenType.COMMA.lexeme])
; | |
| 2576 } else { | |
| 2577 reportError9(ParserErrorCode.MISSING_CLOSING_PARENTHESIS, _currentToke
n.previous, []); | |
| 2578 break; | |
| 2579 } | |
| 2580 } | |
| 2581 initialToken = _currentToken; | |
| 2582 if (matches5(TokenType.OPEN_SQUARE_BRACKET)) { | |
| 2583 wasOptionalParameter = true; | |
| 2584 if (leftSquareBracket != null && !reportedMuliplePositionalGroups) { | |
| 2585 reportError8(ParserErrorCode.MULTIPLE_POSITIONAL_PARAMETER_GROUPS, [])
; | |
| 2586 reportedMuliplePositionalGroups = true; | |
| 2587 } | |
| 2588 if (leftCurlyBracket != null && !reportedMixedGroups) { | |
| 2589 reportError8(ParserErrorCode.MIXED_PARAMETER_GROUPS, []); | |
| 2590 reportedMixedGroups = true; | |
| 2591 } | |
| 2592 leftSquareBracket = andAdvance; | |
| 2593 currentParameters = positionalParameters; | |
| 2594 kind = ParameterKind.POSITIONAL; | |
| 2595 } else if (matches5(TokenType.OPEN_CURLY_BRACKET)) { | |
| 2596 wasOptionalParameter = true; | |
| 2597 if (leftCurlyBracket != null && !reportedMulipleNamedGroups) { | |
| 2598 reportError8(ParserErrorCode.MULTIPLE_NAMED_PARAMETER_GROUPS, []); | |
| 2599 reportedMulipleNamedGroups = true; | |
| 2600 } | |
| 2601 if (leftSquareBracket != null && !reportedMixedGroups) { | |
| 2602 reportError8(ParserErrorCode.MIXED_PARAMETER_GROUPS, []); | |
| 2603 reportedMixedGroups = true; | |
| 2604 } | |
| 2605 leftCurlyBracket = andAdvance; | |
| 2606 currentParameters = namedParameters; | |
| 2607 kind = ParameterKind.NAMED; | |
| 2608 } | |
| 2609 FormalParameter parameter = parseFormalParameter(kind); | |
| 2610 parameters.add(parameter); | |
| 2611 currentParameters.add(parameter); | |
| 2612 if (identical(kind, ParameterKind.REQUIRED) && wasOptionalParameter) { | |
| 2613 reportError(ParserErrorCode.NORMAL_BEFORE_OPTIONAL_PARAMETERS, parameter
, []); | |
| 2614 } | |
| 2615 if (matches5(TokenType.CLOSE_SQUARE_BRACKET)) { | |
| 2616 rightSquareBracket = andAdvance; | |
| 2617 currentParameters = normalParameters; | |
| 2618 if (leftSquareBracket == null) { | |
| 2619 if (leftCurlyBracket != null) { | |
| 2620 reportError8(ParserErrorCode.WRONG_TERMINATOR_FOR_PARAMETER_GROUP, [
"}"]); | |
| 2621 rightCurlyBracket = rightSquareBracket; | |
| 2622 rightSquareBracket = null; | |
| 2623 } else { | |
| 2624 reportError8(ParserErrorCode.UNEXPECTED_TERMINATOR_FOR_PARAMETER_GRO
UP, ["["]); | |
| 2625 } | |
| 2626 } | |
| 2627 kind = ParameterKind.REQUIRED; | |
| 2628 } else if (matches5(TokenType.CLOSE_CURLY_BRACKET)) { | |
| 2629 rightCurlyBracket = andAdvance; | |
| 2630 currentParameters = normalParameters; | |
| 2631 if (leftCurlyBracket == null) { | |
| 2632 if (leftSquareBracket != null) { | |
| 2633 reportError8(ParserErrorCode.WRONG_TERMINATOR_FOR_PARAMETER_GROUP, [
"]"]); | |
| 2634 rightSquareBracket = rightCurlyBracket; | |
| 2635 rightCurlyBracket = null; | |
| 2636 } else { | |
| 2637 reportError8(ParserErrorCode.UNEXPECTED_TERMINATOR_FOR_PARAMETER_GRO
UP, ["{"]); | |
| 2638 } | |
| 2639 } | |
| 2640 kind = ParameterKind.REQUIRED; | |
| 2641 } | |
| 2642 } while (!matches5(TokenType.CLOSE_PAREN) && initialToken != _currentToken); | |
| 2643 Token rightParenthesis = expect2(TokenType.CLOSE_PAREN); | |
| 2644 if (leftSquareBracket != null && rightSquareBracket == null) { | |
| 2645 reportError8(ParserErrorCode.MISSING_TERMINATOR_FOR_PARAMETER_GROUP, ["]"]
); | |
| 2646 } | |
| 2647 if (leftCurlyBracket != null && rightCurlyBracket == null) { | |
| 2648 reportError8(ParserErrorCode.MISSING_TERMINATOR_FOR_PARAMETER_GROUP, ["}"]
); | |
| 2649 } | |
| 2650 if (leftSquareBracket == null) { | |
| 2651 leftSquareBracket = leftCurlyBracket; | |
| 2652 } | |
| 2653 if (rightSquareBracket == null) { | |
| 2654 rightSquareBracket = rightCurlyBracket; | |
| 2655 } | |
| 2656 return new FormalParameterList.full(leftParenthesis, parameters, leftSquareB
racket, rightSquareBracket, rightParenthesis); | |
| 2657 } | |
| 2658 | |
| 2659 /** | |
| 2660 * Parse a for statement. | |
| 2661 * | |
| 2662 * <pre> | |
| 2663 * forStatement ::= | |
| 2664 * 'for' '(' forLoopParts ')' statement | |
| 2665 * | |
| 2666 * forLoopParts ::= | |
| 2667 * forInitializerStatement expression? ';' expressionList? | |
| 2668 * | declaredIdentifier 'in' expression | |
| 2669 * | identifier 'in' expression | |
| 2670 * | |
| 2671 * forInitializerStatement ::= | |
| 2672 * localVariableDeclaration ';' | |
| 2673 * | expression? ';' | |
| 2674 * </pre> | |
| 2675 * | |
| 2676 * @return the for statement that was parsed | |
| 2677 */ | |
| 2678 Statement parseForStatement() { | |
| 2679 bool wasInLoop = _inLoop; | |
| 2680 _inLoop = true; | |
| 2681 try { | |
| 2682 Token forKeyword = expect(Keyword.FOR); | |
| 2683 Token leftParenthesis = expect2(TokenType.OPEN_PAREN); | |
| 2684 VariableDeclarationList variableList = null; | |
| 2685 Expression initialization = null; | |
| 2686 if (!matches5(TokenType.SEMICOLON)) { | |
| 2687 CommentAndMetadata commentAndMetadata = parseCommentAndMetadata(); | |
| 2688 if (matchesIdentifier() && matches3(peek(), Keyword.IN)) { | |
| 2689 List<VariableDeclaration> variables = new List<VariableDeclaration>(); | |
| 2690 SimpleIdentifier variableName = parseSimpleIdentifier(); | |
| 2691 variables.add(new VariableDeclaration.full(null, null, variableName, n
ull, null)); | |
| 2692 variableList = new VariableDeclarationList.full(commentAndMetadata.com
ment, commentAndMetadata.metadata, null, null, variables); | |
| 2693 } else if (isInitializedVariableDeclaration()) { | |
| 2694 variableList = parseVariableDeclarationList(commentAndMetadata); | |
| 2695 } else { | |
| 2696 initialization = parseExpression2(); | |
| 2697 } | |
| 2698 if (matches(Keyword.IN)) { | |
| 2699 DeclaredIdentifier loopVariable = null; | |
| 2700 SimpleIdentifier identifier = null; | |
| 2701 if (variableList == null) { | |
| 2702 reportError8(ParserErrorCode.MISSING_VARIABLE_IN_FOR_EACH, []); | |
| 2703 } else { | |
| 2704 NodeList<VariableDeclaration> variables = variableList.variables; | |
| 2705 if (variables.length > 1) { | |
| 2706 reportError8(ParserErrorCode.MULTIPLE_VARIABLES_IN_FOR_EACH, [vari
ables.length.toString()]); | |
| 2707 } | |
| 2708 VariableDeclaration variable = variables[0]; | |
| 2709 if (variable.initializer != null) { | |
| 2710 reportError8(ParserErrorCode.INITIALIZED_VARIABLE_IN_FOR_EACH, [])
; | |
| 2711 } | |
| 2712 Token keyword = variableList.keyword; | |
| 2713 TypeName type = variableList.type; | |
| 2714 if (keyword != null || type != null) { | |
| 2715 loopVariable = new DeclaredIdentifier.full(commentAndMetadata.comm
ent, commentAndMetadata.metadata, keyword, type, variable.name); | |
| 2716 } else { | |
| 2717 if (!commentAndMetadata.metadata.isEmpty) { | |
| 2718 } | |
| 2719 identifier = variable.name; | |
| 2720 } | |
| 2721 } | |
| 2722 Token inKeyword = expect(Keyword.IN); | |
| 2723 Expression iterator = parseExpression2(); | |
| 2724 Token rightParenthesis = expect2(TokenType.CLOSE_PAREN); | |
| 2725 Statement body = parseStatement2(); | |
| 2726 if (loopVariable == null) { | |
| 2727 return new ForEachStatement.con2_full(forKeyword, leftParenthesis, i
dentifier, inKeyword, iterator, rightParenthesis, body); | |
| 2728 } | |
| 2729 return new ForEachStatement.con1_full(forKeyword, leftParenthesis, loo
pVariable, inKeyword, iterator, rightParenthesis, body); | |
| 2730 } | |
| 2731 } | |
| 2732 Token leftSeparator = expect2(TokenType.SEMICOLON); | |
| 2733 Expression condition = null; | |
| 2734 if (!matches5(TokenType.SEMICOLON)) { | |
| 2735 condition = parseExpression2(); | |
| 2736 } | |
| 2737 Token rightSeparator = expect2(TokenType.SEMICOLON); | |
| 2738 List<Expression> updaters = null; | |
| 2739 if (!matches5(TokenType.CLOSE_PAREN)) { | |
| 2740 updaters = parseExpressionList(); | |
| 2741 } | |
| 2742 Token rightParenthesis = expect2(TokenType.CLOSE_PAREN); | |
| 2743 Statement body = parseStatement2(); | |
| 2744 return new ForStatement.full(forKeyword, leftParenthesis, variableList, in
itialization, leftSeparator, condition, rightSeparator, updaters, rightParenthes
is, body); | |
| 2745 } finally { | |
| 2746 _inLoop = wasInLoop; | |
| 2747 } | |
| 2748 } | |
| 2749 | |
| 2750 /** | |
| 2751 * Parse a function body. | |
| 2752 * | |
| 2753 * <pre> | |
| 2754 * functionBody ::= | |
| 2755 * '=>' expression ';' | |
| 2756 * | block | |
| 2757 * | |
| 2758 * functionExpressionBody ::= | |
| 2759 * '=>' expression | |
| 2760 * | block | |
| 2761 * </pre> | |
| 2762 * | |
| 2763 * @param mayBeEmpty `true` if the function body is allowed to be empty | |
| 2764 * @param emptyErrorCode the error code to report if function body expecte, bu
t not found | |
| 2765 * @param inExpression `true` if the function body is being parsed as part of
an expression | |
| 2766 * and therefore does not have a terminating semicolon | |
| 2767 * @return the function body that was parsed | |
| 2768 */ | |
| 2769 FunctionBody parseFunctionBody(bool mayBeEmpty, ParserErrorCode emptyErrorCode
, bool inExpression) { | |
| 2770 bool wasInLoop = _inLoop; | |
| 2771 bool wasInSwitch = _inSwitch; | |
| 2772 _inLoop = false; | |
| 2773 _inSwitch = false; | |
| 2774 try { | |
| 2775 if (matches5(TokenType.SEMICOLON)) { | |
| 2776 if (!mayBeEmpty) { | |
| 2777 reportError8(emptyErrorCode, []); | |
| 2778 } | |
| 2779 return new EmptyFunctionBody.full(andAdvance); | |
| 2780 } else if (matches5(TokenType.FUNCTION)) { | |
| 2781 Token functionDefinition = andAdvance; | |
| 2782 Expression expression = parseExpression2(); | |
| 2783 Token semicolon = null; | |
| 2784 if (!inExpression) { | |
| 2785 semicolon = expect2(TokenType.SEMICOLON); | |
| 2786 } | |
| 2787 return new ExpressionFunctionBody.full(functionDefinition, expression, s
emicolon); | |
| 2788 } else if (matches5(TokenType.OPEN_CURLY_BRACKET)) { | |
| 2789 return new BlockFunctionBody.full(parseBlock()); | |
| 2790 } else if (matches2(_NATIVE)) { | |
| 2791 Token nativeToken = andAdvance; | |
| 2792 StringLiteral stringLiteral = null; | |
| 2793 if (matches5(TokenType.STRING)) { | |
| 2794 stringLiteral = parseStringLiteral(); | |
| 2795 } | |
| 2796 return new NativeFunctionBody.full(nativeToken, stringLiteral, expect2(T
okenType.SEMICOLON)); | |
| 2797 } else { | |
| 2798 reportError8(emptyErrorCode, []); | |
| 2799 return new EmptyFunctionBody.full(createSyntheticToken2(TokenType.SEMICO
LON)); | |
| 2800 } | |
| 2801 } finally { | |
| 2802 _inLoop = wasInLoop; | |
| 2803 _inSwitch = wasInSwitch; | |
| 2804 } | |
| 2805 } | |
| 2806 | |
| 2807 /** | |
| 2808 * Parse a function declaration. | |
| 2809 * | |
| 2810 * <pre> | |
| 2811 * functionDeclaration ::= | |
| 2812 * functionSignature functionBody | |
| 2813 * | returnType? getOrSet identifier formalParameterList functionBody | |
| 2814 * </pre> | |
| 2815 * | |
| 2816 * @param commentAndMetadata the documentation comment and metadata to be asso
ciated with the | |
| 2817 * declaration | |
| 2818 * @param externalKeyword the 'external' keyword, or `null` if the function is
not external | |
| 2819 * @param returnType the return type, or `null` if there is no return type | |
| 2820 * @param isStatement `true` if the function declaration is being parsed as a
statement | |
| 2821 * @return the function declaration that was parsed | |
| 2822 */ | |
| 2823 FunctionDeclaration parseFunctionDeclaration(CommentAndMetadata commentAndMeta
data, Token externalKeyword, TypeName returnType) { | |
| 2824 Token keyword = null; | |
| 2825 bool isGetter = false; | |
| 2826 if (matches(Keyword.GET) && !matches4(peek(), TokenType.OPEN_PAREN)) { | |
| 2827 keyword = andAdvance; | |
| 2828 isGetter = true; | |
| 2829 } else if (matches(Keyword.SET) && !matches4(peek(), TokenType.OPEN_PAREN))
{ | |
| 2830 keyword = andAdvance; | |
| 2831 } | |
| 2832 SimpleIdentifier name = parseSimpleIdentifier(); | |
| 2833 FormalParameterList parameters = null; | |
| 2834 if (!isGetter) { | |
| 2835 if (matches5(TokenType.OPEN_PAREN)) { | |
| 2836 parameters = parseFormalParameterList(); | |
| 2837 validateFormalParameterList(parameters); | |
| 2838 } else { | |
| 2839 reportError8(ParserErrorCode.MISSING_FUNCTION_PARAMETERS, []); | |
| 2840 } | |
| 2841 } else if (matches5(TokenType.OPEN_PAREN)) { | |
| 2842 reportError8(ParserErrorCode.GETTER_WITH_PARAMETERS, []); | |
| 2843 parseFormalParameterList(); | |
| 2844 } | |
| 2845 FunctionBody body; | |
| 2846 if (externalKeyword == null) { | |
| 2847 body = parseFunctionBody(false, ParserErrorCode.MISSING_FUNCTION_BODY, fal
se); | |
| 2848 } else { | |
| 2849 body = new EmptyFunctionBody.full(expect2(TokenType.SEMICOLON)); | |
| 2850 } | |
| 2851 return new FunctionDeclaration.full(commentAndMetadata.comment, commentAndMe
tadata.metadata, externalKeyword, returnType, keyword, name, new FunctionExpress
ion.full(parameters, body)); | |
| 2852 } | |
| 2853 | |
| 2854 /** | |
| 2855 * Parse a function declaration statement. | |
| 2856 * | |
| 2857 * <pre> | |
| 2858 * functionDeclarationStatement ::= | |
| 2859 * functionSignature functionBody | |
| 2860 * </pre> | |
| 2861 * | |
| 2862 * @return the function declaration statement that was parsed | |
| 2863 */ | |
| 2864 Statement parseFunctionDeclarationStatement() { | |
| 2865 Modifiers modifiers = parseModifiers(); | |
| 2866 validateModifiersForFunctionDeclarationStatement(modifiers); | |
| 2867 return parseFunctionDeclarationStatement2(parseCommentAndMetadata(), parseOp
tionalReturnType()); | |
| 2868 } | |
| 2869 | |
| 2870 /** | |
| 2871 * Parse a function declaration statement. | |
| 2872 * | |
| 2873 * <pre> | |
| 2874 * functionDeclarationStatement ::= | |
| 2875 * functionSignature functionBody | |
| 2876 * </pre> | |
| 2877 * | |
| 2878 * @param commentAndMetadata the documentation comment and metadata to be asso
ciated with the | |
| 2879 * declaration | |
| 2880 * @param returnType the return type, or `null` if there is no return type | |
| 2881 * @return the function declaration statement that was parsed | |
| 2882 */ | |
| 2883 Statement parseFunctionDeclarationStatement2(CommentAndMetadata commentAndMeta
data, TypeName returnType) { | |
| 2884 FunctionDeclaration declaration = parseFunctionDeclaration(commentAndMetadat
a, null, returnType); | |
| 2885 Token propertyKeyword = declaration.propertyKeyword; | |
| 2886 if (propertyKeyword != null) { | |
| 2887 if (identical(((propertyKeyword as KeywordToken)).keyword, Keyword.GET)) { | |
| 2888 reportError9(ParserErrorCode.GETTER_IN_FUNCTION, propertyKeyword, []); | |
| 2889 } else { | |
| 2890 reportError9(ParserErrorCode.SETTER_IN_FUNCTION, propertyKeyword, []); | |
| 2891 } | |
| 2892 } | |
| 2893 return new FunctionDeclarationStatement.full(declaration); | |
| 2894 } | |
| 2895 | |
| 2896 /** | |
| 2897 * Parse a function expression. | |
| 2898 * | |
| 2899 * <pre> | |
| 2900 * functionExpression ::= | |
| 2901 * formalParameterList functionExpressionBody | |
| 2902 * </pre> | |
| 2903 * | |
| 2904 * @return the function expression that was parsed | |
| 2905 */ | |
| 2906 FunctionExpression parseFunctionExpression() { | |
| 2907 FormalParameterList parameters = parseFormalParameterList(); | |
| 2908 validateFormalParameterList(parameters); | |
| 2909 FunctionBody body = parseFunctionBody(false, ParserErrorCode.MISSING_FUNCTIO
N_BODY, true); | |
| 2910 return new FunctionExpression.full(parameters, body); | |
| 2911 } | |
| 2912 | |
| 2913 /** | |
| 2914 * Parse a function type alias. | |
| 2915 * | |
| 2916 * <pre> | |
| 2917 * functionTypeAlias ::= | |
| 2918 * functionPrefix typeParameterList? formalParameterList ';' | |
| 2919 * | |
| 2920 * functionPrefix ::= | |
| 2921 * returnType? name | |
| 2922 * </pre> | |
| 2923 * | |
| 2924 * @param commentAndMetadata the metadata to be associated with the member | |
| 2925 * @param keyword the token representing the 'typedef' keyword | |
| 2926 * @return the function type alias that was parsed | |
| 2927 */ | |
| 2928 FunctionTypeAlias parseFunctionTypeAlias(CommentAndMetadata commentAndMetadata
, Token keyword) { | |
| 2929 TypeName returnType = null; | |
| 2930 if (hasReturnTypeInTypeAlias()) { | |
| 2931 returnType = parseReturnType(); | |
| 2932 } | |
| 2933 SimpleIdentifier name = parseSimpleIdentifier(); | |
| 2934 TypeParameterList typeParameters = null; | |
| 2935 if (matches5(TokenType.LT)) { | |
| 2936 typeParameters = parseTypeParameterList(); | |
| 2937 } | |
| 2938 if (matches5(TokenType.SEMICOLON) || matches5(TokenType.EOF)) { | |
| 2939 reportError8(ParserErrorCode.MISSING_TYPEDEF_PARAMETERS, []); | |
| 2940 FormalParameterList parameters = new FormalParameterList.full(createSynthe
ticToken2(TokenType.OPEN_PAREN), null, null, null, createSyntheticToken2(TokenTy
pe.CLOSE_PAREN)); | |
| 2941 Token semicolon = expect2(TokenType.SEMICOLON); | |
| 2942 return new FunctionTypeAlias.full(commentAndMetadata.comment, commentAndMe
tadata.metadata, keyword, returnType, name, typeParameters, parameters, semicolo
n); | |
| 2943 } else if (!matches5(TokenType.OPEN_PAREN)) { | |
| 2944 reportError8(ParserErrorCode.MISSING_TYPEDEF_PARAMETERS, []); | |
| 2945 return new FunctionTypeAlias.full(commentAndMetadata.comment, commentAndMe
tadata.metadata, keyword, returnType, name, typeParameters, new FormalParameterL
ist.full(createSyntheticToken2(TokenType.OPEN_PAREN), null, null, null, createSy
ntheticToken2(TokenType.CLOSE_PAREN)), createSyntheticToken2(TokenType.SEMICOLON
)); | |
| 2946 } | |
| 2947 FormalParameterList parameters = parseFormalParameterList(); | |
| 2948 validateFormalParameterList(parameters); | |
| 2949 Token semicolon = expect2(TokenType.SEMICOLON); | |
| 2950 return new FunctionTypeAlias.full(commentAndMetadata.comment, commentAndMeta
data.metadata, keyword, returnType, name, typeParameters, parameters, semicolon)
; | |
| 2951 } | |
| 2952 | |
| 2953 /** | |
| 2954 * Parse a getter. | |
| 2955 * | |
| 2956 * <pre> | |
| 2957 * getter ::= | |
| 2958 * getterSignature functionBody? | |
| 2959 * | |
| 2960 * getterSignature ::= | |
| 2961 * 'external'? 'static'? returnType? 'get' identifier | |
| 2962 * </pre> | |
| 2963 * | |
| 2964 * @param commentAndMetadata the documentation comment and metadata to be asso
ciated with the | |
| 2965 * declaration | |
| 2966 * @param externalKeyword the 'external' token | |
| 2967 * @param staticKeyword the static keyword, or `null` if the getter is not sta
tic | |
| 2968 * @param the return type that has already been parsed, or `null` if there was
no return | |
| 2969 * type | |
| 2970 * @return the getter that was parsed | |
| 2971 */ | |
| 2972 MethodDeclaration parseGetter(CommentAndMetadata commentAndMetadata, Token ext
ernalKeyword, Token staticKeyword, TypeName returnType) { | |
| 2973 Token propertyKeyword = expect(Keyword.GET); | |
| 2974 SimpleIdentifier name = parseSimpleIdentifier(); | |
| 2975 if (matches5(TokenType.OPEN_PAREN) && matches4(peek(), TokenType.CLOSE_PAREN
)) { | |
| 2976 reportError8(ParserErrorCode.GETTER_WITH_PARAMETERS, []); | |
| 2977 advance(); | |
| 2978 advance(); | |
| 2979 } | |
| 2980 FunctionBody body = parseFunctionBody(externalKeyword != null || staticKeywo
rd == null, ParserErrorCode.STATIC_GETTER_WITHOUT_BODY, false); | |
| 2981 if (externalKeyword != null && body is! EmptyFunctionBody) { | |
| 2982 reportError8(ParserErrorCode.EXTERNAL_GETTER_WITH_BODY, []); | |
| 2983 } | |
| 2984 return new MethodDeclaration.full(commentAndMetadata.comment, commentAndMeta
data.metadata, externalKeyword, staticKeyword, returnType, propertyKeyword, null
, name, null, body); | |
| 2985 } | |
| 2986 | |
| 2987 /** | |
| 2988 * Parse a list of identifiers. | |
| 2989 * | |
| 2990 * <pre> | |
| 2991 * identifierList ::= | |
| 2992 * identifier (',' identifier)* | |
| 2993 * </pre> | |
| 2994 * | |
| 2995 * @return the list of identifiers that were parsed | |
| 2996 */ | |
| 2997 List<SimpleIdentifier> parseIdentifierList() { | |
| 2998 List<SimpleIdentifier> identifiers = new List<SimpleIdentifier>(); | |
| 2999 identifiers.add(parseSimpleIdentifier()); | |
| 3000 while (matches5(TokenType.COMMA)) { | |
| 3001 advance(); | |
| 3002 identifiers.add(parseSimpleIdentifier()); | |
| 3003 } | |
| 3004 return identifiers; | |
| 3005 } | |
| 3006 | |
| 3007 /** | |
| 3008 * Parse an if statement. | |
| 3009 * | |
| 3010 * <pre> | |
| 3011 * ifStatement ::= | |
| 3012 * 'if' '(' expression ')' statement ('else' statement)? | |
| 3013 * </pre> | |
| 3014 * | |
| 3015 * @return the if statement that was parsed | |
| 3016 */ | |
| 3017 Statement parseIfStatement() { | |
| 3018 Token ifKeyword = expect(Keyword.IF); | |
| 3019 Token leftParenthesis = expect2(TokenType.OPEN_PAREN); | |
| 3020 Expression condition = parseExpression2(); | |
| 3021 Token rightParenthesis = expect2(TokenType.CLOSE_PAREN); | |
| 3022 Statement thenStatement = parseStatement2(); | |
| 3023 Token elseKeyword = null; | |
| 3024 Statement elseStatement = null; | |
| 3025 if (matches(Keyword.ELSE)) { | |
| 3026 elseKeyword = andAdvance; | |
| 3027 elseStatement = parseStatement2(); | |
| 3028 } | |
| 3029 return new IfStatement.full(ifKeyword, leftParenthesis, condition, rightPare
nthesis, thenStatement, elseKeyword, elseStatement); | |
| 3030 } | |
| 3031 | |
| 3032 /** | |
| 3033 * Parse an implements clause. | |
| 3034 * | |
| 3035 * <pre> | |
| 3036 * implementsClause ::= | |
| 3037 * 'implements' type (',' type)* | |
| 3038 * </pre> | |
| 3039 * | |
| 3040 * @return the implements clause that was parsed | |
| 3041 */ | |
| 3042 ImplementsClause parseImplementsClause() { | |
| 3043 Token keyword = expect(Keyword.IMPLEMENTS); | |
| 3044 List<TypeName> interfaces = new List<TypeName>(); | |
| 3045 interfaces.add(parseTypeName()); | |
| 3046 while (optional(TokenType.COMMA)) { | |
| 3047 interfaces.add(parseTypeName()); | |
| 3048 } | |
| 3049 return new ImplementsClause.full(keyword, interfaces); | |
| 3050 } | |
| 3051 | |
| 3052 /** | |
| 3053 * Parse an import directive. | |
| 3054 * | |
| 3055 * <pre> | |
| 3056 * importDirective ::= | |
| 3057 * metadata 'import' stringLiteral ('as' identifier)? combinator*';' | |
| 3058 * </pre> | |
| 3059 * | |
| 3060 * @param commentAndMetadata the metadata to be associated with the directive | |
| 3061 * @return the import directive that was parsed | |
| 3062 */ | |
| 3063 ImportDirective parseImportDirective(CommentAndMetadata commentAndMetadata) { | |
| 3064 Token importKeyword = expect(Keyword.IMPORT); | |
| 3065 StringLiteral libraryUri = parseStringLiteral(); | |
| 3066 Token asToken = null; | |
| 3067 SimpleIdentifier prefix = null; | |
| 3068 if (matches(Keyword.AS)) { | |
| 3069 asToken = andAdvance; | |
| 3070 prefix = parseSimpleIdentifier(); | |
| 3071 } | |
| 3072 List<Combinator> combinators = parseCombinators(); | |
| 3073 Token semicolon = expect2(TokenType.SEMICOLON); | |
| 3074 return new ImportDirective.full(commentAndMetadata.comment, commentAndMetada
ta.metadata, importKeyword, libraryUri, asToken, prefix, combinators, semicolon)
; | |
| 3075 } | |
| 3076 | |
| 3077 /** | |
| 3078 * Parse a list of initialized identifiers. | |
| 3079 * | |
| 3080 * <pre> | |
| 3081 * ?? ::= | |
| 3082 * 'static'? ('var' | type) initializedIdentifierList ';' | |
| 3083 * | 'final' type? initializedIdentifierList ';' | |
| 3084 * | |
| 3085 * initializedIdentifierList ::= | |
| 3086 * initializedIdentifier (',' initializedIdentifier)* | |
| 3087 * | |
| 3088 * initializedIdentifier ::= | |
| 3089 * identifier ('=' expression)? | |
| 3090 * </pre> | |
| 3091 * | |
| 3092 * @param commentAndMetadata the documentation comment and metadata to be asso
ciated with the | |
| 3093 * declaration | |
| 3094 * @param staticKeyword the static keyword, or `null` if the getter is not sta
tic | |
| 3095 * @param keyword the token representing the 'final', 'const' or 'var' keyword
, or `null` if | |
| 3096 * there is no keyword | |
| 3097 * @param type the type that has already been parsed, or `null` if 'var' was p
rovided | |
| 3098 * @return the getter that was parsed | |
| 3099 */ | |
| 3100 FieldDeclaration parseInitializedIdentifierList(CommentAndMetadata commentAndM
etadata, Token staticKeyword, Token keyword, TypeName type) { | |
| 3101 VariableDeclarationList fieldList = parseVariableDeclarationList2(null, keyw
ord, type); | |
| 3102 return new FieldDeclaration.full(commentAndMetadata.comment, commentAndMetad
ata.metadata, staticKeyword, fieldList, expect2(TokenType.SEMICOLON)); | |
| 3103 } | |
| 3104 | |
| 3105 /** | |
| 3106 * Parse an instance creation expression. | |
| 3107 * | |
| 3108 * <pre> | |
| 3109 * instanceCreationExpression ::= | |
| 3110 * ('new' | 'const') type ('.' identifier)? argumentList | |
| 3111 * </pre> | |
| 3112 * | |
| 3113 * @param keyword the 'new' or 'const' keyword that introduces the expression | |
| 3114 * @return the instance creation expression that was parsed | |
| 3115 */ | |
| 3116 InstanceCreationExpression parseInstanceCreationExpression(Token keyword) { | |
| 3117 ConstructorName constructorName = parseConstructorName(); | |
| 3118 ArgumentList argumentList = parseArgumentList(); | |
| 3119 return new InstanceCreationExpression.full(keyword, constructorName, argumen
tList); | |
| 3120 } | |
| 3121 | |
| 3122 /** | |
| 3123 * Parse a library directive. | |
| 3124 * | |
| 3125 * <pre> | |
| 3126 * libraryDirective ::= | |
| 3127 * metadata 'library' identifier ';' | |
| 3128 * </pre> | |
| 3129 * | |
| 3130 * @param commentAndMetadata the metadata to be associated with the directive | |
| 3131 * @return the library directive that was parsed | |
| 3132 */ | |
| 3133 LibraryDirective parseLibraryDirective(CommentAndMetadata commentAndMetadata)
{ | |
| 3134 Token keyword = expect(Keyword.LIBRARY); | |
| 3135 LibraryIdentifier libraryName = parseLibraryName(ParserErrorCode.MISSING_NAM
E_IN_LIBRARY_DIRECTIVE, keyword); | |
| 3136 Token semicolon = expect2(TokenType.SEMICOLON); | |
| 3137 return new LibraryDirective.full(commentAndMetadata.comment, commentAndMetad
ata.metadata, keyword, libraryName, semicolon); | |
| 3138 } | |
| 3139 | |
| 3140 /** | |
| 3141 * Parse a library identifier. | |
| 3142 * | |
| 3143 * <pre> | |
| 3144 * libraryIdentifier ::= | |
| 3145 * identifier ('.' identifier)* | |
| 3146 * </pre> | |
| 3147 * | |
| 3148 * @return the library identifier that was parsed | |
| 3149 */ | |
| 3150 LibraryIdentifier parseLibraryIdentifier() { | |
| 3151 List<SimpleIdentifier> components = new List<SimpleIdentifier>(); | |
| 3152 components.add(parseSimpleIdentifier()); | |
| 3153 while (matches5(TokenType.PERIOD)) { | |
| 3154 advance(); | |
| 3155 components.add(parseSimpleIdentifier()); | |
| 3156 } | |
| 3157 return new LibraryIdentifier.full(components); | |
| 3158 } | |
| 3159 | |
| 3160 /** | |
| 3161 * Parse a library name. | |
| 3162 * | |
| 3163 * <pre> | |
| 3164 * libraryName ::= | |
| 3165 * libraryIdentifier | |
| 3166 * </pre> | |
| 3167 * | |
| 3168 * @param missingNameError the error code to be used if the library name is mi
ssing | |
| 3169 * @param missingNameToken the token associated with the error produced if the
library name is | |
| 3170 * missing | |
| 3171 * @return the library name that was parsed | |
| 3172 */ | |
| 3173 LibraryIdentifier parseLibraryName(ParserErrorCode missingNameError, Token mis
singNameToken) { | |
| 3174 if (matchesIdentifier()) { | |
| 3175 return parseLibraryIdentifier(); | |
| 3176 } else if (matches5(TokenType.STRING)) { | |
| 3177 StringLiteral string = parseStringLiteral(); | |
| 3178 reportError(ParserErrorCode.NON_IDENTIFIER_LIBRARY_NAME, string, []); | |
| 3179 } else { | |
| 3180 reportError9(missingNameError, missingNameToken, []); | |
| 3181 } | |
| 3182 List<SimpleIdentifier> components = new List<SimpleIdentifier>(); | |
| 3183 components.add(createSyntheticIdentifier()); | |
| 3184 return new LibraryIdentifier.full(components); | |
| 3185 } | |
| 3186 | |
| 3187 /** | |
| 3188 * Parse a list literal. | |
| 3189 * | |
| 3190 * <pre> | |
| 3191 * listLiteral ::= | |
| 3192 * 'const'? typeArguments? '[' (expressionList ','?)? ']' | |
| 3193 * </pre> | |
| 3194 * | |
| 3195 * @param modifier the 'const' modifier appearing before the literal, or `null
` if there is | |
| 3196 * no modifier | |
| 3197 * @param typeArguments the type arguments appearing before the literal, or `n
ull` if there | |
| 3198 * are no type arguments | |
| 3199 * @return the list literal that was parsed | |
| 3200 */ | |
| 3201 ListLiteral parseListLiteral(Token modifier, TypeArgumentList typeArguments) { | |
| 3202 if (matches5(TokenType.INDEX)) { | |
| 3203 BeginToken leftBracket = new BeginToken(TokenType.OPEN_SQUARE_BRACKET, _cu
rrentToken.offset); | |
| 3204 Token rightBracket = new Token(TokenType.CLOSE_SQUARE_BRACKET, _currentTok
en.offset + 1); | |
| 3205 leftBracket.endToken = rightBracket; | |
| 3206 rightBracket.setNext(_currentToken.next); | |
| 3207 leftBracket.setNext(rightBracket); | |
| 3208 _currentToken.previous.setNext(leftBracket); | |
| 3209 _currentToken = _currentToken.next; | |
| 3210 return new ListLiteral.full(modifier, typeArguments, leftBracket, null, ri
ghtBracket); | |
| 3211 } | |
| 3212 Token leftBracket = expect2(TokenType.OPEN_SQUARE_BRACKET); | |
| 3213 if (matches5(TokenType.CLOSE_SQUARE_BRACKET)) { | |
| 3214 return new ListLiteral.full(modifier, typeArguments, leftBracket, null, an
dAdvance); | |
| 3215 } | |
| 3216 List<Expression> elements = new List<Expression>(); | |
| 3217 elements.add(parseExpression2()); | |
| 3218 while (optional(TokenType.COMMA)) { | |
| 3219 if (matches5(TokenType.CLOSE_SQUARE_BRACKET)) { | |
| 3220 return new ListLiteral.full(modifier, typeArguments, leftBracket, elemen
ts, andAdvance); | |
| 3221 } | |
| 3222 elements.add(parseExpression2()); | |
| 3223 } | |
| 3224 Token rightBracket = expect2(TokenType.CLOSE_SQUARE_BRACKET); | |
| 3225 return new ListLiteral.full(modifier, typeArguments, leftBracket, elements,
rightBracket); | |
| 3226 } | |
| 3227 | |
| 3228 /** | |
| 3229 * Parse a list or map literal. | |
| 3230 * | |
| 3231 * <pre> | |
| 3232 * listOrMapLiteral ::= | |
| 3233 * listLiteral | |
| 3234 * | mapLiteral | |
| 3235 * </pre> | |
| 3236 * | |
| 3237 * @param modifier the 'const' modifier appearing before the literal, or `null
` if there is | |
| 3238 * no modifier | |
| 3239 * @return the list or map literal that was parsed | |
| 3240 */ | |
| 3241 TypedLiteral parseListOrMapLiteral(Token modifier) { | |
| 3242 TypeArgumentList typeArguments = null; | |
| 3243 if (matches5(TokenType.LT)) { | |
| 3244 typeArguments = parseTypeArgumentList(); | |
| 3245 } | |
| 3246 if (matches5(TokenType.OPEN_CURLY_BRACKET)) { | |
| 3247 return parseMapLiteral(modifier, typeArguments); | |
| 3248 } else if (matches5(TokenType.OPEN_SQUARE_BRACKET) || matches5(TokenType.IND
EX)) { | |
| 3249 return parseListLiteral(modifier, typeArguments); | |
| 3250 } | |
| 3251 reportError8(ParserErrorCode.EXPECTED_LIST_OR_MAP_LITERAL, []); | |
| 3252 return new ListLiteral.full(modifier, typeArguments, createSyntheticToken2(T
okenType.OPEN_SQUARE_BRACKET), null, createSyntheticToken2(TokenType.CLOSE_SQUAR
E_BRACKET)); | |
| 3253 } | |
| 3254 | |
| 3255 /** | |
| 3256 * Parse a logical and expression. | |
| 3257 * | |
| 3258 * <pre> | |
| 3259 * logicalAndExpression ::= | |
| 3260 * equalityExpression ('&&' equalityExpression)* | |
| 3261 * </pre> | |
| 3262 * | |
| 3263 * @return the logical and expression that was parsed | |
| 3264 */ | |
| 3265 Expression parseLogicalAndExpression() { | |
| 3266 Expression expression = parseEqualityExpression(); | |
| 3267 while (matches5(TokenType.AMPERSAND_AMPERSAND)) { | |
| 3268 Token operator = andAdvance; | |
| 3269 expression = new BinaryExpression.full(expression, operator, parseEquality
Expression()); | |
| 3270 } | |
| 3271 return expression; | |
| 3272 } | |
| 3273 | |
| 3274 /** | |
| 3275 * Parse a logical or expression. | |
| 3276 * | |
| 3277 * <pre> | |
| 3278 * logicalOrExpression ::= | |
| 3279 * logicalAndExpression ('||' logicalAndExpression)* | |
| 3280 * </pre> | |
| 3281 * | |
| 3282 * @return the logical or expression that was parsed | |
| 3283 */ | |
| 3284 Expression parseLogicalOrExpression() { | |
| 3285 Expression expression = parseLogicalAndExpression(); | |
| 3286 while (matches5(TokenType.BAR_BAR)) { | |
| 3287 Token operator = andAdvance; | |
| 3288 expression = new BinaryExpression.full(expression, operator, parseLogicalA
ndExpression()); | |
| 3289 } | |
| 3290 return expression; | |
| 3291 } | |
| 3292 | |
| 3293 /** | |
| 3294 * Parse a map literal. | |
| 3295 * | |
| 3296 * <pre> | |
| 3297 * mapLiteral ::= | |
| 3298 * 'const'? typeArguments? '{' (mapLiteralEntry (',' mapLiteralEntry)* ','
?)? '}' | |
| 3299 * </pre> | |
| 3300 * | |
| 3301 * @param modifier the 'const' modifier appearing before the literal, or `null
` if there is | |
| 3302 * no modifier | |
| 3303 * @param typeArguments the type arguments that were declared, or `null` if th
ere are no | |
| 3304 * type arguments | |
| 3305 * @return the map literal that was parsed | |
| 3306 */ | |
| 3307 MapLiteral parseMapLiteral(Token modifier, TypeArgumentList typeArguments) { | |
| 3308 Token leftBracket = expect2(TokenType.OPEN_CURLY_BRACKET); | |
| 3309 List<MapLiteralEntry> entries = new List<MapLiteralEntry>(); | |
| 3310 if (matches5(TokenType.CLOSE_CURLY_BRACKET)) { | |
| 3311 return new MapLiteral.full(modifier, typeArguments, leftBracket, entries,
andAdvance); | |
| 3312 } | |
| 3313 entries.add(parseMapLiteralEntry()); | |
| 3314 while (optional(TokenType.COMMA)) { | |
| 3315 if (matches5(TokenType.CLOSE_CURLY_BRACKET)) { | |
| 3316 return new MapLiteral.full(modifier, typeArguments, leftBracket, entries
, andAdvance); | |
| 3317 } | |
| 3318 entries.add(parseMapLiteralEntry()); | |
| 3319 } | |
| 3320 Token rightBracket = expect2(TokenType.CLOSE_CURLY_BRACKET); | |
| 3321 return new MapLiteral.full(modifier, typeArguments, leftBracket, entries, ri
ghtBracket); | |
| 3322 } | |
| 3323 | |
| 3324 /** | |
| 3325 * Parse a map literal entry. | |
| 3326 * | |
| 3327 * <pre> | |
| 3328 * mapLiteralEntry ::= | |
| 3329 * expression ':' expression | |
| 3330 * </pre> | |
| 3331 * | |
| 3332 * @return the map literal entry that was parsed | |
| 3333 */ | |
| 3334 MapLiteralEntry parseMapLiteralEntry() { | |
| 3335 Expression key = parseExpression2(); | |
| 3336 Token separator = expect2(TokenType.COLON); | |
| 3337 Expression value = parseExpression2(); | |
| 3338 return new MapLiteralEntry.full(key, separator, value); | |
| 3339 } | |
| 3340 | |
| 3341 /** | |
| 3342 * Parse a method declaration. | |
| 3343 * | |
| 3344 * <pre> | |
| 3345 * functionDeclaration ::= | |
| 3346 * 'external'? 'static'? functionSignature functionBody | |
| 3347 * | 'external'? functionSignature ';' | |
| 3348 * </pre> | |
| 3349 * | |
| 3350 * @param commentAndMetadata the documentation comment and metadata to be asso
ciated with the | |
| 3351 * declaration | |
| 3352 * @param externalKeyword the 'external' token | |
| 3353 * @param staticKeyword the static keyword, or `null` if the getter is not sta
tic | |
| 3354 * @param returnType the return type of the method | |
| 3355 * @return the method declaration that was parsed | |
| 3356 */ | |
| 3357 MethodDeclaration parseMethodDeclaration(CommentAndMetadata commentAndMetadata
, Token externalKeyword, Token staticKeyword, TypeName returnType) { | |
| 3358 SimpleIdentifier methodName = parseSimpleIdentifier(); | |
| 3359 FormalParameterList parameters = parseFormalParameterList(); | |
| 3360 validateFormalParameterList(parameters); | |
| 3361 return parseMethodDeclaration2(commentAndMetadata, externalKeyword, staticKe
yword, returnType, methodName, parameters); | |
| 3362 } | |
| 3363 | |
| 3364 /** | |
| 3365 * Parse a method declaration. | |
| 3366 * | |
| 3367 * <pre> | |
| 3368 * functionDeclaration ::= | |
| 3369 * ('external' 'static'?)? functionSignature functionBody | |
| 3370 * | 'external'? functionSignature ';' | |
| 3371 * </pre> | |
| 3372 * | |
| 3373 * @param commentAndMetadata the documentation comment and metadata to be asso
ciated with the | |
| 3374 * declaration | |
| 3375 * @param externalKeyword the 'external' token | |
| 3376 * @param staticKeyword the static keyword, or `null` if the getter is not sta
tic | |
| 3377 * @param returnType the return type of the method | |
| 3378 * @param name the name of the method | |
| 3379 * @param parameters the parameters to the method | |
| 3380 * @return the method declaration that was parsed | |
| 3381 */ | |
| 3382 MethodDeclaration parseMethodDeclaration2(CommentAndMetadata commentAndMetadat
a, Token externalKeyword, Token staticKeyword, TypeName returnType, SimpleIdenti
fier name, FormalParameterList parameters) { | |
| 3383 FunctionBody body = parseFunctionBody(externalKeyword != null || staticKeywo
rd == null, ParserErrorCode.MISSING_FUNCTION_BODY, false); | |
| 3384 if (externalKeyword != null) { | |
| 3385 if (body is! EmptyFunctionBody) { | |
| 3386 reportError(ParserErrorCode.EXTERNAL_METHOD_WITH_BODY, body, []); | |
| 3387 } | |
| 3388 } else if (staticKeyword != null) { | |
| 3389 if (body is EmptyFunctionBody) { | |
| 3390 reportError(ParserErrorCode.ABSTRACT_STATIC_METHOD, body, []); | |
| 3391 } | |
| 3392 } | |
| 3393 return new MethodDeclaration.full(commentAndMetadata.comment, commentAndMeta
data.metadata, externalKeyword, staticKeyword, returnType, null, null, name, par
ameters, body); | |
| 3394 } | |
| 3395 | |
| 3396 /** | |
| 3397 * Parse the modifiers preceding a declaration. This method allows the modifie
rs to appear in any | |
| 3398 * order but does generate errors for duplicated modifiers. Checks for other p
roblems, such as | |
| 3399 * having the modifiers appear in the wrong order or specifying both 'const' a
nd 'final', are | |
| 3400 * reported in one of the methods whose name is prefixed with `validateModifie
rsFor`. | |
| 3401 * | |
| 3402 * <pre> | |
| 3403 * modifiers ::= | |
| 3404 * ('abstract' | 'const' | 'external' | 'factory' | 'final' | 'static' | '
var')* | |
| 3405 * </pre> | |
| 3406 * | |
| 3407 * @return the modifiers that were parsed | |
| 3408 */ | |
| 3409 Modifiers parseModifiers() { | |
| 3410 Modifiers modifiers = new Modifiers(); | |
| 3411 bool progress = true; | |
| 3412 while (progress) { | |
| 3413 if (matches(Keyword.ABSTRACT) && !matches4(peek(), TokenType.PERIOD) && !m
atches4(peek(), TokenType.LT)) { | |
| 3414 if (modifiers.abstractKeyword != null) { | |
| 3415 reportError8(ParserErrorCode.DUPLICATED_MODIFIER, [_currentToken.lexem
e]); | |
| 3416 advance(); | |
| 3417 } else { | |
| 3418 modifiers.abstractKeyword = andAdvance; | |
| 3419 } | |
| 3420 } else if (matches(Keyword.CONST)) { | |
| 3421 if (modifiers.constKeyword != null) { | |
| 3422 reportError8(ParserErrorCode.DUPLICATED_MODIFIER, [_currentToken.lexem
e]); | |
| 3423 advance(); | |
| 3424 } else { | |
| 3425 modifiers.constKeyword = andAdvance; | |
| 3426 } | |
| 3427 } else if (matches(Keyword.EXTERNAL) && !matches4(peek(), TokenType.PERIOD
) && !matches4(peek(), TokenType.LT)) { | |
| 3428 if (modifiers.externalKeyword != null) { | |
| 3429 reportError8(ParserErrorCode.DUPLICATED_MODIFIER, [_currentToken.lexem
e]); | |
| 3430 advance(); | |
| 3431 } else { | |
| 3432 modifiers.externalKeyword = andAdvance; | |
| 3433 } | |
| 3434 } else if (matches(Keyword.FACTORY) && !matches4(peek(), TokenType.PERIOD)
&& !matches4(peek(), TokenType.LT)) { | |
| 3435 if (modifiers.factoryKeyword != null) { | |
| 3436 reportError8(ParserErrorCode.DUPLICATED_MODIFIER, [_currentToken.lexem
e]); | |
| 3437 advance(); | |
| 3438 } else { | |
| 3439 modifiers.factoryKeyword = andAdvance; | |
| 3440 } | |
| 3441 } else if (matches(Keyword.FINAL)) { | |
| 3442 if (modifiers.finalKeyword != null) { | |
| 3443 reportError8(ParserErrorCode.DUPLICATED_MODIFIER, [_currentToken.lexem
e]); | |
| 3444 advance(); | |
| 3445 } else { | |
| 3446 modifiers.finalKeyword = andAdvance; | |
| 3447 } | |
| 3448 } else if (matches(Keyword.STATIC) && !matches4(peek(), TokenType.PERIOD)
&& !matches4(peek(), TokenType.LT)) { | |
| 3449 if (modifiers.staticKeyword != null) { | |
| 3450 reportError8(ParserErrorCode.DUPLICATED_MODIFIER, [_currentToken.lexem
e]); | |
| 3451 advance(); | |
| 3452 } else { | |
| 3453 modifiers.staticKeyword = andAdvance; | |
| 3454 } | |
| 3455 } else if (matches(Keyword.VAR)) { | |
| 3456 if (modifiers.varKeyword != null) { | |
| 3457 reportError8(ParserErrorCode.DUPLICATED_MODIFIER, [_currentToken.lexem
e]); | |
| 3458 advance(); | |
| 3459 } else { | |
| 3460 modifiers.varKeyword = andAdvance; | |
| 3461 } | |
| 3462 } else { | |
| 3463 progress = false; | |
| 3464 } | |
| 3465 } | |
| 3466 return modifiers; | |
| 3467 } | |
| 3468 | |
| 3469 /** | |
| 3470 * Parse a multiplicative expression. | |
| 3471 * | |
| 3472 * <pre> | |
| 3473 * multiplicativeExpression ::= | |
| 3474 * unaryExpression (multiplicativeOperator unaryExpression)* | |
| 3475 * | 'super' (multiplicativeOperator unaryExpression)+ | |
| 3476 * </pre> | |
| 3477 * | |
| 3478 * @return the multiplicative expression that was parsed | |
| 3479 */ | |
| 3480 Expression parseMultiplicativeExpression() { | |
| 3481 Expression expression; | |
| 3482 if (matches(Keyword.SUPER) && _currentToken.next.type.isMultiplicativeOperat
or) { | |
| 3483 expression = new SuperExpression.full(andAdvance); | |
| 3484 } else { | |
| 3485 expression = parseUnaryExpression(); | |
| 3486 } | |
| 3487 while (_currentToken.type.isMultiplicativeOperator) { | |
| 3488 Token operator = andAdvance; | |
| 3489 expression = new BinaryExpression.full(expression, operator, parseUnaryExp
ression()); | |
| 3490 } | |
| 3491 return expression; | |
| 3492 } | |
| 3493 | |
| 3494 /** | |
| 3495 * Parse a class native clause. | |
| 3496 * | |
| 3497 * <pre> | |
| 3498 * classNativeClause ::= | |
| 3499 * 'native' name | |
| 3500 * </pre> | |
| 3501 * | |
| 3502 * @return the class native clause that was parsed | |
| 3503 */ | |
| 3504 NativeClause parseNativeClause() { | |
| 3505 Token keyword = andAdvance; | |
| 3506 StringLiteral name = parseStringLiteral(); | |
| 3507 return new NativeClause.full(keyword, name); | |
| 3508 } | |
| 3509 | |
| 3510 /** | |
| 3511 * Parse a new expression. | |
| 3512 * | |
| 3513 * <pre> | |
| 3514 * newExpression ::= | |
| 3515 * instanceCreationExpression | |
| 3516 * </pre> | |
| 3517 * | |
| 3518 * @return the new expression that was parsed | |
| 3519 */ | |
| 3520 InstanceCreationExpression parseNewExpression() => parseInstanceCreationExpres
sion(expect(Keyword.NEW)); | |
| 3521 | |
| 3522 /** | |
| 3523 * Parse a non-labeled statement. | |
| 3524 * | |
| 3525 * <pre> | |
| 3526 * nonLabeledStatement ::= | |
| 3527 * block | |
| 3528 * | assertStatement | |
| 3529 * | breakStatement | |
| 3530 * | continueStatement | |
| 3531 * | doStatement | |
| 3532 * | forStatement | |
| 3533 * | ifStatement | |
| 3534 * | returnStatement | |
| 3535 * | switchStatement | |
| 3536 * | tryStatement | |
| 3537 * | whileStatement | |
| 3538 * | variableDeclarationList ';' | |
| 3539 * | expressionStatement | |
| 3540 * | functionSignature functionBody | |
| 3541 * </pre> | |
| 3542 * | |
| 3543 * @return the non-labeled statement that was parsed | |
| 3544 */ | |
| 3545 Statement parseNonLabeledStatement() { | |
| 3546 CommentAndMetadata commentAndMetadata = parseCommentAndMetadata(); | |
| 3547 if (matches5(TokenType.OPEN_CURLY_BRACKET)) { | |
| 3548 if (matches4(peek(), TokenType.STRING)) { | |
| 3549 Token afterString = skipStringLiteral(_currentToken.next); | |
| 3550 if (afterString != null && identical(afterString.type, TokenType.COLON))
{ | |
| 3551 return new ExpressionStatement.full(parseExpression2(), expect2(TokenT
ype.SEMICOLON)); | |
| 3552 } | |
| 3553 } | |
| 3554 return parseBlock(); | |
| 3555 } else if (matches5(TokenType.KEYWORD) && !((_currentToken as KeywordToken))
.keyword.isPseudoKeyword) { | |
| 3556 Keyword keyword = ((_currentToken as KeywordToken)).keyword; | |
| 3557 if (identical(keyword, Keyword.ASSERT)) { | |
| 3558 return parseAssertStatement(); | |
| 3559 } else if (identical(keyword, Keyword.BREAK)) { | |
| 3560 return parseBreakStatement(); | |
| 3561 } else if (identical(keyword, Keyword.CONTINUE)) { | |
| 3562 return parseContinueStatement(); | |
| 3563 } else if (identical(keyword, Keyword.DO)) { | |
| 3564 return parseDoStatement(); | |
| 3565 } else if (identical(keyword, Keyword.FOR)) { | |
| 3566 return parseForStatement(); | |
| 3567 } else if (identical(keyword, Keyword.IF)) { | |
| 3568 return parseIfStatement(); | |
| 3569 } else if (identical(keyword, Keyword.RETHROW)) { | |
| 3570 return new ExpressionStatement.full(parseRethrowExpression(), expect2(To
kenType.SEMICOLON)); | |
| 3571 } else if (identical(keyword, Keyword.RETURN)) { | |
| 3572 return parseReturnStatement(); | |
| 3573 } else if (identical(keyword, Keyword.SWITCH)) { | |
| 3574 return parseSwitchStatement(); | |
| 3575 } else if (identical(keyword, Keyword.THROW)) { | |
| 3576 return new ExpressionStatement.full(parseThrowExpression(), expect2(Toke
nType.SEMICOLON)); | |
| 3577 } else if (identical(keyword, Keyword.TRY)) { | |
| 3578 return parseTryStatement(); | |
| 3579 } else if (identical(keyword, Keyword.WHILE)) { | |
| 3580 return parseWhileStatement(); | |
| 3581 } else if (identical(keyword, Keyword.VAR) || identical(keyword, Keyword.F
INAL)) { | |
| 3582 return parseVariableDeclarationStatement(commentAndMetadata); | |
| 3583 } else if (identical(keyword, Keyword.VOID)) { | |
| 3584 TypeName returnType = parseReturnType(); | |
| 3585 if (matchesIdentifier() && matchesAny(peek(), [ | |
| 3586 TokenType.OPEN_PAREN, | |
| 3587 TokenType.OPEN_CURLY_BRACKET, | |
| 3588 TokenType.FUNCTION])) { | |
| 3589 return parseFunctionDeclarationStatement2(commentAndMetadata, returnTy
pe); | |
| 3590 } else { | |
| 3591 if (matchesIdentifier()) { | |
| 3592 if (matchesAny(peek(), [TokenType.EQ, TokenType.COMMA, TokenType.SEM
ICOLON])) { | |
| 3593 reportError(ParserErrorCode.VOID_VARIABLE, returnType, []); | |
| 3594 return parseVariableDeclarationStatement(commentAndMetadata); | |
| 3595 } | |
| 3596 } else if (matches5(TokenType.CLOSE_CURLY_BRACKET)) { | |
| 3597 return parseVariableDeclarationStatement2(commentAndMetadata, null,
returnType); | |
| 3598 } | |
| 3599 reportError8(ParserErrorCode.MISSING_STATEMENT, []); | |
| 3600 return new EmptyStatement.full(createSyntheticToken2(TokenType.SEMICOL
ON)); | |
| 3601 } | |
| 3602 } else if (identical(keyword, Keyword.CONST)) { | |
| 3603 if (matchesAny(peek(), [ | |
| 3604 TokenType.LT, | |
| 3605 TokenType.OPEN_CURLY_BRACKET, | |
| 3606 TokenType.OPEN_SQUARE_BRACKET, | |
| 3607 TokenType.INDEX])) { | |
| 3608 return new ExpressionStatement.full(parseExpression2(), expect2(TokenT
ype.SEMICOLON)); | |
| 3609 } else if (matches4(peek(), TokenType.IDENTIFIER)) { | |
| 3610 Token afterType = skipTypeName(peek()); | |
| 3611 if (afterType != null) { | |
| 3612 if (matches4(afterType, TokenType.OPEN_PAREN) || (matches4(afterType
, TokenType.PERIOD) && matches4(afterType.next, TokenType.IDENTIFIER) && matches
4(afterType.next.next, TokenType.OPEN_PAREN))) { | |
| 3613 return new ExpressionStatement.full(parseExpression2(), expect2(To
kenType.SEMICOLON)); | |
| 3614 } | |
| 3615 } | |
| 3616 } | |
| 3617 return parseVariableDeclarationStatement(commentAndMetadata); | |
| 3618 } else if (identical(keyword, Keyword.NEW) || identical(keyword, Keyword.T
RUE) || identical(keyword, Keyword.FALSE) || identical(keyword, Keyword.NULL) ||
identical(keyword, Keyword.SUPER) || identical(keyword, Keyword.THIS)) { | |
| 3619 return new ExpressionStatement.full(parseExpression2(), expect2(TokenTyp
e.SEMICOLON)); | |
| 3620 } else { | |
| 3621 reportError8(ParserErrorCode.MISSING_STATEMENT, []); | |
| 3622 return new EmptyStatement.full(createSyntheticToken2(TokenType.SEMICOLON
)); | |
| 3623 } | |
| 3624 } else if (matches5(TokenType.SEMICOLON)) { | |
| 3625 return parseEmptyStatement(); | |
| 3626 } else if (isInitializedVariableDeclaration()) { | |
| 3627 return parseVariableDeclarationStatement(commentAndMetadata); | |
| 3628 } else if (isFunctionDeclaration()) { | |
| 3629 return parseFunctionDeclarationStatement(); | |
| 3630 } else if (matches5(TokenType.CLOSE_CURLY_BRACKET)) { | |
| 3631 reportError8(ParserErrorCode.MISSING_STATEMENT, []); | |
| 3632 return new EmptyStatement.full(createSyntheticToken2(TokenType.SEMICOLON))
; | |
| 3633 } else { | |
| 3634 return new ExpressionStatement.full(parseExpression2(), expect2(TokenType.
SEMICOLON)); | |
| 3635 } | |
| 3636 } | |
| 3637 | |
| 3638 /** | |
| 3639 * Parse a normal formal parameter. | |
| 3640 * | |
| 3641 * <pre> | |
| 3642 * normalFormalParameter ::= | |
| 3643 * functionSignature | |
| 3644 * | fieldFormalParameter | |
| 3645 * | simpleFormalParameter | |
| 3646 * | |
| 3647 * functionSignature: | |
| 3648 * metadata returnType? identifier formalParameterList | |
| 3649 * | |
| 3650 * fieldFormalParameter ::= | |
| 3651 * metadata finalConstVarOrType? 'this' '.' identifier | |
| 3652 * | |
| 3653 * simpleFormalParameter ::= | |
| 3654 * declaredIdentifier | |
| 3655 * | metadata identifier | |
| 3656 * </pre> | |
| 3657 * | |
| 3658 * @return the normal formal parameter that was parsed | |
| 3659 */ | |
| 3660 NormalFormalParameter parseNormalFormalParameter() { | |
| 3661 CommentAndMetadata commentAndMetadata = parseCommentAndMetadata(); | |
| 3662 FinalConstVarOrType holder = parseFinalConstVarOrType(true); | |
| 3663 Token thisKeyword = null; | |
| 3664 Token period = null; | |
| 3665 if (matches(Keyword.THIS)) { | |
| 3666 thisKeyword = andAdvance; | |
| 3667 period = expect2(TokenType.PERIOD); | |
| 3668 } | |
| 3669 SimpleIdentifier identifier = parseSimpleIdentifier(); | |
| 3670 if (matches5(TokenType.OPEN_PAREN)) { | |
| 3671 FormalParameterList parameters = parseFormalParameterList(); | |
| 3672 if (thisKeyword == null) { | |
| 3673 if (holder.keyword != null) { | |
| 3674 reportError9(ParserErrorCode.FUNCTION_TYPED_PARAMETER_VAR, holder.keyw
ord, []); | |
| 3675 } | |
| 3676 return new FunctionTypedFormalParameter.full(commentAndMetadata.comment,
commentAndMetadata.metadata, holder.type, identifier, parameters); | |
| 3677 } else { | |
| 3678 return new FieldFormalParameter.full(commentAndMetadata.comment, comment
AndMetadata.metadata, holder.keyword, holder.type, thisKeyword, period, identifi
er, parameters); | |
| 3679 } | |
| 3680 } | |
| 3681 TypeName type = holder.type; | |
| 3682 if (type != null) { | |
| 3683 if (matches3(type.name.beginToken, Keyword.VOID)) { | |
| 3684 reportError9(ParserErrorCode.VOID_PARAMETER, type.name.beginToken, []); | |
| 3685 } else if (holder.keyword != null && matches3(holder.keyword, Keyword.VAR)
) { | |
| 3686 reportError9(ParserErrorCode.VAR_AND_TYPE, holder.keyword, []); | |
| 3687 } | |
| 3688 } | |
| 3689 if (thisKeyword != null) { | |
| 3690 return new FieldFormalParameter.full(commentAndMetadata.comment, commentAn
dMetadata.metadata, holder.keyword, holder.type, thisKeyword, period, identifier
, null); | |
| 3691 } | |
| 3692 return new SimpleFormalParameter.full(commentAndMetadata.comment, commentAnd
Metadata.metadata, holder.keyword, holder.type, identifier); | |
| 3693 } | |
| 3694 | |
| 3695 /** | |
| 3696 * Parse an operator declaration. | |
| 3697 * | |
| 3698 * <pre> | |
| 3699 * operatorDeclaration ::= | |
| 3700 * operatorSignature (';' | functionBody) | |
| 3701 * | |
| 3702 * operatorSignature ::= | |
| 3703 * 'external'? returnType? 'operator' operator formalParameterList | |
| 3704 * </pre> | |
| 3705 * | |
| 3706 * @param commentAndMetadata the documentation comment and metadata to be asso
ciated with the | |
| 3707 * declaration | |
| 3708 * @param externalKeyword the 'external' token | |
| 3709 * @param the return type that has already been parsed, or `null` if there was
no return | |
| 3710 * type | |
| 3711 * @return the operator declaration that was parsed | |
| 3712 */ | |
| 3713 MethodDeclaration parseOperator(CommentAndMetadata commentAndMetadata, Token e
xternalKeyword, TypeName returnType) { | |
| 3714 Token operatorKeyword; | |
| 3715 if (matches(Keyword.OPERATOR)) { | |
| 3716 operatorKeyword = andAdvance; | |
| 3717 } else { | |
| 3718 reportError9(ParserErrorCode.MISSING_KEYWORD_OPERATOR, _currentToken, []); | |
| 3719 operatorKeyword = createSyntheticToken(Keyword.OPERATOR); | |
| 3720 } | |
| 3721 if (!_currentToken.isUserDefinableOperator) { | |
| 3722 reportError8(ParserErrorCode.NON_USER_DEFINABLE_OPERATOR, [_currentToken.l
exeme]); | |
| 3723 } | |
| 3724 SimpleIdentifier name = new SimpleIdentifier.full(andAdvance); | |
| 3725 if (matches5(TokenType.EQ)) { | |
| 3726 Token previous = _currentToken.previous; | |
| 3727 if ((matches4(previous, TokenType.EQ_EQ) || matches4(previous, TokenType.B
ANG_EQ)) && _currentToken.offset == previous.offset + 2) { | |
| 3728 reportError8(ParserErrorCode.INVALID_OPERATOR, ["${previous.lexeme}${_cu
rrentToken.lexeme}"]); | |
| 3729 advance(); | |
| 3730 } | |
| 3731 } | |
| 3732 FormalParameterList parameters = parseFormalParameterList(); | |
| 3733 validateFormalParameterList(parameters); | |
| 3734 FunctionBody body = parseFunctionBody(true, ParserErrorCode.MISSING_FUNCTION
_BODY, false); | |
| 3735 if (externalKeyword != null && body is! EmptyFunctionBody) { | |
| 3736 reportError8(ParserErrorCode.EXTERNAL_OPERATOR_WITH_BODY, []); | |
| 3737 } | |
| 3738 return new MethodDeclaration.full(commentAndMetadata.comment, commentAndMeta
data.metadata, externalKeyword, null, returnType, null, operatorKeyword, name, p
arameters, body); | |
| 3739 } | |
| 3740 | |
| 3741 /** | |
| 3742 * Parse a return type if one is given, otherwise return `null` without advanc
ing. | |
| 3743 * | |
| 3744 * @return the return type that was parsed | |
| 3745 */ | |
| 3746 TypeName parseOptionalReturnType() { | |
| 3747 if (matches(Keyword.VOID)) { | |
| 3748 return parseReturnType(); | |
| 3749 } else if (matchesIdentifier() && !matches(Keyword.GET) && !matches(Keyword.
SET) && !matches(Keyword.OPERATOR) && (matchesIdentifier2(peek()) || matches4(pe
ek(), TokenType.LT))) { | |
| 3750 return parseReturnType(); | |
| 3751 } else if (matchesIdentifier() && matches4(peek(), TokenType.PERIOD) && matc
hesIdentifier2(peek2(2)) && (matchesIdentifier2(peek2(3)) || matches4(peek2(3),
TokenType.LT))) { | |
| 3752 return parseReturnType(); | |
| 3753 } | |
| 3754 return null; | |
| 3755 } | |
| 3756 | |
| 3757 /** | |
| 3758 * Parse a part or part-of directive. | |
| 3759 * | |
| 3760 * <pre> | |
| 3761 * partDirective ::= | |
| 3762 * metadata 'part' stringLiteral ';' | |
| 3763 * | |
| 3764 * partOfDirective ::= | |
| 3765 * metadata 'part' 'of' identifier ';' | |
| 3766 * </pre> | |
| 3767 * | |
| 3768 * @param commentAndMetadata the metadata to be associated with the directive | |
| 3769 * @return the part or part-of directive that was parsed | |
| 3770 */ | |
| 3771 Directive parsePartDirective(CommentAndMetadata commentAndMetadata) { | |
| 3772 Token partKeyword = expect(Keyword.PART); | |
| 3773 if (matches2(_OF)) { | |
| 3774 Token ofKeyword = andAdvance; | |
| 3775 LibraryIdentifier libraryName = parseLibraryName(ParserErrorCode.MISSING_N
AME_IN_PART_OF_DIRECTIVE, ofKeyword); | |
| 3776 Token semicolon = expect2(TokenType.SEMICOLON); | |
| 3777 return new PartOfDirective.full(commentAndMetadata.comment, commentAndMeta
data.metadata, partKeyword, ofKeyword, libraryName, semicolon); | |
| 3778 } | |
| 3779 StringLiteral partUri = parseStringLiteral(); | |
| 3780 Token semicolon = expect2(TokenType.SEMICOLON); | |
| 3781 return new PartDirective.full(commentAndMetadata.comment, commentAndMetadata
.metadata, partKeyword, partUri, semicolon); | |
| 3782 } | |
| 3783 | |
| 3784 /** | |
| 3785 * Parse a postfix expression. | |
| 3786 * | |
| 3787 * <pre> | |
| 3788 * postfixExpression ::= | |
| 3789 * assignableExpression postfixOperator | |
| 3790 * | primary selector* | |
| 3791 * | |
| 3792 * selector ::= | |
| 3793 * assignableSelector | |
| 3794 * | argumentList | |
| 3795 * </pre> | |
| 3796 * | |
| 3797 * @return the postfix expression that was parsed | |
| 3798 */ | |
| 3799 Expression parsePostfixExpression() { | |
| 3800 Expression operand = parseAssignableExpression(true); | |
| 3801 if (matches5(TokenType.OPEN_SQUARE_BRACKET) || matches5(TokenType.PERIOD) ||
matches5(TokenType.OPEN_PAREN)) { | |
| 3802 do { | |
| 3803 if (matches5(TokenType.OPEN_PAREN)) { | |
| 3804 ArgumentList argumentList = parseArgumentList(); | |
| 3805 if (operand is PropertyAccess) { | |
| 3806 PropertyAccess access = operand as PropertyAccess; | |
| 3807 operand = new MethodInvocation.full(access.target, access.operator,
access.propertyName, argumentList); | |
| 3808 } else { | |
| 3809 operand = new FunctionExpressionInvocation.full(operand, argumentLis
t); | |
| 3810 } | |
| 3811 } else { | |
| 3812 operand = parseAssignableSelector(operand, true); | |
| 3813 } | |
| 3814 } while (matches5(TokenType.OPEN_SQUARE_BRACKET) || matches5(TokenType.PER
IOD) || matches5(TokenType.OPEN_PAREN)); | |
| 3815 return operand; | |
| 3816 } | |
| 3817 if (!_currentToken.type.isIncrementOperator) { | |
| 3818 return operand; | |
| 3819 } | |
| 3820 if (operand is Literal || operand is FunctionExpressionInvocation) { | |
| 3821 reportError8(ParserErrorCode.MISSING_ASSIGNABLE_SELECTOR, []); | |
| 3822 } | |
| 3823 Token operator = andAdvance; | |
| 3824 return new PostfixExpression.full(operand, operator); | |
| 3825 } | |
| 3826 | |
| 3827 /** | |
| 3828 * Parse a prefixed identifier. | |
| 3829 * | |
| 3830 * <pre> | |
| 3831 * prefixedIdentifier ::= | |
| 3832 * identifier ('.' identifier)? | |
| 3833 * </pre> | |
| 3834 * | |
| 3835 * @return the prefixed identifier that was parsed | |
| 3836 */ | |
| 3837 Identifier parsePrefixedIdentifier() { | |
| 3838 SimpleIdentifier qualifier = parseSimpleIdentifier(); | |
| 3839 if (!matches5(TokenType.PERIOD)) { | |
| 3840 return qualifier; | |
| 3841 } | |
| 3842 Token period = andAdvance; | |
| 3843 SimpleIdentifier qualified = parseSimpleIdentifier(); | |
| 3844 return new PrefixedIdentifier.full(qualifier, period, qualified); | |
| 3845 } | |
| 3846 | |
| 3847 /** | |
| 3848 * Parse a primary expression. | |
| 3849 * | |
| 3850 * <pre> | |
| 3851 * primary ::= | |
| 3852 * thisExpression | |
| 3853 * | 'super' assignableSelector | |
| 3854 * | functionExpression | |
| 3855 * | literal | |
| 3856 * | identifier | |
| 3857 * | newExpression | |
| 3858 * | constObjectExpression | |
| 3859 * | '(' expression ')' | |
| 3860 * | argumentDefinitionTest | |
| 3861 * | |
| 3862 * literal ::= | |
| 3863 * nullLiteral | |
| 3864 * | booleanLiteral | |
| 3865 * | numericLiteral | |
| 3866 * | stringLiteral | |
| 3867 * | symbolLiteral | |
| 3868 * | mapLiteral | |
| 3869 * | listLiteral | |
| 3870 * </pre> | |
| 3871 * | |
| 3872 * @return the primary expression that was parsed | |
| 3873 */ | |
| 3874 Expression parsePrimaryExpression() { | |
| 3875 if (matches(Keyword.THIS)) { | |
| 3876 return new ThisExpression.full(andAdvance); | |
| 3877 } else if (matches(Keyword.SUPER)) { | |
| 3878 return parseAssignableSelector(new SuperExpression.full(andAdvance), false
); | |
| 3879 } else if (matches(Keyword.NULL)) { | |
| 3880 return new NullLiteral.full(andAdvance); | |
| 3881 } else if (matches(Keyword.FALSE)) { | |
| 3882 return new BooleanLiteral.full(andAdvance, false); | |
| 3883 } else if (matches(Keyword.TRUE)) { | |
| 3884 return new BooleanLiteral.full(andAdvance, true); | |
| 3885 } else if (matches5(TokenType.DOUBLE)) { | |
| 3886 Token token = andAdvance; | |
| 3887 double value = 0.0; | |
| 3888 try { | |
| 3889 value = double.parse(token.lexeme); | |
| 3890 } on FormatException catch (exception) { | |
| 3891 } | |
| 3892 return new DoubleLiteral.full(token, value); | |
| 3893 } else if (matches5(TokenType.HEXADECIMAL)) { | |
| 3894 Token token = andAdvance; | |
| 3895 int value = null; | |
| 3896 try { | |
| 3897 value = int.parse(token.lexeme.substring(2), radix: 16); | |
| 3898 } on FormatException catch (exception) { | |
| 3899 } | |
| 3900 return new IntegerLiteral.full(token, value); | |
| 3901 } else if (matches5(TokenType.INT)) { | |
| 3902 Token token = andAdvance; | |
| 3903 int value = null; | |
| 3904 try { | |
| 3905 value = int.parse(token.lexeme); | |
| 3906 } on FormatException catch (exception) { | |
| 3907 } | |
| 3908 return new IntegerLiteral.full(token, value); | |
| 3909 } else if (matches5(TokenType.STRING)) { | |
| 3910 return parseStringLiteral(); | |
| 3911 } else if (matches5(TokenType.OPEN_CURLY_BRACKET)) { | |
| 3912 return parseMapLiteral(null, null); | |
| 3913 } else if (matches5(TokenType.OPEN_SQUARE_BRACKET) || matches5(TokenType.IND
EX)) { | |
| 3914 return parseListLiteral(null, null); | |
| 3915 } else if (matchesIdentifier()) { | |
| 3916 return parsePrefixedIdentifier(); | |
| 3917 } else if (matches(Keyword.NEW)) { | |
| 3918 return parseNewExpression(); | |
| 3919 } else if (matches(Keyword.CONST)) { | |
| 3920 return parseConstExpression(); | |
| 3921 } else if (matches5(TokenType.OPEN_PAREN)) { | |
| 3922 if (isFunctionExpression(_currentToken)) { | |
| 3923 return parseFunctionExpression(); | |
| 3924 } | |
| 3925 Token leftParenthesis = andAdvance; | |
| 3926 Expression expression = parseExpression2(); | |
| 3927 Token rightParenthesis = expect2(TokenType.CLOSE_PAREN); | |
| 3928 return new ParenthesizedExpression.full(leftParenthesis, expression, right
Parenthesis); | |
| 3929 } else if (matches5(TokenType.LT)) { | |
| 3930 return parseListOrMapLiteral(null); | |
| 3931 } else if (matches5(TokenType.QUESTION)) { | |
| 3932 return parseArgumentDefinitionTest(); | |
| 3933 } else if (matches(Keyword.VOID)) { | |
| 3934 reportError8(ParserErrorCode.UNEXPECTED_TOKEN, [_currentToken.lexeme]); | |
| 3935 advance(); | |
| 3936 return parsePrimaryExpression(); | |
| 3937 } else if (matches5(TokenType.HASH)) { | |
| 3938 return parseSymbolLiteral(); | |
| 3939 } else { | |
| 3940 reportError8(ParserErrorCode.MISSING_IDENTIFIER, []); | |
| 3941 return createSyntheticIdentifier(); | |
| 3942 } | |
| 3943 } | |
| 3944 | |
| 3945 /** | |
| 3946 * Parse a redirecting constructor invocation. | |
| 3947 * | |
| 3948 * <pre> | |
| 3949 * redirectingConstructorInvocation ::= | |
| 3950 * 'this' ('.' identifier)? arguments | |
| 3951 * </pre> | |
| 3952 * | |
| 3953 * @return the redirecting constructor invocation that was parsed | |
| 3954 */ | |
| 3955 RedirectingConstructorInvocation parseRedirectingConstructorInvocation() { | |
| 3956 Token keyword = expect(Keyword.THIS); | |
| 3957 Token period = null; | |
| 3958 SimpleIdentifier constructorName = null; | |
| 3959 if (matches5(TokenType.PERIOD)) { | |
| 3960 period = andAdvance; | |
| 3961 constructorName = parseSimpleIdentifier(); | |
| 3962 } | |
| 3963 ArgumentList argumentList = parseArgumentList(); | |
| 3964 return new RedirectingConstructorInvocation.full(keyword, period, constructo
rName, argumentList); | |
| 3965 } | |
| 3966 | |
| 3967 /** | |
| 3968 * Parse a relational expression. | |
| 3969 * | |
| 3970 * <pre> | |
| 3971 * relationalExpression ::= | |
| 3972 * bitwiseOrExpression ('is' '!'? type | 'as' type | relationalOperator bi
twiseOrExpression)? | |
| 3973 * | 'super' relationalOperator bitwiseOrExpression | |
| 3974 * </pre> | |
| 3975 * | |
| 3976 * @return the relational expression that was parsed | |
| 3977 */ | |
| 3978 Expression parseRelationalExpression() { | |
| 3979 if (matches(Keyword.SUPER) && _currentToken.next.type.isRelationalOperator)
{ | |
| 3980 Expression expression = new SuperExpression.full(andAdvance); | |
| 3981 Token operator = andAdvance; | |
| 3982 expression = new BinaryExpression.full(expression, operator, parseBitwiseO
rExpression()); | |
| 3983 return expression; | |
| 3984 } | |
| 3985 Expression expression = parseBitwiseOrExpression(); | |
| 3986 if (matches(Keyword.AS)) { | |
| 3987 Token asOperator = andAdvance; | |
| 3988 expression = new AsExpression.full(expression, asOperator, parseTypeName()
); | |
| 3989 } else if (matches(Keyword.IS)) { | |
| 3990 Token isOperator = andAdvance; | |
| 3991 Token notOperator = null; | |
| 3992 if (matches5(TokenType.BANG)) { | |
| 3993 notOperator = andAdvance; | |
| 3994 } | |
| 3995 expression = new IsExpression.full(expression, isOperator, notOperator, pa
rseTypeName()); | |
| 3996 } else if (_currentToken.type.isRelationalOperator) { | |
| 3997 Token operator = andAdvance; | |
| 3998 expression = new BinaryExpression.full(expression, operator, parseBitwiseO
rExpression()); | |
| 3999 } | |
| 4000 return expression; | |
| 4001 } | |
| 4002 | |
| 4003 /** | |
| 4004 * Parse a rethrow expression. | |
| 4005 * | |
| 4006 * <pre> | |
| 4007 * rethrowExpression ::= | |
| 4008 * 'rethrow' | |
| 4009 * </pre> | |
| 4010 * | |
| 4011 * @return the rethrow expression that was parsed | |
| 4012 */ | |
| 4013 Expression parseRethrowExpression() => new RethrowExpression.full(expect(Keywo
rd.RETHROW)); | |
| 4014 | |
| 4015 /** | |
| 4016 * Parse a return statement. | |
| 4017 * | |
| 4018 * <pre> | |
| 4019 * returnStatement ::= | |
| 4020 * 'return' expression? ';' | |
| 4021 * </pre> | |
| 4022 * | |
| 4023 * @return the return statement that was parsed | |
| 4024 */ | |
| 4025 Statement parseReturnStatement() { | |
| 4026 Token returnKeyword = expect(Keyword.RETURN); | |
| 4027 if (matches5(TokenType.SEMICOLON)) { | |
| 4028 return new ReturnStatement.full(returnKeyword, null, andAdvance); | |
| 4029 } | |
| 4030 Expression expression = parseExpression2(); | |
| 4031 Token semicolon = expect2(TokenType.SEMICOLON); | |
| 4032 return new ReturnStatement.full(returnKeyword, expression, semicolon); | |
| 4033 } | |
| 4034 | |
| 4035 /** | |
| 4036 * Parse a return type. | |
| 4037 * | |
| 4038 * <pre> | |
| 4039 * returnType ::= | |
| 4040 * 'void' | |
| 4041 * | type | |
| 4042 * </pre> | |
| 4043 * | |
| 4044 * @return the return type that was parsed | |
| 4045 */ | |
| 4046 TypeName parseReturnType() { | |
| 4047 if (matches(Keyword.VOID)) { | |
| 4048 return new TypeName.full(new SimpleIdentifier.full(andAdvance), null); | |
| 4049 } else { | |
| 4050 return parseTypeName(); | |
| 4051 } | |
| 4052 } | |
| 4053 | |
| 4054 /** | |
| 4055 * Parse a setter. | |
| 4056 * | |
| 4057 * <pre> | |
| 4058 * setter ::= | |
| 4059 * setterSignature functionBody? | |
| 4060 * | |
| 4061 * setterSignature ::= | |
| 4062 * 'external'? 'static'? returnType? 'set' identifier formalParameterList | |
| 4063 * </pre> | |
| 4064 * | |
| 4065 * @param commentAndMetadata the documentation comment and metadata to be asso
ciated with the | |
| 4066 * declaration | |
| 4067 * @param externalKeyword the 'external' token | |
| 4068 * @param staticKeyword the static keyword, or `null` if the setter is not sta
tic | |
| 4069 * @param the return type that has already been parsed, or `null` if there was
no return | |
| 4070 * type | |
| 4071 * @return the setter that was parsed | |
| 4072 */ | |
| 4073 MethodDeclaration parseSetter(CommentAndMetadata commentAndMetadata, Token ext
ernalKeyword, Token staticKeyword, TypeName returnType) { | |
| 4074 Token propertyKeyword = expect(Keyword.SET); | |
| 4075 SimpleIdentifier name = parseSimpleIdentifier(); | |
| 4076 FormalParameterList parameters = parseFormalParameterList(); | |
| 4077 validateFormalParameterList(parameters); | |
| 4078 FunctionBody body = parseFunctionBody(externalKeyword != null || staticKeywo
rd == null, ParserErrorCode.STATIC_SETTER_WITHOUT_BODY, false); | |
| 4079 if (externalKeyword != null && body is! EmptyFunctionBody) { | |
| 4080 reportError8(ParserErrorCode.EXTERNAL_SETTER_WITH_BODY, []); | |
| 4081 } | |
| 4082 return new MethodDeclaration.full(commentAndMetadata.comment, commentAndMeta
data.metadata, externalKeyword, staticKeyword, returnType, propertyKeyword, null
, name, parameters, body); | |
| 4083 } | |
| 4084 | |
| 4085 /** | |
| 4086 * Parse a shift expression. | |
| 4087 * | |
| 4088 * <pre> | |
| 4089 * shiftExpression ::= | |
| 4090 * additiveExpression (shiftOperator additiveExpression)* | |
| 4091 * | 'super' (shiftOperator additiveExpression)+ | |
| 4092 * </pre> | |
| 4093 * | |
| 4094 * @return the shift expression that was parsed | |
| 4095 */ | |
| 4096 Expression parseShiftExpression() { | |
| 4097 Expression expression; | |
| 4098 if (matches(Keyword.SUPER) && _currentToken.next.type.isShiftOperator) { | |
| 4099 expression = new SuperExpression.full(andAdvance); | |
| 4100 } else { | |
| 4101 expression = parseAdditiveExpression(); | |
| 4102 } | |
| 4103 while (_currentToken.type.isShiftOperator) { | |
| 4104 Token operator = andAdvance; | |
| 4105 expression = new BinaryExpression.full(expression, operator, parseAdditive
Expression()); | |
| 4106 } | |
| 4107 return expression; | |
| 4108 } | |
| 4109 | |
| 4110 /** | |
| 4111 * Parse a simple identifier. | |
| 4112 * | |
| 4113 * <pre> | |
| 4114 * identifier ::= | |
| 4115 * IDENTIFIER | |
| 4116 * </pre> | |
| 4117 * | |
| 4118 * @return the simple identifier that was parsed | |
| 4119 */ | |
| 4120 SimpleIdentifier parseSimpleIdentifier() { | |
| 4121 if (matchesIdentifier()) { | |
| 4122 return new SimpleIdentifier.full(andAdvance); | |
| 4123 } | |
| 4124 reportError8(ParserErrorCode.MISSING_IDENTIFIER, []); | |
| 4125 return createSyntheticIdentifier(); | |
| 4126 } | |
| 4127 | |
| 4128 /** | |
| 4129 * Parse a statement. | |
| 4130 * | |
| 4131 * <pre> | |
| 4132 * statement ::= | |
| 4133 * label* nonLabeledStatement | |
| 4134 * </pre> | |
| 4135 * | |
| 4136 * @return the statement that was parsed | |
| 4137 */ | |
| 4138 Statement parseStatement2() { | |
| 4139 List<Label> labels = new List<Label>(); | |
| 4140 while (matchesIdentifier() && matches4(peek(), TokenType.COLON)) { | |
| 4141 SimpleIdentifier label = parseSimpleIdentifier(); | |
| 4142 Token colon = expect2(TokenType.COLON); | |
| 4143 labels.add(new Label.full(label, colon)); | |
| 4144 } | |
| 4145 Statement statement = parseNonLabeledStatement(); | |
| 4146 if (labels.isEmpty) { | |
| 4147 return statement; | |
| 4148 } | |
| 4149 return new LabeledStatement.full(labels, statement); | |
| 4150 } | |
| 4151 | |
| 4152 /** | |
| 4153 * Parse a list of statements within a switch statement. | |
| 4154 * | |
| 4155 * <pre> | |
| 4156 * statements ::= | |
| 4157 * statement* | |
| 4158 * </pre> | |
| 4159 * | |
| 4160 * @return the statements that were parsed | |
| 4161 */ | |
| 4162 List<Statement> parseStatements2() { | |
| 4163 List<Statement> statements = new List<Statement>(); | |
| 4164 Token statementStart = _currentToken; | |
| 4165 while (!matches5(TokenType.EOF) && !matches5(TokenType.CLOSE_CURLY_BRACKET)
&& !isSwitchMember()) { | |
| 4166 statements.add(parseStatement2()); | |
| 4167 if (identical(_currentToken, statementStart)) { | |
| 4168 reportError9(ParserErrorCode.UNEXPECTED_TOKEN, _currentToken, [_currentT
oken.lexeme]); | |
| 4169 advance(); | |
| 4170 } | |
| 4171 statementStart = _currentToken; | |
| 4172 } | |
| 4173 return statements; | |
| 4174 } | |
| 4175 | |
| 4176 /** | |
| 4177 * Parse a string literal that contains interpolations. | |
| 4178 * | |
| 4179 * @return the string literal that was parsed | |
| 4180 */ | |
| 4181 StringInterpolation parseStringInterpolation(Token string) { | |
| 4182 List<InterpolationElement> elements = new List<InterpolationElement>(); | |
| 4183 bool hasMore = matches5(TokenType.STRING_INTERPOLATION_EXPRESSION) || matche
s5(TokenType.STRING_INTERPOLATION_IDENTIFIER); | |
| 4184 elements.add(new InterpolationString.full(string, computeStringValue(string.
lexeme, true, !hasMore))); | |
| 4185 while (hasMore) { | |
| 4186 if (matches5(TokenType.STRING_INTERPOLATION_EXPRESSION)) { | |
| 4187 Token openToken = andAdvance; | |
| 4188 Expression expression = parseExpression2(); | |
| 4189 Token rightBracket = expect2(TokenType.CLOSE_CURLY_BRACKET); | |
| 4190 elements.add(new InterpolationExpression.full(openToken, expression, rig
htBracket)); | |
| 4191 } else { | |
| 4192 Token openToken = andAdvance; | |
| 4193 Expression expression = null; | |
| 4194 if (matches(Keyword.THIS)) { | |
| 4195 expression = new ThisExpression.full(andAdvance); | |
| 4196 } else { | |
| 4197 expression = parseSimpleIdentifier(); | |
| 4198 } | |
| 4199 elements.add(new InterpolationExpression.full(openToken, expression, nul
l)); | |
| 4200 } | |
| 4201 if (matches5(TokenType.STRING)) { | |
| 4202 string = andAdvance; | |
| 4203 hasMore = matches5(TokenType.STRING_INTERPOLATION_EXPRESSION) || matches
5(TokenType.STRING_INTERPOLATION_IDENTIFIER); | |
| 4204 elements.add(new InterpolationString.full(string, computeStringValue(str
ing.lexeme, false, !hasMore))); | |
| 4205 } | |
| 4206 } | |
| 4207 return new StringInterpolation.full(elements); | |
| 4208 } | |
| 4209 | |
| 4210 /** | |
| 4211 * Parse a string literal. | |
| 4212 * | |
| 4213 * <pre> | |
| 4214 * stringLiteral ::= | |
| 4215 * MULTI_LINE_STRING+ | |
| 4216 * | SINGLE_LINE_STRING+ | |
| 4217 * </pre> | |
| 4218 * | |
| 4219 * @return the string literal that was parsed | |
| 4220 */ | |
| 4221 StringLiteral parseStringLiteral() { | |
| 4222 List<StringLiteral> strings = new List<StringLiteral>(); | |
| 4223 while (matches5(TokenType.STRING)) { | |
| 4224 Token string = andAdvance; | |
| 4225 if (matches5(TokenType.STRING_INTERPOLATION_EXPRESSION) || matches5(TokenT
ype.STRING_INTERPOLATION_IDENTIFIER)) { | |
| 4226 strings.add(parseStringInterpolation(string)); | |
| 4227 } else { | |
| 4228 strings.add(new SimpleStringLiteral.full(string, computeStringValue(stri
ng.lexeme, true, true))); | |
| 4229 } | |
| 4230 } | |
| 4231 if (strings.length < 1) { | |
| 4232 reportError8(ParserErrorCode.EXPECTED_STRING_LITERAL, []); | |
| 4233 return createSyntheticStringLiteral(); | |
| 4234 } else if (strings.length == 1) { | |
| 4235 return strings[0]; | |
| 4236 } else { | |
| 4237 return new AdjacentStrings.full(strings); | |
| 4238 } | |
| 4239 } | |
| 4240 | |
| 4241 /** | |
| 4242 * Parse a super constructor invocation. | |
| 4243 * | |
| 4244 * <pre> | |
| 4245 * superConstructorInvocation ::= | |
| 4246 * 'super' ('.' identifier)? arguments | |
| 4247 * </pre> | |
| 4248 * | |
| 4249 * @return the super constructor invocation that was parsed | |
| 4250 */ | |
| 4251 SuperConstructorInvocation parseSuperConstructorInvocation() { | |
| 4252 Token keyword = expect(Keyword.SUPER); | |
| 4253 Token period = null; | |
| 4254 SimpleIdentifier constructorName = null; | |
| 4255 if (matches5(TokenType.PERIOD)) { | |
| 4256 period = andAdvance; | |
| 4257 constructorName = parseSimpleIdentifier(); | |
| 4258 } | |
| 4259 ArgumentList argumentList = parseArgumentList(); | |
| 4260 return new SuperConstructorInvocation.full(keyword, period, constructorName,
argumentList); | |
| 4261 } | |
| 4262 | |
| 4263 /** | |
| 4264 * Parse a switch statement. | |
| 4265 * | |
| 4266 * <pre> | |
| 4267 * switchStatement ::= | |
| 4268 * 'switch' '(' expression ')' '{' switchCase* defaultCase? '}' | |
| 4269 * | |
| 4270 * switchCase ::= | |
| 4271 * label* ('case' expression ':') statements | |
| 4272 * | |
| 4273 * defaultCase ::= | |
| 4274 * label* 'default' ':' statements | |
| 4275 * </pre> | |
| 4276 * | |
| 4277 * @return the switch statement that was parsed | |
| 4278 */ | |
| 4279 SwitchStatement parseSwitchStatement() { | |
| 4280 bool wasInSwitch = _inSwitch; | |
| 4281 _inSwitch = true; | |
| 4282 try { | |
| 4283 Set<String> definedLabels = new Set<String>(); | |
| 4284 Token keyword = expect(Keyword.SWITCH); | |
| 4285 Token leftParenthesis = expect2(TokenType.OPEN_PAREN); | |
| 4286 Expression expression = parseExpression2(); | |
| 4287 Token rightParenthesis = expect2(TokenType.CLOSE_PAREN); | |
| 4288 Token leftBracket = expect2(TokenType.OPEN_CURLY_BRACKET); | |
| 4289 Token defaultKeyword = null; | |
| 4290 List<SwitchMember> members = new List<SwitchMember>(); | |
| 4291 while (!matches5(TokenType.EOF) && !matches5(TokenType.CLOSE_CURLY_BRACKET
)) { | |
| 4292 List<Label> labels = new List<Label>(); | |
| 4293 while (matchesIdentifier() && matches4(peek(), TokenType.COLON)) { | |
| 4294 SimpleIdentifier identifier = parseSimpleIdentifier(); | |
| 4295 String label = identifier.token.lexeme; | |
| 4296 if (definedLabels.contains(label)) { | |
| 4297 reportError9(ParserErrorCode.DUPLICATE_LABEL_IN_SWITCH_STATEMENT, id
entifier.token, [label]); | |
| 4298 } else { | |
| 4299 javaSetAdd(definedLabels, label); | |
| 4300 } | |
| 4301 Token colon = expect2(TokenType.COLON); | |
| 4302 labels.add(new Label.full(identifier, colon)); | |
| 4303 } | |
| 4304 if (matches(Keyword.CASE)) { | |
| 4305 Token caseKeyword = andAdvance; | |
| 4306 Expression caseExpression = parseExpression2(); | |
| 4307 Token colon = expect2(TokenType.COLON); | |
| 4308 members.add(new SwitchCase.full(labels, caseKeyword, caseExpression, c
olon, parseStatements2())); | |
| 4309 if (defaultKeyword != null) { | |
| 4310 reportError9(ParserErrorCode.SWITCH_HAS_CASE_AFTER_DEFAULT_CASE, cas
eKeyword, []); | |
| 4311 } | |
| 4312 } else if (matches(Keyword.DEFAULT)) { | |
| 4313 if (defaultKeyword != null) { | |
| 4314 reportError9(ParserErrorCode.SWITCH_HAS_MULTIPLE_DEFAULT_CASES, peek
(), []); | |
| 4315 } | |
| 4316 defaultKeyword = andAdvance; | |
| 4317 Token colon = expect2(TokenType.COLON); | |
| 4318 members.add(new SwitchDefault.full(labels, defaultKeyword, colon, pars
eStatements2())); | |
| 4319 } else { | |
| 4320 reportError8(ParserErrorCode.EXPECTED_CASE_OR_DEFAULT, []); | |
| 4321 while (!matches5(TokenType.EOF) && !matches5(TokenType.CLOSE_CURLY_BRA
CKET) && !matches(Keyword.CASE) && !matches(Keyword.DEFAULT)) { | |
| 4322 advance(); | |
| 4323 } | |
| 4324 } | |
| 4325 } | |
| 4326 Token rightBracket = expect2(TokenType.CLOSE_CURLY_BRACKET); | |
| 4327 return new SwitchStatement.full(keyword, leftParenthesis, expression, righ
tParenthesis, leftBracket, members, rightBracket); | |
| 4328 } finally { | |
| 4329 _inSwitch = wasInSwitch; | |
| 4330 } | |
| 4331 } | |
| 4332 | |
| 4333 /** | |
| 4334 * Parse a symbol literal. | |
| 4335 * | |
| 4336 * <pre> | |
| 4337 * symbolLiteral ::= | |
| 4338 * '#' identifier ('.' identifier)* | |
| 4339 * </pre> | |
| 4340 * | |
| 4341 * @return the symbol literal that was parsed | |
| 4342 */ | |
| 4343 SymbolLiteral parseSymbolLiteral() { | |
| 4344 Token poundSign = andAdvance; | |
| 4345 List<Token> components = new List<Token>(); | |
| 4346 if (matchesIdentifier()) { | |
| 4347 components.add(andAdvance); | |
| 4348 while (matches5(TokenType.PERIOD)) { | |
| 4349 advance(); | |
| 4350 if (matchesIdentifier()) { | |
| 4351 components.add(andAdvance); | |
| 4352 } else { | |
| 4353 reportError8(ParserErrorCode.MISSING_IDENTIFIER, []); | |
| 4354 components.add(createSyntheticToken2(TokenType.IDENTIFIER)); | |
| 4355 break; | |
| 4356 } | |
| 4357 } | |
| 4358 } else if (_currentToken.isOperator) { | |
| 4359 components.add(andAdvance); | |
| 4360 } else { | |
| 4361 reportError8(ParserErrorCode.MISSING_IDENTIFIER, []); | |
| 4362 components.add(createSyntheticToken2(TokenType.IDENTIFIER)); | |
| 4363 } | |
| 4364 return new SymbolLiteral.full(poundSign, new List.from(components)); | |
| 4365 } | |
| 4366 | |
| 4367 /** | |
| 4368 * Parse a throw expression. | |
| 4369 * | |
| 4370 * <pre> | |
| 4371 * throwExpression ::= | |
| 4372 * 'throw' expression | |
| 4373 * </pre> | |
| 4374 * | |
| 4375 * @return the throw expression that was parsed | |
| 4376 */ | |
| 4377 Expression parseThrowExpression() { | |
| 4378 Token keyword = expect(Keyword.THROW); | |
| 4379 if (matches5(TokenType.SEMICOLON) || matches5(TokenType.CLOSE_PAREN)) { | |
| 4380 reportError9(ParserErrorCode.MISSING_EXPRESSION_IN_THROW, _currentToken, [
]); | |
| 4381 return new ThrowExpression.full(keyword, createSyntheticIdentifier()); | |
| 4382 } | |
| 4383 Expression expression = parseExpression2(); | |
| 4384 return new ThrowExpression.full(keyword, expression); | |
| 4385 } | |
| 4386 | |
| 4387 /** | |
| 4388 * Parse a throw expression. | |
| 4389 * | |
| 4390 * <pre> | |
| 4391 * throwExpressionWithoutCascade ::= | |
| 4392 * 'throw' expressionWithoutCascade | |
| 4393 * </pre> | |
| 4394 * | |
| 4395 * @return the throw expression that was parsed | |
| 4396 */ | |
| 4397 Expression parseThrowExpressionWithoutCascade() { | |
| 4398 Token keyword = expect(Keyword.THROW); | |
| 4399 if (matches5(TokenType.SEMICOLON) || matches5(TokenType.CLOSE_PAREN)) { | |
| 4400 reportError9(ParserErrorCode.MISSING_EXPRESSION_IN_THROW, _currentToken, [
]); | |
| 4401 return new ThrowExpression.full(keyword, createSyntheticIdentifier()); | |
| 4402 } | |
| 4403 Expression expression = parseExpressionWithoutCascade(); | |
| 4404 return new ThrowExpression.full(keyword, expression); | |
| 4405 } | |
| 4406 | |
| 4407 /** | |
| 4408 * Parse a try statement. | |
| 4409 * | |
| 4410 * <pre> | |
| 4411 * tryStatement ::= | |
| 4412 * 'try' block (onPart+ finallyPart? | finallyPart) | |
| 4413 * | |
| 4414 * onPart ::= | |
| 4415 * catchPart block | |
| 4416 * | 'on' type catchPart? block | |
| 4417 * | |
| 4418 * catchPart ::= | |
| 4419 * 'catch' '(' identifier (',' identifier)? ')' | |
| 4420 * | |
| 4421 * finallyPart ::= | |
| 4422 * 'finally' block | |
| 4423 * </pre> | |
| 4424 * | |
| 4425 * @return the try statement that was parsed | |
| 4426 */ | |
| 4427 Statement parseTryStatement() { | |
| 4428 Token tryKeyword = expect(Keyword.TRY); | |
| 4429 Block body = parseBlock(); | |
| 4430 List<CatchClause> catchClauses = new List<CatchClause>(); | |
| 4431 Block finallyClause = null; | |
| 4432 while (matches2(_ON) || matches(Keyword.CATCH)) { | |
| 4433 Token onKeyword = null; | |
| 4434 TypeName exceptionType = null; | |
| 4435 if (matches2(_ON)) { | |
| 4436 onKeyword = andAdvance; | |
| 4437 exceptionType = parseTypeName(); | |
| 4438 } | |
| 4439 Token catchKeyword = null; | |
| 4440 Token leftParenthesis = null; | |
| 4441 SimpleIdentifier exceptionParameter = null; | |
| 4442 Token comma = null; | |
| 4443 SimpleIdentifier stackTraceParameter = null; | |
| 4444 Token rightParenthesis = null; | |
| 4445 if (matches(Keyword.CATCH)) { | |
| 4446 catchKeyword = andAdvance; | |
| 4447 leftParenthesis = expect2(TokenType.OPEN_PAREN); | |
| 4448 exceptionParameter = parseSimpleIdentifier(); | |
| 4449 if (matches5(TokenType.COMMA)) { | |
| 4450 comma = andAdvance; | |
| 4451 stackTraceParameter = parseSimpleIdentifier(); | |
| 4452 } | |
| 4453 rightParenthesis = expect2(TokenType.CLOSE_PAREN); | |
| 4454 } | |
| 4455 Block catchBody = parseBlock(); | |
| 4456 catchClauses.add(new CatchClause.full(onKeyword, exceptionType, catchKeywo
rd, leftParenthesis, exceptionParameter, comma, stackTraceParameter, rightParent
hesis, catchBody)); | |
| 4457 } | |
| 4458 Token finallyKeyword = null; | |
| 4459 if (matches(Keyword.FINALLY)) { | |
| 4460 finallyKeyword = andAdvance; | |
| 4461 finallyClause = parseBlock(); | |
| 4462 } else { | |
| 4463 if (catchClauses.isEmpty) { | |
| 4464 reportError8(ParserErrorCode.MISSING_CATCH_OR_FINALLY, []); | |
| 4465 } | |
| 4466 } | |
| 4467 return new TryStatement.full(tryKeyword, body, catchClauses, finallyKeyword,
finallyClause); | |
| 4468 } | |
| 4469 | |
| 4470 /** | |
| 4471 * Parse a type alias. | |
| 4472 * | |
| 4473 * <pre> | |
| 4474 * typeAlias ::= | |
| 4475 * 'typedef' typeAliasBody | |
| 4476 * | |
| 4477 * typeAliasBody ::= | |
| 4478 * classTypeAlias | |
| 4479 * | functionTypeAlias | |
| 4480 * | |
| 4481 * classTypeAlias ::= | |
| 4482 * identifier typeParameters? '=' 'abstract'? mixinApplication | |
| 4483 * | |
| 4484 * mixinApplication ::= | |
| 4485 * qualified withClause implementsClause? ';' | |
| 4486 * | |
| 4487 * functionTypeAlias ::= | |
| 4488 * functionPrefix typeParameterList? formalParameterList ';' | |
| 4489 * | |
| 4490 * functionPrefix ::= | |
| 4491 * returnType? name | |
| 4492 * </pre> | |
| 4493 * | |
| 4494 * @param commentAndMetadata the metadata to be associated with the member | |
| 4495 * @return the type alias that was parsed | |
| 4496 */ | |
| 4497 TypeAlias parseTypeAlias(CommentAndMetadata commentAndMetadata) { | |
| 4498 Token keyword = expect(Keyword.TYPEDEF); | |
| 4499 if (matchesIdentifier()) { | |
| 4500 Token next = peek(); | |
| 4501 if (matches4(next, TokenType.LT)) { | |
| 4502 next = skipTypeParameterList(next); | |
| 4503 if (next != null && matches4(next, TokenType.EQ)) { | |
| 4504 TypeAlias typeAlias = parseClassTypeAlias(commentAndMetadata, keyword)
; | |
| 4505 reportError9(ParserErrorCode.DEPRECATED_CLASS_TYPE_ALIAS, keyword, [])
; | |
| 4506 return typeAlias; | |
| 4507 } | |
| 4508 } else if (matches4(next, TokenType.EQ)) { | |
| 4509 TypeAlias typeAlias = parseClassTypeAlias(commentAndMetadata, keyword); | |
| 4510 reportError9(ParserErrorCode.DEPRECATED_CLASS_TYPE_ALIAS, keyword, []); | |
| 4511 return typeAlias; | |
| 4512 } | |
| 4513 } | |
| 4514 return parseFunctionTypeAlias(commentAndMetadata, keyword); | |
| 4515 } | |
| 4516 | |
| 4517 /** | |
| 4518 * Parse a list of type arguments. | |
| 4519 * | |
| 4520 * <pre> | |
| 4521 * typeArguments ::= | |
| 4522 * '<' typeList '>' | |
| 4523 * | |
| 4524 * typeList ::= | |
| 4525 * type (',' type)* | |
| 4526 * </pre> | |
| 4527 * | |
| 4528 * @return the type argument list that was parsed | |
| 4529 */ | |
| 4530 TypeArgumentList parseTypeArgumentList() { | |
| 4531 Token leftBracket = expect2(TokenType.LT); | |
| 4532 List<TypeName> arguments = new List<TypeName>(); | |
| 4533 arguments.add(parseTypeName()); | |
| 4534 while (optional(TokenType.COMMA)) { | |
| 4535 arguments.add(parseTypeName()); | |
| 4536 } | |
| 4537 Token rightBracket = expect2(TokenType.GT); | |
| 4538 return new TypeArgumentList.full(leftBracket, arguments, rightBracket); | |
| 4539 } | |
| 4540 | |
| 4541 /** | |
| 4542 * Parse a type name. | |
| 4543 * | |
| 4544 * <pre> | |
| 4545 * type ::= | |
| 4546 * qualified typeArguments? | |
| 4547 * </pre> | |
| 4548 * | |
| 4549 * @return the type name that was parsed | |
| 4550 */ | |
| 4551 TypeName parseTypeName() { | |
| 4552 Identifier typeName; | |
| 4553 if (matches(Keyword.VAR)) { | |
| 4554 reportError8(ParserErrorCode.VAR_AS_TYPE_NAME, []); | |
| 4555 typeName = new SimpleIdentifier.full(andAdvance); | |
| 4556 } else if (matchesIdentifier()) { | |
| 4557 typeName = parsePrefixedIdentifier(); | |
| 4558 } else { | |
| 4559 typeName = createSyntheticIdentifier(); | |
| 4560 reportError8(ParserErrorCode.EXPECTED_TYPE_NAME, []); | |
| 4561 } | |
| 4562 TypeArgumentList typeArguments = null; | |
| 4563 if (matches5(TokenType.LT)) { | |
| 4564 typeArguments = parseTypeArgumentList(); | |
| 4565 } | |
| 4566 return new TypeName.full(typeName, typeArguments); | |
| 4567 } | |
| 4568 | |
| 4569 /** | |
| 4570 * Parse a type parameter. | |
| 4571 * | |
| 4572 * <pre> | |
| 4573 * typeParameter ::= | |
| 4574 * metadata name ('extends' bound)? | |
| 4575 * </pre> | |
| 4576 * | |
| 4577 * @return the type parameter that was parsed | |
| 4578 */ | |
| 4579 TypeParameter parseTypeParameter() { | |
| 4580 CommentAndMetadata commentAndMetadata = parseCommentAndMetadata(); | |
| 4581 SimpleIdentifier name = parseSimpleIdentifier(); | |
| 4582 if (matches(Keyword.EXTENDS)) { | |
| 4583 Token keyword = andAdvance; | |
| 4584 TypeName bound = parseTypeName(); | |
| 4585 return new TypeParameter.full(commentAndMetadata.comment, commentAndMetada
ta.metadata, name, keyword, bound); | |
| 4586 } | |
| 4587 return new TypeParameter.full(commentAndMetadata.comment, commentAndMetadata
.metadata, name, null, null); | |
| 4588 } | |
| 4589 | |
| 4590 /** | |
| 4591 * Parse a list of type parameters. | |
| 4592 * | |
| 4593 * <pre> | |
| 4594 * typeParameterList ::= | |
| 4595 * '<' typeParameter (',' typeParameter)* '>' | |
| 4596 * </pre> | |
| 4597 * | |
| 4598 * @return the list of type parameters that were parsed | |
| 4599 */ | |
| 4600 TypeParameterList parseTypeParameterList() { | |
| 4601 Token leftBracket = expect2(TokenType.LT); | |
| 4602 List<TypeParameter> typeParameters = new List<TypeParameter>(); | |
| 4603 typeParameters.add(parseTypeParameter()); | |
| 4604 while (optional(TokenType.COMMA)) { | |
| 4605 typeParameters.add(parseTypeParameter()); | |
| 4606 } | |
| 4607 Token rightBracket = expect2(TokenType.GT); | |
| 4608 return new TypeParameterList.full(leftBracket, typeParameters, rightBracket)
; | |
| 4609 } | |
| 4610 | |
| 4611 /** | |
| 4612 * Parse a unary expression. | |
| 4613 * | |
| 4614 * <pre> | |
| 4615 * unaryExpression ::= | |
| 4616 * prefixOperator unaryExpression | |
| 4617 * | postfixExpression | |
| 4618 * | unaryOperator 'super' | |
| 4619 * | '-' 'super' | |
| 4620 * | incrementOperator assignableExpression | |
| 4621 * </pre> | |
| 4622 * | |
| 4623 * @return the unary expression that was parsed | |
| 4624 */ | |
| 4625 Expression parseUnaryExpression() { | |
| 4626 if (matches5(TokenType.MINUS) || matches5(TokenType.BANG) || matches5(TokenT
ype.TILDE)) { | |
| 4627 Token operator = andAdvance; | |
| 4628 if (matches(Keyword.SUPER)) { | |
| 4629 if (matches4(peek(), TokenType.OPEN_SQUARE_BRACKET) || matches4(peek(),
TokenType.PERIOD)) { | |
| 4630 return new PrefixExpression.full(operator, parseUnaryExpression()); | |
| 4631 } | |
| 4632 return new PrefixExpression.full(operator, new SuperExpression.full(andA
dvance)); | |
| 4633 } | |
| 4634 return new PrefixExpression.full(operator, parseUnaryExpression()); | |
| 4635 } else if (_currentToken.type.isIncrementOperator) { | |
| 4636 Token operator = andAdvance; | |
| 4637 if (matches(Keyword.SUPER)) { | |
| 4638 if (matches4(peek(), TokenType.OPEN_SQUARE_BRACKET) || matches4(peek(),
TokenType.PERIOD)) { | |
| 4639 return new PrefixExpression.full(operator, parseUnaryExpression()); | |
| 4640 } | |
| 4641 if (identical(operator.type, TokenType.MINUS_MINUS)) { | |
| 4642 int offset = operator.offset; | |
| 4643 Token firstOperator = new Token(TokenType.MINUS, offset); | |
| 4644 Token secondOperator = new Token(TokenType.MINUS, offset + 1); | |
| 4645 secondOperator.setNext(_currentToken); | |
| 4646 firstOperator.setNext(secondOperator); | |
| 4647 operator.previous.setNext(firstOperator); | |
| 4648 return new PrefixExpression.full(firstOperator, new PrefixExpression.f
ull(secondOperator, new SuperExpression.full(andAdvance))); | |
| 4649 } else { | |
| 4650 reportError8(ParserErrorCode.INVALID_OPERATOR_FOR_SUPER, [operator.lex
eme]); | |
| 4651 return new PrefixExpression.full(operator, new SuperExpression.full(an
dAdvance)); | |
| 4652 } | |
| 4653 } | |
| 4654 return new PrefixExpression.full(operator, parseAssignableExpression(false
)); | |
| 4655 } else if (matches5(TokenType.PLUS)) { | |
| 4656 reportError8(ParserErrorCode.MISSING_IDENTIFIER, []); | |
| 4657 return createSyntheticIdentifier(); | |
| 4658 } | |
| 4659 return parsePostfixExpression(); | |
| 4660 } | |
| 4661 | |
| 4662 /** | |
| 4663 * Parse a variable declaration. | |
| 4664 * | |
| 4665 * <pre> | |
| 4666 * variableDeclaration ::= | |
| 4667 * identifier ('=' expression)? | |
| 4668 * </pre> | |
| 4669 * | |
| 4670 * @return the variable declaration that was parsed | |
| 4671 */ | |
| 4672 VariableDeclaration parseVariableDeclaration() { | |
| 4673 CommentAndMetadata commentAndMetadata = parseCommentAndMetadata(); | |
| 4674 SimpleIdentifier name = parseSimpleIdentifier(); | |
| 4675 Token equals = null; | |
| 4676 Expression initializer = null; | |
| 4677 if (matches5(TokenType.EQ)) { | |
| 4678 equals = andAdvance; | |
| 4679 initializer = parseExpression2(); | |
| 4680 } | |
| 4681 return new VariableDeclaration.full(commentAndMetadata.comment, commentAndMe
tadata.metadata, name, equals, initializer); | |
| 4682 } | |
| 4683 | |
| 4684 /** | |
| 4685 * Parse a variable declaration list. | |
| 4686 * | |
| 4687 * <pre> | |
| 4688 * variableDeclarationList ::= | |
| 4689 * finalConstVarOrType variableDeclaration (',' variableDeclaration)* | |
| 4690 * </pre> | |
| 4691 * | |
| 4692 * @param commentAndMetadata the metadata to be associated with the variable d
eclaration list | |
| 4693 * @return the variable declaration list that was parsed | |
| 4694 */ | |
| 4695 VariableDeclarationList parseVariableDeclarationList(CommentAndMetadata commen
tAndMetadata) { | |
| 4696 FinalConstVarOrType holder = parseFinalConstVarOrType(false); | |
| 4697 return parseVariableDeclarationList2(commentAndMetadata, holder.keyword, hol
der.type); | |
| 4698 } | |
| 4699 | |
| 4700 /** | |
| 4701 * Parse a variable declaration list. | |
| 4702 * | |
| 4703 * <pre> | |
| 4704 * variableDeclarationList ::= | |
| 4705 * finalConstVarOrType variableDeclaration (',' variableDeclaration)* | |
| 4706 * </pre> | |
| 4707 * | |
| 4708 * @param commentAndMetadata the metadata to be associated with the variable d
eclaration list, or | |
| 4709 * `null` if there is no attempt at parsing the comment and metadata | |
| 4710 * @param keyword the token representing the 'final', 'const' or 'var' keyword
, or `null` if | |
| 4711 * there is no keyword | |
| 4712 * @param type the type of the variables in the list | |
| 4713 * @return the variable declaration list that was parsed | |
| 4714 */ | |
| 4715 VariableDeclarationList parseVariableDeclarationList2(CommentAndMetadata comme
ntAndMetadata, Token keyword, TypeName type) { | |
| 4716 if (type != null && keyword != null && matches3(keyword, Keyword.VAR)) { | |
| 4717 reportError9(ParserErrorCode.VAR_AND_TYPE, keyword, []); | |
| 4718 } | |
| 4719 List<VariableDeclaration> variables = new List<VariableDeclaration>(); | |
| 4720 variables.add(parseVariableDeclaration()); | |
| 4721 while (matches5(TokenType.COMMA)) { | |
| 4722 advance(); | |
| 4723 variables.add(parseVariableDeclaration()); | |
| 4724 } | |
| 4725 return new VariableDeclarationList.full(commentAndMetadata != null ? comment
AndMetadata.comment : null, commentAndMetadata != null ? commentAndMetadata.meta
data : null, keyword, type, variables); | |
| 4726 } | |
| 4727 | |
| 4728 /** | |
| 4729 * Parse a variable declaration statement. | |
| 4730 * | |
| 4731 * <pre> | |
| 4732 * variableDeclarationStatement ::= | |
| 4733 * variableDeclarationList ';' | |
| 4734 * </pre> | |
| 4735 * | |
| 4736 * @param commentAndMetadata the metadata to be associated with the variable d
eclaration | |
| 4737 * statement, or `null` if there is no attempt at parsing the comment
and metadata | |
| 4738 * @return the variable declaration statement that was parsed | |
| 4739 */ | |
| 4740 VariableDeclarationStatement parseVariableDeclarationStatement(CommentAndMetad
ata commentAndMetadata) { | |
| 4741 VariableDeclarationList variableList = parseVariableDeclarationList(commentA
ndMetadata); | |
| 4742 Token semicolon = expect2(TokenType.SEMICOLON); | |
| 4743 return new VariableDeclarationStatement.full(variableList, semicolon); | |
| 4744 } | |
| 4745 | |
| 4746 /** | |
| 4747 * Parse a variable declaration statement. | |
| 4748 * | |
| 4749 * <pre> | |
| 4750 * variableDeclarationStatement ::= | |
| 4751 * variableDeclarationList ';' | |
| 4752 * </pre> | |
| 4753 * | |
| 4754 * @param commentAndMetadata the metadata to be associated with the variable d
eclaration | |
| 4755 * statement, or `null` if there is no attempt at parsing the comment
and metadata | |
| 4756 * @param keyword the token representing the 'final', 'const' or 'var' keyword
, or `null` if | |
| 4757 * there is no keyword | |
| 4758 * @param type the type of the variables in the list | |
| 4759 * @return the variable declaration statement that was parsed | |
| 4760 */ | |
| 4761 VariableDeclarationStatement parseVariableDeclarationStatement2(CommentAndMeta
data commentAndMetadata, Token keyword, TypeName type) { | |
| 4762 VariableDeclarationList variableList = parseVariableDeclarationList2(comment
AndMetadata, keyword, type); | |
| 4763 Token semicolon = expect2(TokenType.SEMICOLON); | |
| 4764 return new VariableDeclarationStatement.full(variableList, semicolon); | |
| 4765 } | |
| 4766 | |
| 4767 /** | |
| 4768 * Parse a while statement. | |
| 4769 * | |
| 4770 * <pre> | |
| 4771 * whileStatement ::= | |
| 4772 * 'while' '(' expression ')' statement | |
| 4773 * </pre> | |
| 4774 * | |
| 4775 * @return the while statement that was parsed | |
| 4776 */ | |
| 4777 Statement parseWhileStatement() { | |
| 4778 bool wasInLoop = _inLoop; | |
| 4779 _inLoop = true; | |
| 4780 try { | |
| 4781 Token keyword = expect(Keyword.WHILE); | |
| 4782 Token leftParenthesis = expect2(TokenType.OPEN_PAREN); | |
| 4783 Expression condition = parseExpression2(); | |
| 4784 Token rightParenthesis = expect2(TokenType.CLOSE_PAREN); | |
| 4785 Statement body = parseStatement2(); | |
| 4786 return new WhileStatement.full(keyword, leftParenthesis, condition, rightP
arenthesis, body); | |
| 4787 } finally { | |
| 4788 _inLoop = wasInLoop; | |
| 4789 } | |
| 4790 } | |
| 4791 | |
| 4792 /** | |
| 4793 * Parse a with clause. | |
| 4794 * | |
| 4795 * <pre> | |
| 4796 * withClause ::= | |
| 4797 * 'with' typeName (',' typeName)* | |
| 4798 * </pre> | |
| 4799 * | |
| 4800 * @return the with clause that was parsed | |
| 4801 */ | |
| 4802 WithClause parseWithClause() { | |
| 4803 Token with2 = expect(Keyword.WITH); | |
| 4804 List<TypeName> types = new List<TypeName>(); | |
| 4805 types.add(parseTypeName()); | |
| 4806 while (optional(TokenType.COMMA)) { | |
| 4807 types.add(parseTypeName()); | |
| 4808 } | |
| 4809 return new WithClause.full(with2, types); | |
| 4810 } | |
| 4811 | |
| 4812 /** | |
| 4813 * Return the token that is immediately after the current token. This is equiv
alent to | |
| 4814 * [peek]. | |
| 4815 * | |
| 4816 * @return the token that is immediately after the current token | |
| 4817 */ | |
| 4818 Token peek() => _currentToken.next; | |
| 4819 | |
| 4820 /** | |
| 4821 * Return the token that is the given distance after the current token. | |
| 4822 * | |
| 4823 * @param distance the number of tokens to look ahead, where `0` is the curren
t token, | |
| 4824 * `1` is the next token, etc. | |
| 4825 * @return the token that is the given distance after the current token | |
| 4826 */ | |
| 4827 Token peek2(int distance) { | |
| 4828 Token token = _currentToken; | |
| 4829 for (int i = 0; i < distance; i++) { | |
| 4830 token = token.next; | |
| 4831 } | |
| 4832 return token; | |
| 4833 } | |
| 4834 | |
| 4835 /** | |
| 4836 * Report an error with the given error code and arguments. | |
| 4837 * | |
| 4838 * @param errorCode the error code of the error to be reported | |
| 4839 * @param node the node specifying the location of the error | |
| 4840 * @param arguments the arguments to the error, used to compose the error mess
age | |
| 4841 */ | |
| 4842 void reportError(ParserErrorCode errorCode, ASTNode node, List<Object> argumen
ts) { | |
| 4843 _errorListener.onError(new AnalysisError.con2(_source, node.offset, node.len
gth, errorCode, arguments)); | |
| 4844 } | |
| 4845 | |
| 4846 /** | |
| 4847 * Report an error with the given error code and arguments. | |
| 4848 * | |
| 4849 * @param errorCode the error code of the error to be reported | |
| 4850 * @param arguments the arguments to the error, used to compose the error mess
age | |
| 4851 */ | |
| 4852 void reportError8(ParserErrorCode errorCode, List<Object> arguments) { | |
| 4853 reportError9(errorCode, _currentToken, arguments); | |
| 4854 } | |
| 4855 | |
| 4856 /** | |
| 4857 * Report an error with the given error code and arguments. | |
| 4858 * | |
| 4859 * @param errorCode the error code of the error to be reported | |
| 4860 * @param token the token specifying the location of the error | |
| 4861 * @param arguments the arguments to the error, used to compose the error mess
age | |
| 4862 */ | |
| 4863 void reportError9(ParserErrorCode errorCode, Token token, List<Object> argumen
ts) { | |
| 4864 _errorListener.onError(new AnalysisError.con2(_source, token.offset, token.l
ength, errorCode, arguments)); | |
| 4865 } | |
| 4866 | |
| 4867 /** | |
| 4868 * Look for user defined tasks in comments and convert them into info level an
alysis issues. | |
| 4869 * | |
| 4870 * @param commentToken the comment token to analyze | |
| 4871 */ | |
| 4872 void scrapeTodoComment(Token commentToken) { | |
| 4873 JavaPatternMatcher matcher = new JavaPatternMatcher(TodoCode.TODO_REGEX, com
mentToken.lexeme); | |
| 4874 if (matcher.find()) { | |
| 4875 int offset = commentToken.offset + matcher.start() + matcher.group(1).leng
th; | |
| 4876 int length = matcher.group(2).length; | |
| 4877 // _errorListener.onError(new AnalysisError.con2(_source, offset, length,
TodoCode.TODO, [matcher.group(2)])); | |
| 4878 } | |
| 4879 } | |
| 4880 | |
| 4881 /** | |
| 4882 * Parse the 'final', 'const', 'var' or type preceding a variable declaration,
starting at the | |
| 4883 * given token, without actually creating a type or changing the current token
. Return the token | |
| 4884 * following the type that was parsed, or `null` if the given token is not the
first token | |
| 4885 * in a valid type. | |
| 4886 * | |
| 4887 * <pre> | |
| 4888 * finalConstVarOrType ::= | |
| 4889 * | 'final' type? | |
| 4890 * | 'const' type? | |
| 4891 * | 'var' | |
| 4892 * | type | |
| 4893 * </pre> | |
| 4894 * | |
| 4895 * @param startToken the token at which parsing is to begin | |
| 4896 * @return the token following the type that was parsed | |
| 4897 */ | |
| 4898 Token skipFinalConstVarOrType(Token startToken) { | |
| 4899 if (matches3(startToken, Keyword.FINAL) || matches3(startToken, Keyword.CONS
T)) { | |
| 4900 Token next = startToken.next; | |
| 4901 if (matchesIdentifier2(next.next) || matches4(next.next, TokenType.LT) ||
matches3(next.next, Keyword.THIS)) { | |
| 4902 return skipTypeName(next); | |
| 4903 } | |
| 4904 } else if (matches3(startToken, Keyword.VAR)) { | |
| 4905 return startToken.next; | |
| 4906 } else if (matchesIdentifier2(startToken)) { | |
| 4907 Token next = startToken.next; | |
| 4908 if (matchesIdentifier2(next) || matches4(next, TokenType.LT) || matches3(n
ext, Keyword.THIS) || (matches4(next, TokenType.PERIOD) && matchesIdentifier2(ne
xt.next) && (matchesIdentifier2(next.next.next) || matches4(next.next.next, Toke
nType.LT) || matches3(next.next.next, Keyword.THIS)))) { | |
| 4909 return skipReturnType(startToken); | |
| 4910 } | |
| 4911 } | |
| 4912 return null; | |
| 4913 } | |
| 4914 | |
| 4915 /** | |
| 4916 * Parse a list of formal parameters, starting at the given token, without act
ually creating a | |
| 4917 * formal parameter list or changing the current token. Return the token follo
wing the formal | |
| 4918 * parameter list that was parsed, or `null` if the given token is not the fir
st token in a | |
| 4919 * valid list of formal parameter. | |
| 4920 * | |
| 4921 * Note that unlike other skip methods, this method uses a heuristic. In the w
orst case, the | |
| 4922 * parameters could be prefixed by metadata, which would require us to be able
to skip arbitrary | |
| 4923 * expressions. Rather than duplicate the logic of most of the parse methods w
e simply look for | |
| 4924 * something that is likely to be a list of parameters and then skip to return
ing the token after | |
| 4925 * the closing parenthesis. | |
| 4926 * | |
| 4927 * This method must be kept in sync with [parseFormalParameterList]. | |
| 4928 * | |
| 4929 * <pre> | |
| 4930 * formalParameterList ::= | |
| 4931 * '(' ')' | |
| 4932 * | '(' normalFormalParameters (',' optionalFormalParameters)? ')' | |
| 4933 * | '(' optionalFormalParameters ')' | |
| 4934 * | |
| 4935 * normalFormalParameters ::= | |
| 4936 * normalFormalParameter (',' normalFormalParameter)* | |
| 4937 * | |
| 4938 * optionalFormalParameters ::= | |
| 4939 * optionalPositionalFormalParameters | |
| 4940 * | namedFormalParameters | |
| 4941 * | |
| 4942 * optionalPositionalFormalParameters ::= | |
| 4943 * '[' defaultFormalParameter (',' defaultFormalParameter)* ']' | |
| 4944 * | |
| 4945 * namedFormalParameters ::= | |
| 4946 * '{' defaultNamedParameter (',' defaultNamedParameter)* '}' | |
| 4947 * </pre> | |
| 4948 * | |
| 4949 * @param startToken the token at which parsing is to begin | |
| 4950 * @return the token following the formal parameter list that was parsed | |
| 4951 */ | |
| 4952 Token skipFormalParameterList(Token startToken) { | |
| 4953 if (!matches4(startToken, TokenType.OPEN_PAREN)) { | |
| 4954 return null; | |
| 4955 } | |
| 4956 Token next = startToken.next; | |
| 4957 if (matches4(next, TokenType.CLOSE_PAREN)) { | |
| 4958 return next.next; | |
| 4959 } | |
| 4960 if (matchesAny(next, [ | |
| 4961 TokenType.AT, | |
| 4962 TokenType.OPEN_SQUARE_BRACKET, | |
| 4963 TokenType.OPEN_CURLY_BRACKET]) || matches3(next, Keyword.VOID) || (match
esIdentifier2(next) && (matchesAny(next.next, [TokenType.COMMA, TokenType.CLOSE_
PAREN])))) { | |
| 4964 return skipPastMatchingToken(startToken); | |
| 4965 } | |
| 4966 if (matchesIdentifier2(next) && matches4(next.next, TokenType.OPEN_PAREN)) { | |
| 4967 Token afterParameters = skipFormalParameterList(next.next); | |
| 4968 if (afterParameters != null && (matchesAny(afterParameters, [TokenType.COM
MA, TokenType.CLOSE_PAREN]))) { | |
| 4969 return skipPastMatchingToken(startToken); | |
| 4970 } | |
| 4971 } | |
| 4972 Token afterType = skipFinalConstVarOrType(next); | |
| 4973 if (afterType == null) { | |
| 4974 return null; | |
| 4975 } | |
| 4976 if (skipSimpleIdentifier(afterType) == null) { | |
| 4977 return null; | |
| 4978 } | |
| 4979 return skipPastMatchingToken(startToken); | |
| 4980 } | |
| 4981 | |
| 4982 /** | |
| 4983 * If the given token is a begin token with an associated end token, then retu
rn the token | |
| 4984 * following the end token. Otherwise, return `null`. | |
| 4985 * | |
| 4986 * @param startToken the token that is assumed to be a being token | |
| 4987 * @return the token following the matching end token | |
| 4988 */ | |
| 4989 Token skipPastMatchingToken(Token startToken) { | |
| 4990 if (startToken is! BeginToken) { | |
| 4991 return null; | |
| 4992 } | |
| 4993 Token closeParen = ((startToken as BeginToken)).endToken; | |
| 4994 if (closeParen == null) { | |
| 4995 return null; | |
| 4996 } | |
| 4997 return closeParen.next; | |
| 4998 } | |
| 4999 | |
| 5000 /** | |
| 5001 * Parse a prefixed identifier, starting at the given token, without actually
creating a prefixed | |
| 5002 * identifier or changing the current token. Return the token following the pr
efixed identifier | |
| 5003 * that was parsed, or `null` if the given token is not the first token in a v
alid prefixed | |
| 5004 * identifier. | |
| 5005 * | |
| 5006 * This method must be kept in sync with [parsePrefixedIdentifier]. | |
| 5007 * | |
| 5008 * <pre> | |
| 5009 * prefixedIdentifier ::= | |
| 5010 * identifier ('.' identifier)? | |
| 5011 * </pre> | |
| 5012 * | |
| 5013 * @param startToken the token at which parsing is to begin | |
| 5014 * @return the token following the prefixed identifier that was parsed | |
| 5015 */ | |
| 5016 Token skipPrefixedIdentifier(Token startToken) { | |
| 5017 Token token = skipSimpleIdentifier(startToken); | |
| 5018 if (token == null) { | |
| 5019 return null; | |
| 5020 } else if (!matches4(token, TokenType.PERIOD)) { | |
| 5021 return token; | |
| 5022 } | |
| 5023 return skipSimpleIdentifier(token.next); | |
| 5024 } | |
| 5025 | |
| 5026 /** | |
| 5027 * Parse a return type, starting at the given token, without actually creating
a return type or | |
| 5028 * changing the current token. Return the token following the return type that
was parsed, or | |
| 5029 * `null` if the given token is not the first token in a valid return type. | |
| 5030 * | |
| 5031 * This method must be kept in sync with [parseReturnType]. | |
| 5032 * | |
| 5033 * <pre> | |
| 5034 * returnType ::= | |
| 5035 * 'void' | |
| 5036 * | type | |
| 5037 * </pre> | |
| 5038 * | |
| 5039 * @param startToken the token at which parsing is to begin | |
| 5040 * @return the token following the return type that was parsed | |
| 5041 */ | |
| 5042 Token skipReturnType(Token startToken) { | |
| 5043 if (matches3(startToken, Keyword.VOID)) { | |
| 5044 return startToken.next; | |
| 5045 } else { | |
| 5046 return skipTypeName(startToken); | |
| 5047 } | |
| 5048 } | |
| 5049 | |
| 5050 /** | |
| 5051 * Parse a simple identifier, starting at the given token, without actually cr
eating a simple | |
| 5052 * identifier or changing the current token. Return the token following the si
mple identifier that | |
| 5053 * was parsed, or `null` if the given token is not the first token in a valid
simple | |
| 5054 * identifier. | |
| 5055 * | |
| 5056 * This method must be kept in sync with [parseSimpleIdentifier]. | |
| 5057 * | |
| 5058 * <pre> | |
| 5059 * identifier ::= | |
| 5060 * IDENTIFIER | |
| 5061 * </pre> | |
| 5062 * | |
| 5063 * @param startToken the token at which parsing is to begin | |
| 5064 * @return the token following the simple identifier that was parsed | |
| 5065 */ | |
| 5066 Token skipSimpleIdentifier(Token startToken) { | |
| 5067 if (matches4(startToken, TokenType.IDENTIFIER) || (matches4(startToken, Toke
nType.KEYWORD) && ((startToken as KeywordToken)).keyword.isPseudoKeyword)) { | |
| 5068 return startToken.next; | |
| 5069 } | |
| 5070 return null; | |
| 5071 } | |
| 5072 | |
| 5073 /** | |
| 5074 * Parse a string literal that contains interpolations, starting at the given
token, without | |
| 5075 * actually creating a string literal or changing the current token. Return th
e token following | |
| 5076 * the string literal that was parsed, or `null` if the given token is not the
first token | |
| 5077 * in a valid string literal. | |
| 5078 * | |
| 5079 * This method must be kept in sync with [parseStringInterpolation]. | |
| 5080 * | |
| 5081 * @param startToken the token at which parsing is to begin | |
| 5082 * @return the string literal that was parsed | |
| 5083 */ | |
| 5084 Token skipStringInterpolation(Token startToken) { | |
| 5085 Token token = startToken; | |
| 5086 TokenType type = token.type; | |
| 5087 while (identical(type, TokenType.STRING_INTERPOLATION_EXPRESSION) || identic
al(type, TokenType.STRING_INTERPOLATION_IDENTIFIER)) { | |
| 5088 if (identical(type, TokenType.STRING_INTERPOLATION_EXPRESSION)) { | |
| 5089 token = token.next; | |
| 5090 type = token.type; | |
| 5091 int bracketNestingLevel = 1; | |
| 5092 while (bracketNestingLevel > 0) { | |
| 5093 if (identical(type, TokenType.EOF)) { | |
| 5094 return null; | |
| 5095 } else if (identical(type, TokenType.OPEN_CURLY_BRACKET)) { | |
| 5096 bracketNestingLevel++; | |
| 5097 } else if (identical(type, TokenType.CLOSE_CURLY_BRACKET)) { | |
| 5098 bracketNestingLevel--; | |
| 5099 } else if (identical(type, TokenType.STRING)) { | |
| 5100 token = skipStringLiteral(token); | |
| 5101 if (token == null) { | |
| 5102 return null; | |
| 5103 } | |
| 5104 } else { | |
| 5105 token = token.next; | |
| 5106 } | |
| 5107 type = token.type; | |
| 5108 } | |
| 5109 token = token.next; | |
| 5110 type = token.type; | |
| 5111 } else { | |
| 5112 token = token.next; | |
| 5113 if (token.type != TokenType.IDENTIFIER) { | |
| 5114 return null; | |
| 5115 } | |
| 5116 token = token.next; | |
| 5117 } | |
| 5118 type = token.type; | |
| 5119 if (identical(type, TokenType.STRING)) { | |
| 5120 token = token.next; | |
| 5121 type = token.type; | |
| 5122 } | |
| 5123 } | |
| 5124 return token; | |
| 5125 } | |
| 5126 | |
| 5127 /** | |
| 5128 * Parse a string literal, starting at the given token, without actually creat
ing a string literal | |
| 5129 * or changing the current token. Return the token following the string litera
l that was parsed, | |
| 5130 * or `null` if the given token is not the first token in a valid string liter
al. | |
| 5131 * | |
| 5132 * This method must be kept in sync with [parseStringLiteral]. | |
| 5133 * | |
| 5134 * <pre> | |
| 5135 * stringLiteral ::= | |
| 5136 * MULTI_LINE_STRING+ | |
| 5137 * | SINGLE_LINE_STRING+ | |
| 5138 * </pre> | |
| 5139 * | |
| 5140 * @param startToken the token at which parsing is to begin | |
| 5141 * @return the token following the string literal that was parsed | |
| 5142 */ | |
| 5143 Token skipStringLiteral(Token startToken) { | |
| 5144 Token token = startToken; | |
| 5145 while (token != null && matches4(token, TokenType.STRING)) { | |
| 5146 token = token.next; | |
| 5147 TokenType type = token.type; | |
| 5148 if (identical(type, TokenType.STRING_INTERPOLATION_EXPRESSION) || identica
l(type, TokenType.STRING_INTERPOLATION_IDENTIFIER)) { | |
| 5149 token = skipStringInterpolation(token); | |
| 5150 } | |
| 5151 } | |
| 5152 if (identical(token, startToken)) { | |
| 5153 return null; | |
| 5154 } | |
| 5155 return token; | |
| 5156 } | |
| 5157 | |
| 5158 /** | |
| 5159 * Parse a list of type arguments, starting at the given token, without actual
ly creating a type argument list | |
| 5160 * or changing the current token. Return the token following the type argument
list that was parsed, | |
| 5161 * or `null` if the given token is not the first token in a valid type argumen
t list. | |
| 5162 * | |
| 5163 * This method must be kept in sync with [parseTypeArgumentList]. | |
| 5164 * | |
| 5165 * <pre> | |
| 5166 * typeArguments ::= | |
| 5167 * '<' typeList '>' | |
| 5168 * | |
| 5169 * typeList ::= | |
| 5170 * type (',' type)* | |
| 5171 * </pre> | |
| 5172 * | |
| 5173 * @param startToken the token at which parsing is to begin | |
| 5174 * @return the token following the type argument list that was parsed | |
| 5175 */ | |
| 5176 Token skipTypeArgumentList(Token startToken) { | |
| 5177 Token token = startToken; | |
| 5178 if (!matches4(token, TokenType.LT)) { | |
| 5179 return null; | |
| 5180 } | |
| 5181 token = skipTypeName(token.next); | |
| 5182 if (token == null) { | |
| 5183 return null; | |
| 5184 } | |
| 5185 while (matches4(token, TokenType.COMMA)) { | |
| 5186 token = skipTypeName(token.next); | |
| 5187 if (token == null) { | |
| 5188 return null; | |
| 5189 } | |
| 5190 } | |
| 5191 if (identical(token.type, TokenType.GT)) { | |
| 5192 return token.next; | |
| 5193 } else if (identical(token.type, TokenType.GT_GT)) { | |
| 5194 Token second = new Token(TokenType.GT, token.offset + 1); | |
| 5195 second.setNextWithoutSettingPrevious(token.next); | |
| 5196 return second; | |
| 5197 } | |
| 5198 return null; | |
| 5199 } | |
| 5200 | |
| 5201 /** | |
| 5202 * Parse a type name, starting at the given token, without actually creating a
type name or | |
| 5203 * changing the current token. Return the token following the type name that w
as parsed, or | |
| 5204 * `null` if the given token is not the first token in a valid type name. | |
| 5205 * | |
| 5206 * This method must be kept in sync with [parseTypeName]. | |
| 5207 * | |
| 5208 * <pre> | |
| 5209 * type ::= | |
| 5210 * qualified typeArguments? | |
| 5211 * </pre> | |
| 5212 * | |
| 5213 * @param startToken the token at which parsing is to begin | |
| 5214 * @return the token following the type name that was parsed | |
| 5215 */ | |
| 5216 Token skipTypeName(Token startToken) { | |
| 5217 Token token = skipPrefixedIdentifier(startToken); | |
| 5218 if (token == null) { | |
| 5219 return null; | |
| 5220 } | |
| 5221 if (matches4(token, TokenType.LT)) { | |
| 5222 token = skipTypeArgumentList(token); | |
| 5223 } | |
| 5224 return token; | |
| 5225 } | |
| 5226 | |
| 5227 /** | |
| 5228 * Parse a list of type parameters, starting at the given token, without actua
lly creating a type | |
| 5229 * parameter list or changing the current token. Return the token following th
e type parameter | |
| 5230 * list that was parsed, or `null` if the given token is not the first token i
n a valid type | |
| 5231 * parameter list. | |
| 5232 * | |
| 5233 * This method must be kept in sync with [parseTypeParameterList]. | |
| 5234 * | |
| 5235 * <pre> | |
| 5236 * typeParameterList ::= | |
| 5237 * '<' typeParameter (',' typeParameter)* '>' | |
| 5238 * </pre> | |
| 5239 * | |
| 5240 * @param startToken the token at which parsing is to begin | |
| 5241 * @return the token following the type parameter list that was parsed | |
| 5242 */ | |
| 5243 Token skipTypeParameterList(Token startToken) { | |
| 5244 if (!matches4(startToken, TokenType.LT)) { | |
| 5245 return null; | |
| 5246 } | |
| 5247 int depth = 1; | |
| 5248 Token next = startToken.next; | |
| 5249 while (depth > 0) { | |
| 5250 if (matches4(next, TokenType.EOF)) { | |
| 5251 return null; | |
| 5252 } else if (matches4(next, TokenType.LT)) { | |
| 5253 depth++; | |
| 5254 } else if (matches4(next, TokenType.GT)) { | |
| 5255 depth--; | |
| 5256 } else if (matches4(next, TokenType.GT_EQ)) { | |
| 5257 if (depth == 1) { | |
| 5258 Token fakeEquals = new Token(TokenType.EQ, next.offset + 2); | |
| 5259 fakeEquals.setNextWithoutSettingPrevious(next.next); | |
| 5260 return fakeEquals; | |
| 5261 } | |
| 5262 depth--; | |
| 5263 } else if (matches4(next, TokenType.GT_GT)) { | |
| 5264 depth -= 2; | |
| 5265 } else if (matches4(next, TokenType.GT_GT_EQ)) { | |
| 5266 if (depth < 2) { | |
| 5267 return null; | |
| 5268 } else if (depth == 2) { | |
| 5269 Token fakeEquals = new Token(TokenType.EQ, next.offset + 2); | |
| 5270 fakeEquals.setNextWithoutSettingPrevious(next.next); | |
| 5271 return fakeEquals; | |
| 5272 } | |
| 5273 depth -= 2; | |
| 5274 } | |
| 5275 next = next.next; | |
| 5276 } | |
| 5277 return next; | |
| 5278 } | |
| 5279 | |
| 5280 /** | |
| 5281 * Translate the characters at the given index in the given string, appending
the translated | |
| 5282 * character to the given builder. The index is assumed to be valid. | |
| 5283 * | |
| 5284 * @param builder the builder to which the translated character is to be appen
ded | |
| 5285 * @param lexeme the string containing the character(s) to be translated | |
| 5286 * @param index the index of the character to be translated | |
| 5287 * @return the index of the next character to be translated | |
| 5288 */ | |
| 5289 int translateCharacter(JavaStringBuilder builder, String lexeme, int index) { | |
| 5290 int currentChar = lexeme.codeUnitAt(index); | |
| 5291 if (currentChar != 0x5C) { | |
| 5292 builder.appendChar(currentChar); | |
| 5293 return index + 1; | |
| 5294 } | |
| 5295 int length = lexeme.length; | |
| 5296 int currentIndex = index + 1; | |
| 5297 if (currentIndex >= length) { | |
| 5298 return length; | |
| 5299 } | |
| 5300 currentChar = lexeme.codeUnitAt(currentIndex); | |
| 5301 if (currentChar == 0x6E) { | |
| 5302 builder.appendChar(0xA); | |
| 5303 } else if (currentChar == 0x72) { | |
| 5304 builder.appendChar(0xD); | |
| 5305 } else if (currentChar == 0x66) { | |
| 5306 builder.appendChar(0xC); | |
| 5307 } else if (currentChar == 0x62) { | |
| 5308 builder.appendChar(0x8); | |
| 5309 } else if (currentChar == 0x74) { | |
| 5310 builder.appendChar(0x9); | |
| 5311 } else if (currentChar == 0x76) { | |
| 5312 builder.appendChar(0xB); | |
| 5313 } else if (currentChar == 0x78) { | |
| 5314 if (currentIndex + 2 >= length) { | |
| 5315 reportError8(ParserErrorCode.INVALID_HEX_ESCAPE, []); | |
| 5316 return length; | |
| 5317 } | |
| 5318 int firstDigit = lexeme.codeUnitAt(currentIndex + 1); | |
| 5319 int secondDigit = lexeme.codeUnitAt(currentIndex + 2); | |
| 5320 if (!isHexDigit(firstDigit) || !isHexDigit(secondDigit)) { | |
| 5321 reportError8(ParserErrorCode.INVALID_HEX_ESCAPE, []); | |
| 5322 } else { | |
| 5323 builder.appendChar(((Character.digit(firstDigit, 16) << 4) + Character.d
igit(secondDigit, 16)) as int); | |
| 5324 } | |
| 5325 return currentIndex + 3; | |
| 5326 } else if (currentChar == 0x75) { | |
| 5327 currentIndex++; | |
| 5328 if (currentIndex >= length) { | |
| 5329 reportError8(ParserErrorCode.INVALID_UNICODE_ESCAPE, []); | |
| 5330 return length; | |
| 5331 } | |
| 5332 currentChar = lexeme.codeUnitAt(currentIndex); | |
| 5333 if (currentChar == 0x7B) { | |
| 5334 currentIndex++; | |
| 5335 if (currentIndex >= length) { | |
| 5336 reportError8(ParserErrorCode.INVALID_UNICODE_ESCAPE, []); | |
| 5337 return length; | |
| 5338 } | |
| 5339 currentChar = lexeme.codeUnitAt(currentIndex); | |
| 5340 int digitCount = 0; | |
| 5341 int value = 0; | |
| 5342 while (currentChar != 0x7D) { | |
| 5343 if (!isHexDigit(currentChar)) { | |
| 5344 reportError8(ParserErrorCode.INVALID_UNICODE_ESCAPE, []); | |
| 5345 currentIndex++; | |
| 5346 while (currentIndex < length && lexeme.codeUnitAt(currentIndex) != 0
x7D) { | |
| 5347 currentIndex++; | |
| 5348 } | |
| 5349 return currentIndex + 1; | |
| 5350 } | |
| 5351 digitCount++; | |
| 5352 value = (value << 4) + Character.digit(currentChar, 16); | |
| 5353 currentIndex++; | |
| 5354 if (currentIndex >= length) { | |
| 5355 reportError8(ParserErrorCode.INVALID_UNICODE_ESCAPE, []); | |
| 5356 return length; | |
| 5357 } | |
| 5358 currentChar = lexeme.codeUnitAt(currentIndex); | |
| 5359 } | |
| 5360 if (digitCount < 1 || digitCount > 6) { | |
| 5361 reportError8(ParserErrorCode.INVALID_UNICODE_ESCAPE, []); | |
| 5362 } | |
| 5363 appendScalarValue(builder, lexeme.substring(index, currentIndex + 1), va
lue, index, currentIndex); | |
| 5364 return currentIndex + 1; | |
| 5365 } else { | |
| 5366 if (currentIndex + 3 >= length) { | |
| 5367 reportError8(ParserErrorCode.INVALID_UNICODE_ESCAPE, []); | |
| 5368 return length; | |
| 5369 } | |
| 5370 int firstDigit = currentChar; | |
| 5371 int secondDigit = lexeme.codeUnitAt(currentIndex + 1); | |
| 5372 int thirdDigit = lexeme.codeUnitAt(currentIndex + 2); | |
| 5373 int fourthDigit = lexeme.codeUnitAt(currentIndex + 3); | |
| 5374 if (!isHexDigit(firstDigit) || !isHexDigit(secondDigit) || !isHexDigit(t
hirdDigit) || !isHexDigit(fourthDigit)) { | |
| 5375 reportError8(ParserErrorCode.INVALID_UNICODE_ESCAPE, []); | |
| 5376 } else { | |
| 5377 appendScalarValue(builder, lexeme.substring(index, currentIndex + 1),
(((((Character.digit(firstDigit, 16) << 4) + Character.digit(secondDigit, 16)) <
< 4) + Character.digit(thirdDigit, 16)) << 4) + Character.digit(fourthDigit, 16)
, index, currentIndex + 3); | |
| 5378 } | |
| 5379 return currentIndex + 4; | |
| 5380 } | |
| 5381 } else { | |
| 5382 builder.appendChar(currentChar); | |
| 5383 } | |
| 5384 return currentIndex + 1; | |
| 5385 } | |
| 5386 | |
| 5387 /** | |
| 5388 * Validate that the given parameter list does not contain any field initializ
ers. | |
| 5389 * | |
| 5390 * @param parameterList the parameter list to be validated | |
| 5391 */ | |
| 5392 void validateFormalParameterList(FormalParameterList parameterList) { | |
| 5393 for (FormalParameter parameter in parameterList.parameters) { | |
| 5394 if (parameter is FieldFormalParameter) { | |
| 5395 reportError(ParserErrorCode.FIELD_INITIALIZER_OUTSIDE_CONSTRUCTOR, ((par
ameter as FieldFormalParameter)).identifier, []); | |
| 5396 } | |
| 5397 } | |
| 5398 } | |
| 5399 | |
| 5400 /** | |
| 5401 * Validate that the given set of modifiers is appropriate for a class and ret
urn the 'abstract' | |
| 5402 * keyword if there is one. | |
| 5403 * | |
| 5404 * @param modifiers the modifiers being validated | |
| 5405 */ | |
| 5406 Token validateModifiersForClass(Modifiers modifiers) { | |
| 5407 validateModifiersForTopLevelDeclaration(modifiers); | |
| 5408 if (modifiers.constKeyword != null) { | |
| 5409 reportError9(ParserErrorCode.CONST_CLASS, modifiers.constKeyword, []); | |
| 5410 } | |
| 5411 if (modifiers.externalKeyword != null) { | |
| 5412 reportError9(ParserErrorCode.EXTERNAL_CLASS, modifiers.externalKeyword, []
); | |
| 5413 } | |
| 5414 if (modifiers.finalKeyword != null) { | |
| 5415 reportError9(ParserErrorCode.FINAL_CLASS, modifiers.finalKeyword, []); | |
| 5416 } | |
| 5417 if (modifiers.varKeyword != null) { | |
| 5418 reportError9(ParserErrorCode.VAR_CLASS, modifiers.varKeyword, []); | |
| 5419 } | |
| 5420 return modifiers.abstractKeyword; | |
| 5421 } | |
| 5422 | |
| 5423 /** | |
| 5424 * Validate that the given set of modifiers is appropriate for a constructor a
nd return the | |
| 5425 * 'const' keyword if there is one. | |
| 5426 * | |
| 5427 * @param modifiers the modifiers being validated | |
| 5428 * @return the 'const' or 'final' keyword associated with the constructor | |
| 5429 */ | |
| 5430 Token validateModifiersForConstructor(Modifiers modifiers) { | |
| 5431 if (modifiers.abstractKeyword != null) { | |
| 5432 reportError8(ParserErrorCode.ABSTRACT_CLASS_MEMBER, []); | |
| 5433 } | |
| 5434 if (modifiers.finalKeyword != null) { | |
| 5435 reportError9(ParserErrorCode.FINAL_CONSTRUCTOR, modifiers.finalKeyword, []
); | |
| 5436 } | |
| 5437 if (modifiers.staticKeyword != null) { | |
| 5438 reportError9(ParserErrorCode.STATIC_CONSTRUCTOR, modifiers.staticKeyword,
[]); | |
| 5439 } | |
| 5440 if (modifiers.varKeyword != null) { | |
| 5441 reportError9(ParserErrorCode.CONSTRUCTOR_WITH_RETURN_TYPE, modifiers.varKe
yword, []); | |
| 5442 } | |
| 5443 Token externalKeyword = modifiers.externalKeyword; | |
| 5444 Token constKeyword = modifiers.constKeyword; | |
| 5445 Token factoryKeyword = modifiers.factoryKeyword; | |
| 5446 if (externalKeyword != null && constKeyword != null && constKeyword.offset <
externalKeyword.offset) { | |
| 5447 reportError9(ParserErrorCode.EXTERNAL_AFTER_CONST, externalKeyword, []); | |
| 5448 } | |
| 5449 if (externalKeyword != null && factoryKeyword != null && factoryKeyword.offs
et < externalKeyword.offset) { | |
| 5450 reportError9(ParserErrorCode.EXTERNAL_AFTER_FACTORY, externalKeyword, []); | |
| 5451 } | |
| 5452 return constKeyword; | |
| 5453 } | |
| 5454 | |
| 5455 /** | |
| 5456 * Validate that the given set of modifiers is appropriate for a field and ret
urn the 'final', | |
| 5457 * 'const' or 'var' keyword if there is one. | |
| 5458 * | |
| 5459 * @param modifiers the modifiers being validated | |
| 5460 * @return the 'final', 'const' or 'var' keyword associated with the field | |
| 5461 */ | |
| 5462 Token validateModifiersForField(Modifiers modifiers) { | |
| 5463 if (modifiers.abstractKeyword != null) { | |
| 5464 reportError8(ParserErrorCode.ABSTRACT_CLASS_MEMBER, []); | |
| 5465 } | |
| 5466 if (modifiers.externalKeyword != null) { | |
| 5467 reportError9(ParserErrorCode.EXTERNAL_FIELD, modifiers.externalKeyword, []
); | |
| 5468 } | |
| 5469 if (modifiers.factoryKeyword != null) { | |
| 5470 reportError9(ParserErrorCode.NON_CONSTRUCTOR_FACTORY, modifiers.factoryKey
word, []); | |
| 5471 } | |
| 5472 Token staticKeyword = modifiers.staticKeyword; | |
| 5473 Token constKeyword = modifiers.constKeyword; | |
| 5474 Token finalKeyword = modifiers.finalKeyword; | |
| 5475 Token varKeyword = modifiers.varKeyword; | |
| 5476 if (constKeyword != null) { | |
| 5477 if (finalKeyword != null) { | |
| 5478 reportError9(ParserErrorCode.CONST_AND_FINAL, finalKeyword, []); | |
| 5479 } | |
| 5480 if (varKeyword != null) { | |
| 5481 reportError9(ParserErrorCode.CONST_AND_VAR, varKeyword, []); | |
| 5482 } | |
| 5483 if (staticKeyword != null && constKeyword.offset < staticKeyword.offset) { | |
| 5484 reportError9(ParserErrorCode.STATIC_AFTER_CONST, staticKeyword, []); | |
| 5485 } | |
| 5486 } else if (finalKeyword != null) { | |
| 5487 if (varKeyword != null) { | |
| 5488 reportError9(ParserErrorCode.FINAL_AND_VAR, varKeyword, []); | |
| 5489 } | |
| 5490 if (staticKeyword != null && finalKeyword.offset < staticKeyword.offset) { | |
| 5491 reportError9(ParserErrorCode.STATIC_AFTER_FINAL, staticKeyword, []); | |
| 5492 } | |
| 5493 } else if (varKeyword != null && staticKeyword != null && varKeyword.offset
< staticKeyword.offset) { | |
| 5494 reportError9(ParserErrorCode.STATIC_AFTER_VAR, staticKeyword, []); | |
| 5495 } | |
| 5496 return lexicallyFirst([constKeyword, finalKeyword, varKeyword]); | |
| 5497 } | |
| 5498 | |
| 5499 /** | |
| 5500 * Validate that the given set of modifiers is appropriate for a local functio
n. | |
| 5501 * | |
| 5502 * @param modifiers the modifiers being validated | |
| 5503 */ | |
| 5504 void validateModifiersForFunctionDeclarationStatement(Modifiers modifiers) { | |
| 5505 if (modifiers.abstractKeyword != null || modifiers.constKeyword != null || m
odifiers.externalKeyword != null || modifiers.factoryKeyword != null || modifier
s.finalKeyword != null || modifiers.staticKeyword != null || modifiers.varKeywor
d != null) { | |
| 5506 reportError8(ParserErrorCode.LOCAL_FUNCTION_DECLARATION_MODIFIER, []); | |
| 5507 } | |
| 5508 } | |
| 5509 | |
| 5510 /** | |
| 5511 * Validate that the given set of modifiers is appropriate for a getter, sette
r, or method. | |
| 5512 * | |
| 5513 * @param modifiers the modifiers being validated | |
| 5514 */ | |
| 5515 void validateModifiersForGetterOrSetterOrMethod(Modifiers modifiers) { | |
| 5516 if (modifiers.abstractKeyword != null) { | |
| 5517 reportError8(ParserErrorCode.ABSTRACT_CLASS_MEMBER, []); | |
| 5518 } | |
| 5519 if (modifiers.constKeyword != null) { | |
| 5520 reportError9(ParserErrorCode.CONST_METHOD, modifiers.constKeyword, []); | |
| 5521 } | |
| 5522 if (modifiers.factoryKeyword != null) { | |
| 5523 reportError9(ParserErrorCode.NON_CONSTRUCTOR_FACTORY, modifiers.factoryKey
word, []); | |
| 5524 } | |
| 5525 if (modifiers.finalKeyword != null) { | |
| 5526 reportError9(ParserErrorCode.FINAL_METHOD, modifiers.finalKeyword, []); | |
| 5527 } | |
| 5528 if (modifiers.varKeyword != null) { | |
| 5529 reportError9(ParserErrorCode.VAR_RETURN_TYPE, modifiers.varKeyword, []); | |
| 5530 } | |
| 5531 Token externalKeyword = modifiers.externalKeyword; | |
| 5532 Token staticKeyword = modifiers.staticKeyword; | |
| 5533 if (externalKeyword != null && staticKeyword != null && staticKeyword.offset
< externalKeyword.offset) { | |
| 5534 reportError9(ParserErrorCode.EXTERNAL_AFTER_STATIC, externalKeyword, []); | |
| 5535 } | |
| 5536 } | |
| 5537 | |
| 5538 /** | |
| 5539 * Validate that the given set of modifiers is appropriate for a getter, sette
r, or method. | |
| 5540 * | |
| 5541 * @param modifiers the modifiers being validated | |
| 5542 */ | |
| 5543 void validateModifiersForOperator(Modifiers modifiers) { | |
| 5544 if (modifiers.abstractKeyword != null) { | |
| 5545 reportError8(ParserErrorCode.ABSTRACT_CLASS_MEMBER, []); | |
| 5546 } | |
| 5547 if (modifiers.constKeyword != null) { | |
| 5548 reportError9(ParserErrorCode.CONST_METHOD, modifiers.constKeyword, []); | |
| 5549 } | |
| 5550 if (modifiers.factoryKeyword != null) { | |
| 5551 reportError9(ParserErrorCode.NON_CONSTRUCTOR_FACTORY, modifiers.factoryKey
word, []); | |
| 5552 } | |
| 5553 if (modifiers.finalKeyword != null) { | |
| 5554 reportError9(ParserErrorCode.FINAL_METHOD, modifiers.finalKeyword, []); | |
| 5555 } | |
| 5556 if (modifiers.staticKeyword != null) { | |
| 5557 reportError9(ParserErrorCode.STATIC_OPERATOR, modifiers.staticKeyword, [])
; | |
| 5558 } | |
| 5559 if (modifiers.varKeyword != null) { | |
| 5560 reportError9(ParserErrorCode.VAR_RETURN_TYPE, modifiers.varKeyword, []); | |
| 5561 } | |
| 5562 } | |
| 5563 | |
| 5564 /** | |
| 5565 * Validate that the given set of modifiers is appropriate for a top-level dec
laration. | |
| 5566 * | |
| 5567 * @param modifiers the modifiers being validated | |
| 5568 */ | |
| 5569 void validateModifiersForTopLevelDeclaration(Modifiers modifiers) { | |
| 5570 if (modifiers.factoryKeyword != null) { | |
| 5571 reportError9(ParserErrorCode.FACTORY_TOP_LEVEL_DECLARATION, modifiers.fact
oryKeyword, []); | |
| 5572 } | |
| 5573 if (modifiers.staticKeyword != null) { | |
| 5574 reportError9(ParserErrorCode.STATIC_TOP_LEVEL_DECLARATION, modifiers.stati
cKeyword, []); | |
| 5575 } | |
| 5576 } | |
| 5577 | |
| 5578 /** | |
| 5579 * Validate that the given set of modifiers is appropriate for a top-level fun
ction. | |
| 5580 * | |
| 5581 * @param modifiers the modifiers being validated | |
| 5582 */ | |
| 5583 void validateModifiersForTopLevelFunction(Modifiers modifiers) { | |
| 5584 validateModifiersForTopLevelDeclaration(modifiers); | |
| 5585 if (modifiers.abstractKeyword != null) { | |
| 5586 reportError8(ParserErrorCode.ABSTRACT_TOP_LEVEL_FUNCTION, []); | |
| 5587 } | |
| 5588 if (modifiers.constKeyword != null) { | |
| 5589 reportError9(ParserErrorCode.CONST_CLASS, modifiers.constKeyword, []); | |
| 5590 } | |
| 5591 if (modifiers.finalKeyword != null) { | |
| 5592 reportError9(ParserErrorCode.FINAL_CLASS, modifiers.finalKeyword, []); | |
| 5593 } | |
| 5594 if (modifiers.varKeyword != null) { | |
| 5595 reportError9(ParserErrorCode.VAR_RETURN_TYPE, modifiers.varKeyword, []); | |
| 5596 } | |
| 5597 } | |
| 5598 | |
| 5599 /** | |
| 5600 * Validate that the given set of modifiers is appropriate for a field and ret
urn the 'final', | |
| 5601 * 'const' or 'var' keyword if there is one. | |
| 5602 * | |
| 5603 * @param modifiers the modifiers being validated | |
| 5604 * @return the 'final', 'const' or 'var' keyword associated with the field | |
| 5605 */ | |
| 5606 Token validateModifiersForTopLevelVariable(Modifiers modifiers) { | |
| 5607 validateModifiersForTopLevelDeclaration(modifiers); | |
| 5608 if (modifiers.abstractKeyword != null) { | |
| 5609 reportError8(ParserErrorCode.ABSTRACT_TOP_LEVEL_VARIABLE, []); | |
| 5610 } | |
| 5611 if (modifiers.externalKeyword != null) { | |
| 5612 reportError9(ParserErrorCode.EXTERNAL_FIELD, modifiers.externalKeyword, []
); | |
| 5613 } | |
| 5614 Token constKeyword = modifiers.constKeyword; | |
| 5615 Token finalKeyword = modifiers.finalKeyword; | |
| 5616 Token varKeyword = modifiers.varKeyword; | |
| 5617 if (constKeyword != null) { | |
| 5618 if (finalKeyword != null) { | |
| 5619 reportError9(ParserErrorCode.CONST_AND_FINAL, finalKeyword, []); | |
| 5620 } | |
| 5621 if (varKeyword != null) { | |
| 5622 reportError9(ParserErrorCode.CONST_AND_VAR, varKeyword, []); | |
| 5623 } | |
| 5624 } else if (finalKeyword != null) { | |
| 5625 if (varKeyword != null) { | |
| 5626 reportError9(ParserErrorCode.FINAL_AND_VAR, varKeyword, []); | |
| 5627 } | |
| 5628 } | |
| 5629 return lexicallyFirst([constKeyword, finalKeyword, varKeyword]); | |
| 5630 } | |
| 5631 | |
| 5632 /** | |
| 5633 * Validate that the given set of modifiers is appropriate for a class and ret
urn the 'abstract' | |
| 5634 * keyword if there is one. | |
| 5635 * | |
| 5636 * @param modifiers the modifiers being validated | |
| 5637 */ | |
| 5638 void validateModifiersForTypedef(Modifiers modifiers) { | |
| 5639 validateModifiersForTopLevelDeclaration(modifiers); | |
| 5640 if (modifiers.abstractKeyword != null) { | |
| 5641 reportError9(ParserErrorCode.ABSTRACT_TYPEDEF, modifiers.abstractKeyword,
[]); | |
| 5642 } | |
| 5643 if (modifiers.constKeyword != null) { | |
| 5644 reportError9(ParserErrorCode.CONST_TYPEDEF, modifiers.constKeyword, []); | |
| 5645 } | |
| 5646 if (modifiers.externalKeyword != null) { | |
| 5647 reportError9(ParserErrorCode.EXTERNAL_TYPEDEF, modifiers.externalKeyword,
[]); | |
| 5648 } | |
| 5649 if (modifiers.finalKeyword != null) { | |
| 5650 reportError9(ParserErrorCode.FINAL_TYPEDEF, modifiers.finalKeyword, []); | |
| 5651 } | |
| 5652 if (modifiers.varKeyword != null) { | |
| 5653 reportError9(ParserErrorCode.VAR_TYPEDEF, modifiers.varKeyword, []); | |
| 5654 } | |
| 5655 } | |
| 5656 } | |
| 5657 /** | |
| 5658 * Instances of the class `SyntheticKeywordToken` implement a synthetic keyword
token. | |
| 5659 */ | |
| 5660 class Parser_SyntheticKeywordToken extends KeywordToken { | |
| 5661 | |
| 5662 /** | |
| 5663 * Initialize a newly created token to represent the given keyword. | |
| 5664 * | |
| 5665 * @param keyword the keyword being represented by this token | |
| 5666 * @param offset the offset from the beginning of the file to the first charac
ter in the token | |
| 5667 */ | |
| 5668 Parser_SyntheticKeywordToken(Keyword keyword, int offset) : super(keyword, off
set); | |
| 5669 Token copy() => new Parser_SyntheticKeywordToken(keyword, offset); | |
| 5670 int get length => 0; | |
| 5671 } | |
| 5672 class AnalysisErrorListener_15 implements AnalysisErrorListener { | |
| 5673 List<bool> errorFound; | |
| 5674 AnalysisErrorListener_15(this.errorFound); | |
| 5675 void onError(AnalysisError error) { | |
| 5676 errorFound[0] = true; | |
| 5677 } | |
| 5678 } | |
| 5679 /** | |
| 5680 * The enumeration `ParserErrorCode` defines the error codes used for errors det
ected by the | |
| 5681 * parser. The convention for this class is for the name of the error code to in
dicate the problem | |
| 5682 * that caused the error to be generated and for the error message to explain wh
at is wrong and, | |
| 5683 * when appropriate, how the problem can be corrected. | |
| 5684 * | |
| 5685 * @coverage dart.engine.parser | |
| 5686 */ | |
| 5687 class ParserErrorCode extends Enum<ParserErrorCode> implements ErrorCode { | |
| 5688 static final ParserErrorCode ABSTRACT_CLASS_MEMBER = new ParserErrorCode.con3(
'ABSTRACT_CLASS_MEMBER', 0, "Members of classes cannot be declared to be 'abstra
ct'"); | |
| 5689 static final ParserErrorCode ABSTRACT_STATIC_METHOD = new ParserErrorCode.con3
('ABSTRACT_STATIC_METHOD', 1, "Static methods cannot be declared to be 'abstract
'"); | |
| 5690 static final ParserErrorCode ABSTRACT_TOP_LEVEL_FUNCTION = new ParserErrorCode
.con3('ABSTRACT_TOP_LEVEL_FUNCTION', 2, "Top-level functions cannot be declared
to be 'abstract'"); | |
| 5691 static final ParserErrorCode ABSTRACT_TOP_LEVEL_VARIABLE = new ParserErrorCode
.con3('ABSTRACT_TOP_LEVEL_VARIABLE', 3, "Top-level variables cannot be declared
to be 'abstract'"); | |
| 5692 static final ParserErrorCode ABSTRACT_TYPEDEF = new ParserErrorCode.con3('ABST
RACT_TYPEDEF', 4, "Type aliases cannot be declared to be 'abstract'"); | |
| 5693 static final ParserErrorCode ASSERT_DOES_NOT_TAKE_ASSIGNMENT = new ParserError
Code.con3('ASSERT_DOES_NOT_TAKE_ASSIGNMENT', 5, "Assert cannot be called on an a
ssignment"); | |
| 5694 static final ParserErrorCode ASSERT_DOES_NOT_TAKE_CASCADE = new ParserErrorCod
e.con3('ASSERT_DOES_NOT_TAKE_CASCADE', 6, "Assert cannot be called on cascade"); | |
| 5695 static final ParserErrorCode ASSERT_DOES_NOT_TAKE_THROW = new ParserErrorCode.
con3('ASSERT_DOES_NOT_TAKE_THROW', 7, "Assert cannot be called on throws"); | |
| 5696 static final ParserErrorCode ASSERT_DOES_NOT_TAKE_RETHROW = new ParserErrorCod
e.con3('ASSERT_DOES_NOT_TAKE_RETHROW', 8, "Assert cannot be called on rethrows")
; | |
| 5697 static final ParserErrorCode BREAK_OUTSIDE_OF_LOOP = new ParserErrorCode.con3(
'BREAK_OUTSIDE_OF_LOOP', 9, "A break statement cannot be used outside of a loop
or switch statement"); | |
| 5698 static final ParserErrorCode CONST_AND_FINAL = new ParserErrorCode.con3('CONST
_AND_FINAL', 10, "Members cannot be declared to be both 'const' and 'final'"); | |
| 5699 static final ParserErrorCode CONST_AND_VAR = new ParserErrorCode.con3('CONST_A
ND_VAR', 11, "Members cannot be declared to be both 'const' and 'var'"); | |
| 5700 static final ParserErrorCode CONST_CLASS = new ParserErrorCode.con3('CONST_CLA
SS', 12, "Classes cannot be declared to be 'const'"); | |
| 5701 static final ParserErrorCode CONST_CONSTRUCTOR_WITH_BODY = new ParserErrorCode
.con3('CONST_CONSTRUCTOR_WITH_BODY', 13, "'const' constructors cannot have a bod
y"); | |
| 5702 static final ParserErrorCode CONST_FACTORY = new ParserErrorCode.con3('CONST_F
ACTORY', 14, "Only redirecting factory constructors can be declared to be 'const
'"); | |
| 5703 static final ParserErrorCode CONST_METHOD = new ParserErrorCode.con3('CONST_ME
THOD', 15, "Getters, setters and methods cannot be declared to be 'const'"); | |
| 5704 static final ParserErrorCode CONST_TYPEDEF = new ParserErrorCode.con3('CONST_T
YPEDEF', 16, "Type aliases cannot be declared to be 'const'"); | |
| 5705 static final ParserErrorCode CONSTRUCTOR_WITH_RETURN_TYPE = new ParserErrorCod
e.con3('CONSTRUCTOR_WITH_RETURN_TYPE', 17, "Constructors cannot have a return ty
pe"); | |
| 5706 static final ParserErrorCode CONTINUE_OUTSIDE_OF_LOOP = new ParserErrorCode.co
n3('CONTINUE_OUTSIDE_OF_LOOP', 18, "A continue statement cannot be used outside
of a loop or switch statement"); | |
| 5707 static final ParserErrorCode CONTINUE_WITHOUT_LABEL_IN_CASE = new ParserErrorC
ode.con3('CONTINUE_WITHOUT_LABEL_IN_CASE', 19, "A continue statement in a switch
statement must have a label as a target"); | |
| 5708 static final ParserErrorCode DEPRECATED_ARGUMENT_DEFINITION_TEST = new ParserE
rrorCode.con3('DEPRECATED_ARGUMENT_DEFINITION_TEST', 20, "The argument definitio
n test ('?' operator) has been deprecated"); | |
| 5709 static final ParserErrorCode DEPRECATED_CLASS_TYPE_ALIAS = new ParserErrorCode
.con3('DEPRECATED_CLASS_TYPE_ALIAS', 21, "The 'typedef' mixin application was re
placed with 'class'"); | |
| 5710 static final ParserErrorCode DIRECTIVE_AFTER_DECLARATION = new ParserErrorCode
.con3('DIRECTIVE_AFTER_DECLARATION', 22, "Directives must appear before any decl
arations"); | |
| 5711 static final ParserErrorCode DUPLICATE_LABEL_IN_SWITCH_STATEMENT = new ParserE
rrorCode.con3('DUPLICATE_LABEL_IN_SWITCH_STATEMENT', 23, "The label %s was alrea
dy used in this switch statement"); | |
| 5712 static final ParserErrorCode DUPLICATED_MODIFIER = new ParserErrorCode.con3('D
UPLICATED_MODIFIER', 24, "The modifier '%s' was already specified."); | |
| 5713 static final ParserErrorCode EQUALITY_CANNOT_BE_EQUALITY_OPERAND = new ParserE
rrorCode.con3('EQUALITY_CANNOT_BE_EQUALITY_OPERAND', 25, "Equality expression ca
nnot be operand of another equality expression."); | |
| 5714 static final ParserErrorCode EXPECTED_CASE_OR_DEFAULT = new ParserErrorCode.co
n3('EXPECTED_CASE_OR_DEFAULT', 26, "Expected 'case' or 'default'"); | |
| 5715 static final ParserErrorCode EXPECTED_CLASS_MEMBER = new ParserErrorCode.con3(
'EXPECTED_CLASS_MEMBER', 27, "Expected a class member"); | |
| 5716 static final ParserErrorCode EXPECTED_EXECUTABLE = new ParserErrorCode.con3('E
XPECTED_EXECUTABLE', 28, "Expected a method, getter, setter or operator declarat
ion"); | |
| 5717 static final ParserErrorCode EXPECTED_LIST_OR_MAP_LITERAL = new ParserErrorCod
e.con3('EXPECTED_LIST_OR_MAP_LITERAL', 29, "Expected a list or map literal"); | |
| 5718 static final ParserErrorCode EXPECTED_STRING_LITERAL = new ParserErrorCode.con
3('EXPECTED_STRING_LITERAL', 30, "Expected a string literal"); | |
| 5719 static final ParserErrorCode EXPECTED_TOKEN = new ParserErrorCode.con3('EXPECT
ED_TOKEN', 31, "Expected to find '%s'"); | |
| 5720 static final ParserErrorCode EXPECTED_TYPE_NAME = new ParserErrorCode.con3('EX
PECTED_TYPE_NAME', 32, "Expected a type name"); | |
| 5721 static final ParserErrorCode EXPORT_DIRECTIVE_AFTER_PART_DIRECTIVE = new Parse
rErrorCode.con3('EXPORT_DIRECTIVE_AFTER_PART_DIRECTIVE', 33, "Export directives
must preceed part directives"); | |
| 5722 static final ParserErrorCode EXTERNAL_AFTER_CONST = new ParserErrorCode.con3('
EXTERNAL_AFTER_CONST', 34, "The modifier 'external' should be before the modifie
r 'const'"); | |
| 5723 static final ParserErrorCode EXTERNAL_AFTER_FACTORY = new ParserErrorCode.con3
('EXTERNAL_AFTER_FACTORY', 35, "The modifier 'external' should be before the mod
ifier 'factory'"); | |
| 5724 static final ParserErrorCode EXTERNAL_AFTER_STATIC = new ParserErrorCode.con3(
'EXTERNAL_AFTER_STATIC', 36, "The modifier 'external' should be before the modif
ier 'static'"); | |
| 5725 static final ParserErrorCode EXTERNAL_CLASS = new ParserErrorCode.con3('EXTERN
AL_CLASS', 37, "Classes cannot be declared to be 'external'"); | |
| 5726 static final ParserErrorCode EXTERNAL_CONSTRUCTOR_WITH_BODY = new ParserErrorC
ode.con3('EXTERNAL_CONSTRUCTOR_WITH_BODY', 38, "External constructors cannot hav
e a body"); | |
| 5727 static final ParserErrorCode EXTERNAL_FIELD = new ParserErrorCode.con3('EXTERN
AL_FIELD', 39, "Fields cannot be declared to be 'external'"); | |
| 5728 static final ParserErrorCode EXTERNAL_GETTER_WITH_BODY = new ParserErrorCode.c
on3('EXTERNAL_GETTER_WITH_BODY', 40, "External getters cannot have a body"); | |
| 5729 static final ParserErrorCode EXTERNAL_METHOD_WITH_BODY = new ParserErrorCode.c
on3('EXTERNAL_METHOD_WITH_BODY', 41, "External methods cannot have a body"); | |
| 5730 static final ParserErrorCode EXTERNAL_OPERATOR_WITH_BODY = new ParserErrorCode
.con3('EXTERNAL_OPERATOR_WITH_BODY', 42, "External operators cannot have a body"
); | |
| 5731 static final ParserErrorCode EXTERNAL_SETTER_WITH_BODY = new ParserErrorCode.c
on3('EXTERNAL_SETTER_WITH_BODY', 43, "External setters cannot have a body"); | |
| 5732 static final ParserErrorCode EXTERNAL_TYPEDEF = new ParserErrorCode.con3('EXTE
RNAL_TYPEDEF', 44, "Type aliases cannot be declared to be 'external'"); | |
| 5733 static final ParserErrorCode FACTORY_TOP_LEVEL_DECLARATION = new ParserErrorCo
de.con3('FACTORY_TOP_LEVEL_DECLARATION', 45, "Top-level declarations cannot be d
eclared to be 'factory'"); | |
| 5734 static final ParserErrorCode FACTORY_WITHOUT_BODY = new ParserErrorCode.con3('
FACTORY_WITHOUT_BODY', 46, "A non-redirecting 'factory' constructor must have a
body"); | |
| 5735 static final ParserErrorCode FIELD_INITIALIZER_OUTSIDE_CONSTRUCTOR = new Parse
rErrorCode.con3('FIELD_INITIALIZER_OUTSIDE_CONSTRUCTOR', 47, "Field initializers
can only be used in a constructor"); | |
| 5736 static final ParserErrorCode FINAL_AND_VAR = new ParserErrorCode.con3('FINAL_A
ND_VAR', 48, "Members cannot be declared to be both 'final' and 'var'"); | |
| 5737 static final ParserErrorCode FINAL_CLASS = new ParserErrorCode.con3('FINAL_CLA
SS', 49, "Classes cannot be declared to be 'final'"); | |
| 5738 static final ParserErrorCode FINAL_CONSTRUCTOR = new ParserErrorCode.con3('FIN
AL_CONSTRUCTOR', 50, "A constructor cannot be declared to be 'final'"); | |
| 5739 static final ParserErrorCode FINAL_METHOD = new ParserErrorCode.con3('FINAL_ME
THOD', 51, "Getters, setters and methods cannot be declared to be 'final'"); | |
| 5740 static final ParserErrorCode FINAL_TYPEDEF = new ParserErrorCode.con3('FINAL_T
YPEDEF', 52, "Type aliases cannot be declared to be 'final'"); | |
| 5741 static final ParserErrorCode FUNCTION_TYPED_PARAMETER_VAR = new ParserErrorCod
e.con3('FUNCTION_TYPED_PARAMETER_VAR', 53, "Function typed parameters cannot spe
cify 'const', 'final' or 'var' instead of return type"); | |
| 5742 static final ParserErrorCode GETTER_IN_FUNCTION = new ParserErrorCode.con3('GE
TTER_IN_FUNCTION', 54, "Getters cannot be defined within methods or functions"); | |
| 5743 static final ParserErrorCode GETTER_WITH_PARAMETERS = new ParserErrorCode.con3
('GETTER_WITH_PARAMETERS', 55, "Getter should be declared without a parameter li
st"); | |
| 5744 static final ParserErrorCode ILLEGAL_ASSIGNMENT_TO_NON_ASSIGNABLE = new Parser
ErrorCode.con3('ILLEGAL_ASSIGNMENT_TO_NON_ASSIGNABLE', 56, "Illegal assignment t
o non-assignable expression"); | |
| 5745 static final ParserErrorCode IMPLEMENTS_BEFORE_EXTENDS = new ParserErrorCode.c
on3('IMPLEMENTS_BEFORE_EXTENDS', 57, "The extends clause must be before the impl
ements clause"); | |
| 5746 static final ParserErrorCode IMPLEMENTS_BEFORE_WITH = new ParserErrorCode.con3
('IMPLEMENTS_BEFORE_WITH', 58, "The with clause must be before the implements cl
ause"); | |
| 5747 static final ParserErrorCode IMPORT_DIRECTIVE_AFTER_PART_DIRECTIVE = new Parse
rErrorCode.con3('IMPORT_DIRECTIVE_AFTER_PART_DIRECTIVE', 59, "Import directives
must preceed part directives"); | |
| 5748 static final ParserErrorCode INITIALIZED_VARIABLE_IN_FOR_EACH = new ParserErro
rCode.con3('INITIALIZED_VARIABLE_IN_FOR_EACH', 60, "The loop variable in a for-e
ach loop cannot be initialized"); | |
| 5749 static final ParserErrorCode INVALID_CODE_POINT = new ParserErrorCode.con3('IN
VALID_CODE_POINT', 61, "The escape sequence '%s' is not a valid code point"); | |
| 5750 static final ParserErrorCode INVALID_COMMENT_REFERENCE = new ParserErrorCode.c
on3('INVALID_COMMENT_REFERENCE', 62, "Comment references should contain a possib
ly prefixed identifier and can start with 'new', but should not contain anything
else"); | |
| 5751 static final ParserErrorCode INVALID_HEX_ESCAPE = new ParserErrorCode.con3('IN
VALID_HEX_ESCAPE', 63, "An escape sequence starting with '\\x' must be followed
by 2 hexidecimal digits"); | |
| 5752 static final ParserErrorCode INVALID_OPERATOR = new ParserErrorCode.con3('INVA
LID_OPERATOR', 64, "The string '%s' is not a valid operator"); | |
| 5753 static final ParserErrorCode INVALID_OPERATOR_FOR_SUPER = new ParserErrorCode.
con3('INVALID_OPERATOR_FOR_SUPER', 65, "The operator '%s' cannot be used with 's
uper'"); | |
| 5754 static final ParserErrorCode INVALID_UNICODE_ESCAPE = new ParserErrorCode.con3
('INVALID_UNICODE_ESCAPE', 66, "An escape sequence starting with '\\u' must be f
ollowed by 4 hexidecimal digits or from 1 to 6 digits between '{' and '}'"); | |
| 5755 static final ParserErrorCode LIBRARY_DIRECTIVE_NOT_FIRST = new ParserErrorCode
.con3('LIBRARY_DIRECTIVE_NOT_FIRST', 67, "The library directive must appear befo
re all other directives"); | |
| 5756 static final ParserErrorCode LOCAL_FUNCTION_DECLARATION_MODIFIER = new ParserE
rrorCode.con3('LOCAL_FUNCTION_DECLARATION_MODIFIER', 68, "Local function declara
tions cannot specify any modifier"); | |
| 5757 static final ParserErrorCode MISSING_ASSIGNABLE_SELECTOR = new ParserErrorCode
.con3('MISSING_ASSIGNABLE_SELECTOR', 69, "Missing selector such as \".<identifie
r>\" or \"[0]\""); | |
| 5758 static final ParserErrorCode MISSING_CATCH_OR_FINALLY = new ParserErrorCode.co
n3('MISSING_CATCH_OR_FINALLY', 70, "A try statement must have either a catch or
finally clause"); | |
| 5759 static final ParserErrorCode MISSING_CLASS_BODY = new ParserErrorCode.con3('MI
SSING_CLASS_BODY', 71, "A class definition must have a body, even if it is empty
"); | |
| 5760 static final ParserErrorCode MISSING_CLOSING_PARENTHESIS = new ParserErrorCode
.con3('MISSING_CLOSING_PARENTHESIS', 72, "The closing parenthesis is missing"); | |
| 5761 static final ParserErrorCode MISSING_CONST_FINAL_VAR_OR_TYPE = new ParserError
Code.con3('MISSING_CONST_FINAL_VAR_OR_TYPE', 73, "Variables must be declared usi
ng the keywords 'const', 'final', 'var' or a type name"); | |
| 5762 static final ParserErrorCode MISSING_EXPRESSION_IN_THROW = new ParserErrorCode
.con3('MISSING_EXPRESSION_IN_THROW', 74, "Throw expressions must compute the obj
ect to be thrown"); | |
| 5763 static final ParserErrorCode MISSING_FUNCTION_BODY = new ParserErrorCode.con3(
'MISSING_FUNCTION_BODY', 75, "A function body must be provided"); | |
| 5764 static final ParserErrorCode MISSING_FUNCTION_PARAMETERS = new ParserErrorCode
.con3('MISSING_FUNCTION_PARAMETERS', 76, "Functions must have an explicit list o
f parameters"); | |
| 5765 static final ParserErrorCode MISSING_IDENTIFIER = new ParserErrorCode.con3('MI
SSING_IDENTIFIER', 77, "Expected an identifier"); | |
| 5766 static final ParserErrorCode MISSING_KEYWORD_OPERATOR = new ParserErrorCode.co
n3('MISSING_KEYWORD_OPERATOR', 78, "Operator declarations must be preceeded by t
he keyword 'operator'"); | |
| 5767 static final ParserErrorCode MISSING_NAME_IN_LIBRARY_DIRECTIVE = new ParserErr
orCode.con3('MISSING_NAME_IN_LIBRARY_DIRECTIVE', 79, "Library directives must in
clude a library name"); | |
| 5768 static final ParserErrorCode MISSING_NAME_IN_PART_OF_DIRECTIVE = new ParserErr
orCode.con3('MISSING_NAME_IN_PART_OF_DIRECTIVE', 80, "Library directives must in
clude a library name"); | |
| 5769 static final ParserErrorCode MISSING_STATEMENT = new ParserErrorCode.con3('MIS
SING_STATEMENT', 81, "Expected a statement"); | |
| 5770 static final ParserErrorCode MISSING_TERMINATOR_FOR_PARAMETER_GROUP = new Pars
erErrorCode.con3('MISSING_TERMINATOR_FOR_PARAMETER_GROUP', 82, "There is no '%s'
to close the parameter group"); | |
| 5771 static final ParserErrorCode MISSING_TYPEDEF_PARAMETERS = new ParserErrorCode.
con3('MISSING_TYPEDEF_PARAMETERS', 83, "Type aliases for functions must have an
explicit list of parameters"); | |
| 5772 static final ParserErrorCode MISSING_VARIABLE_IN_FOR_EACH = new ParserErrorCod
e.con3('MISSING_VARIABLE_IN_FOR_EACH', 84, "A loop variable must be declared in
a for-each loop before the 'in', but none were found"); | |
| 5773 static final ParserErrorCode MIXED_PARAMETER_GROUPS = new ParserErrorCode.con3
('MIXED_PARAMETER_GROUPS', 85, "Cannot have both positional and named parameters
in a single parameter list"); | |
| 5774 static final ParserErrorCode MULTIPLE_EXTENDS_CLAUSES = new ParserErrorCode.co
n3('MULTIPLE_EXTENDS_CLAUSES', 86, "Each class definition can have at most one e
xtends clause"); | |
| 5775 static final ParserErrorCode MULTIPLE_IMPLEMENTS_CLAUSES = new ParserErrorCode
.con3('MULTIPLE_IMPLEMENTS_CLAUSES', 87, "Each class definition can have at most
one implements clause"); | |
| 5776 static final ParserErrorCode MULTIPLE_LIBRARY_DIRECTIVES = new ParserErrorCode
.con3('MULTIPLE_LIBRARY_DIRECTIVES', 88, "Only one library directive may be decl
ared in a file"); | |
| 5777 static final ParserErrorCode MULTIPLE_NAMED_PARAMETER_GROUPS = new ParserError
Code.con3('MULTIPLE_NAMED_PARAMETER_GROUPS', 89, "Cannot have multiple groups of
named parameters in a single parameter list"); | |
| 5778 static final ParserErrorCode MULTIPLE_PART_OF_DIRECTIVES = new ParserErrorCode
.con3('MULTIPLE_PART_OF_DIRECTIVES', 90, "Only one part-of directive may be decl
ared in a file"); | |
| 5779 static final ParserErrorCode MULTIPLE_POSITIONAL_PARAMETER_GROUPS = new Parser
ErrorCode.con3('MULTIPLE_POSITIONAL_PARAMETER_GROUPS', 91, "Cannot have multiple
groups of positional parameters in a single parameter list"); | |
| 5780 static final ParserErrorCode MULTIPLE_VARIABLES_IN_FOR_EACH = new ParserErrorC
ode.con3('MULTIPLE_VARIABLES_IN_FOR_EACH', 92, "A single loop variable must be d
eclared in a for-each loop before the 'in', but %s were found"); | |
| 5781 static final ParserErrorCode MULTIPLE_WITH_CLAUSES = new ParserErrorCode.con3(
'MULTIPLE_WITH_CLAUSES', 93, "Each class definition can have at most one with cl
ause"); | |
| 5782 static final ParserErrorCode NAMED_FUNCTION_EXPRESSION = new ParserErrorCode.c
on3('NAMED_FUNCTION_EXPRESSION', 94, "Function expressions cannot be named"); | |
| 5783 static final ParserErrorCode NAMED_PARAMETER_OUTSIDE_GROUP = new ParserErrorCo
de.con3('NAMED_PARAMETER_OUTSIDE_GROUP', 95, "Named parameters must be enclosed
in curly braces ('{' and '}')"); | |
| 5784 static final ParserErrorCode NATIVE_CLAUSE_IN_NON_SDK_CODE = new ParserErrorCo
de.con3('NATIVE_CLAUSE_IN_NON_SDK_CODE', 96, "Native clause can only be used in
the SDK and code that is loaded through native extensions"); | |
| 5785 static final ParserErrorCode NATIVE_FUNCTION_BODY_IN_NON_SDK_CODE = new Parser
ErrorCode.con3('NATIVE_FUNCTION_BODY_IN_NON_SDK_CODE', 97, "Native functions can
only be declared in the SDK and code that is loaded through native extensions")
; | |
| 5786 static final ParserErrorCode NON_CONSTRUCTOR_FACTORY = new ParserErrorCode.con
3('NON_CONSTRUCTOR_FACTORY', 98, "Only constructors can be declared to be a 'fac
tory'"); | |
| 5787 static final ParserErrorCode NON_IDENTIFIER_LIBRARY_NAME = new ParserErrorCode
.con3('NON_IDENTIFIER_LIBRARY_NAME', 99, "The name of a library must be an ident
ifier"); | |
| 5788 static final ParserErrorCode NON_PART_OF_DIRECTIVE_IN_PART = new ParserErrorCo
de.con3('NON_PART_OF_DIRECTIVE_IN_PART', 100, "The part-of directive must be the
only directive in a part"); | |
| 5789 static final ParserErrorCode NON_USER_DEFINABLE_OPERATOR = new ParserErrorCode
.con3('NON_USER_DEFINABLE_OPERATOR', 101, "The operator '%s' is not user definab
le"); | |
| 5790 static final ParserErrorCode NORMAL_BEFORE_OPTIONAL_PARAMETERS = new ParserErr
orCode.con3('NORMAL_BEFORE_OPTIONAL_PARAMETERS', 102, "Normal parameters must oc
cur before optional parameters"); | |
| 5791 static final ParserErrorCode POSITIONAL_AFTER_NAMED_ARGUMENT = new ParserError
Code.con3('POSITIONAL_AFTER_NAMED_ARGUMENT', 103, "Positional arguments must occ
ur before named arguments"); | |
| 5792 static final ParserErrorCode POSITIONAL_PARAMETER_OUTSIDE_GROUP = new ParserEr
rorCode.con3('POSITIONAL_PARAMETER_OUTSIDE_GROUP', 104, "Positional parameters m
ust be enclosed in square brackets ('[' and ']')"); | |
| 5793 static final ParserErrorCode REDIRECTION_IN_NON_FACTORY_CONSTRUCTOR = new Pars
erErrorCode.con3('REDIRECTION_IN_NON_FACTORY_CONSTRUCTOR', 105, "Only factory co
nstructor can specify '=' redirection."); | |
| 5794 static final ParserErrorCode SETTER_IN_FUNCTION = new ParserErrorCode.con3('SE
TTER_IN_FUNCTION', 106, "Setters cannot be defined within methods or functions")
; | |
| 5795 static final ParserErrorCode STATIC_AFTER_CONST = new ParserErrorCode.con3('ST
ATIC_AFTER_CONST', 107, "The modifier 'static' should be before the modifier 'co
nst'"); | |
| 5796 static final ParserErrorCode STATIC_AFTER_FINAL = new ParserErrorCode.con3('ST
ATIC_AFTER_FINAL', 108, "The modifier 'static' should be before the modifier 'fi
nal'"); | |
| 5797 static final ParserErrorCode STATIC_AFTER_VAR = new ParserErrorCode.con3('STAT
IC_AFTER_VAR', 109, "The modifier 'static' should be before the modifier 'var'")
; | |
| 5798 static final ParserErrorCode STATIC_CONSTRUCTOR = new ParserErrorCode.con3('ST
ATIC_CONSTRUCTOR', 110, "Constructors cannot be static"); | |
| 5799 static final ParserErrorCode STATIC_GETTER_WITHOUT_BODY = new ParserErrorCode.
con3('STATIC_GETTER_WITHOUT_BODY', 111, "A 'static' getter must have a body"); | |
| 5800 static final ParserErrorCode STATIC_OPERATOR = new ParserErrorCode.con3('STATI
C_OPERATOR', 112, "Operators cannot be static"); | |
| 5801 static final ParserErrorCode STATIC_SETTER_WITHOUT_BODY = new ParserErrorCode.
con3('STATIC_SETTER_WITHOUT_BODY', 113, "A 'static' setter must have a body"); | |
| 5802 static final ParserErrorCode STATIC_TOP_LEVEL_DECLARATION = new ParserErrorCod
e.con3('STATIC_TOP_LEVEL_DECLARATION', 114, "Top-level declarations cannot be de
clared to be 'static'"); | |
| 5803 static final ParserErrorCode SWITCH_HAS_CASE_AFTER_DEFAULT_CASE = new ParserEr
rorCode.con3('SWITCH_HAS_CASE_AFTER_DEFAULT_CASE', 115, "The 'default' case shou
ld be the last case in a switch statement"); | |
| 5804 static final ParserErrorCode SWITCH_HAS_MULTIPLE_DEFAULT_CASES = new ParserErr
orCode.con3('SWITCH_HAS_MULTIPLE_DEFAULT_CASES', 116, "The 'default' case can on
ly be declared once"); | |
| 5805 static final ParserErrorCode TOP_LEVEL_OPERATOR = new ParserErrorCode.con3('TO
P_LEVEL_OPERATOR', 117, "Operators must be declared within a class"); | |
| 5806 static final ParserErrorCode UNEXPECTED_TERMINATOR_FOR_PARAMETER_GROUP = new P
arserErrorCode.con3('UNEXPECTED_TERMINATOR_FOR_PARAMETER_GROUP', 118, "There is
no '%s' to open a parameter group"); | |
| 5807 static final ParserErrorCode UNEXPECTED_TOKEN = new ParserErrorCode.con3('UNEX
PECTED_TOKEN', 119, "Unexpected token '%s'"); | |
| 5808 static final ParserErrorCode WITH_BEFORE_EXTENDS = new ParserErrorCode.con3('W
ITH_BEFORE_EXTENDS', 120, "The extends clause must be before the with clause"); | |
| 5809 static final ParserErrorCode WITH_WITHOUT_EXTENDS = new ParserErrorCode.con3('
WITH_WITHOUT_EXTENDS', 121, "The with clause cannot be used without an extends c
lause"); | |
| 5810 static final ParserErrorCode WRONG_SEPARATOR_FOR_NAMED_PARAMETER = new ParserE
rrorCode.con3('WRONG_SEPARATOR_FOR_NAMED_PARAMETER', 122, "The default value of
a named parameter should be preceeded by ':'"); | |
| 5811 static final ParserErrorCode WRONG_SEPARATOR_FOR_POSITIONAL_PARAMETER = new Pa
rserErrorCode.con3('WRONG_SEPARATOR_FOR_POSITIONAL_PARAMETER', 123, "The default
value of a positional parameter should be preceeded by '='"); | |
| 5812 static final ParserErrorCode WRONG_TERMINATOR_FOR_PARAMETER_GROUP = new Parser
ErrorCode.con3('WRONG_TERMINATOR_FOR_PARAMETER_GROUP', 124, "Expected '%s' to cl
ose parameter group"); | |
| 5813 static final ParserErrorCode VAR_AND_TYPE = new ParserErrorCode.con3('VAR_AND_
TYPE', 125, "Variables cannot be declared using both 'var' and a type name; remo
ve the 'var'"); | |
| 5814 static final ParserErrorCode VAR_AS_TYPE_NAME = new ParserErrorCode.con3('VAR_
AS_TYPE_NAME', 126, "The keyword 'var' cannot be used as a type name"); | |
| 5815 static final ParserErrorCode VAR_CLASS = new ParserErrorCode.con3('VAR_CLASS',
127, "Classes cannot be declared to be 'var'"); | |
| 5816 static final ParserErrorCode VAR_RETURN_TYPE = new ParserErrorCode.con3('VAR_R
ETURN_TYPE', 128, "The return type cannot be 'var'"); | |
| 5817 static final ParserErrorCode VAR_TYPEDEF = new ParserErrorCode.con3('VAR_TYPED
EF', 129, "Type aliases cannot be declared to be 'var'"); | |
| 5818 static final ParserErrorCode VOID_PARAMETER = new ParserErrorCode.con3('VOID_P
ARAMETER', 130, "Parameters cannot have a type of 'void'"); | |
| 5819 static final ParserErrorCode VOID_VARIABLE = new ParserErrorCode.con3('VOID_VA
RIABLE', 131, "Variables cannot have a type of 'void'"); | |
| 5820 static final List<ParserErrorCode> values = [ | |
| 5821 ABSTRACT_CLASS_MEMBER, | |
| 5822 ABSTRACT_STATIC_METHOD, | |
| 5823 ABSTRACT_TOP_LEVEL_FUNCTION, | |
| 5824 ABSTRACT_TOP_LEVEL_VARIABLE, | |
| 5825 ABSTRACT_TYPEDEF, | |
| 5826 ASSERT_DOES_NOT_TAKE_ASSIGNMENT, | |
| 5827 ASSERT_DOES_NOT_TAKE_CASCADE, | |
| 5828 ASSERT_DOES_NOT_TAKE_THROW, | |
| 5829 ASSERT_DOES_NOT_TAKE_RETHROW, | |
| 5830 BREAK_OUTSIDE_OF_LOOP, | |
| 5831 CONST_AND_FINAL, | |
| 5832 CONST_AND_VAR, | |
| 5833 CONST_CLASS, | |
| 5834 CONST_CONSTRUCTOR_WITH_BODY, | |
| 5835 CONST_FACTORY, | |
| 5836 CONST_METHOD, | |
| 5837 CONST_TYPEDEF, | |
| 5838 CONSTRUCTOR_WITH_RETURN_TYPE, | |
| 5839 CONTINUE_OUTSIDE_OF_LOOP, | |
| 5840 CONTINUE_WITHOUT_LABEL_IN_CASE, | |
| 5841 DEPRECATED_ARGUMENT_DEFINITION_TEST, | |
| 5842 DEPRECATED_CLASS_TYPE_ALIAS, | |
| 5843 DIRECTIVE_AFTER_DECLARATION, | |
| 5844 DUPLICATE_LABEL_IN_SWITCH_STATEMENT, | |
| 5845 DUPLICATED_MODIFIER, | |
| 5846 EQUALITY_CANNOT_BE_EQUALITY_OPERAND, | |
| 5847 EXPECTED_CASE_OR_DEFAULT, | |
| 5848 EXPECTED_CLASS_MEMBER, | |
| 5849 EXPECTED_EXECUTABLE, | |
| 5850 EXPECTED_LIST_OR_MAP_LITERAL, | |
| 5851 EXPECTED_STRING_LITERAL, | |
| 5852 EXPECTED_TOKEN, | |
| 5853 EXPECTED_TYPE_NAME, | |
| 5854 EXPORT_DIRECTIVE_AFTER_PART_DIRECTIVE, | |
| 5855 EXTERNAL_AFTER_CONST, | |
| 5856 EXTERNAL_AFTER_FACTORY, | |
| 5857 EXTERNAL_AFTER_STATIC, | |
| 5858 EXTERNAL_CLASS, | |
| 5859 EXTERNAL_CONSTRUCTOR_WITH_BODY, | |
| 5860 EXTERNAL_FIELD, | |
| 5861 EXTERNAL_GETTER_WITH_BODY, | |
| 5862 EXTERNAL_METHOD_WITH_BODY, | |
| 5863 EXTERNAL_OPERATOR_WITH_BODY, | |
| 5864 EXTERNAL_SETTER_WITH_BODY, | |
| 5865 EXTERNAL_TYPEDEF, | |
| 5866 FACTORY_TOP_LEVEL_DECLARATION, | |
| 5867 FACTORY_WITHOUT_BODY, | |
| 5868 FIELD_INITIALIZER_OUTSIDE_CONSTRUCTOR, | |
| 5869 FINAL_AND_VAR, | |
| 5870 FINAL_CLASS, | |
| 5871 FINAL_CONSTRUCTOR, | |
| 5872 FINAL_METHOD, | |
| 5873 FINAL_TYPEDEF, | |
| 5874 FUNCTION_TYPED_PARAMETER_VAR, | |
| 5875 GETTER_IN_FUNCTION, | |
| 5876 GETTER_WITH_PARAMETERS, | |
| 5877 ILLEGAL_ASSIGNMENT_TO_NON_ASSIGNABLE, | |
| 5878 IMPLEMENTS_BEFORE_EXTENDS, | |
| 5879 IMPLEMENTS_BEFORE_WITH, | |
| 5880 IMPORT_DIRECTIVE_AFTER_PART_DIRECTIVE, | |
| 5881 INITIALIZED_VARIABLE_IN_FOR_EACH, | |
| 5882 INVALID_CODE_POINT, | |
| 5883 INVALID_COMMENT_REFERENCE, | |
| 5884 INVALID_HEX_ESCAPE, | |
| 5885 INVALID_OPERATOR, | |
| 5886 INVALID_OPERATOR_FOR_SUPER, | |
| 5887 INVALID_UNICODE_ESCAPE, | |
| 5888 LIBRARY_DIRECTIVE_NOT_FIRST, | |
| 5889 LOCAL_FUNCTION_DECLARATION_MODIFIER, | |
| 5890 MISSING_ASSIGNABLE_SELECTOR, | |
| 5891 MISSING_CATCH_OR_FINALLY, | |
| 5892 MISSING_CLASS_BODY, | |
| 5893 MISSING_CLOSING_PARENTHESIS, | |
| 5894 MISSING_CONST_FINAL_VAR_OR_TYPE, | |
| 5895 MISSING_EXPRESSION_IN_THROW, | |
| 5896 MISSING_FUNCTION_BODY, | |
| 5897 MISSING_FUNCTION_PARAMETERS, | |
| 5898 MISSING_IDENTIFIER, | |
| 5899 MISSING_KEYWORD_OPERATOR, | |
| 5900 MISSING_NAME_IN_LIBRARY_DIRECTIVE, | |
| 5901 MISSING_NAME_IN_PART_OF_DIRECTIVE, | |
| 5902 MISSING_STATEMENT, | |
| 5903 MISSING_TERMINATOR_FOR_PARAMETER_GROUP, | |
| 5904 MISSING_TYPEDEF_PARAMETERS, | |
| 5905 MISSING_VARIABLE_IN_FOR_EACH, | |
| 5906 MIXED_PARAMETER_GROUPS, | |
| 5907 MULTIPLE_EXTENDS_CLAUSES, | |
| 5908 MULTIPLE_IMPLEMENTS_CLAUSES, | |
| 5909 MULTIPLE_LIBRARY_DIRECTIVES, | |
| 5910 MULTIPLE_NAMED_PARAMETER_GROUPS, | |
| 5911 MULTIPLE_PART_OF_DIRECTIVES, | |
| 5912 MULTIPLE_POSITIONAL_PARAMETER_GROUPS, | |
| 5913 MULTIPLE_VARIABLES_IN_FOR_EACH, | |
| 5914 MULTIPLE_WITH_CLAUSES, | |
| 5915 NAMED_FUNCTION_EXPRESSION, | |
| 5916 NAMED_PARAMETER_OUTSIDE_GROUP, | |
| 5917 NATIVE_CLAUSE_IN_NON_SDK_CODE, | |
| 5918 NATIVE_FUNCTION_BODY_IN_NON_SDK_CODE, | |
| 5919 NON_CONSTRUCTOR_FACTORY, | |
| 5920 NON_IDENTIFIER_LIBRARY_NAME, | |
| 5921 NON_PART_OF_DIRECTIVE_IN_PART, | |
| 5922 NON_USER_DEFINABLE_OPERATOR, | |
| 5923 NORMAL_BEFORE_OPTIONAL_PARAMETERS, | |
| 5924 POSITIONAL_AFTER_NAMED_ARGUMENT, | |
| 5925 POSITIONAL_PARAMETER_OUTSIDE_GROUP, | |
| 5926 REDIRECTION_IN_NON_FACTORY_CONSTRUCTOR, | |
| 5927 SETTER_IN_FUNCTION, | |
| 5928 STATIC_AFTER_CONST, | |
| 5929 STATIC_AFTER_FINAL, | |
| 5930 STATIC_AFTER_VAR, | |
| 5931 STATIC_CONSTRUCTOR, | |
| 5932 STATIC_GETTER_WITHOUT_BODY, | |
| 5933 STATIC_OPERATOR, | |
| 5934 STATIC_SETTER_WITHOUT_BODY, | |
| 5935 STATIC_TOP_LEVEL_DECLARATION, | |
| 5936 SWITCH_HAS_CASE_AFTER_DEFAULT_CASE, | |
| 5937 SWITCH_HAS_MULTIPLE_DEFAULT_CASES, | |
| 5938 TOP_LEVEL_OPERATOR, | |
| 5939 UNEXPECTED_TERMINATOR_FOR_PARAMETER_GROUP, | |
| 5940 UNEXPECTED_TOKEN, | |
| 5941 WITH_BEFORE_EXTENDS, | |
| 5942 WITH_WITHOUT_EXTENDS, | |
| 5943 WRONG_SEPARATOR_FOR_NAMED_PARAMETER, | |
| 5944 WRONG_SEPARATOR_FOR_POSITIONAL_PARAMETER, | |
| 5945 WRONG_TERMINATOR_FOR_PARAMETER_GROUP, | |
| 5946 VAR_AND_TYPE, | |
| 5947 VAR_AS_TYPE_NAME, | |
| 5948 VAR_CLASS, | |
| 5949 VAR_RETURN_TYPE, | |
| 5950 VAR_TYPEDEF, | |
| 5951 VOID_PARAMETER, | |
| 5952 VOID_VARIABLE]; | |
| 5953 | |
| 5954 /** | |
| 5955 * The severity of this error. | |
| 5956 */ | |
| 5957 ErrorSeverity _severity; | |
| 5958 | |
| 5959 /** | |
| 5960 * The template used to create the message to be displayed for this error. | |
| 5961 */ | |
| 5962 String _message; | |
| 5963 | |
| 5964 /** | |
| 5965 * The template used to create the correction to be displayed for this error,
or `null` if | |
| 5966 * there is no correction information for this error. | |
| 5967 */ | |
| 5968 String correction8; | |
| 5969 | |
| 5970 /** | |
| 5971 * Initialize a newly created error code to have the given severity and messag
e. | |
| 5972 * | |
| 5973 * @param severity the severity of the error | |
| 5974 * @param message the message template used to create the message to be displa
yed for the error | |
| 5975 */ | |
| 5976 ParserErrorCode.con1(String name, int ordinal, ErrorSeverity severity, String
message) : super(name, ordinal) { | |
| 5977 this._severity = severity; | |
| 5978 this._message = message; | |
| 5979 } | |
| 5980 | |
| 5981 /** | |
| 5982 * Initialize a newly created error code to have the given severity, message a
nd correction. | |
| 5983 * | |
| 5984 * @param severity the severity of the error | |
| 5985 * @param message the template used to create the message to be displayed for
the error | |
| 5986 * @param correction the template used to create the correction to be displaye
d for the error | |
| 5987 */ | |
| 5988 ParserErrorCode.con2(String name, int ordinal, ErrorSeverity severity, String
message, String correction) : super(name, ordinal) { | |
| 5989 this._severity = severity; | |
| 5990 this._message = message; | |
| 5991 this.correction8 = correction; | |
| 5992 } | |
| 5993 | |
| 5994 /** | |
| 5995 * Initialize a newly created error code to have the given message and a sever
ity of ERROR. | |
| 5996 * | |
| 5997 * @param message the message template used to create the message to be displa
yed for the error | |
| 5998 */ | |
| 5999 ParserErrorCode.con3(String name, int ordinal, String message) : this.con1(nam
e, ordinal, ErrorSeverity.ERROR, message); | |
| 6000 String get correction => correction8; | |
| 6001 ErrorSeverity get errorSeverity => _severity; | |
| 6002 String get message => _message; | |
| 6003 ErrorType get type => ErrorType.SYNTACTIC_ERROR; | |
| 6004 } | |
| 6005 /** | |
| 6006 * Instances of the class {link ToFormattedSourceVisitor} write a source represe
ntation of a visited | |
| 6007 * AST node (and all of it's children) to a writer. | |
| 6008 */ | |
| 6009 class ToFormattedSourceVisitor implements ASTVisitor<Object> { | |
| 6010 | |
| 6011 /** | |
| 6012 * The writer to which the source is to be written. | |
| 6013 */ | |
| 6014 PrintWriter _writer; | |
| 6015 int _indentLevel = 0; | |
| 6016 String _indentString = ""; | |
| 6017 | |
| 6018 /** | |
| 6019 * Initialize a newly created visitor to write source code representing the vi
sited nodes to the | |
| 6020 * given writer. | |
| 6021 * | |
| 6022 * @param writer the writer to which the source is to be written | |
| 6023 */ | |
| 6024 ToFormattedSourceVisitor(PrintWriter writer) { | |
| 6025 this._writer = writer; | |
| 6026 } | |
| 6027 Object visitAdjacentStrings(AdjacentStrings node) { | |
| 6028 visitList5(node.strings, " "); | |
| 6029 return null; | |
| 6030 } | |
| 6031 Object visitAnnotation(Annotation node) { | |
| 6032 _writer.print('@'); | |
| 6033 visit(node.name); | |
| 6034 visit7(".", node.constructorName); | |
| 6035 visit(node.arguments); | |
| 6036 return null; | |
| 6037 } | |
| 6038 Object visitArgumentDefinitionTest(ArgumentDefinitionTest node) { | |
| 6039 _writer.print('?'); | |
| 6040 visit(node.identifier); | |
| 6041 return null; | |
| 6042 } | |
| 6043 Object visitArgumentList(ArgumentList node) { | |
| 6044 _writer.print('('); | |
| 6045 visitList5(node.arguments, ", "); | |
| 6046 _writer.print(')'); | |
| 6047 return null; | |
| 6048 } | |
| 6049 Object visitAsExpression(AsExpression node) { | |
| 6050 visit(node.expression); | |
| 6051 _writer.print(" as "); | |
| 6052 visit(node.type); | |
| 6053 return null; | |
| 6054 } | |
| 6055 Object visitAssertStatement(AssertStatement node) { | |
| 6056 _writer.print("assert("); | |
| 6057 visit(node.condition); | |
| 6058 _writer.print(");"); | |
| 6059 return null; | |
| 6060 } | |
| 6061 Object visitAssignmentExpression(AssignmentExpression node) { | |
| 6062 visit(node.leftHandSide); | |
| 6063 _writer.print(' '); | |
| 6064 _writer.print(node.operator.lexeme); | |
| 6065 _writer.print(' '); | |
| 6066 visit(node.rightHandSide); | |
| 6067 return null; | |
| 6068 } | |
| 6069 Object visitBinaryExpression(BinaryExpression node) { | |
| 6070 visit(node.leftOperand); | |
| 6071 _writer.print(' '); | |
| 6072 _writer.print(node.operator.lexeme); | |
| 6073 _writer.print(' '); | |
| 6074 visit(node.rightOperand); | |
| 6075 return null; | |
| 6076 } | |
| 6077 Object visitBlock(Block node) { | |
| 6078 _writer.print('{'); | |
| 6079 { | |
| 6080 indentInc(); | |
| 6081 visitList5(node.statements, "\n"); | |
| 6082 indentDec(); | |
| 6083 } | |
| 6084 nl2(); | |
| 6085 _writer.print('}'); | |
| 6086 return null; | |
| 6087 } | |
| 6088 Object visitBlockFunctionBody(BlockFunctionBody node) { | |
| 6089 visit(node.block); | |
| 6090 return null; | |
| 6091 } | |
| 6092 Object visitBooleanLiteral(BooleanLiteral node) { | |
| 6093 _writer.print(node.literal.lexeme); | |
| 6094 return null; | |
| 6095 } | |
| 6096 Object visitBreakStatement(BreakStatement node) { | |
| 6097 _writer.print("break"); | |
| 6098 visit7(" ", node.label); | |
| 6099 _writer.print(";"); | |
| 6100 return null; | |
| 6101 } | |
| 6102 Object visitCascadeExpression(CascadeExpression node) { | |
| 6103 visit(node.target); | |
| 6104 visitList(node.cascadeSections); | |
| 6105 return null; | |
| 6106 } | |
| 6107 Object visitCatchClause(CatchClause node) { | |
| 6108 visit7("on ", node.exceptionType); | |
| 6109 if (node.catchKeyword != null) { | |
| 6110 if (node.exceptionType != null) { | |
| 6111 _writer.print(' '); | |
| 6112 } | |
| 6113 _writer.print("catch ("); | |
| 6114 visit(node.exceptionParameter); | |
| 6115 visit7(", ", node.stackTraceParameter); | |
| 6116 _writer.print(") "); | |
| 6117 } else { | |
| 6118 _writer.print(" "); | |
| 6119 } | |
| 6120 visit(node.body); | |
| 6121 return null; | |
| 6122 } | |
| 6123 Object visitClassDeclaration(ClassDeclaration node) { | |
| 6124 visit(node.documentationComment); | |
| 6125 visit8(node.abstractKeyword, " "); | |
| 6126 _writer.print("class "); | |
| 6127 visit(node.name); | |
| 6128 visit(node.typeParameters); | |
| 6129 visit7(" ", node.extendsClause); | |
| 6130 visit7(" ", node.withClause); | |
| 6131 visit7(" ", node.implementsClause); | |
| 6132 _writer.print(" {"); | |
| 6133 { | |
| 6134 indentInc(); | |
| 6135 visitList5(node.members, "\n"); | |
| 6136 indentDec(); | |
| 6137 } | |
| 6138 nl2(); | |
| 6139 _writer.print("}"); | |
| 6140 return null; | |
| 6141 } | |
| 6142 Object visitClassTypeAlias(ClassTypeAlias node) { | |
| 6143 _writer.print("typedef "); | |
| 6144 visit(node.name); | |
| 6145 visit(node.typeParameters); | |
| 6146 _writer.print(" = "); | |
| 6147 if (node.abstractKeyword != null) { | |
| 6148 _writer.print("abstract "); | |
| 6149 } | |
| 6150 visit(node.superclass); | |
| 6151 visit7(" ", node.withClause); | |
| 6152 visit7(" ", node.implementsClause); | |
| 6153 _writer.print(";"); | |
| 6154 return null; | |
| 6155 } | |
| 6156 Object visitComment(Comment node) { | |
| 6157 Token token = node.beginToken; | |
| 6158 while (token != null) { | |
| 6159 bool firstLine = true; | |
| 6160 for (String line in StringUtils.split(token.lexeme, "\n")) { | |
| 6161 if (firstLine) { | |
| 6162 firstLine = false; | |
| 6163 if (node.isDocumentation) { | |
| 6164 nl2(); | |
| 6165 } | |
| 6166 } else { | |
| 6167 line = " ${line.trim()}"; | |
| 6168 line = StringUtils.replace(line, "/*", "/ *"); | |
| 6169 } | |
| 6170 _writer.print(line); | |
| 6171 nl2(); | |
| 6172 } | |
| 6173 if (identical(token, node.endToken)) { | |
| 6174 break; | |
| 6175 } | |
| 6176 } | |
| 6177 return null; | |
| 6178 } | |
| 6179 Object visitCommentReference(CommentReference node) => null; | |
| 6180 Object visitCompilationUnit(CompilationUnit node) { | |
| 6181 ScriptTag scriptTag = node.scriptTag; | |
| 6182 NodeList<Directive> directives = node.directives; | |
| 6183 visit(scriptTag); | |
| 6184 String prefix = scriptTag == null ? "" : " "; | |
| 6185 visitList7(prefix, directives, "\n"); | |
| 6186 prefix = scriptTag == null && directives.isEmpty ? "" : "\n\n"; | |
| 6187 visitList7(prefix, node.declarations, "\n"); | |
| 6188 return null; | |
| 6189 } | |
| 6190 Object visitConditionalExpression(ConditionalExpression node) { | |
| 6191 visit(node.condition); | |
| 6192 _writer.print(" ? "); | |
| 6193 visit(node.thenExpression); | |
| 6194 _writer.print(" : "); | |
| 6195 visit(node.elseExpression); | |
| 6196 return null; | |
| 6197 } | |
| 6198 Object visitConstructorDeclaration(ConstructorDeclaration node) { | |
| 6199 visit(node.documentationComment); | |
| 6200 visit8(node.externalKeyword, " "); | |
| 6201 visit8(node.constKeyword, " "); | |
| 6202 visit8(node.factoryKeyword, " "); | |
| 6203 visit(node.returnType); | |
| 6204 visit7(".", node.name); | |
| 6205 visit(node.parameters); | |
| 6206 visitList7(" : ", node.initializers, ", "); | |
| 6207 visit7(" = ", node.redirectedConstructor); | |
| 6208 if (node.body is! EmptyFunctionBody) { | |
| 6209 _writer.print(' '); | |
| 6210 } | |
| 6211 visit(node.body); | |
| 6212 return null; | |
| 6213 } | |
| 6214 Object visitConstructorFieldInitializer(ConstructorFieldInitializer node) { | |
| 6215 visit8(node.keyword, "."); | |
| 6216 visit(node.fieldName); | |
| 6217 _writer.print(" = "); | |
| 6218 visit(node.expression); | |
| 6219 return null; | |
| 6220 } | |
| 6221 Object visitConstructorName(ConstructorName node) { | |
| 6222 visit(node.type); | |
| 6223 visit7(".", node.name); | |
| 6224 return null; | |
| 6225 } | |
| 6226 Object visitContinueStatement(ContinueStatement node) { | |
| 6227 _writer.print("continue"); | |
| 6228 visit7(" ", node.label); | |
| 6229 _writer.print(";"); | |
| 6230 return null; | |
| 6231 } | |
| 6232 Object visitDeclaredIdentifier(DeclaredIdentifier node) { | |
| 6233 visit8(node.keyword, " "); | |
| 6234 visit6(node.type, " "); | |
| 6235 visit(node.identifier); | |
| 6236 return null; | |
| 6237 } | |
| 6238 Object visitDefaultFormalParameter(DefaultFormalParameter node) { | |
| 6239 visit(node.parameter); | |
| 6240 if (node.separator != null) { | |
| 6241 _writer.print(" "); | |
| 6242 _writer.print(node.separator.lexeme); | |
| 6243 visit7(" ", node.defaultValue); | |
| 6244 } | |
| 6245 return null; | |
| 6246 } | |
| 6247 Object visitDoStatement(DoStatement node) { | |
| 6248 _writer.print("do "); | |
| 6249 visit(node.body); | |
| 6250 _writer.print(" while ("); | |
| 6251 visit(node.condition); | |
| 6252 _writer.print(");"); | |
| 6253 return null; | |
| 6254 } | |
| 6255 Object visitDoubleLiteral(DoubleLiteral node) { | |
| 6256 _writer.print(node.literal.lexeme); | |
| 6257 return null; | |
| 6258 } | |
| 6259 Object visitEmptyFunctionBody(EmptyFunctionBody node) { | |
| 6260 _writer.print(';'); | |
| 6261 return null; | |
| 6262 } | |
| 6263 Object visitEmptyStatement(EmptyStatement node) { | |
| 6264 _writer.print(';'); | |
| 6265 return null; | |
| 6266 } | |
| 6267 Object visitExportDirective(ExportDirective node) { | |
| 6268 _writer.print("export "); | |
| 6269 visit(node.uri); | |
| 6270 visitList7(" ", node.combinators, " "); | |
| 6271 _writer.print(';'); | |
| 6272 return null; | |
| 6273 } | |
| 6274 Object visitExpressionFunctionBody(ExpressionFunctionBody node) { | |
| 6275 _writer.print("=> "); | |
| 6276 visit(node.expression); | |
| 6277 if (node.semicolon != null) { | |
| 6278 _writer.print(';'); | |
| 6279 } | |
| 6280 return null; | |
| 6281 } | |
| 6282 Object visitExpressionStatement(ExpressionStatement node) { | |
| 6283 visit(node.expression); | |
| 6284 _writer.print(';'); | |
| 6285 return null; | |
| 6286 } | |
| 6287 Object visitExtendsClause(ExtendsClause node) { | |
| 6288 _writer.print("extends "); | |
| 6289 visit(node.superclass); | |
| 6290 return null; | |
| 6291 } | |
| 6292 Object visitFieldDeclaration(FieldDeclaration node) { | |
| 6293 visit(node.documentationComment); | |
| 6294 visit8(node.staticKeyword, " "); | |
| 6295 visit(node.fields); | |
| 6296 _writer.print(";"); | |
| 6297 return null; | |
| 6298 } | |
| 6299 Object visitFieldFormalParameter(FieldFormalParameter node) { | |
| 6300 visit8(node.keyword, " "); | |
| 6301 visit6(node.type, " "); | |
| 6302 _writer.print("this."); | |
| 6303 visit(node.identifier); | |
| 6304 visit(node.parameters); | |
| 6305 return null; | |
| 6306 } | |
| 6307 Object visitForEachStatement(ForEachStatement node) { | |
| 6308 DeclaredIdentifier loopVariable = node.loopVariable; | |
| 6309 _writer.print("for ("); | |
| 6310 if (loopVariable == null) { | |
| 6311 visit(node.identifier); | |
| 6312 } else { | |
| 6313 visit(loopVariable); | |
| 6314 } | |
| 6315 _writer.print(" in "); | |
| 6316 visit(node.iterator); | |
| 6317 _writer.print(") "); | |
| 6318 visit(node.body); | |
| 6319 return null; | |
| 6320 } | |
| 6321 Object visitFormalParameterList(FormalParameterList node) { | |
| 6322 String groupEnd = null; | |
| 6323 _writer.print('('); | |
| 6324 NodeList<FormalParameter> parameters = node.parameters; | |
| 6325 int size = parameters.length; | |
| 6326 for (int i = 0; i < size; i++) { | |
| 6327 FormalParameter parameter = parameters[i]; | |
| 6328 if (i > 0) { | |
| 6329 _writer.print(", "); | |
| 6330 } | |
| 6331 if (groupEnd == null && parameter is DefaultFormalParameter) { | |
| 6332 if (identical(parameter.kind, ParameterKind.NAMED)) { | |
| 6333 groupEnd = "}"; | |
| 6334 _writer.print('{'); | |
| 6335 } else { | |
| 6336 groupEnd = "]"; | |
| 6337 _writer.print('['); | |
| 6338 } | |
| 6339 } | |
| 6340 parameter.accept(this); | |
| 6341 } | |
| 6342 if (groupEnd != null) { | |
| 6343 _writer.print(groupEnd); | |
| 6344 } | |
| 6345 _writer.print(')'); | |
| 6346 return null; | |
| 6347 } | |
| 6348 Object visitForStatement(ForStatement node) { | |
| 6349 Expression initialization = node.initialization; | |
| 6350 _writer.print("for ("); | |
| 6351 if (initialization != null) { | |
| 6352 visit(initialization); | |
| 6353 } else { | |
| 6354 visit(node.variables); | |
| 6355 } | |
| 6356 _writer.print(";"); | |
| 6357 visit7(" ", node.condition); | |
| 6358 _writer.print(";"); | |
| 6359 visitList7(" ", node.updaters, ", "); | |
| 6360 _writer.print(") "); | |
| 6361 visit(node.body); | |
| 6362 return null; | |
| 6363 } | |
| 6364 Object visitFunctionDeclaration(FunctionDeclaration node) { | |
| 6365 visit6(node.returnType, " "); | |
| 6366 visit8(node.propertyKeyword, " "); | |
| 6367 visit(node.name); | |
| 6368 visit(node.functionExpression); | |
| 6369 return null; | |
| 6370 } | |
| 6371 Object visitFunctionDeclarationStatement(FunctionDeclarationStatement node) { | |
| 6372 visit(node.functionDeclaration); | |
| 6373 _writer.print(';'); | |
| 6374 return null; | |
| 6375 } | |
| 6376 Object visitFunctionExpression(FunctionExpression node) { | |
| 6377 visit(node.parameters); | |
| 6378 _writer.print(' '); | |
| 6379 visit(node.body); | |
| 6380 return null; | |
| 6381 } | |
| 6382 Object visitFunctionExpressionInvocation(FunctionExpressionInvocation node) { | |
| 6383 visit(node.function); | |
| 6384 visit(node.argumentList); | |
| 6385 return null; | |
| 6386 } | |
| 6387 Object visitFunctionTypeAlias(FunctionTypeAlias node) { | |
| 6388 _writer.print("typedef "); | |
| 6389 visit6(node.returnType, " "); | |
| 6390 visit(node.name); | |
| 6391 visit(node.typeParameters); | |
| 6392 visit(node.parameters); | |
| 6393 _writer.print(";"); | |
| 6394 return null; | |
| 6395 } | |
| 6396 Object visitFunctionTypedFormalParameter(FunctionTypedFormalParameter node) { | |
| 6397 visit6(node.returnType, " "); | |
| 6398 visit(node.identifier); | |
| 6399 visit(node.parameters); | |
| 6400 return null; | |
| 6401 } | |
| 6402 Object visitHideCombinator(HideCombinator node) { | |
| 6403 _writer.print("hide "); | |
| 6404 visitList5(node.hiddenNames, ", "); | |
| 6405 return null; | |
| 6406 } | |
| 6407 Object visitIfStatement(IfStatement node) { | |
| 6408 _writer.print("if ("); | |
| 6409 visit(node.condition); | |
| 6410 _writer.print(") "); | |
| 6411 visit(node.thenStatement); | |
| 6412 visit7(" else ", node.elseStatement); | |
| 6413 return null; | |
| 6414 } | |
| 6415 Object visitImplementsClause(ImplementsClause node) { | |
| 6416 _writer.print("implements "); | |
| 6417 visitList5(node.interfaces, ", "); | |
| 6418 return null; | |
| 6419 } | |
| 6420 Object visitImportDirective(ImportDirective node) { | |
| 6421 _writer.print("import "); | |
| 6422 visit(node.uri); | |
| 6423 visit7(" as ", node.prefix); | |
| 6424 visitList7(" ", node.combinators, " "); | |
| 6425 _writer.print(';'); | |
| 6426 return null; | |
| 6427 } | |
| 6428 Object visitIndexExpression(IndexExpression node) { | |
| 6429 if (node.isCascaded) { | |
| 6430 _writer.print(".."); | |
| 6431 } else { | |
| 6432 visit(node.target); | |
| 6433 } | |
| 6434 _writer.print('['); | |
| 6435 visit(node.index); | |
| 6436 _writer.print(']'); | |
| 6437 return null; | |
| 6438 } | |
| 6439 Object visitInstanceCreationExpression(InstanceCreationExpression node) { | |
| 6440 visit8(node.keyword, " "); | |
| 6441 visit(node.constructorName); | |
| 6442 visit(node.argumentList); | |
| 6443 return null; | |
| 6444 } | |
| 6445 Object visitIntegerLiteral(IntegerLiteral node) { | |
| 6446 _writer.print(node.literal.lexeme); | |
| 6447 return null; | |
| 6448 } | |
| 6449 Object visitInterpolationExpression(InterpolationExpression node) { | |
| 6450 if (node.rightBracket != null) { | |
| 6451 _writer.print("\${"); | |
| 6452 visit(node.expression); | |
| 6453 _writer.print("}"); | |
| 6454 } else { | |
| 6455 _writer.print("\$"); | |
| 6456 visit(node.expression); | |
| 6457 } | |
| 6458 return null; | |
| 6459 } | |
| 6460 Object visitInterpolationString(InterpolationString node) { | |
| 6461 _writer.print(node.contents.lexeme); | |
| 6462 return null; | |
| 6463 } | |
| 6464 Object visitIsExpression(IsExpression node) { | |
| 6465 visit(node.expression); | |
| 6466 if (node.notOperator == null) { | |
| 6467 _writer.print(" is "); | |
| 6468 } else { | |
| 6469 _writer.print(" is! "); | |
| 6470 } | |
| 6471 visit(node.type); | |
| 6472 return null; | |
| 6473 } | |
| 6474 Object visitLabel(Label node) { | |
| 6475 visit(node.label); | |
| 6476 _writer.print(":"); | |
| 6477 return null; | |
| 6478 } | |
| 6479 Object visitLabeledStatement(LabeledStatement node) { | |
| 6480 visitList6(node.labels, " ", " "); | |
| 6481 visit(node.statement); | |
| 6482 return null; | |
| 6483 } | |
| 6484 Object visitLibraryDirective(LibraryDirective node) { | |
| 6485 _writer.print("library "); | |
| 6486 visit(node.name); | |
| 6487 _writer.print(';'); | |
| 6488 nl(); | |
| 6489 return null; | |
| 6490 } | |
| 6491 Object visitLibraryIdentifier(LibraryIdentifier node) { | |
| 6492 _writer.print(node.name); | |
| 6493 return null; | |
| 6494 } | |
| 6495 Object visitListLiteral(ListLiteral node) { | |
| 6496 if (node.constKeyword != null) { | |
| 6497 _writer.print(node.constKeyword.lexeme); | |
| 6498 _writer.print(' '); | |
| 6499 } | |
| 6500 visit6(node.typeArguments, " "); | |
| 6501 _writer.print("["); | |
| 6502 { | |
| 6503 NodeList<Expression> elements = node.elements; | |
| 6504 if (elements.length < 2 || elements.toString().length < 60) { | |
| 6505 visitList5(elements, ", "); | |
| 6506 } else { | |
| 6507 String elementIndent = "${_indentString} "; | |
| 6508 _writer.print("\n"); | |
| 6509 _writer.print(elementIndent); | |
| 6510 visitList5(elements, ",\n${elementIndent}"); | |
| 6511 } | |
| 6512 } | |
| 6513 _writer.print("]"); | |
| 6514 return null; | |
| 6515 } | |
| 6516 Object visitMapLiteral(MapLiteral node) { | |
| 6517 if (node.constKeyword != null) { | |
| 6518 _writer.print(node.constKeyword.lexeme); | |
| 6519 _writer.print(' '); | |
| 6520 } | |
| 6521 visit6(node.typeArguments, " "); | |
| 6522 _writer.print("{"); | |
| 6523 visitList5(node.entries, ", "); | |
| 6524 _writer.print("}"); | |
| 6525 return null; | |
| 6526 } | |
| 6527 Object visitMapLiteralEntry(MapLiteralEntry node) { | |
| 6528 visit(node.key); | |
| 6529 _writer.print(" : "); | |
| 6530 visit(node.value); | |
| 6531 return null; | |
| 6532 } | |
| 6533 Object visitMethodDeclaration(MethodDeclaration node) { | |
| 6534 visit(node.documentationComment); | |
| 6535 visit8(node.externalKeyword, " "); | |
| 6536 visit8(node.modifierKeyword, " "); | |
| 6537 visit6(node.returnType, " "); | |
| 6538 visit8(node.propertyKeyword, " "); | |
| 6539 visit8(node.operatorKeyword, " "); | |
| 6540 visit(node.name); | |
| 6541 if (!node.isGetter) { | |
| 6542 visit(node.parameters); | |
| 6543 } | |
| 6544 if (node.body is! EmptyFunctionBody) { | |
| 6545 _writer.print(' '); | |
| 6546 } | |
| 6547 visit(node.body); | |
| 6548 return null; | |
| 6549 } | |
| 6550 Object visitMethodInvocation(MethodInvocation node) { | |
| 6551 if (node.isCascaded) { | |
| 6552 _writer.print(".."); | |
| 6553 } else { | |
| 6554 visit6(node.target, "."); | |
| 6555 } | |
| 6556 visit(node.methodName); | |
| 6557 visit(node.argumentList); | |
| 6558 return null; | |
| 6559 } | |
| 6560 Object visitNamedExpression(NamedExpression node) { | |
| 6561 visit(node.name); | |
| 6562 visit7(" ", node.expression); | |
| 6563 return null; | |
| 6564 } | |
| 6565 Object visitNativeClause(NativeClause node) { | |
| 6566 _writer.print("native "); | |
| 6567 visit(node.name); | |
| 6568 return null; | |
| 6569 } | |
| 6570 Object visitNativeFunctionBody(NativeFunctionBody node) { | |
| 6571 _writer.print("native "); | |
| 6572 visit(node.stringLiteral); | |
| 6573 _writer.print(';'); | |
| 6574 return null; | |
| 6575 } | |
| 6576 Object visitNullLiteral(NullLiteral node) { | |
| 6577 _writer.print("null"); | |
| 6578 return null; | |
| 6579 } | |
| 6580 Object visitParenthesizedExpression(ParenthesizedExpression node) { | |
| 6581 _writer.print('('); | |
| 6582 visit(node.expression); | |
| 6583 _writer.print(')'); | |
| 6584 return null; | |
| 6585 } | |
| 6586 Object visitPartDirective(PartDirective node) { | |
| 6587 _writer.print("part "); | |
| 6588 visit(node.uri); | |
| 6589 _writer.print(';'); | |
| 6590 return null; | |
| 6591 } | |
| 6592 Object visitPartOfDirective(PartOfDirective node) { | |
| 6593 _writer.print("part of "); | |
| 6594 visit(node.libraryName); | |
| 6595 _writer.print(';'); | |
| 6596 return null; | |
| 6597 } | |
| 6598 Object visitPostfixExpression(PostfixExpression node) { | |
| 6599 visit(node.operand); | |
| 6600 _writer.print(node.operator.lexeme); | |
| 6601 return null; | |
| 6602 } | |
| 6603 Object visitPrefixedIdentifier(PrefixedIdentifier node) { | |
| 6604 visit(node.prefix); | |
| 6605 _writer.print('.'); | |
| 6606 visit(node.identifier); | |
| 6607 return null; | |
| 6608 } | |
| 6609 Object visitPrefixExpression(PrefixExpression node) { | |
| 6610 _writer.print(node.operator.lexeme); | |
| 6611 visit(node.operand); | |
| 6612 return null; | |
| 6613 } | |
| 6614 Object visitPropertyAccess(PropertyAccess node) { | |
| 6615 if (node.isCascaded) { | |
| 6616 _writer.print(".."); | |
| 6617 } else { | |
| 6618 visit6(node.target, "."); | |
| 6619 } | |
| 6620 visit(node.propertyName); | |
| 6621 return null; | |
| 6622 } | |
| 6623 Object visitRedirectingConstructorInvocation(RedirectingConstructorInvocation
node) { | |
| 6624 _writer.print("this"); | |
| 6625 visit7(".", node.constructorName); | |
| 6626 visit(node.argumentList); | |
| 6627 return null; | |
| 6628 } | |
| 6629 Object visitRethrowExpression(RethrowExpression node) { | |
| 6630 _writer.print("rethrow"); | |
| 6631 return null; | |
| 6632 } | |
| 6633 Object visitReturnStatement(ReturnStatement node) { | |
| 6634 Expression expression = node.expression; | |
| 6635 if (expression == null) { | |
| 6636 _writer.print("return;"); | |
| 6637 } else { | |
| 6638 _writer.print("return "); | |
| 6639 expression.accept(this); | |
| 6640 _writer.print(";"); | |
| 6641 } | |
| 6642 return null; | |
| 6643 } | |
| 6644 Object visitScriptTag(ScriptTag node) { | |
| 6645 _writer.print(node.scriptTag.lexeme); | |
| 6646 return null; | |
| 6647 } | |
| 6648 Object visitShowCombinator(ShowCombinator node) { | |
| 6649 _writer.print("show "); | |
| 6650 visitList5(node.shownNames, ", "); | |
| 6651 return null; | |
| 6652 } | |
| 6653 Object visitSimpleFormalParameter(SimpleFormalParameter node) { | |
| 6654 visit8(node.keyword, " "); | |
| 6655 visit6(node.type, " "); | |
| 6656 visit(node.identifier); | |
| 6657 return null; | |
| 6658 } | |
| 6659 Object visitSimpleIdentifier(SimpleIdentifier node) { | |
| 6660 _writer.print(node.token.lexeme); | |
| 6661 return null; | |
| 6662 } | |
| 6663 Object visitSimpleStringLiteral(SimpleStringLiteral node) { | |
| 6664 _writer.print(node.literal.lexeme); | |
| 6665 return null; | |
| 6666 } | |
| 6667 Object visitStringInterpolation(StringInterpolation node) { | |
| 6668 visitList(node.elements); | |
| 6669 return null; | |
| 6670 } | |
| 6671 Object visitSuperConstructorInvocation(SuperConstructorInvocation node) { | |
| 6672 _writer.print("super"); | |
| 6673 visit7(".", node.constructorName); | |
| 6674 visit(node.argumentList); | |
| 6675 return null; | |
| 6676 } | |
| 6677 Object visitSuperExpression(SuperExpression node) { | |
| 6678 _writer.print("super"); | |
| 6679 return null; | |
| 6680 } | |
| 6681 Object visitSwitchCase(SwitchCase node) { | |
| 6682 visitList6(node.labels, " ", " "); | |
| 6683 _writer.print("case "); | |
| 6684 visit(node.expression); | |
| 6685 _writer.print(": "); | |
| 6686 { | |
| 6687 indentInc(); | |
| 6688 visitList5(node.statements, "\n"); | |
| 6689 indentDec(); | |
| 6690 } | |
| 6691 return null; | |
| 6692 } | |
| 6693 Object visitSwitchDefault(SwitchDefault node) { | |
| 6694 visitList6(node.labels, " ", " "); | |
| 6695 _writer.print("default: "); | |
| 6696 { | |
| 6697 indentInc(); | |
| 6698 visitList5(node.statements, "\n"); | |
| 6699 indentDec(); | |
| 6700 } | |
| 6701 return null; | |
| 6702 } | |
| 6703 Object visitSwitchStatement(SwitchStatement node) { | |
| 6704 _writer.print("switch ("); | |
| 6705 visit(node.expression); | |
| 6706 _writer.print(") {"); | |
| 6707 { | |
| 6708 indentInc(); | |
| 6709 visitList5(node.members, "\n"); | |
| 6710 indentDec(); | |
| 6711 } | |
| 6712 nl2(); | |
| 6713 _writer.print('}'); | |
| 6714 return null; | |
| 6715 } | |
| 6716 Object visitSymbolLiteral(SymbolLiteral node) { | |
| 6717 _writer.print("#"); | |
| 6718 visitList8(node.components, "."); | |
| 6719 return null; | |
| 6720 } | |
| 6721 Object visitThisExpression(ThisExpression node) { | |
| 6722 _writer.print("this"); | |
| 6723 return null; | |
| 6724 } | |
| 6725 Object visitThrowExpression(ThrowExpression node) { | |
| 6726 _writer.print("throw "); | |
| 6727 visit(node.expression); | |
| 6728 return null; | |
| 6729 } | |
| 6730 Object visitTopLevelVariableDeclaration(TopLevelVariableDeclaration node) { | |
| 6731 visit6(node.variables, ";"); | |
| 6732 return null; | |
| 6733 } | |
| 6734 Object visitTryStatement(TryStatement node) { | |
| 6735 _writer.print("try "); | |
| 6736 visit(node.body); | |
| 6737 visitList7(" ", node.catchClauses, " "); | |
| 6738 visit7(" finally ", node.finallyBlock); | |
| 6739 return null; | |
| 6740 } | |
| 6741 Object visitTypeArgumentList(TypeArgumentList node) { | |
| 6742 _writer.print('<'); | |
| 6743 visitList5(node.arguments, ", "); | |
| 6744 _writer.print('>'); | |
| 6745 return null; | |
| 6746 } | |
| 6747 Object visitTypeName(TypeName node) { | |
| 6748 visit(node.name); | |
| 6749 visit(node.typeArguments); | |
| 6750 return null; | |
| 6751 } | |
| 6752 Object visitTypeParameter(TypeParameter node) { | |
| 6753 visit(node.name); | |
| 6754 visit7(" extends ", node.bound); | |
| 6755 return null; | |
| 6756 } | |
| 6757 Object visitTypeParameterList(TypeParameterList node) { | |
| 6758 _writer.print('<'); | |
| 6759 visitList5(node.typeParameters, ", "); | |
| 6760 _writer.print('>'); | |
| 6761 return null; | |
| 6762 } | |
| 6763 Object visitVariableDeclaration(VariableDeclaration node) { | |
| 6764 visit(node.name); | |
| 6765 visit7(" = ", node.initializer); | |
| 6766 return null; | |
| 6767 } | |
| 6768 Object visitVariableDeclarationList(VariableDeclarationList node) { | |
| 6769 visit8(node.keyword, " "); | |
| 6770 visit6(node.type, " "); | |
| 6771 visitList5(node.variables, ", "); | |
| 6772 return null; | |
| 6773 } | |
| 6774 Object visitVariableDeclarationStatement(VariableDeclarationStatement node) { | |
| 6775 visit(node.variables); | |
| 6776 _writer.print(";"); | |
| 6777 return null; | |
| 6778 } | |
| 6779 Object visitWhileStatement(WhileStatement node) { | |
| 6780 _writer.print("while ("); | |
| 6781 visit(node.condition); | |
| 6782 _writer.print(") "); | |
| 6783 visit(node.body); | |
| 6784 return null; | |
| 6785 } | |
| 6786 Object visitWithClause(WithClause node) { | |
| 6787 _writer.print("with "); | |
| 6788 visitList5(node.mixinTypes, ", "); | |
| 6789 return null; | |
| 6790 } | |
| 6791 void indent() { | |
| 6792 _writer.print(_indentString); | |
| 6793 } | |
| 6794 void indentDec() { | |
| 6795 _indentLevel -= 2; | |
| 6796 _indentString = StringUtils.repeat(" ", _indentLevel); | |
| 6797 } | |
| 6798 void indentInc() { | |
| 6799 _indentLevel += 2; | |
| 6800 _indentString = StringUtils.repeat(" ", _indentLevel); | |
| 6801 } | |
| 6802 void nl() { | |
| 6803 _writer.print("\n"); | |
| 6804 } | |
| 6805 void nl2() { | |
| 6806 nl(); | |
| 6807 indent(); | |
| 6808 } | |
| 6809 | |
| 6810 /** | |
| 6811 * Safely visit the given node. | |
| 6812 * | |
| 6813 * @param node the node to be visited | |
| 6814 */ | |
| 6815 void visit(ASTNode node) { | |
| 6816 if (node != null) { | |
| 6817 node.accept(this); | |
| 6818 } | |
| 6819 } | |
| 6820 | |
| 6821 /** | |
| 6822 * Safely visit the given node, printing the suffix after the node if it is no
n-<code>null</code>. | |
| 6823 * | |
| 6824 * @param suffix the suffix to be printed if there is a node to visit | |
| 6825 * @param node the node to be visited | |
| 6826 */ | |
| 6827 void visit6(ASTNode node, String suffix) { | |
| 6828 if (node != null) { | |
| 6829 node.accept(this); | |
| 6830 _writer.print(suffix); | |
| 6831 } | |
| 6832 } | |
| 6833 | |
| 6834 /** | |
| 6835 * Safely visit the given node, printing the prefix before the node if it is n
on-<code>null</code> | |
| 6836 * . | |
| 6837 * | |
| 6838 * @param prefix the prefix to be printed if there is a node to visit | |
| 6839 * @param node the node to be visited | |
| 6840 */ | |
| 6841 void visit7(String prefix, ASTNode node) { | |
| 6842 if (node != null) { | |
| 6843 _writer.print(prefix); | |
| 6844 node.accept(this); | |
| 6845 } | |
| 6846 } | |
| 6847 | |
| 6848 /** | |
| 6849 * Safely visit the given node, printing the suffix after the node if it is no
n-<code>null</code>. | |
| 6850 * | |
| 6851 * @param suffix the suffix to be printed if there is a node to visit | |
| 6852 * @param node the node to be visited | |
| 6853 */ | |
| 6854 void visit8(Token token, String suffix) { | |
| 6855 if (token != null) { | |
| 6856 _writer.print(token.lexeme); | |
| 6857 _writer.print(suffix); | |
| 6858 } | |
| 6859 } | |
| 6860 | |
| 6861 /** | |
| 6862 * Print a list of nodes without any separation. | |
| 6863 * | |
| 6864 * @param nodes the nodes to be printed | |
| 6865 * @param separator the separator to be printed between adjacent nodes | |
| 6866 */ | |
| 6867 void visitList(NodeList<ASTNode> nodes) { | |
| 6868 visitList5(nodes, ""); | |
| 6869 } | |
| 6870 | |
| 6871 /** | |
| 6872 * Print a list of nodes, separated by the given separator. | |
| 6873 * | |
| 6874 * @param nodes the nodes to be printed | |
| 6875 * @param separator the separator to be printed between adjacent nodes | |
| 6876 */ | |
| 6877 void visitList5(NodeList<ASTNode> nodes, String separator) { | |
| 6878 if (nodes != null) { | |
| 6879 int size = nodes.length; | |
| 6880 for (int i = 0; i < size; i++) { | |
| 6881 if ("\n" == separator) { | |
| 6882 _writer.print("\n"); | |
| 6883 indent(); | |
| 6884 } else if (i > 0) { | |
| 6885 _writer.print(separator); | |
| 6886 } | |
| 6887 nodes[i].accept(this); | |
| 6888 } | |
| 6889 } | |
| 6890 } | |
| 6891 | |
| 6892 /** | |
| 6893 * Print a list of nodes, separated by the given separator. | |
| 6894 * | |
| 6895 * @param nodes the nodes to be printed | |
| 6896 * @param separator the separator to be printed between adjacent nodes | |
| 6897 * @param suffix the suffix to be printed if the list is not empty | |
| 6898 */ | |
| 6899 void visitList6(NodeList<ASTNode> nodes, String separator, String suffix) { | |
| 6900 if (nodes != null) { | |
| 6901 int size = nodes.length; | |
| 6902 if (size > 0) { | |
| 6903 for (int i = 0; i < size; i++) { | |
| 6904 if (i > 0) { | |
| 6905 _writer.print(separator); | |
| 6906 } | |
| 6907 nodes[i].accept(this); | |
| 6908 } | |
| 6909 _writer.print(suffix); | |
| 6910 } | |
| 6911 } | |
| 6912 } | |
| 6913 | |
| 6914 /** | |
| 6915 * Print a list of nodes, separated by the given separator. | |
| 6916 * | |
| 6917 * @param prefix the prefix to be printed if the list is not empty | |
| 6918 * @param nodes the nodes to be printed | |
| 6919 * @param separator the separator to be printed between adjacent nodes | |
| 6920 */ | |
| 6921 void visitList7(String prefix, NodeList<ASTNode> nodes, String separator) { | |
| 6922 if (nodes != null) { | |
| 6923 int size = nodes.length; | |
| 6924 if (size > 0) { | |
| 6925 _writer.print(prefix); | |
| 6926 for (int i = 0; i < size; i++) { | |
| 6927 if (i > 0) { | |
| 6928 _writer.print(separator); | |
| 6929 } | |
| 6930 nodes[i].accept(this); | |
| 6931 } | |
| 6932 } | |
| 6933 } | |
| 6934 } | |
| 6935 | |
| 6936 /** | |
| 6937 * Print a list of tokens, separated by the given separator. | |
| 6938 * | |
| 6939 * @param tokens the tokens to be printed | |
| 6940 * @param separator the separator to be printed between adjacent tokens | |
| 6941 */ | |
| 6942 void visitList8(List<Token> tokens, String separator) { | |
| 6943 int size = tokens.length; | |
| 6944 for (int i = 0; i < size; i++) { | |
| 6945 if ("\n" == separator) { | |
| 6946 _writer.print("\n"); | |
| 6947 indent(); | |
| 6948 } else if (i > 0) { | |
| 6949 _writer.print(separator); | |
| 6950 } | |
| 6951 _writer.print(tokens[i].lexeme); | |
| 6952 } | |
| 6953 } | |
| 6954 } | |
| OLD | NEW |