| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | |
| 2 // for details. All rights reserved. Use of this source code is governed by a | |
| 3 // BSD-style license that can be found in the LICENSE file. | |
| 4 | |
| 5 /** | |
| 6 * An event generating parser of Dart programs. This parser expects | |
| 7 * all tokens in a linked list. | |
| 8 */ | |
| 9 class Parser { | |
| 10 final Listener listener; | |
| 11 bool mayParseFunctionExpressions = true; | |
| 12 | |
| 13 Parser(Listener this.listener); | |
| 14 | |
| 15 void parseUnit(Token token) { | |
| 16 while (token.kind !== EOF_TOKEN) { | |
| 17 token = parseTopLevelDeclaration(token); | |
| 18 } | |
| 19 } | |
| 20 | |
| 21 Token parseTopLevelDeclaration(Token token) { | |
| 22 final String value = token.stringValue; | |
| 23 if (value === 'interface') { | |
| 24 return parseInterface(token); | |
| 25 } else if ((value === 'abstract') || (value === 'class')) { | |
| 26 return parseClass(token); | |
| 27 } else if (value === 'typedef') { | |
| 28 return parseNamedFunctionAlias(token); | |
| 29 } else if (value === '#') { | |
| 30 return parseScriptTags(token); | |
| 31 } else { | |
| 32 return parseTopLevelMember(token); | |
| 33 } | |
| 34 } | |
| 35 | |
| 36 Token parseInterface(Token token) { | |
| 37 Token interfaceKeyword = token; | |
| 38 listener.beginInterface(token); | |
| 39 token = parseIdentifier(token.next); | |
| 40 token = parseTypeVariablesOpt(token); | |
| 41 int supertypeCount = 0; | |
| 42 Token extendsKeyword = null; | |
| 43 if (optional('extends', token)) { | |
| 44 extendsKeyword = token; | |
| 45 do { | |
| 46 token = parseType(token.next); | |
| 47 ++supertypeCount; | |
| 48 } while (optional(',', token)); | |
| 49 } | |
| 50 token = parseDefaultClauseOpt(token); | |
| 51 token = parseInterfaceBody(token); | |
| 52 listener.endInterface(supertypeCount, interfaceKeyword, | |
| 53 extendsKeyword, token); | |
| 54 return token.next; | |
| 55 } | |
| 56 | |
| 57 Token parseInterfaceBody(Token token) { | |
| 58 return parseClassBody(token); | |
| 59 } | |
| 60 | |
| 61 Token parseNamedFunctionAlias(Token token) { | |
| 62 Token typedefKeyword = token; | |
| 63 listener.beginFunctionTypeAlias(token); | |
| 64 token = parseReturnTypeOpt(token.next); | |
| 65 token = parseIdentifier(token); | |
| 66 token = parseTypeVariablesOpt(token); | |
| 67 token = parseFormalParameters(token); | |
| 68 listener.endFunctionTypeAlias(typedefKeyword, token); | |
| 69 return expect(';', token); | |
| 70 } | |
| 71 | |
| 72 Token parseReturnTypeOpt(Token token) { | |
| 73 if (token.stringValue === 'void') { | |
| 74 listener.handleVoidKeyword(token); | |
| 75 return token.next; | |
| 76 } else { | |
| 77 return parseTypeOpt(token); | |
| 78 } | |
| 79 } | |
| 80 | |
| 81 Token parseFormalParameters(Token token) { | |
| 82 Token begin = token; | |
| 83 listener.beginFormalParameters(begin); | |
| 84 expect('(', token); | |
| 85 int parameterCount = 0; | |
| 86 if (optional(')', token.next)) { | |
| 87 listener.endFormalParameters(parameterCount, begin, token.next); | |
| 88 return token.next.next; | |
| 89 } | |
| 90 do { | |
| 91 ++parameterCount; | |
| 92 token = token.next; | |
| 93 if (optional('[', token)) { | |
| 94 token = parseOptionalFormalParameters(token); | |
| 95 break; | |
| 96 } | |
| 97 token = parseFormalParameter(token); | |
| 98 } while (optional(',', token)); | |
| 99 listener.endFormalParameters(parameterCount, begin, token); | |
| 100 return expect(')', token); | |
| 101 } | |
| 102 | |
| 103 Token parseFormalParameter(Token token) { | |
| 104 listener.beginFormalParameter(token); | |
| 105 token = parseModifiers(token); | |
| 106 // TODO(ahe): Validate that there are formal parameters if void. | |
| 107 token = parseReturnTypeOpt(token); | |
| 108 Token thisKeyword = null; | |
| 109 if (optional('this', token)) { | |
| 110 thisKeyword = token; | |
| 111 // TODO(ahe): Validate field initializers are only used in | |
| 112 // constructors, and not for function-typed arguments. | |
| 113 token = expect('.', token.next); | |
| 114 } | |
| 115 token = parseIdentifier(token); | |
| 116 if (optional('(', token)) { | |
| 117 token = parseFormalParameters(token); | |
| 118 listener.handleFunctionTypedFormalParameter(token); | |
| 119 } | |
| 120 if (optional('=', token)) { | |
| 121 // TODO(ahe): Validate that these are only used for optional parameters. | |
| 122 Token equal = token; | |
| 123 token = parseExpression(token.next); | |
| 124 listener.handleValuedFormalParameter(equal, token); | |
| 125 } | |
| 126 listener.endFormalParameter(token, thisKeyword); | |
| 127 return token; | |
| 128 } | |
| 129 | |
| 130 Token parseOptionalFormalParameters(Token token) { | |
| 131 Token begin = token; | |
| 132 listener.beginOptionalFormalParameters(begin); | |
| 133 assert(optional('[', token)); | |
| 134 int parameterCount = 0; | |
| 135 do { | |
| 136 token = token.next; | |
| 137 token = parseFormalParameter(token); | |
| 138 ++parameterCount; | |
| 139 } while (optional(',', token)); | |
| 140 listener.endOptionalFormalParameters(parameterCount, begin, token); | |
| 141 return expect(']', token); | |
| 142 } | |
| 143 | |
| 144 Token parseTypeOpt(Token token) { | |
| 145 String value = token.stringValue; | |
| 146 if (value === 'var') return parseType(token); | |
| 147 if (value !== 'this') { | |
| 148 Token peek = peekAfterType(token); | |
| 149 if (isIdentifier(peek) || optional('this', peek)) { | |
| 150 return parseType(token); | |
| 151 } | |
| 152 } | |
| 153 listener.handleNoType(token); | |
| 154 return token; | |
| 155 } | |
| 156 | |
| 157 bool isIdentifier(Token token) { | |
| 158 final kind = token.kind; | |
| 159 if (kind === IDENTIFIER_TOKEN) return true; | |
| 160 if (kind === KEYWORD_TOKEN) return token.value.isPseudo; | |
| 161 return false; | |
| 162 } | |
| 163 | |
| 164 Token parseDefaultClauseOpt(Token token) { | |
| 165 if (isDefaultKeyword(token)) { | |
| 166 // TODO(ahe): Remove support for 'factory' in this position. | |
| 167 Token defaultKeyword = token; | |
| 168 listener.beginDefaultClause(defaultKeyword); | |
| 169 token = parseIdentifier(token.next); | |
| 170 token = parseQualifiedRestOpt(token); | |
| 171 token = parseTypeVariablesOpt(token); | |
| 172 listener.endDefaultClause(defaultKeyword); | |
| 173 } else { | |
| 174 listener.handleNoDefaultClause(token); | |
| 175 } | |
| 176 return token; | |
| 177 } | |
| 178 | |
| 179 Token parseQualifiedRestOpt(Token token) { | |
| 180 if (optional('.', token)) { | |
| 181 Token period = token; | |
| 182 token = parseIdentifier(token.next); | |
| 183 listener.handleQualified(period); | |
| 184 } | |
| 185 return token; | |
| 186 } | |
| 187 | |
| 188 bool isDefaultKeyword(Token token) { | |
| 189 String value = token.stringValue; | |
| 190 if (value === 'default') return true; | |
| 191 if (value === 'factory') { | |
| 192 listener.recoverableError("expected 'default'", token: token); | |
| 193 return true; | |
| 194 } | |
| 195 return false; | |
| 196 } | |
| 197 | |
| 198 Token skipBlock(Token token) { | |
| 199 if (!optional('{', token)) { | |
| 200 return listener.expectedBlockToSkip(token); | |
| 201 } | |
| 202 BeginGroupToken beginGroupToken = token; | |
| 203 assert(beginGroupToken.endGroup === null || | |
| 204 beginGroupToken.endGroup.kind === $CLOSE_CURLY_BRACKET); | |
| 205 return beginGroupToken.endGroup; | |
| 206 } | |
| 207 | |
| 208 Token parseClass(Token token) { | |
| 209 Token begin = token; | |
| 210 listener.beginClassDeclaration(token); | |
| 211 if (optional('abstract', token)) { | |
| 212 // TODO(ahe): Notify listener about abstract modifier. | |
| 213 token = token.next; | |
| 214 } | |
| 215 token = parseIdentifier(token.next); | |
| 216 token = parseTypeVariablesOpt(token); | |
| 217 Token extendsKeyword; | |
| 218 if (optional('extends', token)) { | |
| 219 extendsKeyword = token; | |
| 220 token = parseType(token.next); | |
| 221 } else { | |
| 222 extendsKeyword = null; | |
| 223 listener.handleNoType(token); | |
| 224 } | |
| 225 Token implementsKeyword; | |
| 226 int interfacesCount = 0; | |
| 227 if (optional('implements', token)) { | |
| 228 do { | |
| 229 token = parseType(token.next); | |
| 230 ++interfacesCount; | |
| 231 } while (optional(',', token)); | |
| 232 } | |
| 233 token = parseClassBody(token); | |
| 234 listener.endClassDeclaration(interfacesCount, begin, extendsKeyword, | |
| 235 implementsKeyword, token); | |
| 236 return token.next; | |
| 237 } | |
| 238 | |
| 239 | |
| 240 Token parseStringPart(Token token) { | |
| 241 if (token.kind === STRING_TOKEN) { | |
| 242 listener.handleStringPart(token); | |
| 243 return token.next; | |
| 244 } else { | |
| 245 return listener.expected('string', token); | |
| 246 } | |
| 247 } | |
| 248 | |
| 249 Token parseIdentifier(Token token) { | |
| 250 if (isIdentifier(token)) { | |
| 251 listener.handleIdentifier(token); | |
| 252 } else { | |
| 253 listener.expectedIdentifier(token); | |
| 254 } | |
| 255 return token.next; | |
| 256 } | |
| 257 | |
| 258 Token expect(String string, Token token) { | |
| 259 if (string !== token.stringValue) { | |
| 260 if (string === '>') { | |
| 261 if (token.stringValue === '>>') { | |
| 262 Token gt = new Token(GT_INFO, token.charOffset + 1); | |
| 263 gt.next = token.next; | |
| 264 return gt; | |
| 265 } else if (token.stringValue === '>>>') { | |
| 266 Token gtgt = new Token(GT_GT_INFO, token.charOffset + 1); | |
| 267 gtgt.next = token.next; | |
| 268 return gtgt; | |
| 269 } | |
| 270 } | |
| 271 return listener.expected(string, token); | |
| 272 } | |
| 273 return token.next; | |
| 274 } | |
| 275 | |
| 276 Token parseTypeVariable(Token token) { | |
| 277 listener.beginTypeVariable(token); | |
| 278 token = parseIdentifier(token); | |
| 279 if (optional('extends', token)) { | |
| 280 token = parseType(token.next); | |
| 281 } else { | |
| 282 listener.handleNoType(token); | |
| 283 } | |
| 284 listener.endTypeVariable(token); | |
| 285 return token; | |
| 286 } | |
| 287 | |
| 288 bool optional(String value, Token token) => value === token.stringValue; | |
| 289 | |
| 290 bool notEofOrValue(String value, Token token) { | |
| 291 return token.kind !== EOF_TOKEN && value !== token.stringValue; | |
| 292 } | |
| 293 | |
| 294 Token parseType(Token token) { | |
| 295 Token begin = token; | |
| 296 if (isIdentifier(token)) { | |
| 297 token = parseIdentifier(token); | |
| 298 token = parseQualifiedRestOpt(token); | |
| 299 } else { | |
| 300 token = listener.expectedType(token); | |
| 301 } | |
| 302 token = parseTypeArgumentsOpt(token); | |
| 303 listener.endType(begin, token); | |
| 304 return token; | |
| 305 } | |
| 306 | |
| 307 Token parseTypeArgumentsOpt(Token token) { | |
| 308 return parseStuff(token, | |
| 309 (t) => listener.beginTypeArguments(t), | |
| 310 (t) => parseType(t), | |
| 311 (c, bt, et) => listener.endTypeArguments(c, bt, et), | |
| 312 (t) => listener.handleNoTypeArguments(t)); | |
| 313 } | |
| 314 | |
| 315 Token parseTypeVariablesOpt(Token token) { | |
| 316 return parseStuff(token, | |
| 317 (t) => listener.beginTypeVariables(t), | |
| 318 (t) => parseTypeVariable(t), | |
| 319 (c, bt, et) => listener.endTypeVariables(c, bt, et), | |
| 320 (t) => listener.handleNoTypeVariables(t)); | |
| 321 } | |
| 322 | |
| 323 // TODO(ahe): Clean this up. | |
| 324 Token parseStuff(Token token, Function beginStuff, Function stuffParser, | |
| 325 Function endStuff, Function handleNoStuff) { | |
| 326 if (optional('<', token)) { | |
| 327 Token begin = token; | |
| 328 beginStuff(begin); | |
| 329 int count = 0; | |
| 330 do { | |
| 331 token = stuffParser(token.next); | |
| 332 ++count; | |
| 333 } while (optional(',', token)); | |
| 334 endStuff(count, begin, token); | |
| 335 return expect('>', token); | |
| 336 } | |
| 337 handleNoStuff(token); | |
| 338 return token; | |
| 339 } | |
| 340 | |
| 341 Token parseTopLevelMember(Token token) { | |
| 342 Token start = token; | |
| 343 listener.beginTopLevelMember(token); | |
| 344 token = parseModifiers(token); | |
| 345 Token getOrSet = findGetOrSet(token); | |
| 346 if (token === getOrSet) token = token.next; | |
| 347 Token peek = peekAfterType(token); | |
| 348 if (isIdentifier(peek)) { | |
| 349 // Skip type. | |
| 350 token = peek; | |
| 351 } | |
| 352 if (token === getOrSet) token = token.next; | |
| 353 token = parseIdentifier(token); | |
| 354 bool isField; | |
| 355 while (true) { | |
| 356 // Loop to allow the listener to rewrite the token stream for | |
| 357 // error handling. | |
| 358 final String value = token.stringValue; | |
| 359 if (value === '(') { | |
| 360 isField = false; | |
| 361 break; | |
| 362 } else if ((value === '=') || (value === ';') || (value === ',')) { | |
| 363 isField = true; | |
| 364 break; | |
| 365 } else { | |
| 366 token = listener.unexpected(token); | |
| 367 if (token.kind === EOF_TOKEN) { | |
| 368 // TODO(ahe): This is a hack. It would be better to tell the | |
| 369 // listener more explicitly that it must pop an identifier. | |
| 370 listener.endTopLevelFields(1, start, token); | |
| 371 return token; | |
| 372 } | |
| 373 } | |
| 374 } | |
| 375 if (isField) { | |
| 376 int fieldCount = 1; | |
| 377 token = parseVariableInitializerOpt(token); | |
| 378 while (optional(',', token)) { | |
| 379 token = parseIdentifier(token.next); | |
| 380 token = parseVariableInitializerOpt(token); | |
| 381 ++fieldCount; | |
| 382 } | |
| 383 expectSemicolon(token); | |
| 384 listener.endTopLevelFields(fieldCount, start, token); | |
| 385 } else { | |
| 386 token = parseFormalParameters(token); | |
| 387 token = parseFunctionBody(token, false); | |
| 388 listener.endTopLevelMethod(start, getOrSet, token); | |
| 389 } | |
| 390 return token.next; | |
| 391 } | |
| 392 | |
| 393 Token parseVariableInitializerOpt(Token token) { | |
| 394 if (optional('=', token)) { | |
| 395 Token assignment = token; | |
| 396 listener.beginInitializer(token); | |
| 397 token = parseExpression(token.next); | |
| 398 listener.endInitializer(assignment); | |
| 399 } | |
| 400 return token; | |
| 401 } | |
| 402 | |
| 403 Token parseInitializersOpt(Token token) { | |
| 404 if (optional(':', token)) { | |
| 405 return parseInitializers(token); | |
| 406 } else { | |
| 407 listener.handleNoInitializers(); | |
| 408 return token; | |
| 409 } | |
| 410 } | |
| 411 | |
| 412 Token parseInitializers(Token token) { | |
| 413 Token begin = token; | |
| 414 listener.beginInitializers(begin); | |
| 415 expect(':', token); | |
| 416 int count = 0; | |
| 417 bool old = mayParseFunctionExpressions; | |
| 418 mayParseFunctionExpressions = false; | |
| 419 do { | |
| 420 token = parseExpression(token.next); | |
| 421 ++count; | |
| 422 } while (optional(',', token)); | |
| 423 mayParseFunctionExpressions = old; | |
| 424 listener.endInitializers(count, begin, token); | |
| 425 return token; | |
| 426 } | |
| 427 | |
| 428 Token parseScriptTags(Token token) { | |
| 429 Token begin = token; | |
| 430 listener.beginScriptTag(token); | |
| 431 token = parseIdentifier(token.next); | |
| 432 token = expect('(', token); | |
| 433 token = parseLiteralStringOrRecoverExpression(token); | |
| 434 bool hasPrefix = false; | |
| 435 if (optional(',', token)) { | |
| 436 hasPrefix = true; | |
| 437 token = parseIdentifier(token.next); | |
| 438 token = expect(':', token); | |
| 439 token = parseLiteralStringOrRecoverExpression(token); | |
| 440 } | |
| 441 token = expect(')', token); | |
| 442 listener.endScriptTag(hasPrefix, begin, token); | |
| 443 return expectSemicolon(token); | |
| 444 } | |
| 445 | |
| 446 Token parseLiteralStringOrRecoverExpression(Token token) { | |
| 447 if (token.kind === STRING_TOKEN) { | |
| 448 return parseLiteralString(token); | |
| 449 } else { | |
| 450 listener.recoverableError("unexpected", token: token); | |
| 451 return parseExpression(token); | |
| 452 } | |
| 453 } | |
| 454 | |
| 455 Token expectSemicolon(Token token) { | |
| 456 return expect(';', token); | |
| 457 } | |
| 458 | |
| 459 Token parseModifier(Token token) { | |
| 460 assert(('final' === token.stringValue) || | |
| 461 ('var' === token.stringValue) || | |
| 462 ('const' === token.stringValue) || | |
| 463 ('abstract' === token.stringValue) || | |
| 464 ('static' === token.stringValue)); | |
| 465 listener.handleModifier(token); | |
| 466 return token.next; | |
| 467 } | |
| 468 | |
| 469 Token parseModifiers(Token token) { | |
| 470 int count = 0; | |
| 471 while (token.kind === KEYWORD_TOKEN) { | |
| 472 final String value = token.stringValue; | |
| 473 if (('final' !== value) && | |
| 474 ('var' !== value) && | |
| 475 ('const' !== value) && | |
| 476 ('abstract' !== value) && | |
| 477 ('static' !== value)) | |
| 478 break; | |
| 479 token = parseModifier(token); | |
| 480 count++; | |
| 481 } | |
| 482 listener.handleModifiers(count); | |
| 483 return token; | |
| 484 } | |
| 485 | |
| 486 Token peekAfterType(Token token) { | |
| 487 // TODO(ahe): Also handle var? | |
| 488 if ('void' !== token.stringValue && !isIdentifier(token)) { | |
| 489 listener.unexpected(token); | |
| 490 } | |
| 491 // We are looking at "identifier ...". | |
| 492 Token peek = token.next; | |
| 493 if (peek.kind === PERIOD_TOKEN) { | |
| 494 if (isIdentifier(peek.next)) { | |
| 495 // Look past a library prefix. | |
| 496 peek = peek.next.next; | |
| 497 } | |
| 498 } | |
| 499 // We are looking at "qualified ...". | |
| 500 if (peek.kind === LT_TOKEN) { | |
| 501 // Possibly generic type. | |
| 502 // We are looking at "qualified '<'". | |
| 503 BeginGroupToken beginGroupToken = peek; | |
| 504 Token gtToken = beginGroupToken.endGroup; | |
| 505 if (gtToken !== null) { | |
| 506 // We are looking at "qualified '<' ... '>' ...". | |
| 507 return gtToken.next; | |
| 508 } | |
| 509 } | |
| 510 return peek; | |
| 511 } | |
| 512 | |
| 513 Token parseClassBody(Token token) { | |
| 514 Token begin = token; | |
| 515 listener.beginClassBody(token); | |
| 516 if (!optional('{', token)) { | |
| 517 token = listener.expectedClassBody(token); | |
| 518 } | |
| 519 token = token.next; | |
| 520 int count = 0; | |
| 521 while (notEofOrValue('}', token)) { | |
| 522 token = parseMember(token); | |
| 523 ++count; | |
| 524 } | |
| 525 listener.endClassBody(count, begin, token); | |
| 526 return token; | |
| 527 } | |
| 528 | |
| 529 bool isGetOrSet(Token token) { | |
| 530 final String value = token.stringValue; | |
| 531 return (value === 'get') || (value === 'set'); | |
| 532 } | |
| 533 | |
| 534 Token findGetOrSet(Token token) { | |
| 535 if (isGetOrSet(token)) { | |
| 536 if (optional('<', token.next)) { | |
| 537 // For example: get<T> ... | |
| 538 final Token peek = peekAfterType(token); | |
| 539 if (isGetOrSet(peek) && isIdentifier(peek.next)) { | |
| 540 // For example: get<T> get identifier | |
| 541 return peek; | |
| 542 } | |
| 543 } else { | |
| 544 // For example: get ... | |
| 545 if (isGetOrSet(token.next) && isIdentifier(token.next.next)) { | |
| 546 // For example: get get identifier | |
| 547 return token.next; | |
| 548 } else { | |
| 549 // For example: get identifier | |
| 550 return token; | |
| 551 } | |
| 552 } | |
| 553 } else if (token.stringValue !== 'operator') { | |
| 554 final Token peek = peekAfterType(token); | |
| 555 if (isGetOrSet(peek) && isIdentifier(peek.next)) { | |
| 556 // type? get identifier | |
| 557 return peek; | |
| 558 } | |
| 559 } | |
| 560 return null; | |
| 561 } | |
| 562 | |
| 563 Token parseMember(Token token) { | |
| 564 if (optional('factory', token)) { | |
| 565 return parseFactoryMethod(token); | |
| 566 } | |
| 567 Token start = token; | |
| 568 listener.beginMember(token); | |
| 569 token = parseModifiers(token); | |
| 570 Token getOrSet = findGetOrSet(token); | |
| 571 if (token === getOrSet) token = token.next; | |
| 572 Token peek = peekAfterType(token); | |
| 573 if (isIdentifier(peek) && token.stringValue !== 'operator') { | |
| 574 // Skip type. | |
| 575 token = peek; | |
| 576 } | |
| 577 if (token === getOrSet) token = token.next; | |
| 578 if (optional('operator', token)) { | |
| 579 token = parseOperatorName(token); | |
| 580 } else { | |
| 581 token = parseIdentifier(token); | |
| 582 } | |
| 583 bool isField; | |
| 584 while (true) { | |
| 585 // Loop to allow the listener to rewrite the token stream for | |
| 586 // error handling. | |
| 587 final String value = token.stringValue; | |
| 588 if ((value === '(') || (value === '.')) { | |
| 589 isField = false; | |
| 590 break; | |
| 591 } else if ((value === '=') || (value === ';') || (value === ',')) { | |
| 592 isField = true; | |
| 593 break; | |
| 594 } else { | |
| 595 token = listener.unexpected(token); | |
| 596 if (token.kind === EOF_TOKEN) { | |
| 597 // TODO(ahe): This is a hack, see parseTopLevelMember. | |
| 598 listener.endFields(1, start, token); | |
| 599 return token; | |
| 600 } | |
| 601 } | |
| 602 } | |
| 603 if (isField) { | |
| 604 int fieldCount = 1; | |
| 605 token = parseVariableInitializerOpt(token); | |
| 606 if (getOrSet !== null) { | |
| 607 listener.recoverableError("unexpected", token: getOrSet); | |
| 608 } | |
| 609 while (optional(',', token)) { | |
| 610 // TODO(ahe): Count these. | |
| 611 token = parseIdentifier(token.next); | |
| 612 token = parseVariableInitializerOpt(token); | |
| 613 ++fieldCount; | |
| 614 } | |
| 615 expectSemicolon(token); | |
| 616 listener.endFields(fieldCount, start, token); | |
| 617 } else { | |
| 618 token = parseQualifiedRestOpt(token); | |
| 619 token = parseFormalParameters(token); | |
| 620 token = parseInitializersOpt(token); | |
| 621 token = parseFunctionBody(token, false); | |
| 622 listener.endMethod(getOrSet, start, token); | |
| 623 } | |
| 624 return token.next; | |
| 625 } | |
| 626 | |
| 627 Token parseFactoryMethod(Token token) { | |
| 628 assert(optional('factory', token)); | |
| 629 Token factoryKeyword = token; | |
| 630 listener.beginFactoryMethod(factoryKeyword); | |
| 631 token = token.next; // Skip 'factory'. | |
| 632 token = parseIdentifier(token); | |
| 633 token = parseQualifiedRestOpt(token); | |
| 634 token = parseTypeVariablesOpt(token); | |
| 635 Token period = null; | |
| 636 if (optional('.', token)) { | |
| 637 period = token; | |
| 638 token = parseIdentifier(token.next); | |
| 639 } | |
| 640 token = parseFormalParameters(token); | |
| 641 token = parseFunctionBody(token, false); | |
| 642 listener.endFactoryMethod(factoryKeyword, period, token); | |
| 643 return token.next; | |
| 644 } | |
| 645 | |
| 646 Token parseOperatorName(Token token) { | |
| 647 assert(optional('operator', token)); | |
| 648 if (isUserDefinableOperator(token.next.stringValue)) { | |
| 649 Token operator = token; | |
| 650 token = token.next; | |
| 651 listener.handleOperatorName(operator, token); | |
| 652 return token.next; | |
| 653 } else { | |
| 654 return parseIdentifier(token); | |
| 655 } | |
| 656 } | |
| 657 | |
| 658 Token parseFunction(Token token, Token getOrSet) { | |
| 659 listener.beginFunction(token); | |
| 660 token = parseModifiers(token); | |
| 661 if (getOrSet === token) token = token.next; | |
| 662 token = parseReturnTypeOpt(token); | |
| 663 if (getOrSet === token) token = token.next; | |
| 664 listener.beginFunctionName(token); | |
| 665 if (optional('operator', token)) { | |
| 666 token = parseOperatorName(token); | |
| 667 } else { | |
| 668 token = parseIdentifier(token); | |
| 669 } | |
| 670 token = parseQualifiedRestOpt(token); | |
| 671 listener.endFunctionName(token); | |
| 672 token = parseFormalParameters(token); | |
| 673 token = parseInitializersOpt(token); | |
| 674 token = parseFunctionBody(token, false); | |
| 675 listener.endFunction(getOrSet, token); | |
| 676 return token.next; | |
| 677 } | |
| 678 | |
| 679 Token parseUnamedFunction(Token token) { | |
| 680 listener.beginUnamedFunction(token); | |
| 681 token = parseFormalParameters(token); | |
| 682 bool isBlock = optional('{', token); | |
| 683 token = parseFunctionBody(token, true); | |
| 684 listener.endUnamedFunction(token); | |
| 685 return isBlock ? token.next : token; | |
| 686 } | |
| 687 | |
| 688 Token parseFunctionDeclaration(Token token) { | |
| 689 listener.beginFunctionDeclaration(token); | |
| 690 token = parseFunction(token, null); | |
| 691 listener.endFunctionDeclaration(token); | |
| 692 return token; | |
| 693 } | |
| 694 | |
| 695 Token parseFunctionExpression(Token token) { | |
| 696 listener.beginFunction(token); | |
| 697 listener.handleModifiers(0); | |
| 698 token = parseReturnTypeOpt(token); | |
| 699 listener.beginFunctionName(token); | |
| 700 token = parseIdentifier(token); | |
| 701 listener.endFunctionName(token); | |
| 702 token = parseFormalParameters(token); | |
| 703 listener.handleNoInitializers(); | |
| 704 bool isBlock = optional('{', token); | |
| 705 token = parseFunctionBody(token, true); | |
| 706 listener.endFunction(null, token); | |
| 707 return isBlock ? token.next : token; | |
| 708 } | |
| 709 | |
| 710 Token parseFunctionBody(Token token, bool isExpression) { | |
| 711 if (optional(';', token)) { | |
| 712 listener.endFunctionBody(0, null, token); | |
| 713 return token; | |
| 714 } else if (optional('=>', token)) { | |
| 715 Token begin = token; | |
| 716 token = parseExpression(token.next); | |
| 717 if (!isExpression) { | |
| 718 expectSemicolon(token); | |
| 719 listener.endReturnStatement(true, begin, token); | |
| 720 } else { | |
| 721 listener.endReturnStatement(true, begin, null); | |
| 722 } | |
| 723 return token; | |
| 724 } | |
| 725 Token begin = token; | |
| 726 int statementCount = 0; | |
| 727 listener.beginFunctionBody(begin); | |
| 728 if (!optional('{', token)) { | |
| 729 return listener.expectedFunctionBody(token); | |
| 730 } else { | |
| 731 token = token.next; | |
| 732 } | |
| 733 while (notEofOrValue('}', token)) { | |
| 734 token = parseStatement(token); | |
| 735 ++statementCount; | |
| 736 } | |
| 737 listener.endFunctionBody(statementCount, begin, token); | |
| 738 expect('}', token); | |
| 739 return token; | |
| 740 } | |
| 741 | |
| 742 Token parseStatement(Token token) { | |
| 743 final value = token.stringValue; | |
| 744 if (token.kind === IDENTIFIER_TOKEN) { | |
| 745 return parseExpressionStatementOrDeclaration(token); | |
| 746 } else if (value === '{') { | |
| 747 return parseBlock(token); | |
| 748 } else if (value === 'return') { | |
| 749 return parseReturnStatement(token); | |
| 750 } else if (value === 'var' || value === 'final') { | |
| 751 return parseVariablesDeclaration(token); | |
| 752 } else if (value === 'if') { | |
| 753 return parseIfStatement(token); | |
| 754 } else if (value === 'for') { | |
| 755 return parseForStatement(token); | |
| 756 } else if (value === 'throw') { | |
| 757 return parseThrowStatement(token); | |
| 758 } else if (value === 'void') { | |
| 759 return parseExpressionStatementOrDeclaration(token); | |
| 760 } else if (value === 'while') { | |
| 761 return parseWhileStatement(token); | |
| 762 } else if (value === 'do') { | |
| 763 return parseDoWhileStatement(token); | |
| 764 } else if (value === 'try') { | |
| 765 return parseTryStatement(token); | |
| 766 } else if (value === 'switch') { | |
| 767 return parseSwitchStatement(token); | |
| 768 } else if (value === 'break') { | |
| 769 return parseBreakStatement(token); | |
| 770 } else if (value === 'continue') { | |
| 771 return parseContinueStatement(token); | |
| 772 } else if (value === ';') { | |
| 773 return parseEmptyStatement(token); | |
| 774 } else { | |
| 775 return parseExpressionStatement(token); | |
| 776 } | |
| 777 } | |
| 778 | |
| 779 Token parseReturnStatement(Token token) { | |
| 780 Token begin = token; | |
| 781 listener.beginReturnStatement(begin); | |
| 782 assert('return' === token.stringValue); | |
| 783 token = token.next; | |
| 784 if (optional(';', token)) { | |
| 785 listener.endReturnStatement(false, begin, token); | |
| 786 } else { | |
| 787 token = parseExpression(token); | |
| 788 listener.endReturnStatement(true, begin, token); | |
| 789 } | |
| 790 return expectSemicolon(token); | |
| 791 } | |
| 792 | |
| 793 Token peekIdentifierAfterType(Token token) { | |
| 794 Token peek = peekAfterType(token); | |
| 795 if (peek !== null && isIdentifier(peek)) { | |
| 796 // We are looking at "type identifier". | |
| 797 return peek; | |
| 798 } else { | |
| 799 return null; | |
| 800 } | |
| 801 } | |
| 802 | |
| 803 Token parseExpressionStatementOrDeclaration(Token token) { | |
| 804 assert(isIdentifier(token) || token.stringValue === 'void'); | |
| 805 Token identifier = peekIdentifierAfterType(token); | |
| 806 if (identifier !== null) { | |
| 807 assert(isIdentifier(identifier)); | |
| 808 Token afterId = identifier.next; | |
| 809 int afterIdKind = afterId.kind; | |
| 810 if (afterIdKind === EQ_TOKEN || | |
| 811 afterIdKind === SEMICOLON_TOKEN || | |
| 812 afterIdKind === COMMA_TOKEN) { | |
| 813 // We are looking at "type identifier" followed by '=', ';', ','. | |
| 814 return parseVariablesDeclaration(token); | |
| 815 } else if (afterIdKind === OPEN_PAREN_TOKEN) { | |
| 816 // We are looking at "type identifier '('". | |
| 817 BeginGroupToken beginParen = afterId; | |
| 818 Token endParen = beginParen.endGroup; | |
| 819 Token afterParens = endParen.next; | |
| 820 if (optional('{', afterParens) || optional('=>', afterParens)) { | |
| 821 // We are looking at "type identifier '(' ... ')'" followed | |
| 822 // by '=>' or '{'. | |
| 823 return parseFunctionDeclaration(token); | |
| 824 } | |
| 825 } | |
| 826 // Fall-through to expression statement. | |
| 827 } else { | |
| 828 if (optional(':', token.next)) { | |
| 829 return parseLabeledStatement(token); | |
| 830 } else if (optional('(', token.next)) { | |
| 831 BeginGroupToken begin = token.next; | |
| 832 String afterParens = begin.endGroup.next.stringValue; | |
| 833 if (afterParens === '{' || afterParens === '=>') { | |
| 834 return parseFunctionDeclaration(token); | |
| 835 } | |
| 836 } | |
| 837 } | |
| 838 return parseExpressionStatement(token); | |
| 839 } | |
| 840 | |
| 841 Token parseLabeledStatement(Token token) { | |
| 842 listener.beginLabeledStatement(token); | |
| 843 token = parseIdentifier(token); | |
| 844 Token colon = token; | |
| 845 token = expect(':', token); | |
| 846 token = parseStatement(token); | |
| 847 listener.endLabeledStatement(colon); | |
| 848 return token; | |
| 849 } | |
| 850 | |
| 851 Token parseExpressionStatement(Token token) { | |
| 852 listener.beginExpressionStatement(token); | |
| 853 token = parseExpression(token); | |
| 854 listener.endExpressionStatement(token); | |
| 855 return expectSemicolon(token); | |
| 856 } | |
| 857 | |
| 858 Token parseExpression(Token token) { | |
| 859 return parsePrecedenceExpression(token, 2); | |
| 860 } | |
| 861 | |
| 862 Token parseConditionalExpressionRest(Token token) { | |
| 863 assert(optional('?', token)); | |
| 864 Token question = token; | |
| 865 token = parseExpression(token.next); | |
| 866 Token colon = token; | |
| 867 token = expect(':', token); | |
| 868 token = parseExpression(token); | |
| 869 listener.handleConditionalExpression(question, colon); | |
| 870 return token; | |
| 871 } | |
| 872 | |
| 873 Token parsePrecedenceExpression(Token token, int precedence) { | |
| 874 assert(precedence >= 2); | |
| 875 assert(precedence <= POSTFIX_PRECEDENCE); | |
| 876 token = parseUnaryExpression(token); | |
| 877 PrecedenceInfo info = token.info; | |
| 878 int tokenLevel = info.precedence; | |
| 879 for (int level = tokenLevel; level >= precedence; --level) { | |
| 880 while (tokenLevel === level) { | |
| 881 Token operator = token; | |
| 882 if (tokenLevel === ASSIGNMENT_PRECEDENCE) { | |
| 883 // Right associative, so we recurse at the same precedence | |
| 884 // level. | |
| 885 token = parsePrecedenceExpression(token.next, level); | |
| 886 listener.handleAssignmentExpression(operator); | |
| 887 } else if (tokenLevel === POSTFIX_PRECEDENCE) { | |
| 888 if (info === PERIOD_INFO) { | |
| 889 // Left associative, so we recurse at the next higher | |
| 890 // precedence level. However, POSTFIX_PRECEDENCE is the | |
| 891 // highest level, so we just call parseUnaryExpression | |
| 892 // directly. | |
| 893 token = parseUnaryExpression(token.next); | |
| 894 listener.handleBinaryExpression(operator); | |
| 895 } else if ((info === OPEN_PAREN_INFO) || | |
| 896 (info === OPEN_SQUARE_BRACKET_INFO)) { | |
| 897 token = parseArgumentOrIndexStar(token); | |
| 898 } else if ((info === PLUS_PLUS_INFO) || | |
| 899 (info === MINUS_MINUS_INFO)) { | |
| 900 listener.handleUnaryPostfixAssignmentExpression(token); | |
| 901 token = token.next; | |
| 902 } else { | |
| 903 token = listener.unexpected(token); | |
| 904 } | |
| 905 } else if (info === IS_INFO) { | |
| 906 token = parseIsOperatorRest(token); | |
| 907 } else if (info === QUESTION_INFO) { | |
| 908 token = parseConditionalExpressionRest(token); | |
| 909 } else { | |
| 910 // Left associative, so we recurse at the next higher | |
| 911 // precedence level. | |
| 912 token = parsePrecedenceExpression(token.next, level + 1); | |
| 913 listener.handleBinaryExpression(operator); | |
| 914 } | |
| 915 info = token.info; | |
| 916 tokenLevel = info.precedence; | |
| 917 } | |
| 918 } | |
| 919 return token; | |
| 920 } | |
| 921 | |
| 922 Token parseUnaryExpression(Token token) { | |
| 923 String value = token.stringValue; | |
| 924 // Prefix: | |
| 925 if (value === '+') { | |
| 926 // Dart only allows "prefix plus" as an initial part of a | |
| 927 // decimal literal. We scan it as a separate token and let | |
| 928 // the parser listener combine it with the digits. | |
| 929 Token next = token.next; | |
| 930 if (next.charOffset === token.charOffset + 1) { | |
| 931 if (next.kind === INT_TOKEN) { | |
| 932 listener.handleLiteralInt(token); | |
| 933 return next.next; | |
| 934 } | |
| 935 if (next.kind === DOUBLE_TOKEN) { | |
| 936 listener.handleLiteralDouble(token); | |
| 937 return next.next; | |
| 938 } | |
| 939 } | |
| 940 listener.recoverableError("Unexpected token '+'", token: token); | |
| 941 return parsePrecedenceExpression(next, POSTFIX_PRECEDENCE); | |
| 942 } else if ((value === '!') || | |
| 943 (value === '-') || | |
| 944 (value === '~')) { | |
| 945 Token operator = token; | |
| 946 // Right associative, so we recurse at the same precedence | |
| 947 // level. | |
| 948 token = parsePrecedenceExpression(token.next, POSTFIX_PRECEDENCE); | |
| 949 listener.handleUnaryPrefixExpression(operator); | |
| 950 } else if ((value === '++') || value === '--') { | |
| 951 // TODO(ahe): Validate this is used correctly. | |
| 952 Token operator = token; | |
| 953 // Right associative, so we recurse at the same precedence | |
| 954 // level. | |
| 955 token = parsePrecedenceExpression(token.next, POSTFIX_PRECEDENCE); | |
| 956 listener.handleUnaryPrefixAssignmentExpression(operator); | |
| 957 } else { | |
| 958 token = parsePrimary(token); | |
| 959 } | |
| 960 return token; | |
| 961 } | |
| 962 | |
| 963 Token parseArgumentOrIndexStar(Token token) { | |
| 964 while (true) { | |
| 965 if (optional('[', token)) { | |
| 966 Token openSquareBracket = token; | |
| 967 bool old = mayParseFunctionExpressions; | |
| 968 mayParseFunctionExpressions = true; | |
| 969 token = parseExpression(token.next); | |
| 970 mayParseFunctionExpressions = old; | |
| 971 listener.handleIndexedExpression(openSquareBracket, token); | |
| 972 token = expect(']', token); | |
| 973 } else if (optional('(', token)) { | |
| 974 token = parseArguments(token); | |
| 975 listener.endSend(token); | |
| 976 } else { | |
| 977 break; | |
| 978 } | |
| 979 } | |
| 980 return token; | |
| 981 } | |
| 982 | |
| 983 Token parsePrimary(Token token) { | |
| 984 final kind = token.kind; | |
| 985 if (kind === IDENTIFIER_TOKEN) { | |
| 986 return parseSendOrFunctionLiteral(token); | |
| 987 } else if (kind === INT_TOKEN || kind === HEXADECIMAL_TOKEN) { | |
| 988 return parseLiteralInt(token); | |
| 989 } else if (kind === DOUBLE_TOKEN) { | |
| 990 return parseLiteralDouble(token); | |
| 991 } else if (kind === STRING_TOKEN) { | |
| 992 return parseLiteralString(token); | |
| 993 } else if (kind === KEYWORD_TOKEN) { | |
| 994 final value = token.stringValue; | |
| 995 if ((value === 'true') || (value === 'false')) { | |
| 996 return parseLiteralBool(token); | |
| 997 } else if (value === 'null') { | |
| 998 return parseLiteralNull(token); | |
| 999 } else if (value === 'this') { | |
| 1000 return parseThisExpression(token); | |
| 1001 } else if (value === 'super') { | |
| 1002 return parseSuperExpression(token); | |
| 1003 } else if (value === 'new') { | |
| 1004 return parseNewExpression(token); | |
| 1005 } else if (value === 'const') { | |
| 1006 return parseConstExpression(token); | |
| 1007 } else if (value === 'void') { | |
| 1008 return parseFunctionExpression(token); | |
| 1009 } else if (isIdentifier(token)) { | |
| 1010 return parseSendOrFunctionLiteral(token); | |
| 1011 } else { | |
| 1012 return listener.expectedExpression(token); | |
| 1013 } | |
| 1014 } else if (kind === OPEN_PAREN_TOKEN) { | |
| 1015 return parseParenthesizedExpressionOrFunctionLiteral(token); | |
| 1016 } else if ((kind === LT_TOKEN) || | |
| 1017 (kind === OPEN_SQUARE_BRACKET_TOKEN) || | |
| 1018 (kind === OPEN_CURLY_BRACKET_TOKEN) || | |
| 1019 token.stringValue === '[]') { | |
| 1020 return parseLiteralListOrMap(token); | |
| 1021 } else { | |
| 1022 return listener.expectedExpression(token); | |
| 1023 } | |
| 1024 } | |
| 1025 | |
| 1026 Token parseParenthesizedExpressionOrFunctionLiteral(Token token) { | |
| 1027 BeginGroupToken beginGroup = token; | |
| 1028 int kind = beginGroup.endGroup.next.kind; | |
| 1029 if (mayParseFunctionExpressions && | |
| 1030 (kind === FUNCTION_TOKEN || kind === OPEN_CURLY_BRACKET_TOKEN)) { | |
| 1031 return parseUnamedFunction(token); | |
| 1032 } else { | |
| 1033 bool old = mayParseFunctionExpressions; | |
| 1034 mayParseFunctionExpressions = true; | |
| 1035 token = parseParenthesizedExpression(token); | |
| 1036 mayParseFunctionExpressions = old; | |
| 1037 return token; | |
| 1038 } | |
| 1039 } | |
| 1040 | |
| 1041 Token parseParenthesizedExpression(Token token) { | |
| 1042 BeginGroupToken begin = token; | |
| 1043 token = expect('(', token); | |
| 1044 token = parseExpression(token); | |
| 1045 if (begin.endGroup !== token) { | |
| 1046 listener.unexpected(token); | |
| 1047 token = begin.endGroup; | |
| 1048 } | |
| 1049 listener.handleParenthesizedExpression(begin); | |
| 1050 return expect(')', token); | |
| 1051 } | |
| 1052 | |
| 1053 Token parseThisExpression(Token token) { | |
| 1054 listener.handleThisExpression(token); | |
| 1055 token = token.next; | |
| 1056 if (optional('(', token)) { | |
| 1057 // Constructor forwarding. | |
| 1058 token = parseArguments(token); | |
| 1059 listener.endSend(token); | |
| 1060 } | |
| 1061 return token; | |
| 1062 } | |
| 1063 | |
| 1064 Token parseSuperExpression(Token token) { | |
| 1065 listener.handleSuperExpression(token); | |
| 1066 token = token.next; | |
| 1067 if (optional('(', token)) { | |
| 1068 // Super constructor. | |
| 1069 token = parseArguments(token); | |
| 1070 listener.endSend(token); | |
| 1071 } | |
| 1072 return token; | |
| 1073 } | |
| 1074 | |
| 1075 Token parseLiteralListOrMap(Token token) { | |
| 1076 Token constKeyword = null; | |
| 1077 if (optional('const', token)) { | |
| 1078 constKeyword = token; | |
| 1079 token = token.next; | |
| 1080 } | |
| 1081 token = parseTypeArgumentsOpt(token); | |
| 1082 Token beginToken = token; | |
| 1083 int count = 0; | |
| 1084 if (optional('{', token)) { | |
| 1085 bool old = mayParseFunctionExpressions; | |
| 1086 mayParseFunctionExpressions = true; | |
| 1087 do { | |
| 1088 if (optional('}', token.next)) { | |
| 1089 token = token.next; | |
| 1090 break; | |
| 1091 } | |
| 1092 token = parseMapLiteralEntry(token.next); | |
| 1093 ++count; | |
| 1094 } while (optional(',', token)); | |
| 1095 mayParseFunctionExpressions = old; | |
| 1096 listener.handleLiteralMap(count, beginToken, constKeyword, token); | |
| 1097 return expect('}', token); | |
| 1098 } else if (optional('[', token)) { | |
| 1099 bool old = mayParseFunctionExpressions; | |
| 1100 mayParseFunctionExpressions = true; | |
| 1101 do { | |
| 1102 if (optional(']', token.next)) { | |
| 1103 token = token.next; | |
| 1104 break; | |
| 1105 } | |
| 1106 token = parseExpression(token.next); | |
| 1107 ++count; | |
| 1108 } while (optional(',', token)); | |
| 1109 mayParseFunctionExpressions = old; | |
| 1110 listener.handleLiteralList(count, beginToken, constKeyword, token); | |
| 1111 return expect(']', token); | |
| 1112 } else if (optional('[]', token)) { | |
| 1113 listener.handleLiteralList(0, token, constKeyword, token); | |
| 1114 return token.next; | |
| 1115 } else { | |
| 1116 listener.unexpected(token); | |
| 1117 } | |
| 1118 } | |
| 1119 | |
| 1120 Token parseMapLiteralEntry(Token token) { | |
| 1121 listener.beginLiteralMapEntry(token); | |
| 1122 // Assume the listener rejects non-string keys. | |
| 1123 token = parseExpression(token); | |
| 1124 Token colon = token; | |
| 1125 token = expect(':', token); | |
| 1126 token = parseExpression(token); | |
| 1127 listener.endLiteralMapEntry(colon, token); | |
| 1128 return token; | |
| 1129 } | |
| 1130 | |
| 1131 Token parseSendOrFunctionLiteral(Token token) { | |
| 1132 if (!mayParseFunctionExpressions) return parseSend(token); | |
| 1133 Token peek = peekAfterType(token); | |
| 1134 if (peek.kind === IDENTIFIER_TOKEN && isFunctionDeclaration(peek.next)) { | |
| 1135 return parseFunctionExpression(token); | |
| 1136 } else if (isFunctionDeclaration(token.next)) { | |
| 1137 return parseFunctionExpression(token); | |
| 1138 } else { | |
| 1139 return parseSend(token); | |
| 1140 } | |
| 1141 } | |
| 1142 | |
| 1143 bool isFunctionDeclaration(Token token) { | |
| 1144 if (optional('(', token)) { | |
| 1145 BeginGroupToken begin = token; | |
| 1146 String afterParens = begin.endGroup.next.stringValue; | |
| 1147 if (afterParens === '{' || afterParens === '=>') { | |
| 1148 return true; | |
| 1149 } | |
| 1150 } | |
| 1151 return false; | |
| 1152 } | |
| 1153 | |
| 1154 Token parseNewExpression(Token token) { | |
| 1155 Token newKeyword = token; | |
| 1156 token = expect('new', token); | |
| 1157 token = parseType(token); | |
| 1158 bool named = false; | |
| 1159 if (optional('.', token)) { | |
| 1160 named = true; | |
| 1161 token = parseIdentifier(token.next); | |
| 1162 } | |
| 1163 if (optional('(', token)) { | |
| 1164 token = parseArguments(token); | |
| 1165 } else { | |
| 1166 listener.handleNoArguments(token); | |
| 1167 token = listener.unexpected(token); | |
| 1168 } | |
| 1169 listener.handleNewExpression(newKeyword, named); | |
| 1170 return token; | |
| 1171 } | |
| 1172 | |
| 1173 Token parseConstExpression(Token token) { | |
| 1174 Token constKeyword = token; | |
| 1175 token = expect('const', token); | |
| 1176 final String value = token.stringValue; | |
| 1177 if ((value === '<') || | |
| 1178 (value === '[') || | |
| 1179 (value === '[]') || | |
| 1180 (value === '{')) { | |
| 1181 return parseLiteralListOrMap(constKeyword); | |
| 1182 } | |
| 1183 token = parseType(token); | |
| 1184 bool named = false; | |
| 1185 if (optional('.', token)) { | |
| 1186 named = true; | |
| 1187 token = parseIdentifier(token.next); | |
| 1188 } | |
| 1189 expect('(', token); | |
| 1190 token = parseArguments(token); | |
| 1191 listener.handleConstExpression(constKeyword, named); | |
| 1192 return token; | |
| 1193 } | |
| 1194 | |
| 1195 Token parseLiteralInt(Token token) { | |
| 1196 listener.handleLiteralInt(token); | |
| 1197 return token.next; | |
| 1198 } | |
| 1199 | |
| 1200 Token parseLiteralDouble(Token token) { | |
| 1201 listener.handleLiteralDouble(token); | |
| 1202 return token.next; | |
| 1203 } | |
| 1204 | |
| 1205 Token parseLiteralString(Token token) { | |
| 1206 token = parseSingleLiteralString(token); | |
| 1207 int count = 1; | |
| 1208 while (token.kind === STRING_TOKEN) { | |
| 1209 token = parseSingleLiteralString(token); | |
| 1210 count++; | |
| 1211 } | |
| 1212 if (count > 1) { | |
| 1213 listener.handleStringJuxtaposition(count); | |
| 1214 } | |
| 1215 return token; | |
| 1216 } | |
| 1217 | |
| 1218 Token parseSingleLiteralString(Token token) { | |
| 1219 listener.beginLiteralString(token); | |
| 1220 token = token.next; | |
| 1221 int interpolationCount = 0; | |
| 1222 while (optional('\${', token)) { | |
| 1223 token = token.next; | |
| 1224 token = parseExpression(token); | |
| 1225 token = expect('}', token); | |
| 1226 token = parseStringPart(token); | |
| 1227 ++interpolationCount; | |
| 1228 } | |
| 1229 listener.endLiteralString(interpolationCount); | |
| 1230 return token; | |
| 1231 } | |
| 1232 | |
| 1233 Token parseLiteralBool(Token token) { | |
| 1234 listener.handleLiteralBool(token); | |
| 1235 return token.next; | |
| 1236 } | |
| 1237 | |
| 1238 Token parseLiteralNull(Token token) { | |
| 1239 listener.handleLiteralNull(token); | |
| 1240 return token.next; | |
| 1241 } | |
| 1242 | |
| 1243 Token parseSend(Token token) { | |
| 1244 listener.beginSend(token); | |
| 1245 token = parseIdentifier(token); | |
| 1246 token = parseArgumentsOpt(token); | |
| 1247 listener.endSend(token); | |
| 1248 return token; | |
| 1249 } | |
| 1250 | |
| 1251 Token parseArgumentsOpt(Token token) { | |
| 1252 if (!optional('(', token)) { | |
| 1253 listener.handleNoArguments(token); | |
| 1254 return token; | |
| 1255 } else { | |
| 1256 return parseArguments(token); | |
| 1257 } | |
| 1258 } | |
| 1259 | |
| 1260 Token parseArguments(Token token) { | |
| 1261 Token begin = token; | |
| 1262 listener.beginArguments(begin); | |
| 1263 assert('(' === token.stringValue); | |
| 1264 int argumentCount = 0; | |
| 1265 if (optional(')', token.next)) { | |
| 1266 listener.endArguments(argumentCount, begin, token.next); | |
| 1267 return token.next.next; | |
| 1268 } | |
| 1269 bool old = mayParseFunctionExpressions; | |
| 1270 mayParseFunctionExpressions = true; | |
| 1271 do { | |
| 1272 Token colon = null; | |
| 1273 if (optional(':', token.next.next)) { | |
| 1274 token = parseIdentifier(token.next); | |
| 1275 colon = token; | |
| 1276 } | |
| 1277 token = parseExpression(token.next); | |
| 1278 if (colon !== null) listener.handleNamedArgument(colon); | |
| 1279 ++argumentCount; | |
| 1280 } while (optional(',', token)); | |
| 1281 mayParseFunctionExpressions = old; | |
| 1282 listener.endArguments(argumentCount, begin, token); | |
| 1283 return expect(')', token); | |
| 1284 } | |
| 1285 | |
| 1286 Token parseIsOperatorRest(Token token) { | |
| 1287 assert(optional('is', token)); | |
| 1288 Token operator = token; | |
| 1289 Token not = null; | |
| 1290 if (optional('!', token.next)) { | |
| 1291 token = token.next; | |
| 1292 not = token; | |
| 1293 } | |
| 1294 token = parseType(token.next); | |
| 1295 listener.handleIsOperator(operator, not, token); | |
| 1296 if (optional('is', token)) { | |
| 1297 // The is-operator cannot be chained, but it can take part of | |
| 1298 // expressions like: foo is Foo || foo is Bar. | |
| 1299 listener.unexpected(token); | |
| 1300 } | |
| 1301 return token; | |
| 1302 } | |
| 1303 | |
| 1304 Token parseVariablesDeclaration(Token token) { | |
| 1305 token = parseVariablesDeclarationNoSemicolon(token); | |
| 1306 return expectSemicolon(token); | |
| 1307 } | |
| 1308 | |
| 1309 Token parseVariablesDeclarationNoSemicolon(Token token) { | |
| 1310 int count = 1; | |
| 1311 listener.beginVariablesDeclaration(token); | |
| 1312 token = parseModifiers(token); | |
| 1313 token = parseTypeOpt(token); | |
| 1314 token = parseOptionallyInitializedIdentifier(token); | |
| 1315 while (optional(',', token)) { | |
| 1316 token = parseOptionallyInitializedIdentifier(token.next); | |
| 1317 ++count; | |
| 1318 } | |
| 1319 listener.endVariablesDeclaration(count, token); | |
| 1320 return token; | |
| 1321 } | |
| 1322 | |
| 1323 Token parseOptionallyInitializedIdentifier(Token token) { | |
| 1324 listener.beginInitializedIdentifier(token); | |
| 1325 token = parseIdentifier(token); | |
| 1326 token = parseVariableInitializerOpt(token); | |
| 1327 listener.endInitializedIdentifier(); | |
| 1328 return token; | |
| 1329 } | |
| 1330 | |
| 1331 Token parseIfStatement(Token token) { | |
| 1332 Token ifToken = token; | |
| 1333 listener.beginIfStatement(ifToken); | |
| 1334 token = expect('if', token); | |
| 1335 token = parseParenthesizedExpression(token); | |
| 1336 token = parseStatement(token); | |
| 1337 Token elseToken = null; | |
| 1338 if (optional('else', token)) { | |
| 1339 elseToken = token; | |
| 1340 token = parseStatement(token.next); | |
| 1341 } | |
| 1342 listener.endIfStatement(ifToken, elseToken); | |
| 1343 return token; | |
| 1344 } | |
| 1345 | |
| 1346 Token parseForStatement(Token token) { | |
| 1347 Token forToken = token; | |
| 1348 listener.beginForStatement(forToken); | |
| 1349 token = expect('for', token); | |
| 1350 token = expect('(', token); | |
| 1351 token = parseVariablesDeclarationOrExpressionOpt(token); | |
| 1352 if (optional('in', token)) { | |
| 1353 return parseForInRest(forToken, token); | |
| 1354 } else { | |
| 1355 return parseForRest(forToken, token); | |
| 1356 } | |
| 1357 } | |
| 1358 | |
| 1359 Token parseVariablesDeclarationOrExpressionOpt(Token token) { | |
| 1360 final String value = token.stringValue; | |
| 1361 if (value === ';') { | |
| 1362 listener.handleNoExpression(token); | |
| 1363 return token; | |
| 1364 } else if ((value === 'var') || (value === 'final')) { | |
| 1365 return parseVariablesDeclarationNoSemicolon(token); | |
| 1366 } | |
| 1367 Token identifier = peekIdentifierAfterType(token); | |
| 1368 if (identifier !== null) { | |
| 1369 assert(isIdentifier(identifier)); | |
| 1370 Token afterId = identifier.next; | |
| 1371 int afterIdKind = afterId.kind; | |
| 1372 if (afterIdKind === EQ_TOKEN || afterIdKind === SEMICOLON_TOKEN || | |
| 1373 afterIdKind === COMMA_TOKEN || optional('in', afterId)) { | |
| 1374 return parseVariablesDeclarationNoSemicolon(token); | |
| 1375 } | |
| 1376 } | |
| 1377 return parseExpression(token); | |
| 1378 } | |
| 1379 | |
| 1380 Token parseForRest(Token forToken, Token token) { | |
| 1381 token = expectSemicolon(token); | |
| 1382 if (optional(';', token)) { | |
| 1383 token = parseEmptyStatement(token); | |
| 1384 } else { | |
| 1385 token = parseExpressionStatement(token); | |
| 1386 } | |
| 1387 int expressionCount = 0; | |
| 1388 while (true) { | |
| 1389 if (optional(')', token)) break; | |
| 1390 token = parseExpression(token); | |
| 1391 ++expressionCount; | |
| 1392 if (optional(',', token)) { | |
| 1393 token = token.next; | |
| 1394 } else { | |
| 1395 break; | |
| 1396 } | |
| 1397 } | |
| 1398 token = expect(')', token); | |
| 1399 token = parseStatement(token); | |
| 1400 listener.endForStatement(expressionCount, forToken, token); | |
| 1401 return token; | |
| 1402 } | |
| 1403 | |
| 1404 Token parseForInRest(Token forToken, Token token) { | |
| 1405 assert(optional('in', token)); | |
| 1406 Token inKeyword = token; | |
| 1407 token = parseExpression(token.next); | |
| 1408 token = expect(')', token); | |
| 1409 token = parseStatement(token); | |
| 1410 listener.endForInStatement(forToken, inKeyword, token); | |
| 1411 return token; | |
| 1412 } | |
| 1413 | |
| 1414 Token parseWhileStatement(Token token) { | |
| 1415 Token whileToken = token; | |
| 1416 listener.beginWhileStatement(whileToken); | |
| 1417 token = expect('while', token); | |
| 1418 token = parseParenthesizedExpression(token); | |
| 1419 token = parseStatement(token); | |
| 1420 listener.endWhileStatement(whileToken, token); | |
| 1421 return token; | |
| 1422 } | |
| 1423 | |
| 1424 Token parseDoWhileStatement(Token token) { | |
| 1425 Token doToken = token; | |
| 1426 listener.beginDoWhileStatement(doToken); | |
| 1427 token = expect('do', token); | |
| 1428 token = parseStatement(token); | |
| 1429 Token whileToken = token; | |
| 1430 token = expect('while', token); | |
| 1431 token = parseParenthesizedExpression(token); | |
| 1432 listener.endDoWhileStatement(doToken, whileToken, token); | |
| 1433 return expectSemicolon(token); | |
| 1434 } | |
| 1435 | |
| 1436 Token parseBlock(Token token) { | |
| 1437 Token begin = token; | |
| 1438 listener.beginBlock(begin); | |
| 1439 int statementCount = 0; | |
| 1440 token = expect('{', token); | |
| 1441 while (notEofOrValue('}', token)) { | |
| 1442 token = parseStatement(token); | |
| 1443 ++statementCount; | |
| 1444 } | |
| 1445 listener.endBlock(statementCount, begin, token); | |
| 1446 return expect('}', token); | |
| 1447 } | |
| 1448 | |
| 1449 Token parseThrowStatement(Token token) { | |
| 1450 Token throwToken = token; | |
| 1451 listener.beginThrowStatement(throwToken); | |
| 1452 token = expect('throw', token); | |
| 1453 if (optional(';', token)) { | |
| 1454 listener.endRethrowStatement(throwToken, token); | |
| 1455 return token.next; | |
| 1456 } else { | |
| 1457 token = parseExpression(token); | |
| 1458 listener.endThrowStatement(throwToken, token); | |
| 1459 return expectSemicolon(token); | |
| 1460 } | |
| 1461 } | |
| 1462 | |
| 1463 Token parseTryStatement(Token token) { | |
| 1464 assert(optional('try', token)); | |
| 1465 Token tryKeyword = token; | |
| 1466 listener.beginTryStatement(tryKeyword); | |
| 1467 token = parseBlock(token.next); | |
| 1468 int catchCount = 0; | |
| 1469 while (optional('catch', token)) { | |
| 1470 Token catchKeyword = token; | |
| 1471 // TODO(ahe): Validate the "parameters". | |
| 1472 token = parseFormalParameters(token.next); | |
| 1473 token = parseBlock(token); | |
| 1474 ++catchCount; | |
| 1475 listener.handleCatchBlock(catchKeyword); | |
| 1476 } | |
| 1477 Token finallyKeyword = null; | |
| 1478 if (optional('finally', token)) { | |
| 1479 finallyKeyword = token; | |
| 1480 token = parseBlock(token.next); | |
| 1481 listener.handleFinallyBlock(finallyKeyword); | |
| 1482 } | |
| 1483 listener.endTryStatement(catchCount, tryKeyword, finallyKeyword); | |
| 1484 return token; | |
| 1485 } | |
| 1486 | |
| 1487 Token parseSwitchStatement(Token token) { | |
| 1488 assert(optional('switch', token)); | |
| 1489 Token switchKeyword = token; | |
| 1490 listener.beginSwitchStatement(switchKeyword); | |
| 1491 token = parseParenthesizedExpression(token.next); | |
| 1492 token = parseSwitchBlock(token); | |
| 1493 listener.endSwitchStatement(switchKeyword, token); | |
| 1494 return token.next; | |
| 1495 } | |
| 1496 | |
| 1497 Token parseSwitchBlock(Token token) { | |
| 1498 Token begin = token; | |
| 1499 listener.beginSwitchBlock(begin); | |
| 1500 token = expect('{', token); | |
| 1501 int caseCount = 0; | |
| 1502 while (token.kind !== EOF_TOKEN) { | |
| 1503 if (optional('}', token)) { | |
| 1504 break; | |
| 1505 } | |
| 1506 token = parseSwitchCase(token); | |
| 1507 ++caseCount; | |
| 1508 } | |
| 1509 listener.endSwitchBlock(caseCount, begin, token); | |
| 1510 expect('}', token); | |
| 1511 return token; | |
| 1512 } | |
| 1513 | |
| 1514 Token parseSwitchCase(Token token) { | |
| 1515 Token begin = token; | |
| 1516 Token defaultKeyword = null; | |
| 1517 Token label = null; | |
| 1518 // First an optional label. | |
| 1519 if (isIdentifier(token)) { | |
| 1520 label = token; | |
| 1521 token = parseIdentifier(token); | |
| 1522 token = expect(':', token); | |
| 1523 } | |
| 1524 // Then one or more case expressions, the last of which may be | |
| 1525 // 'default' instead. | |
| 1526 int expressionCount = 0; | |
| 1527 String value = token.stringValue; | |
| 1528 do { | |
| 1529 if (value === 'default') { | |
| 1530 defaultKeyword = token; | |
| 1531 token = expect(':', token.next); | |
| 1532 break; | |
| 1533 } | |
| 1534 token = expect('case', token); | |
| 1535 token = parseExpression(token); | |
| 1536 token = expect(':', token); | |
| 1537 expressionCount++; | |
| 1538 value = token.stringValue; | |
| 1539 } while (value === 'case' || value === 'default'); | |
| 1540 // Finally zero or more statements. | |
| 1541 int statementCount = 0; | |
| 1542 while (token.kind !== EOF_TOKEN) { | |
| 1543 String value; | |
| 1544 if (isIdentifier(token) && optional(':', token.next)) { | |
| 1545 // Skip label. | |
| 1546 value = token.next.next.stringValue; | |
| 1547 } else { | |
| 1548 value = token.stringValue; | |
| 1549 } | |
| 1550 if (value === 'case' || value === 'default' || value === '}') { | |
| 1551 break; | |
| 1552 } else { | |
| 1553 token = parseStatement(token); | |
| 1554 ++statementCount; | |
| 1555 } | |
| 1556 } | |
| 1557 listener.handleSwitchCase(label, expressionCount, defaultKeyword, | |
| 1558 statementCount, begin, token); | |
| 1559 return token; | |
| 1560 } | |
| 1561 | |
| 1562 Token parseBreakStatement(Token token) { | |
| 1563 assert(optional('break', token)); | |
| 1564 Token breakKeyword = token; | |
| 1565 token = token.next; | |
| 1566 bool hasTarget = false; | |
| 1567 if (isIdentifier(token)) { | |
| 1568 token = parseIdentifier(token); | |
| 1569 hasTarget = true; | |
| 1570 } | |
| 1571 listener.handleBreakStatement(hasTarget, breakKeyword, token); | |
| 1572 return expectSemicolon(token); | |
| 1573 } | |
| 1574 | |
| 1575 Token parseContinueStatement(Token token) { | |
| 1576 assert(optional('continue', token)); | |
| 1577 Token continueKeyword = token; | |
| 1578 token = token.next; | |
| 1579 bool hasTarget = false; | |
| 1580 if (isIdentifier(token)) { | |
| 1581 token = parseIdentifier(token); | |
| 1582 hasTarget = true; | |
| 1583 } | |
| 1584 listener.handleContinueStatement(hasTarget, continueKeyword, token); | |
| 1585 return expectSemicolon(token); | |
| 1586 } | |
| 1587 | |
| 1588 Token parseEmptyStatement(Token token) { | |
| 1589 listener.handleEmptyStatement(token); | |
| 1590 return expectSemicolon(token); | |
| 1591 } | |
| 1592 } | |
| OLD | NEW |