1 module d.parser.expression; 2 3 import d.ast.expression; 4 import d.ast.identifier; 5 6 import d.ir.expression; 7 8 import d.parser.ambiguous; 9 import d.parser.base; 10 import d.parser.identifier; 11 import d.parser.statement; 12 import d.parser.type; 13 import source.parserutil; 14 15 /** 16 * Parse Expression 17 */ 18 AstExpression parseExpression(ParseMode mode = ParseMode.Greedy)(ref TokenRange trange) { 19 auto lhs = trange.parsePrefixExpression!mode(); 20 return trange.parseAstBinaryExpression!( 21 TokenType.Comma, 22 AstBinaryOp.Comma, 23 function AstExpression(ref TokenRange trange, AstExpression e) { 24 return trange.parseAssignExpression(e); 25 } 26 )(lhs); 27 } 28 29 /** 30 * Template used to parse basic AstBinaryExpressions. 31 */ 32 private AstExpression parseAstBinaryExpression( 33 TokenType tokenType, 34 AstBinaryOp op, 35 alias parseNext, 36 R, 37 )(ref R trange, AstExpression lhs) { 38 lhs = parseNext(trange, lhs); 39 Location location = lhs.location; 40 41 while (trange.front.type == tokenType) { 42 trange.popFront(); 43 44 auto rhs = trange.parsePrefixExpression(); 45 rhs = parseNext(trange, rhs); 46 47 location.spanTo(rhs.location); 48 lhs = new AstBinaryExpression(location, op, lhs, rhs); 49 } 50 51 return lhs; 52 } 53 54 /** 55 * Parse assignement expressions. 56 */ 57 AstExpression parseAssignExpression(ref TokenRange trange) { 58 return trange.parseAssignExpression(trange.parsePrefixExpression()); 59 } 60 61 AstExpression parseAssignExpression(ref TokenRange trange, AstExpression lhs) { 62 lhs = trange.parseTernaryExpression(lhs); 63 Location location = lhs.location; 64 65 void processToken(AstBinaryOp op) { 66 trange.popFront(); 67 68 auto rhs = trange.parsePrefixExpression(); 69 rhs = trange.parseAssignExpression(rhs); 70 71 location.spanTo(rhs.location); 72 73 lhs = new AstBinaryExpression(location, op, lhs, rhs); 74 } 75 76 switch (trange.front.type) with(AstBinaryOp) with(TokenType) { 77 case Equal: 78 processToken(Assign); 79 break; 80 81 case PlusEqual: 82 processToken(AddAssign); 83 break; 84 85 case MinusEqual: 86 processToken(SubAssign); 87 break; 88 89 case StarEqual: 90 processToken(MulAssign); 91 break; 92 93 case SlashEqual: 94 processToken(DivAssign); 95 break; 96 97 case PercentEqual: 98 processToken(RemAssign); 99 break; 100 101 case AmpersandEqual: 102 processToken(AndAssign); 103 break; 104 105 case PipeEqual: 106 processToken(OrAssign); 107 break; 108 109 case CaretEqual: 110 processToken(XorAssign); 111 break; 112 113 case TildeEqual: 114 processToken(ConcatAssign); 115 break; 116 117 case LessLessEqual: 118 processToken(LeftShiftAssign); 119 break; 120 121 case MoreMoreEqual: 122 processToken(SignedRightShiftAssign); 123 break; 124 125 case MoreMoreMoreEqual: 126 processToken(UnsignedRightShiftAssign); 127 break; 128 129 case CaretCaretEqual: 130 processToken(PowAssign); 131 break; 132 133 default: 134 // No assignement. 135 break; 136 } 137 138 return lhs; 139 } 140 141 /** 142 * Parse ?: 143 */ 144 // FIXME: Should be private, but dmd don't like that. 145 AstExpression parseTernaryExpression(ref TokenRange trange) { 146 return trange.parseTernaryExpression(trange.parsePrefixExpression()); 147 } 148 149 AstExpression parseTernaryExpression(ref TokenRange trange, AstExpression condition) { 150 condition = trange.parseLogicalOrExpression(condition); 151 152 if (trange.front.type == TokenType.QuestionMark) { 153 Location location = condition.location; 154 155 trange.popFront(); 156 auto ifTrue = trange.parseExpression(); 157 158 trange.match(TokenType.Colon); 159 auto ifFalse = trange.parseTernaryExpression(); 160 161 location.spanTo(ifFalse.location); 162 return new AstTernaryExpression(location, condition, ifTrue, ifFalse); 163 } 164 165 return condition; 166 } 167 168 /** 169 * Parse || 170 */ 171 // FIXME: Should be private, but dmd don't like that. 172 AstExpression parseLogicalOrExpression(ref TokenRange trange) { 173 return trange.parseLogicalOrExpression(trange.parsePrefixExpression()); 174 } 175 176 auto parseLogicalOrExpression(ref TokenRange trange, AstExpression lhs) { 177 return trange.parseAstBinaryExpression!( 178 TokenType.PipePipe, 179 AstBinaryOp.LogicalOr, 180 function AstExpression(ref TokenRange trange, AstExpression e) { 181 return trange.parseLogicalAndExpression(e); 182 } 183 )(lhs); 184 } 185 186 /** 187 * Parse && 188 */ 189 // FIXME: Should be private, but dmd don't like that. 190 AstExpression parseLogicalAndExpression(ref TokenRange trange) { 191 return trange.parseLogicalAndExpression(trange.parsePrefixExpression()); 192 } 193 194 auto parseLogicalAndExpression(ref TokenRange trange, AstExpression lhs) { 195 return trange.parseAstBinaryExpression!( 196 TokenType.AmpersandAmpersand, 197 AstBinaryOp.LogicalAnd, 198 function AstExpression(ref TokenRange trange, AstExpression e) { 199 return trange.parseBitwiseOrExpression(e); 200 } 201 )(lhs); 202 } 203 204 /** 205 * Parse | 206 */ 207 // FIXME: Should be private, but dmd don't like that. 208 AstExpression parseBitwiseOrExpression(ref TokenRange trange) { 209 return trange.parseBitwiseOrExpression(trange.parsePrefixExpression()); 210 } 211 212 auto parseBitwiseOrExpression(ref TokenRange trange, AstExpression lhs) { 213 return trange.parseAstBinaryExpression!( 214 TokenType.Pipe, 215 AstBinaryOp.Or, 216 function AstExpression(ref TokenRange trange, AstExpression e) { 217 return trange.parseBitwiseXorExpression(e); 218 } 219 )(lhs); 220 } 221 222 /** 223 * Parse ^ 224 */ 225 // FIXME: Should be private, but dmd don't like that. 226 AstExpression parseBitwiseXorExpression(ref TokenRange trange) { 227 return trange.parseBitwiseXorExpression(trange.parsePrefixExpression()); 228 } 229 230 auto parseBitwiseXorExpression(ref TokenRange trange, AstExpression lhs) { 231 return trange.parseAstBinaryExpression!( 232 TokenType.Caret, 233 AstBinaryOp.Xor, 234 function AstExpression(ref TokenRange trange, AstExpression e) { 235 return trange.parseBitwiseAndExpression(e); 236 } 237 )(lhs); 238 } 239 240 /** 241 * Parse & 242 */ 243 // FIXME: Should be private, but dmd don't like that. 244 AstExpression parseBitwiseAndExpression(ref TokenRange trange) { 245 return trange.parseBitwiseAndExpression(trange.parsePrefixExpression()); 246 } 247 248 auto parseBitwiseAndExpression(ref TokenRange trange, AstExpression lhs) { 249 return trange.parseAstBinaryExpression!( 250 TokenType.Ampersand, 251 AstBinaryOp.And, 252 function AstExpression(ref TokenRange trange, AstExpression e) { 253 return trange.parseComparaisonExpression(e); 254 } 255 )(lhs); 256 } 257 258 /** 259 * Parse ==, != and comparaisons 260 */ 261 // FIXME: Should be private, but dmd don't like that. 262 AstExpression parseComparaisonExpression(ref TokenRange trange) { 263 return trange.parseComparaisonExpression(trange.parsePrefixExpression()); 264 } 265 266 AstExpression parseComparaisonExpression(ref TokenRange trange, AstExpression lhs) { 267 lhs = trange.parseShiftExpression(lhs); 268 Location location = lhs.location; 269 270 void processToken(AstBinaryOp op) { 271 trange.popFront(); 272 273 auto rhs = trange.parseShiftExpression(); 274 275 location.spanTo(rhs.location); 276 lhs = new AstBinaryExpression(location, op, lhs, rhs); 277 } 278 279 switch(trange.front.type) with(TokenType) { 280 case EqualEqual : 281 processToken(AstBinaryOp.Equal); 282 break; 283 284 case BangEqual : 285 processToken(AstBinaryOp.NotEqual); 286 break; 287 288 case More: 289 processToken(AstBinaryOp.Greater); 290 break; 291 292 case MoreEqual: 293 processToken(AstBinaryOp.GreaterEqual); 294 break; 295 296 case Less : 297 processToken(AstBinaryOp.Less); 298 break; 299 300 case LessEqual : 301 processToken(AstBinaryOp.LessEqual); 302 break; 303 304 case BangLessMoreEqual: 305 processToken(AstBinaryOp.Unordered); 306 break; 307 308 case BangLessMore: 309 processToken(AstBinaryOp.UnorderedEqual); 310 break; 311 312 case LessMore: 313 processToken(AstBinaryOp.LessGreater); 314 break; 315 316 case LessMoreEqual: 317 processToken(AstBinaryOp.LessEqualGreater); 318 break; 319 320 case BangMore: 321 processToken(AstBinaryOp.UnorderedLessEqual); 322 break; 323 324 case BangMoreEqual: 325 processToken(AstBinaryOp.UnorderedLess); 326 break; 327 328 case BangLess: 329 processToken(AstBinaryOp.UnorderedGreaterEqual); 330 break; 331 332 case BangLessEqual: 333 processToken(AstBinaryOp.UnorderedGreater); 334 break; 335 336 case Is: 337 processToken(AstBinaryOp.Identical); 338 break; 339 340 case In: 341 processToken(AstBinaryOp.In); 342 break; 343 344 case Bang: 345 trange.popFront(); 346 switch(trange.front.type) { 347 case Is: 348 processToken(AstBinaryOp.NotIdentical); 349 break; 350 351 case In: 352 processToken(AstBinaryOp.NotIn); 353 break; 354 355 default: 356 trange.match(TokenType.Begin); 357 break; 358 } 359 360 break; 361 362 default: 363 // We have no comparaison, so we just return. 364 break; 365 } 366 367 return lhs; 368 } 369 370 /** 371 * Parse <<, >> and >>> 372 */ 373 // FIXME: Should be private, but dmd don't like that. 374 AstExpression parseShiftExpression(ref TokenRange trange) { 375 return trange.parseShiftExpression(trange.parsePrefixExpression()); 376 } 377 378 AstExpression parseShiftExpression(ref TokenRange trange, AstExpression lhs) { 379 lhs = trange.parseAddExpression(lhs); 380 Location location = lhs.location; 381 382 while(1) { 383 void processToken(AstBinaryOp op) { 384 trange.popFront(); 385 386 auto rhs = trange.parseAddExpression(); 387 388 location.spanTo(rhs.location); 389 lhs = new AstBinaryExpression(location, op, lhs, rhs); 390 } 391 392 switch (trange.front.type) with(AstBinaryOp) with(TokenType) { 393 case LessLess: 394 processToken(LeftShift); 395 break; 396 397 case MoreMore: 398 processToken(SignedRightShift); 399 break; 400 401 case MoreMoreMore: 402 processToken(UnsignedRightShift); 403 break; 404 405 default : 406 return lhs; 407 } 408 } 409 } 410 411 /** 412 * Parse +, - and ~ 413 */ 414 // FIXME: Should be private, but dmd don't like that. 415 AstExpression parseAddExpression(ref TokenRange trange) { 416 return trange.parseAddExpression(trange.parsePrefixExpression()); 417 } 418 419 AstExpression parseAddExpression(ref TokenRange trange, AstExpression lhs) { 420 lhs = trange.parseMulExpression(lhs); 421 Location location = lhs.location; 422 423 while(1) { 424 void processToken(AstBinaryOp op) { 425 trange.popFront(); 426 427 auto rhs = trange.parseMulExpression(); 428 429 location.spanTo(rhs.location); 430 lhs = new AstBinaryExpression(location, op, lhs, rhs); 431 } 432 433 switch (trange.front.type) with(AstBinaryOp) with(TokenType) { 434 case Plus: 435 processToken(Add); 436 break; 437 438 case Minus: 439 processToken(Sub); 440 break; 441 442 case Tilde: 443 processToken(Concat); 444 break; 445 446 default : 447 return lhs; 448 } 449 } 450 } 451 452 /** 453 * Parse *, / and % 454 */ 455 // FIXME: Should be private, but dmd don't like that. 456 AstExpression parseMulExpression(ref TokenRange trange) { 457 return trange.parseMulExpression(trange.parsePrefixExpression()); 458 } 459 460 AstExpression parseMulExpression(ref TokenRange trange, AstExpression lhs) { 461 Location location = lhs.location; 462 463 while(1) { 464 void processToken(AstBinaryOp op) { 465 trange.popFront(); 466 467 auto rhs = trange.parsePrefixExpression(); 468 469 location.spanTo(rhs.location); 470 lhs = new AstBinaryExpression(location, op, lhs, rhs); 471 } 472 473 switch (trange.front.type) with(AstBinaryOp) with(TokenType) { 474 case Star: 475 processToken(Mul); 476 break; 477 478 case Slash: 479 processToken(Div); 480 break; 481 482 case Percent: 483 processToken(Rem); 484 break; 485 486 default : 487 return lhs; 488 } 489 } 490 } 491 492 /** 493 * Unary prefixes 494 */ 495 private AstExpression parsePrefixExpression( 496 ParseMode mode = ParseMode.Greedy, 497 )(ref TokenRange trange) { 498 AstExpression result; 499 500 void processToken(UnaryOp op) { 501 Location location = trange.front.location; 502 trange.popFront(); 503 504 // Drop mode on purpose. 505 result = trange.parsePrefixExpression(); 506 507 location.spanTo(result.location); 508 result = new AstUnaryExpression(location, op, result); 509 } 510 511 switch (trange.front.type) with(TokenType) { 512 case Ampersand: 513 processToken(UnaryOp.AddressOf); 514 break; 515 516 case PlusPlus: 517 processToken(UnaryOp.PreInc); 518 break; 519 520 case MinusMinus: 521 processToken(UnaryOp.PreDec); 522 break; 523 524 case Star: 525 processToken(UnaryOp.Dereference); 526 break; 527 528 case Plus: 529 processToken(UnaryOp.Plus); 530 break; 531 532 case Minus: 533 processToken(UnaryOp.Minus); 534 break; 535 536 case Bang: 537 processToken(UnaryOp.Not); 538 break; 539 540 case Tilde: 541 processToken(UnaryOp.Complement); 542 break; 543 544 // TODO: parse qualifier casts. 545 case Cast: 546 Location location = trange.front.location; 547 trange.popFront(); 548 trange.match(OpenParen); 549 550 switch (trange.front.type) { 551 case CloseParen: 552 assert(0, "cast() isn't supported."); 553 554 default: 555 auto type = trange.parseType(); 556 trange.match(CloseParen); 557 558 result = trange.parsePrefixExpression(); 559 location.spanTo(result.location); 560 561 result = new AstCastExpression(location, type, result); 562 } 563 564 break; 565 566 default: 567 result = trange.parsePrimaryExpression(); 568 result = trange.parsePostfixExpression!mode(result); 569 } 570 571 // Ensure we do not screwed up. 572 assert(result); 573 574 return trange.parsePowExpression(result); 575 } 576 577 AstExpression parsePrimaryExpression(ref TokenRange trange) { 578 Location location = trange.front.location; 579 580 switch (trange.front.type) with(TokenType) { 581 // Identified expressions 582 case Identifier: 583 return trange.parseIdentifierExpression(trange.parseIdentifier()); 584 585 case New: 586 trange.popFront(); 587 auto type = trange.parseType(); 588 auto args = trange.parseArguments!OpenParen(); 589 590 location.spanTo(trange.front.location); 591 return new AstNewExpression(location, type, args); 592 593 case Dot: 594 return trange.parseIdentifierExpression(trange.parseDotIdentifier()); 595 596 case This: 597 trange.popFront(); 598 return new ThisExpression(location); 599 600 case Super: 601 trange.popFront(); 602 return new SuperExpression(location); 603 604 case True: 605 trange.popFront(); 606 return new BooleanLiteral(location, true); 607 608 case False: 609 trange.popFront(); 610 return new BooleanLiteral(location, false); 611 612 case Null: 613 trange.popFront(); 614 return new NullLiteral(location); 615 616 case IntegerLiteral: 617 return trange.parseIntegerLiteral(); 618 619 case StringLiteral: 620 return trange.parseStringLiteral(); 621 622 case CharacterLiteral: 623 return trange.parseCharacterLiteral(); 624 625 case OpenBracket: 626 // FIXME: Support map literals. 627 AstExpression[] values; 628 trange.popFront(); 629 630 while (trange.front.type != CloseBracket) { 631 values ~= trange.parseAssignExpression(); 632 if (trange.front.type != Comma) { 633 break; 634 } 635 636 trange.popFront(); 637 } 638 639 location.spanTo(trange.front.location); 640 trange.match(CloseBracket); 641 642 return new AstArrayLiteral(location, values); 643 644 case OpenBrace: 645 return new DelegateLiteral(trange.parseBlock()); 646 647 case Function, Delegate: 648 assert(0, "Functions or Delegates not implemented "); 649 650 case __File__: 651 trange.popFront(); 652 return new __File__Literal(location); 653 654 case __Line__: 655 trange.popFront(); 656 return new __Line__Literal(location); 657 658 case Dollar: 659 trange.popFront(); 660 return new DollarExpression(location); 661 662 case Typeid: 663 trange.popFront(); 664 trange.match(OpenParen); 665 666 return trange.parseAmbiguous!(delegate AstExpression(parsed) { 667 location.spanTo(trange.front.location); 668 trange.match(CloseParen); 669 670 import d.ast.type; 671 672 alias T = typeof(parsed); 673 static if(is(T : AstType)) { 674 return new AstStaticTypeidExpression(location, parsed); 675 } else static if(is(T : AstExpression)) { 676 return new AstTypeidExpression(location, parsed); 677 } else { 678 return new IdentifierTypeidExpression(location, parsed); 679 } 680 })(); 681 682 case Is: 683 return trange.parseIsExpression(); 684 685 case Mixin: 686 import d.parser.conditional; 687 return trange.parseMixin!AstExpression(); 688 689 case OpenParen: 690 auto matchingParen = trange.getLookahead(); 691 matchingParen.popMatchingDelimiter!OpenParen(); 692 693 switch (matchingParen.front.type) { 694 case Dot: 695 trange.popFront(); 696 return trange.parseAmbiguous!((parsed) { 697 trange.match(CloseParen); 698 trange.match(Dot); 699 700 auto qi = trange.parseQualifiedIdentifier( 701 location, 702 parsed, 703 ); 704 return trange.parseIdentifierExpression(qi); 705 })(); 706 707 case OpenBrace: 708 import d.parser.declaration; 709 bool isVariadic; 710 auto params = trange.parseParameters(isVariadic); 711 712 auto block = trange.parseBlock(); 713 location.spanTo(block.location); 714 715 return new DelegateLiteral(location, params, isVariadic, block); 716 717 case EqualMore: 718 import d.parser.declaration; 719 bool isVariadic; 720 auto params = trange.parseParameters(isVariadic); 721 assert(!isVariadic, "Variadic lambda not supported"); 722 723 trange.match(EqualMore); 724 725 auto value = trange.parseExpression(); 726 location.spanTo(value.location); 727 728 return new Lambda(location, params, value); 729 730 default: 731 trange.popFront(); 732 auto expression = trange.parseExpression(); 733 734 location.spanTo(trange.front.location); 735 trange.match(CloseParen); 736 737 return new ParenExpression(location, expression); 738 } 739 740 default: 741 // Our last resort are type.identifier expressions. 742 auto type = trange.parseType!(ParseMode.Reluctant)(); 743 switch (trange.front.type) { 744 case Dot: 745 trange.popFront(); 746 return trange.parseIdentifierExpression( 747 trange.parseQualifiedIdentifier(location, type), 748 ); 749 750 case OpenParen: 751 auto args = trange.parseArguments!OpenParen(); 752 location.spanTo(trange.previous); 753 return new TypeCallExpression(location, type, args); 754 755 default: 756 break; 757 } 758 759 // TODO: error message that make sense. 760 trange.match(Begin); 761 assert(0, "Implement proper error handling :)"); 762 } 763 } 764 765 /** 766 * Parse postfix ++, --, (...), [...], .identifier 767 */ 768 AstExpression parsePostfixExpression(ParseMode mode)(ref TokenRange trange, AstExpression e) { 769 Location location = e.location; 770 771 while (true) { 772 switch (trange.front.type) with(TokenType) { 773 case PlusPlus: 774 location.spanTo(trange.front.location); 775 trange.popFront(); 776 777 e = new AstUnaryExpression(location, UnaryOp.PostInc, e); 778 break; 779 780 case MinusMinus: 781 location.spanTo(trange.front.location); 782 trange.popFront(); 783 784 e = new AstUnaryExpression(location, UnaryOp.PostDec, e); 785 break; 786 787 case OpenParen: 788 auto args = trange.parseArguments!OpenParen(); 789 790 location.spanTo(trange.previous); 791 e = new AstCallExpression(location, e, args); 792 793 break; 794 795 // TODO: Indices, Slices. 796 case OpenBracket: 797 trange.popFront(); 798 799 if (trange.front.type == CloseBracket) { 800 // We have a slicing operation here. 801 assert(0, "Slice expressions can not be parsed yet"); 802 } else { 803 auto args = trange.parseArguments(); 804 switch(trange.front.type) { 805 case CloseBracket: 806 location.spanTo(trange.front.location); 807 e = new AstIndexExpression(location, e, args); 808 809 break; 810 811 case DotDot: 812 trange.popFront(); 813 auto second = trange.parseArguments(); 814 815 location.spanTo(trange.front.location); 816 e = new AstSliceExpression(location, e, args, second); 817 818 break; 819 820 default: 821 // TODO: error message that make sense. 822 trange.match(Begin); 823 break; 824 } 825 } 826 827 trange.match(CloseBracket); 828 break; 829 830 static if (mode == ParseMode.Greedy) { 831 case Dot: 832 trange.popFront(); 833 834 e = trange.parseIdentifierExpression( 835 trange.parseQualifiedIdentifier(location, e), 836 ); 837 838 break; 839 } 840 841 default : 842 return e; 843 } 844 } 845 } 846 847 /** 848 * Parse ^^ 849 */ 850 private 851 AstExpression parsePowExpression(ref TokenRange trange, AstExpression expr) { 852 Location location = expr.location; 853 854 while (trange.front.type == TokenType.CaretCaret) { 855 trange.popFront(); 856 AstExpression power = trange.parsePrefixExpression(); 857 location.spanTo(power.location); 858 expr = new AstBinaryExpression(location, AstBinaryOp.Pow, expr, power); 859 } 860 861 return expr; 862 } 863 864 /** 865 * Parse unary is expression. 866 */ 867 private auto parseIsExpression(ref TokenRange trange) { 868 Location location = trange.front.location; 869 trange.match(TokenType.Is); 870 trange.match(TokenType.OpenParen); 871 872 auto type = trange.parseType(); 873 874 // Handle alias throw is expression. 875 if (trange.front.type == TokenType.Identifier) { 876 trange.popFront(); 877 } 878 879 switch (trange.front.type) with(TokenType) { 880 case Colon: 881 trange.popFront(); 882 trange.parseType(); 883 break; 884 885 case EqualEqual: 886 trange.popFront(); 887 888 switch(trange.front.type) { 889 case Struct, Union, Class, Interface, Enum, Function, Delegate: 890 case Super, Const, Immutable, Inout, Shared, Return: 891 assert(0, "Not implemented."); 892 893 default: 894 trange.parseType(); 895 } 896 897 break; 898 899 default : 900 break; 901 } 902 903 location.spanTo(trange.front.location); 904 trange.match(TokenType.CloseParen); 905 906 return new IsExpression(location, type); 907 } 908 909 /** 910 * Parse identifier expression 911 */ 912 AstExpression parseIdentifierExpression(ref TokenRange trange, Identifier i) { 913 if (trange.front.type != TokenType.OpenParen) { 914 return new IdentifierExpression(i); 915 } 916 917 auto args = trange.parseArguments!(TokenType.OpenParen)(); 918 919 auto location = i.location; 920 location.spanTo(trange.previous); 921 return new IdentifierCallExpression(location, i, args); 922 } 923 924 /** 925 * Parse function arguments 926 */ 927 AstExpression[] parseArguments(TokenType openTokenType)(ref TokenRange trange) { 928 alias closeTokenType = MatchingDelimiter!openTokenType; 929 930 trange.match(openTokenType); 931 932 AstExpression[] args; 933 while (trange.front.type != closeTokenType) { 934 args ~= trange.parseAssignExpression(); 935 if (trange.front.type != TokenType.Comma) { 936 break; 937 } 938 939 trange.popFront(); 940 } 941 942 trange.match(closeTokenType); 943 return args; 944 } 945 946 AstExpression[] parseArguments(ref TokenRange trange) { 947 AstExpression[] args = [trange.parseAssignExpression()]; 948 while(trange.front.type == TokenType.Comma) { 949 trange.popFront(); 950 951 args ~= trange.parseAssignExpression(); 952 } 953 954 return args; 955 } 956 957 /** 958 * Parse integer literals 959 */ 960 IntegerLiteral parseIntegerLiteral(ref TokenRange trange) { 961 Location location = trange.front.location; 962 963 // Consider computing the value in the lexer and make it a Name. 964 // This would avoid the duplication with code here and probably 965 // would be faster as well. 966 auto strVal = trange.front.toString(trange.context); 967 assert(strVal.length > 0); 968 969 trange.match(TokenType.IntegerLiteral); 970 971 bool isUnsigned, isLong; 972 if (strVal.length > 1) { 973 switch (strVal[$ - 1]) { 974 case 'u', 'U': 975 isUnsigned = true; 976 977 auto penultimo = strVal[$ - 2]; 978 if (penultimo == 'l' || penultimo == 'L') { 979 isLong = true; 980 strVal = strVal[0 .. $ - 2]; 981 } else { 982 strVal = strVal[0 .. $ - 1]; 983 } 984 985 break; 986 987 case 'l', 'L': 988 isLong = true; 989 990 auto penultimo = strVal[$ - 2]; 991 if (penultimo == 'u' || penultimo == 'U') { 992 isUnsigned = true; 993 strVal = strVal[0 .. $ - 2]; 994 } else { 995 strVal = strVal[0 .. $ - 1]; 996 } 997 998 break; 999 1000 default: 1001 break; 1002 } 1003 } 1004 1005 import source.strtoint; 1006 ulong value = strToInt(strVal); 1007 1008 import d.common.builtintype; 1009 auto type = isUnsigned 1010 ? ((isLong || value > uint.max) ? BuiltinType.Ulong : BuiltinType.Uint) 1011 : ((isLong || value > int.max) ? BuiltinType.Long : BuiltinType.Int); 1012 1013 return new IntegerLiteral(location, value, type); 1014 } 1015 1016 /** 1017 * Parse character literals 1018 */ 1019 CharacterLiteral parseCharacterLiteral(ref TokenRange trange) { 1020 Location location = trange.front.location; 1021 auto str = trange.front.name.toString(trange.context); 1022 1023 trange.match(TokenType.CharacterLiteral); 1024 1025 size_t i = 0; 1026 1027 import std.utf; 1028 dchar c = str.decode(i); 1029 1030 if (i != str.length) { 1031 import source.exception; 1032 throw new CompileException(location, "Invalid character literal"); 1033 } 1034 1035 import d.common.builtintype : BuiltinType; 1036 return new CharacterLiteral(location, c, BuiltinType.Char); 1037 } 1038 1039 /** 1040 * Parse string literals 1041 */ 1042 StringLiteral parseStringLiteral(ref TokenRange trange) { 1043 Location location = trange.front.location; 1044 auto name = trange.front.name; 1045 1046 trange.match(TokenType.StringLiteral); 1047 1048 return new StringLiteral(location, name.toString(trange.context)); 1049 }