OLD | NEW |
---|---|
1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 // TODO(jimhug): Error recovery needs major work! | 5 // TODO(jimhug): Error recovery needs major work! |
6 /** | 6 /** |
7 * A simple recursive descent parser for the dart language. | 7 * A simple recursive descent parser for the dart language. |
8 * | 8 * |
9 * This parser is designed to be more permissive than the official | 9 * This parser is designed to be more permissive than the official |
10 * Dart grammar. It is expected that many grammar errors would be | 10 * Dart grammar. It is expected that many grammar errors would be |
(...skipping 257 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
268 if (_maybeEat(TokenKind.IMPLEMENTS)) { | 268 if (_maybeEat(TokenKind.IMPLEMENTS)) { |
269 _implements = typeList(); | 269 _implements = typeList(); |
270 } | 270 } |
271 | 271 |
272 var _native = null; | 272 var _native = null; |
273 if (_maybeEat(TokenKind.NATIVE)) { | 273 if (_maybeEat(TokenKind.NATIVE)) { |
274 _native = maybeStringLiteral(); | 274 _native = maybeStringLiteral(); |
275 if (_native != null) _native = new NativeType(_native); | 275 if (_native != null) _native = new NativeType(_native); |
276 } | 276 } |
277 | 277 |
278 var _factory = null; | 278 bool oldFactory = _maybeEat(TokenKind.FACTORY); |
279 if (_maybeEat(TokenKind.FACTORY)) { | 279 var defaultType = null; |
280 // Note: this can't be type(), because for some strange reason these are | 280 if (oldFactory || _maybeEat(TokenKind.DEFAULT)) { |
281 // type parameters, not type arguments. | 281 // TODO(jmesserly): keep old factory support for now. Remove soon. |
282 _factory = nameTypeReference(); | 282 if (oldFactory) { |
283 world.warning('factory no longer supported, use "default" instead', | |
sra1
2011/12/15 02:38:17
I think Frog warnings need to be consistent with q
jimhug
2011/12/15 17:05:04
SGTM. I just checked and both Python and JS use s
Jennifer Messerly
2011/12/15 19:28:18
+1 on consistency. I'm trying to be consistent wit
| |
284 _previousToken.span); | |
285 } | |
286 | |
287 // Note: this can't be type() because it has type parameters not type | |
288 // arguments. | |
289 var baseType = nameTypeReference(); | |
290 var typeParams = null; | |
283 if (_peekKind(TokenKind.LT)) { | 291 if (_peekKind(TokenKind.LT)) { |
284 // TODO(jmesserly): not sure what to do with these. They aren't used for | 292 typeParams = typeParameters(); |
285 // anything as far as I can tell. | |
286 typeParameters(); | |
287 } | 293 } |
294 defaultType = new DefaultTypeReference(oldFactory, | |
295 baseType, typeParams, _makeSpan(baseType.span.start)); | |
288 } | 296 } |
289 | 297 |
290 var body = []; | 298 var body = []; |
291 if (_maybeEat(TokenKind.LBRACE)) { | 299 if (_maybeEat(TokenKind.LBRACE)) { |
292 while (!_maybeEat(TokenKind.RBRACE)) { | 300 while (!_maybeEat(TokenKind.RBRACE)) { |
293 body.add(declaration()); | 301 body.add(declaration()); |
294 if (_recover) { | 302 if (_recover) { |
295 if (!_recoverTo(TokenKind.RBRACE, TokenKind.SEMICOLON)) break; | 303 if (!_recoverTo(TokenKind.RBRACE, TokenKind.SEMICOLON)) break; |
296 _maybeEat(TokenKind.SEMICOLON); | 304 _maybeEat(TokenKind.SEMICOLON); |
297 } | 305 } |
298 } | 306 } |
299 } else { | 307 } else { |
300 _errorExpected('block starting with "{" or ";"'); | 308 _errorExpected('block starting with "{" or ";"'); |
301 } | 309 } |
302 return new TypeDefinition(kind == TokenKind.CLASS, name, typeParams, | 310 return new TypeDefinition(kind == TokenKind.CLASS, name, typeParams, |
303 _extends, _implements, _native, _factory, body, _makeSpan(start)); | 311 _extends, _implements, _native, defaultType, body, _makeSpan(start)); |
304 } | 312 } |
305 | 313 |
306 functionTypeAlias() { | 314 functionTypeAlias() { |
307 int start = _peekToken.start; | 315 int start = _peekToken.start; |
308 _eat(TokenKind.TYPEDEF); | 316 _eat(TokenKind.TYPEDEF); |
309 | 317 |
310 var di = declaredIdentifier(false); | 318 var di = declaredIdentifier(false); |
311 var typeParams = null; | 319 var typeParams = null; |
312 if (_peekKind(TokenKind.LT)) { | 320 if (_peekKind(TokenKind.LT)) { |
313 typeParams = typeParameters(); | 321 typeParams = typeParameters(); |
314 } | 322 } |
315 var formals = formalParameterList(); | 323 var formals = formalParameterList(); |
316 _eatSemicolon(); | 324 _eatSemicolon(); |
317 | 325 |
318 var func = new FunctionDefinition(null, di.type, di.name, formals, | 326 var func = new FunctionDefinition(null, di.type, di.name, formals, |
319 null, null, null, null, _makeSpan(start)); | 327 null, null, null, _makeSpan(start)); |
320 | 328 |
321 return new FunctionTypeDefinition(func, typeParams, _makeSpan(start)); | 329 return new FunctionTypeDefinition(func, typeParams, _makeSpan(start)); |
322 } | 330 } |
323 | 331 |
324 initializers() { | 332 initializers() { |
325 _inhibitLambda = true; | 333 _inhibitLambda = true; |
326 var ret = []; | 334 var ret = []; |
327 do { | 335 do { |
328 ret.add(expression()); | 336 ret.add(expression()); |
329 } while (_maybeEat(TokenKind.COMMA)); | 337 } while (_maybeEat(TokenKind.COMMA)); |
(...skipping 18 matching lines...) Expand all Loading... | |
348 } | 356 } |
349 } else if (!inExpression) { | 357 } else if (!inExpression) { |
350 if (_maybeEat(TokenKind.SEMICOLON)) { | 358 if (_maybeEat(TokenKind.SEMICOLON)) { |
351 return null; | 359 return null; |
352 } | 360 } |
353 } | 361 } |
354 | 362 |
355 _error('Expected function body (neither { nor => found)'); | 363 _error('Expected function body (neither { nor => found)'); |
356 } | 364 } |
357 | 365 |
358 finishField(start, modifiers, typeParams, type, name, value) { | 366 finishField(start, modifiers, type, name, value) { |
359 if (typeParams != null) { | |
360 world.internalError('trying to create a generic field', | |
361 _makeSpan(start)); | |
362 } | |
363 var names = [name]; | 367 var names = [name]; |
364 var values = [value]; | 368 var values = [value]; |
365 | 369 |
366 while (_maybeEat(TokenKind.COMMA)) { | 370 while (_maybeEat(TokenKind.COMMA)) { |
367 names.add(identifier()); | 371 names.add(identifier()); |
368 if (_maybeEat(TokenKind.ASSIGN)) { | 372 if (_maybeEat(TokenKind.ASSIGN)) { |
369 values.add(expression()); | 373 values.add(expression()); |
370 } else { | 374 } else { |
371 values.add(null); | 375 values.add(null); |
372 } | 376 } |
373 } | 377 } |
374 | 378 |
375 _eatSemicolon(); | 379 _eatSemicolon(); |
376 return new VariableDefinition(modifiers, type, names, values, | 380 return new VariableDefinition(modifiers, type, names, values, |
377 _makeSpan(start)); | 381 _makeSpan(start)); |
378 } | 382 } |
379 | 383 |
380 finishDefinition(int start, List<Token> modifiers, di, | 384 finishDefinition(int start, List<Token> modifiers, di) { |
381 List<ParameterType> typeParams) { | |
382 switch(_peek()) { | 385 switch(_peek()) { |
383 case TokenKind.LPAREN: | 386 case TokenKind.LPAREN: |
384 var formals = formalParameterList(); | 387 var formals = formalParameterList(); |
385 var inits = null, native = null; | 388 var inits = null, native = null; |
386 if (_maybeEat(TokenKind.COLON)) { | 389 if (_maybeEat(TokenKind.COLON)) { |
387 inits = initializers(); | 390 inits = initializers(); |
388 } | 391 } |
389 if (_maybeEat(TokenKind.NATIVE)) { | 392 if (_maybeEat(TokenKind.NATIVE)) { |
390 native = maybeStringLiteral(); | 393 native = maybeStringLiteral(); |
391 if (native == null) native = ''; | 394 if (native == null) native = ''; |
392 } | 395 } |
393 var body = functionBody(/*inExpression:*/false); | 396 var body = functionBody(/*inExpression:*/false); |
394 if (di.name == null) { | 397 if (di.name == null) { |
395 // TODO(jimhug): Must be named constructor - verify how? | 398 // TODO(jimhug): Must be named constructor - verify how? |
396 di.name = di.type.name; | 399 di.name = di.type.name; |
397 } | 400 } |
398 return new FunctionDefinition(modifiers, di.type, di.name, formals, | 401 return new FunctionDefinition(modifiers, di.type, di.name, formals, |
399 typeParams, inits, native, body, _makeSpan(start)); | 402 inits, native, body, _makeSpan(start)); |
400 | 403 |
401 case TokenKind.ASSIGN: | 404 case TokenKind.ASSIGN: |
402 _eat(TokenKind.ASSIGN); | 405 _eat(TokenKind.ASSIGN); |
403 var value = expression(); | 406 var value = expression(); |
404 return finishField(start, modifiers, typeParams, di.type, di.name, value ); | 407 return finishField(start, modifiers, di.type, di.name, value); |
405 | 408 |
406 case TokenKind.COMMA: | 409 case TokenKind.COMMA: |
407 case TokenKind.SEMICOLON: | 410 case TokenKind.SEMICOLON: |
408 return finishField(start, modifiers, typeParams, di.type, di.name, null) ; | 411 return finishField(start, modifiers, di.type, di.name, null); |
409 | 412 |
410 default: | 413 default: |
411 // TODO(jimhug): This error message sucks. | 414 // TODO(jimhug): This error message sucks. |
412 _errorExpected('declaration'); | 415 _errorExpected('declaration'); |
413 | 416 |
414 return null; | 417 return null; |
415 } | 418 } |
416 } | 419 } |
417 | 420 |
418 declaration([bool includeOperators=true]) { | 421 declaration([bool includeOperators=true]) { |
419 int start = _peekToken.start; | 422 int start = _peekToken.start; |
420 if (_peekKind(TokenKind.FACTORY)) { | 423 if (_peekKind(TokenKind.FACTORY)) { |
421 return factoryConstructorDeclaration(); | 424 return factoryConstructorDeclaration(); |
422 } | 425 } |
423 | 426 |
424 var modifiers = _readModifiers(); | 427 var modifiers = _readModifiers(); |
425 return finishDefinition(start, modifiers, | 428 return finishDefinition(start, modifiers, |
426 declaredIdentifier(includeOperators), null); | 429 declaredIdentifier(includeOperators)); |
427 } | 430 } |
428 | 431 |
432 // TODO(jmesserly): do we still need this method? | |
433 // I left it here for now to support old-style factories | |
jimhug
2011/12/15 17:05:04
I think we need this "forever" as we still have fa
Jennifer Messerly
2011/12/15 19:28:18
Ah, I might be misremembering the history of the c
| |
429 factoryConstructorDeclaration() { | 434 factoryConstructorDeclaration() { |
430 int start = _peekToken.start; | 435 int start = _peekToken.start; |
431 var factoryToken = _next(); | 436 var factoryToken = _next(); |
432 | 437 |
433 var names = [identifier()]; | 438 var names = [identifier()]; |
434 while (_maybeEat(TokenKind.DOT)) { | 439 while (_maybeEat(TokenKind.DOT)) { |
435 names.add(identifier()); | 440 names.add(identifier()); |
436 } | 441 } |
437 var typeParams = null; | |
438 if (_peekKind(TokenKind.LT)) { | 442 if (_peekKind(TokenKind.LT)) { |
439 typeParams = typeParameters(); | 443 var tp = typeParameters(); |
444 world.warning('type parameters on factories are no longer supported, ' | |
445 + 'place them on the class instead', _makeSpan(tp[0].span.start)); | |
440 } | 446 } |
441 | 447 |
442 var name = null; | 448 var name = null; |
443 var type = null; | 449 var type = null; |
444 if (_maybeEat(TokenKind.DOT)) { | 450 if (_maybeEat(TokenKind.DOT)) { |
445 name = identifier(); | 451 name = identifier(); |
446 } else if (typeParams == null) { | 452 } else { |
447 if (names.length > 1) { | 453 if (names.length > 1) { |
448 name = names.removeLast(); | 454 name = names.removeLast(); |
449 } else { | 455 } else { |
450 name = new Identifier('', names[0].span); | 456 name = new Identifier('', names[0].span); |
451 } | 457 } |
452 } else { | |
453 name = new Identifier('', names[0].span); | |
454 } | 458 } |
455 | 459 |
456 if (names.length > 1) { | 460 if (names.length > 1) { |
457 // TODO(jimhug): This is nasty to support and currently unused. | 461 // TODO(jimhug): This is nasty to support and currently unused. |
458 _error('unsupported qualified name for factory', names[0].span); | 462 _error('unsupported qualified name for factory', names[0].span); |
459 } | 463 } |
460 type = new NameTypeReference(false, names[0], null, names[0].span); | 464 type = new NameTypeReference(false, names[0], null, names[0].span); |
461 var di = new DeclaredIdentifier(type, name, _makeSpan(start)); | 465 var di = new DeclaredIdentifier(type, name, _makeSpan(start)); |
462 return finishDefinition(start, [factoryToken], di, typeParams); | 466 return finishDefinition(start, [factoryToken], di); |
463 } | 467 } |
464 | 468 |
465 /////////////////////////////////////////////////////////////////// | 469 /////////////////////////////////////////////////////////////////// |
466 // Statement productions | 470 // Statement productions |
467 /////////////////////////////////////////////////////////////////// | 471 /////////////////////////////////////////////////////////////////// |
468 Statement statement() { | 472 Statement statement() { |
469 switch (_peek()) { | 473 switch (_peek()) { |
470 case TokenKind.BREAK: | 474 case TokenKind.BREAK: |
471 return breakStatement(); | 475 return breakStatement(); |
472 case TokenKind.CONTINUE: | 476 case TokenKind.CONTINUE: |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
522 if (expr.func.body is! BlockStatement) { | 526 if (expr.func.body is! BlockStatement) { |
523 _eatSemicolon(); | 527 _eatSemicolon(); |
524 expr.func.span = _makeSpan(start); | 528 expr.func.span = _makeSpan(start); |
525 } | 529 } |
526 return expr.func; | 530 return expr.func; |
527 } else if (expr is DeclaredIdentifier) { | 531 } else if (expr is DeclaredIdentifier) { |
528 var value = null; | 532 var value = null; |
529 if (_maybeEat(TokenKind.ASSIGN)) { | 533 if (_maybeEat(TokenKind.ASSIGN)) { |
530 value = expression(); | 534 value = expression(); |
531 } | 535 } |
532 return finishField(start, null, null, expr.type, expr.name, value); | 536 return finishField(start, null, expr.type, expr.name, value); |
533 } else if (_isBin(expr, TokenKind.ASSIGN) && | 537 } else if (_isBin(expr, TokenKind.ASSIGN) && |
534 (expr.x is DeclaredIdentifier)) { | 538 (expr.x is DeclaredIdentifier)) { |
535 DeclaredIdentifier di = expr.x; // TODO(jimhug): inference should handle! | 539 DeclaredIdentifier di = expr.x; // TODO(jimhug): inference should handle! |
536 return finishField(start, null, null, di.type, di.name, expr.y); | 540 return finishField(start, null, di.type, di.name, expr.y); |
537 } else if (_isBin(expr, TokenKind.LT) && _maybeEat(TokenKind.COMMA)) { | 541 } else if (_isBin(expr, TokenKind.LT) && _maybeEat(TokenKind.COMMA)) { |
538 var baseType = _makeType(expr.x); | 542 var baseType = _makeType(expr.x); |
539 var typeArgs = [_makeType(expr.y)]; | 543 var typeArgs = [_makeType(expr.y)]; |
540 var gt = _finishTypeArguments(baseType, 0, typeArgs); | 544 var gt = _finishTypeArguments(baseType, 0, typeArgs); |
541 var name = identifier(); | 545 var name = identifier(); |
542 var value = null; | 546 var value = null; |
543 if (_maybeEat(TokenKind.ASSIGN)) { | 547 if (_maybeEat(TokenKind.ASSIGN)) { |
544 value = expression(); | 548 value = expression(); |
545 } | 549 } |
546 return finishField(expr.span.start, null, null, gt, name, value); | 550 return finishField(expr.span.start, null, gt, name, value); |
547 } else { | 551 } else { |
548 _eatSemicolon(); | 552 _eatSemicolon(); |
549 return new ExpressionStatement(expr, _makeSpan(expr.span.start)); | 553 return new ExpressionStatement(expr, _makeSpan(expr.span.start)); |
550 } | 554 } |
551 } | 555 } |
552 | 556 |
553 Expression testCondition() { | 557 Expression testCondition() { |
554 _eatLeftParen(); | 558 _eatLeftParen(); |
555 var ret = expression(); | 559 var ret = expression(); |
556 _eat(TokenKind.RPAREN); | 560 _eat(TokenKind.RPAREN); |
(...skipping 658 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1215 } | 1219 } |
1216 return null; | 1220 return null; |
1217 } | 1221 } |
1218 | 1222 |
1219 _parenOrLambda() { | 1223 _parenOrLambda() { |
1220 int start = _peekToken.start; | 1224 int start = _peekToken.start; |
1221 if (_atClosureParameters()) { | 1225 if (_atClosureParameters()) { |
1222 var formals = formalParameterList(); | 1226 var formals = formalParameterList(); |
1223 var body = functionBody(true); | 1227 var body = functionBody(true); |
1224 var func = new FunctionDefinition(null, null, null, formals, null, null, | 1228 var func = new FunctionDefinition(null, null, null, formals, null, null, |
1225 null, body, _makeSpan(start)); | 1229 body, _makeSpan(start)); |
1226 return new LambdaExpression(func, func.span); | 1230 return new LambdaExpression(func, func.span); |
1227 } else { | 1231 } else { |
1228 _eatLeftParen(); | 1232 _eatLeftParen(); |
1229 var saved = _inhibitLambda; | 1233 var saved = _inhibitLambda; |
1230 _inhibitLambda = false; | 1234 _inhibitLambda = false; |
1231 var expr = expression(); | 1235 var expr = expression(); |
1232 _eat(TokenKind.RPAREN); | 1236 _eat(TokenKind.RPAREN); |
1233 _inhibitLambda = saved; | 1237 _inhibitLambda = saved; |
1234 return new ParenExpression(expr, _makeSpan(start)); | 1238 return new ParenExpression(expr, _makeSpan(start)); |
1235 } | 1239 } |
(...skipping 403 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1639 | 1643 |
1640 var value = null; | 1644 var value = null; |
1641 if (_maybeEat(TokenKind.ASSIGN)) { | 1645 if (_maybeEat(TokenKind.ASSIGN)) { |
1642 if (!inOptionalBlock) { | 1646 if (!inOptionalBlock) { |
1643 _error('default values only allowed inside [optional] section'); | 1647 _error('default values only allowed inside [optional] section'); |
1644 } | 1648 } |
1645 value = expression(); | 1649 value = expression(); |
1646 } else if (_peekKind(TokenKind.LPAREN)) { | 1650 } else if (_peekKind(TokenKind.LPAREN)) { |
1647 var formals = formalParameterList(); | 1651 var formals = formalParameterList(); |
1648 var func = new FunctionDefinition(null, type, name, formals, | 1652 var func = new FunctionDefinition(null, type, name, formals, |
1649 null, null, null, null, _makeSpan(start)); | 1653 null, null, null, _makeSpan(start)); |
1650 type = new FunctionTypeReference(false, func, func.span); | 1654 type = new FunctionTypeReference(false, func, func.span); |
1651 } | 1655 } |
1652 if (inOptionalBlock && value == null) { | 1656 if (inOptionalBlock && value == null) { |
1653 value = new NullExpression(_makeSpan(start)); | 1657 value = new NullExpression(_makeSpan(start)); |
1654 } | 1658 } |
1655 | 1659 |
1656 return new FormalNode(isThis, isRest, type, name, value, _makeSpan(start)); | 1660 return new FormalNode(isThis, isRest, type, name, value, _makeSpan(start)); |
1657 } | 1661 } |
1658 | 1662 |
1659 formalParameterList() { | 1663 formalParameterList() { |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1706 name = expr.name; | 1710 name = expr.name; |
1707 type = null; | 1711 type = null; |
1708 } else if (expr is DeclaredIdentifier) { | 1712 } else if (expr is DeclaredIdentifier) { |
1709 name = expr.name; | 1713 name = expr.name; |
1710 type = expr.type; | 1714 type = expr.type; |
1711 } else { | 1715 } else { |
1712 _error('bad function body', expr.span); | 1716 _error('bad function body', expr.span); |
1713 } | 1717 } |
1714 var span = new SourceSpan(expr.span.file, expr.span.start, body.span.end); | 1718 var span = new SourceSpan(expr.span.file, expr.span.start, body.span.end); |
1715 var func = new FunctionDefinition(null, type, name, formals, null, null, | 1719 var func = new FunctionDefinition(null, type, name, formals, null, null, |
1716 null, body, span); | 1720 body, span); |
1717 return new LambdaExpression(func, func.span); | 1721 return new LambdaExpression(func, func.span); |
1718 } | 1722 } |
1719 | 1723 |
1720 /** Converts an expression to a [DeclaredIdentifier]. */ | 1724 /** Converts an expression to a [DeclaredIdentifier]. */ |
1721 _makeDeclaredIdentifier(e) { | 1725 _makeDeclaredIdentifier(e) { |
1722 if (e is VarExpression) { | 1726 if (e is VarExpression) { |
1723 return new DeclaredIdentifier(null, e.name, e.span); | 1727 return new DeclaredIdentifier(null, e.name, e.span); |
1724 } else if (e is DeclaredIdentifier) { | 1728 } else if (e is DeclaredIdentifier) { |
1725 return e; | 1729 return e; |
1726 } else { | 1730 } else { |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1765 int _pos = 0; | 1769 int _pos = 0; |
1766 next() { | 1770 next() { |
1767 var token = tokens[_pos]; | 1771 var token = tokens[_pos]; |
1768 ++_pos; | 1772 ++_pos; |
1769 if (_pos == tokens.length) { | 1773 if (_pos == tokens.length) { |
1770 parser.tokenizer = previousTokenizer; | 1774 parser.tokenizer = previousTokenizer; |
1771 } | 1775 } |
1772 return token; | 1776 return token; |
1773 } | 1777 } |
1774 } | 1778 } |
OLD | NEW |