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 |