1 // This file is part of Visual D 2 // 3 // Visual D integrates the D programming language into Visual Studio 4 // Copyright (c) 2010-2011 by Rainer Schuetze, All Rights Reserved 5 // 6 // Distributed under the Boost Software License, Version 1.0. 7 // See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt 8 9 module vdc.parser.stmt; 10 11 import vdc.util; 12 import vdc.lexer; 13 import vdc.parser.engine; 14 import vdc.parser.expr; 15 import vdc.parser.decl; 16 import vdc.parser.iasm; 17 import vdc.parser.mod; 18 import vdc.parser.misc; 19 import vdc.parser.tmpl; 20 import vdc.parser.aggr; 21 22 import ast = vdc.ast.all; 23 24 import stdext.util; 25 26 //-- GRAMMAR_BEGIN -- 27 //Statement: 28 // ScopeStatement 29 class Statement 30 { 31 static Action enter(Parser p) 32 { 33 return ScopeStatement.enter(p); 34 } 35 } 36 37 //-- GRAMMAR_BEGIN -- 38 //ScopeStatement: 39 // ; 40 // NonEmptyStatement 41 // ScopeBlockStatement 42 // 43 //ScopeBlockStatement: 44 // BlockStatement 45 class ScopeStatement : Statement 46 { 47 static Action enter(Parser p) 48 { 49 switch(p.tok.id) 50 { 51 case TOK_semicolon: 52 p.pushNode(new ast.EmptyStatement(p.tok)); 53 return Accept; 54 case TOK_lcurly: 55 return BlockStatement.enter(p); 56 default: 57 return NonEmptyStatement.enter(p); 58 } 59 } 60 } 61 62 //-- GRAMMAR_BEGIN -- 63 //ScopeNonEmptyStatement: 64 // NonEmptyStatement 65 // BlockStatement 66 class ScopeNonEmptyStatement : Statement 67 { 68 static Action enter(Parser p) 69 { 70 switch(p.tok.id) 71 { 72 case TOK_lcurly: 73 return BlockStatement.enter(p); 74 default: 75 return NonEmptyStatement.enter(p); 76 } 77 } 78 } 79 80 //-- GRAMMAR_BEGIN -- 81 //NoScopeNonEmptyStatement: 82 // NonEmptyStatement 83 // BlockStatement 84 alias ScopeNonEmptyStatement NoScopeNonEmptyStatement; 85 86 //-- GRAMMAR_BEGIN -- 87 //NoScopeStatement: 88 // ; 89 // NonEmptyStatement 90 // BlockStatement 91 alias ScopeStatement NoScopeStatement; 92 93 //-- GRAMMAR_BEGIN -- 94 //NonEmptyStatement: 95 // LabeledStatement 96 // ExpressionStatement 97 // DeclarationStatement 98 // IfStatement 99 // WhileStatement 100 // DoStatement 101 // ForStatement 102 // ForeachStatement 103 // SwitchStatement 104 // FinalSwitchStatement 105 // CaseStatement 106 // CaseRangeStatement 107 // DefaultStatement 108 // ContinueStatement 109 // BreakStatement 110 // ReturnStatement 111 // GotoStatement 112 // WithStatement 113 // SynchronizedStatement 114 // VolatileStatement 115 // TryStatement 116 // ScopeGuardStatement 117 // ThrowStatement 118 // AsmStatement 119 // PragmaStatement 120 // MixinStatement 121 // ForeachRangeStatement 122 // ConditionalStatement 123 // StaticAssert 124 // TemplateMixin 125 // EnumDeclaration 126 // ClassDeclaration 127 // InterfaceDeclaration 128 // AggregateDeclaration 129 // TemplateDeclaration 130 // 131 //LabeledStatement: 132 // Identifier : NoScopeStatement 133 class NonEmptyStatement : Statement 134 { 135 static Action enter(Parser p) 136 { 137 switch(p.tok.id) 138 { 139 case TOK_if: 140 return IfStatement.enter(p); 141 case TOK_while: 142 return WhileStatement.enter(p); 143 case TOK_do: 144 return DoStatement.enter(p); 145 case TOK_for: 146 return ForStatement.enter(p); 147 case TOK_foreach: 148 case TOK_foreach_reverse: 149 return ForeachStatement.enter(p); // includes ForeachRangeStatement 150 case TOK_switch: 151 return SwitchStatement.enter(p); 152 case TOK_final: 153 // could also be a declaration? 154 return FinalSwitchStatement.enter(p); 155 case TOK_case: 156 return CaseStatement.enter(p); // includes CaseRangeStatement 157 case TOK_default: 158 return DefaultStatement.enter(p); 159 case TOK_continue: 160 return ContinueStatement.enter(p); 161 case TOK_break: 162 return BreakStatement.enter(p); 163 case TOK_return: 164 return ReturnStatement.enter(p); 165 case TOK_goto: 166 return GotoStatement.enter(p); 167 case TOK_with: 168 return WithStatement.enter(p); 169 case TOK_synchronized: 170 // could also be a declaration? 171 return SynchronizedStatement.enter(p); 172 case TOK_volatile: 173 // could also be a declaration? 174 return VolatileStatement.enter(p); 175 case TOK_try: 176 return TryStatement.enter(p); 177 case TOK_scope: 178 p.pushState(&shiftScope); 179 return Accept; 180 case TOK_throw: 181 return ThrowStatement.enter(p); 182 case TOK_asm: 183 return AsmStatement.enter(p); 184 case TOK_pragma: 185 return PragmaStatement.enter(p); 186 case TOK_mixin: 187 p.pushRollback(&rollbackDeclFailure); 188 p.pushState(&shiftMixin); 189 return Accept; 190 191 case TOK_debug: 192 case TOK_version: 193 return ConditionalStatement.enter(p); 194 195 case TOK_static: // can also be static assert or declaration 196 p.pushToken(p.tok); 197 p.pushState(&shiftStatic); 198 return Accept; 199 200 case TOK_Identifier: 201 // label, declaration or expression 202 p.pushRollback(&rollbackDeclFailure); 203 p.pushToken(p.tok); 204 p.pushState(&shiftIdentifier); 205 return Accept; 206 207 case TOK_enum: 208 p.pushState(&shiftDeclaration); 209 return EnumDeclaration.enter(p); 210 211 case TOK_struct: 212 case TOK_union: 213 case TOK_class: 214 case TOK_interface: 215 p.pushState(&shiftDeclaration); 216 return AggregateDeclaration.enter(p); 217 218 case TOK_template: 219 p.pushState(&shiftDeclaration); 220 return TemplateDeclaration.enter(p); 221 222 case TOK_align: 223 case TOK_extern: 224 p.pushState(&shiftDeclaration); 225 return AttributeSpecifier.enter(p); 226 227 mixin(case_TOKs_BasicTypeX); 228 goto case; 229 case TOK_deprecated: 230 // case TOK_static: 231 // case TOK_final: 232 case TOK_override: 233 case TOK_abstract: 234 case TOK_const: 235 case TOK_auto: 236 // case TOK_scope: 237 case TOK___gshared: 238 case TOK___thread: 239 case TOK___vector: 240 case TOK_shared: 241 case TOK_immutable: 242 case TOK_inout: 243 mixin(case_TOKs_FunctionAttribute); 244 p.pushState(&shiftDeclaration); 245 return Declaration.enter(p); 246 247 case TOK_import: 248 p.pushRollback(&rollbackDeclFailure); 249 p.pushState(&shiftImport); 250 return ImportDeclaration.enter(p); 251 252 default: 253 p.pushRollback(&rollbackDeclFailure); 254 p.pushState(&shiftDecl); 255 return Declaration.enter(p); 256 } 257 } 258 259 // assumes identifier token pushed on token stack 260 static Action shiftIdentifier(Parser p) 261 { 262 switch(p.tok.id) 263 { 264 case TOK_colon: 265 p.popRollback(); 266 Token tok = p.popToken(); 267 p.pushNode(new ast.LabeledStatement(tok)); 268 p.pushState(&shiftLabeledStatement); 269 p.pushState(&NoScopeStatement.enter); 270 return Accept; 271 272 default: 273 p.pushState(&shiftDecl); 274 return Decl!true.enterTypeIdentifier(p); 275 } 276 } 277 278 static Action shiftLabeledStatement(Parser p) 279 { 280 p.popAppendTopNode!(ast.LabeledStatement); 281 return Forward; 282 } 283 284 static Action shiftDecl(Parser p) 285 { 286 p.popRollback(); 287 return shiftDeclaration(p); 288 } 289 290 static rollbackDeclFailure(Parser p) 291 { 292 return ExpressionStatement.enter(p); 293 } 294 295 static Action shiftStatic(Parser p) 296 { 297 switch(p.tok.id) 298 { 299 case TOK_if: 300 p.popToken(); 301 return ConditionalStatement.enterAfterStatic(p); 302 case TOK_assert: 303 p.popToken(); 304 return StaticAssert.enterAfterStatic(p); 305 default: 306 p.pushState(&shiftDeclaration); 307 return AttributeSpecifier.enterAfterStatic(p); 308 } 309 } 310 311 static Action shiftMixin(Parser p) 312 { 313 switch(p.tok.id) 314 { 315 case TOK_template: 316 p.pushState(&shiftDeclaration); 317 return TemplateMixinDeclaration.enterAfterMixin(p); 318 case TOK_lparen: 319 p.pushState(&shiftMixInStatement); 320 return MixinStatement.enterAfterMixin(p); 321 default: 322 return TemplateMixin.enterAfterMixin(p); 323 } 324 } 325 326 static Action shiftScope(Parser p) 327 { 328 switch(p.tok.id) 329 { 330 case TOK_lparen: 331 return ScopeGuardStatement.enterAfterScope(p); 332 default: 333 return Decl!true.enterAfterStorageClass(p, TOK_scope); 334 } 335 } 336 337 static Action shiftDeclaration(Parser p) 338 { 339 p.appendReplaceTopNode(new ast.DeclarationStatement(p.topNode().span)); 340 return Forward; 341 } 342 343 static Action shiftMixInStatement(Parser p) 344 { 345 switch(p.tok.id) 346 { 347 case TOK_semicolon: 348 p.popRollback(); 349 return Accept; 350 default: 351 // roll back for mixin expression 352 return p.parseError("';' expected after mixin statement"); 353 } 354 } 355 356 static Action shiftImport(Parser p) 357 { 358 p.popRollback(); 359 p.appendReplaceTopNode(new ast.ImportStatement(p.topNode().span)); 360 return Forward; 361 } 362 } 363 364 //-- GRAMMAR_BEGIN -- 365 //BlockStatement: 366 // { } 367 // { StatementList } 368 // 369 //StatementList: 370 // Statement 371 // Statement StatementList 372 class BlockStatement : Statement 373 { 374 static Action enter(Parser p) 375 { 376 switch(p.tok.id) 377 { 378 case TOK_lcurly: 379 p.pushNode(new ast.BlockStatement(p.tok)); 380 p.pushRecoverState(&recover); 381 p.pushState(&Parser.keepRecover); // add a "guard" state to avoid popping recover 382 p.pushState(&shiftLcurly); 383 return Accept; 384 default: 385 return p.parseError("opening curly brace expected"); 386 } 387 } 388 389 static Action shiftLcurly(Parser p) 390 { 391 switch(p.tok.id) 392 { 393 case TOK_rcurly: 394 return Accept; 395 case TOK_EOF: 396 return Forward; 397 default: 398 p.pushState(&shiftStatement); 399 return Statement.enter(p); 400 } 401 } 402 403 static Action shiftStatement(Parser p) 404 { 405 p.popAppendTopNode!(ast.BlockStatement)(); 406 return shiftLcurly(p); 407 } 408 409 static Action recover(Parser p) 410 { 411 auto node = new ast.ParseRecoverNode(p.tok); 412 if(p.nodeStack.depth) 413 node.fulspan.start = p.topNode().fulspan.end; // record span of removed text 414 p.pushNode(node); 415 p.pushState(&afterRecover); 416 return Parser.recoverSemiCurly(p); 417 } 418 419 static Action afterRecover(Parser p) 420 { 421 p.popAppendTopNode!(ast.BlockStatement, ast.ParseRecoverNode)(); 422 423 p.pushRecoverState(&recover); 424 p.pushState(&Parser.keepRecover); // add a "guard" state to avoid popping recover 425 426 return shiftLcurly(p); 427 } 428 } 429 430 //-- GRAMMAR_BEGIN -- 431 //ExpressionStatement: 432 // Expression ; 433 class ExpressionStatement : Statement 434 { 435 mixin SequenceNode!(ast.ExpressionStatement, Expression, TOK_semicolon); 436 } 437 438 //-- GRAMMAR_BEGIN -- 439 //DeclarationStatement: 440 // Declaration 441 // 442 //IfStatement: 443 // if ( IfCondition ) ThenStatement 444 // if ( IfCondition ) ThenStatement else ElseStatement 445 // 446 //ThenStatement: 447 // ScopeNonEmptyStatement 448 // 449 //ElseStatement: 450 // ScopeNonEmptyStatement 451 class IfStatement : Statement 452 { 453 // if ( IfCondition ) $ ThenStatement else ElseStatement 454 mixin stateAppendClass!(ScopeNonEmptyStatement, shiftElse) stateThenStatement; 455 456 // if ( IfCondition $ ) ThenStatement else ElseStatement 457 mixin stateShiftToken!(TOK_rparen, stateThenStatement.shift) stateRparen; 458 459 // if ( $ IfCondition ) ThenStatement else ElseStatement 460 mixin stateAppendClass!(IfCondition, stateRparen.shift) stateCondition; 461 462 // if $ ( IfCondition ) ThenStatement else ElseStatement 463 mixin stateShiftToken!(TOK_lparen, stateCondition.shift) stateLparen; 464 465 // $ if ( IfCondition ) ThenStatement else ElseStatement 466 mixin stateEnterToken!(TOK_if, ast.IfStatement, stateLparen.shift); 467 468 // if ( IfCondition ) ThenStatement $ else ElseStatement 469 static Action shiftElse(Parser p) 470 { 471 switch(p.tok.id) 472 { 473 case TOK_else: 474 p.pushState(&shiftElseStatement); 475 p.pushState(&ScopeNonEmptyStatement.enter); 476 return Accept; 477 default: 478 return Forward; 479 } 480 } 481 482 // if ( IfCondition ) ThenStatement else ElseStatement $ 483 static Action shiftElseStatement(Parser p) 484 { 485 p.popAppendTopNode!(ast.IfStatement, ast.Statement)(); 486 return Forward; 487 } 488 } 489 490 //-- GRAMMAR_BEGIN -- 491 //IfCondition: 492 // Expression 493 // auto Identifier = Expression 494 // BasicType BasicTypes2_opt Declarator = Expression 495 // 496 class IfCondition 497 { 498 static Action enter(Parser p) 499 { 500 p.pushRollback(&rollbackTypeFailure); 501 p.pushState(&shiftDecl); 502 return Decl!false.enter(p); 503 } 504 505 static Action shiftDecl(Parser p) 506 { 507 if(p.tok.id != TOK_rparen) 508 return p.parseError("')' expected after declaration"); 509 510 p.popRollback(); 511 return Forward; 512 } 513 514 static Action rollbackTypeFailure(Parser p) 515 { 516 return Expression.enter(p); 517 } 518 } 519 520 //-- GRAMMAR_BEGIN -- 521 //WhileStatement: 522 // while ( Expression ) ScopeNonEmptyStatement 523 class WhileStatement : Statement 524 { 525 mixin SequenceNode!(ast.WhileStatement, TOK_while, TOK_lparen, Expression, TOK_rparen, ScopeNonEmptyStatement); 526 } 527 528 //-- GRAMMAR_BEGIN -- 529 //DoStatement: 530 // do ScopeNonEmptyStatement while ( Expression ) 531 // trailing ';' currently not part of grammar ;-( 532 class DoStatement : Statement 533 { 534 mixin SequenceNode!(ast.DoStatement, TOK_do, ScopeNonEmptyStatement, TOK_while, TOK_lparen, Expression, TOK_rparen); //, TOK_semicolon); 535 } 536 537 //-- GRAMMAR_BEGIN -- 538 //ForStatement: 539 // for ( Initialize Test ; Increment ) ScopeNonEmptyStatement 540 //Initialize: 541 // ; 542 // NoScopeNonEmptyStatement 543 // 544 //Test: 545 // Expression_opt 546 // 547 //Increment: 548 // Expression_opt 549 // 550 class ForStatement : Statement 551 { 552 mixin SequenceNode!(ast.ForStatement, TOK_for, TOK_lparen, Initialize, Expression_opt, TOK_semicolon, Expression_opt, TOK_rparen, ScopeNonEmptyStatement); 553 } 554 555 class Initialize 556 { 557 static Action enter(Parser p) 558 { 559 switch(p.tok.id) 560 { 561 case TOK_semicolon: 562 p.pushNode(new ast.EmptyStatement(p.tok)); 563 return Accept; 564 default: 565 return NoScopeNonEmptyStatement.enter(p); 566 } 567 } 568 } 569 570 class Expression_opt 571 { 572 // cerates "void" if no expression 573 static Action enter(Parser p) 574 { 575 switch(p.tok.id) 576 { 577 case TOK_semicolon: 578 case TOK_rcurly: 579 case TOK_rbracket: 580 case TOK_rparen: 581 p.pushNode(new ast.EmptyExpression(p.tok)); 582 return Forward; 583 default: 584 return Expression.enter(p); 585 } 586 } 587 } 588 589 //-- GRAMMAR_BEGIN -- 590 //ForeachStatement: 591 // Foreach ( ForeachTypeList ; Aggregate ) NoScopeNonEmptyStatement 592 // 593 //Foreach: 594 // foreach 595 // foreach_reverse 596 // 597 //Aggregate: 598 // Expression 599 // Type 600 // 601 //ForeachRangeStatement: 602 // Foreach ( ForeachType ; LwrExpression .. UprExpression ) ScopeNonEmptyStatement 603 // 604 //LwrExpression: 605 // Expression 606 // 607 //UprExpression: 608 // Expression 609 class ForeachStatement : Statement 610 { 611 static Action enter(Parser p) 612 { 613 switch(p.tok.id) 614 { 615 case TOK_foreach: 616 case TOK_foreach_reverse: 617 p.pushNode(new ast.ForeachStatement(p.tok)); 618 p.pushState(&stateLparen.shift); 619 return Accept; 620 default: 621 return p.parseError("foreach or foreach_reverse expected"); 622 } 623 } 624 625 // Foreach ( ForeachTypeList ; Aggregate ) $ NoScopeNonEmptyStatement 626 mixin stateAppendClass!(NoScopeNonEmptyStatement, Parser.forward) stateStatement; 627 628 // Foreach ( ForeachTypeList ; LwrExpression .. UprExpression $ ) NoScopeNonEmptyStatement 629 mixin stateShiftToken!(TOK_rparen, stateStatement.shift) stateRparen; 630 631 // Foreach ( ForeachType ; LwrExpression .. $ UprExpression ) ScopeNonEmptyStatement 632 mixin stateAppendClass!(Expression, stateRparen.shift) stateUprExpression; 633 634 // Foreach ( ForeachTypeList ; Aggregate $ ) NoScopeNonEmptyStatement 635 // Foreach ( ForeachType ; LwrExpression $ .. UprExpression ) ScopeNonEmptyStatement 636 static Action shiftExpression(Parser p) 637 { 638 switch(p.tok.id) 639 { 640 case TOK_slice: 641 p.popAppendTopNode!(); 642 p.popRollback(); 643 p.pushState(&stateUprExpression.shift); 644 return Accept; 645 case TOK_rparen: 646 p.popAppendTopNode!(); 647 p.popRollback(); 648 p.pushState(&stateStatement.shift); 649 return Accept; 650 default: 651 return p.parseError("closing parenthesis expected"); 652 } 653 } 654 655 static Action shiftType(Parser p) 656 { 657 // static foreach with type tuple 658 switch(p.tok.id) 659 { 660 case TOK_rparen: 661 p.popAppendTopNode!(); 662 p.pushState(&stateStatement.shift); 663 return Accept; 664 default: 665 return p.parseError("closing parenthesis expected"); 666 } 667 } 668 669 // Foreach ( ForeachTypeList ; $ Aggregate ) NoScopeNonEmptyStatement 670 static Action stateExpression(Parser p) 671 { 672 p.pushRollback(&rollbackExpression); 673 p.pushState(&shiftExpression); 674 return Expression.enter(p); 675 } 676 static Action rollbackExpression(Parser p) 677 { 678 p.pushState(&shiftType); 679 return Type.enter(p); 680 } 681 682 // Foreach ( ForeachTypeList $ ; Aggregate ) NoScopeNonEmptyStatement 683 mixin stateShiftToken!(TOK_semicolon, stateExpression) stateSemicolon; 684 685 // Foreach ( $ ForeachTypeList ; Aggregate ) NoScopeNonEmptyStatement 686 mixin stateAppendClass!(ForeachTypeList, stateSemicolon.shift) stateForeachTypeList; 687 688 // Foreach $ ( ForeachTypeList ; Aggregate ) NoScopeNonEmptyStatement 689 mixin stateShiftToken!(TOK_lparen, stateForeachTypeList.shift) stateLparen; 690 } 691 692 //-- GRAMMAR_BEGIN -- 693 //ForeachTypeList: 694 // ForeachType 695 // ForeachType , ForeachTypeList 696 class ForeachTypeList 697 { 698 mixin ListNode!(ast.ForeachTypeList, ForeachType, TOK_comma); 699 } 700 701 //-- GRAMMAR_BEGIN -- 702 //ForeachType: 703 // ref_opt Type_opt Identifier 704 // 705 class ForeachType 706 { 707 static Action enter(Parser p) 708 { 709 auto n = new ast.ForeachType(p.tok); 710 p.pushNode(n); 711 return shiftRef(p); 712 } 713 714 static Action shiftRef(Parser p) 715 { 716 switch(p.tok.id) 717 { 718 case TOK_ref: 719 auto n = p.topNode!(ast.ForeachType)(); 720 n.isRef = true; 721 p.pushState(&shiftRef); 722 return Accept; 723 724 case TOK_Identifier: 725 p.pushToken(p.tok); 726 p.pushState(&shiftIdentifier); 727 return Accept; 728 729 case TOK_const: 730 case TOK_immutable: 731 case TOK_shared: 732 case TOK_inout: 733 p.pushToken(p.tok); 734 p.pushState(&shiftTypeModifier); 735 return Accept; 736 737 default: 738 p.pushState(&shiftType); 739 return Type.enter(p); 740 } 741 } 742 743 static Action shiftTypeModifier(Parser p) 744 { 745 switch(p.tok.id) 746 { 747 case TOK_lparen: 748 p.pushState(&shiftType); 749 return Type.enterTypeModifier(p); 750 751 default: 752 auto tok = p.popToken(); 753 auto n = p.topNode!(ast.ForeachType)(); 754 combineAttributes(n.attr, tokenToAttribute(tok.id)); 755 return shiftRef(p); 756 } 757 } 758 759 static Action shiftIdentifier(Parser p) 760 { 761 switch(p.tok.id) 762 { 763 case TOK_semicolon: 764 case TOK_comma: 765 auto tok = p.popToken(); 766 auto n = p.topNode!(ast.ForeachType)(); 767 // add auto type here? 768 n.addMember(new ast.Identifier(tok)); 769 return Forward; 770 default: 771 p.pushState(&shiftType); 772 return Type.enterIdentifier(p); 773 } 774 } 775 776 static Action shiftType(Parser p) 777 { 778 p.popAppendTopNode!(ast.ForeachType, ast.Type)(); 779 780 switch(p.tok.id) 781 { 782 case TOK_Identifier: 783 p.topNode!(ast.ForeachType).addMember(new ast.Identifier(p.tok)); 784 return Accept; 785 default: 786 return p.parseError("identifier expected"); 787 } 788 } 789 } 790 791 //-- GRAMMAR_BEGIN -- 792 //SwitchStatement: 793 // switch ( Expression ) ScopeNonEmptyStatement 794 class SwitchStatement : Statement 795 { 796 mixin SequenceNode!(ast.SwitchStatement, TOK_switch, TOK_lparen, Expression, TOK_rparen, ScopeNonEmptyStatement); 797 } 798 799 //-- GRAMMAR_BEGIN -- 800 //FinalSwitchStatement: 801 // final switch ( Expression ) ScopeNonEmptyStatement 802 // 803 class FinalSwitchStatement : Statement 804 { 805 static Action enter(Parser p) 806 { 807 if(p.tok.id != TOK_final) 808 return p.parseError("final expected"); 809 p.pushState(&shiftFinal); 810 return Accept; 811 } 812 813 static Action shiftFinal(Parser p) 814 { 815 if(p.tok.id != TOK_switch) 816 return p.parseError("switch expected"); 817 p.pushState(&shiftSwitch); 818 return SwitchStatement.enter(p); 819 } 820 821 static Action shiftSwitch(Parser p) 822 { 823 p.topNode!(ast.SwitchStatement)().isFinal = true; 824 return Forward; 825 } 826 } 827 828 //-- GRAMMAR_BEGIN -- 829 //CaseStatement: 830 // case ArgumentList : Statement_opt 831 // 832 //CaseRangeStatement: 833 // case FirstExp : .. case LastExp : Statement_opt 834 // 835 //FirstExp: 836 // AssignExpression 837 // 838 //LastExp: 839 // AssignExpression 840 class CaseStatement : Statement 841 { 842 // also used by DefaultStatement 843 static Action stateStatement(Parser p) 844 { 845 return Forward; 846 /+ 847 switch(p.tok.id) 848 { 849 case TOK_case: 850 case TOK_default: 851 case TOK_rcurly: 852 return Forward; 853 default: 854 p.pushState(&Parser.popForward); 855 return Statement.enter(p); 856 } 857 +/ 858 } 859 860 // argument list 861 mixin stateShiftToken!(TOK_comma, stateArgumentList_shift, 862 TOK_colon, stateStatement) stateAfterArg; 863 864 // mixin expanded due to unresolvable forward references 865 // mixin stateAppendClass!(AssignExpression, stateAfterArg.shift) stateArgumentList; 866 static Action stateArgumentList_shift(Parser p) 867 { 868 p.pushState(&stateArgumentList_reduce); 869 return AssignExpression.enter(p); 870 } 871 static Action stateArgumentList_reduce(Parser p) 872 { 873 p.popAppendTopNode!(); 874 return stateAfterArg.shift(p); 875 } 876 877 // range 878 mixin stateShiftToken!(TOK_colon, stateStatement) stateAfterLast; 879 880 mixin stateAppendClass!(AssignExpression, stateAfterLast.shift) stateCaseLast; 881 882 mixin stateShiftToken!(TOK_case, stateCaseLast.shift) stateRange; 883 884 static Action stateRememberRange(Parser p) 885 { 886 p.topNode!(ast.CaseStatement).id = TOK_slice; 887 return stateRange.shift(p); 888 } 889 890 // disambiguation 891 mixin stateShiftToken!(TOK_slice, stateRememberRange, 892 -1, stateStatement) stateFirstArgument; 893 894 mixin stateShiftToken!(TOK_comma, stateArgumentList_shift, 895 TOK_colon, stateFirstArgument.shift) stateAfterFirstArg; 896 897 mixin stateAppendClass!(AssignExpression, stateAfterFirstArg.shift) stateArgument; 898 899 // $ case ArgumentList : Statement 900 // $ case AssignExpression : Statement 901 // $ case FirstExp : .. case LastExp : Statement 902 mixin stateEnterToken!(TOK_case, ast.CaseStatement, stateArgument.shift); 903 904 } 905 906 //-- GRAMMAR_BEGIN -- 907 //DefaultStatement: 908 // default : Statement_opt 909 class DefaultStatement : Statement 910 { 911 mixin SequenceNode!(ast.DefaultStatement, TOK_default, TOK_colon, CaseStatement.stateStatement); 912 } 913 914 //-- GRAMMAR_BEGIN -- 915 //ContinueStatement: 916 // continue ; 917 // continue Identifier ; 918 class ContinueStatement : Statement 919 { 920 mixin SequenceNode!(ast.ContinueStatement, TOK_continue, Identifier_opt!(ast.ContinueStatement), TOK_semicolon); 921 } 922 923 class Identifier_opt(T) : Statement 924 { 925 enum doNotPopNode = true; 926 927 static Action enter(Parser p) 928 { 929 if(p.tok.id == TOK_Identifier) 930 { 931 p.topNode!T().ident = p.tok.txt; 932 return Accept; 933 } 934 return Forward; 935 } 936 } 937 938 //-- GRAMMAR_BEGIN -- 939 //BreakStatement: 940 // break ; 941 // break Identifier ; 942 class BreakStatement : Statement 943 { 944 mixin SequenceNode!(ast.BreakStatement, TOK_break, Identifier_opt!(ast.BreakStatement), TOK_semicolon); 945 } 946 947 948 //-- GRAMMAR_BEGIN -- 949 //ReturnStatement: 950 // return ; 951 // return Expression ; 952 class ReturnStatement : Statement 953 { 954 mixin SequenceNode!(ast.ReturnStatement, TOK_return, Expression_opt, TOK_semicolon); 955 } 956 957 958 //-- GRAMMAR_BEGIN -- 959 //GotoStatement: 960 // goto Identifier ; 961 // goto default ; 962 // goto case ; 963 // goto case Expression ; 964 class GotoStatement : Statement 965 { 966 mixin stateShiftToken!(TOK_semicolon, Parser.forward) stateSemicolon; 967 968 mixin stateAppendClass!(Expression, stateSemicolon.shift) stateExpression; 969 970 mixin stateShiftToken!(TOK_semicolon, Parser.forward, 971 -1, stateExpression.shift) stateCase; 972 973 static Action rememberArgument(Parser p) 974 { 975 switch(p.tok.id) 976 { 977 case TOK_Identifier: 978 p.topNode!(ast.GotoStatement).ident = p.tok.txt; 979 p.topNode!(ast.GotoStatement).id = TOK_Identifier; 980 p.pushState(&stateSemicolon.shift); 981 return Accept; 982 case TOK_default: 983 p.topNode!(ast.GotoStatement).id = TOK_default; 984 p.pushState(&stateSemicolon.shift); 985 return Accept; 986 case TOK_case: 987 p.topNode!(ast.GotoStatement).id = TOK_case; 988 p.pushState(&stateCase.shift); 989 return Accept; 990 default: 991 return p.parseError("identifier, case or default expected in goto statement"); 992 } 993 } 994 995 mixin stateEnterToken!(TOK_goto, ast.GotoStatement, rememberArgument); 996 } 997 998 //-- GRAMMAR_BEGIN -- 999 //WithStatement: 1000 // with ( Expression ) ScopeNonEmptyStatement 1001 // with ( Symbol ) ScopeNonEmptyStatement 1002 // with ( TemplateInstance ) ScopeNonEmptyStatement 1003 class WithStatement : Statement 1004 { 1005 // Symbol, TemplateInstance also syntactically included by Expression 1006 mixin SequenceNode!(ast.WithStatement, TOK_with, TOK_lparen, Expression, TOK_rparen, ScopeNonEmptyStatement); 1007 } 1008 1009 //-- GRAMMAR_BEGIN -- 1010 //SynchronizedStatement: 1011 // synchronized ScopeNonEmptyStatement 1012 // synchronized ( Expression ) ScopeNonEmptyStatement 1013 class SynchronizedStatement : Statement 1014 { 1015 mixin stateAppendClass!(ScopeNonEmptyStatement, Parser.forward) stateStatement; 1016 1017 mixin stateShiftToken!(TOK_rparen, stateStatement.shift) stateRparen; 1018 1019 mixin stateAppendClass!(Expression, stateRparen.shift) stateExpression; 1020 1021 mixin stateShiftToken!(TOK_lparen, stateExpression.shift, 1022 -1, stateStatement.shift) stateLparen; 1023 1024 mixin stateEnterToken!(TOK_synchronized, ast.SynchronizedStatement, stateLparen.shift); 1025 } 1026 1027 //-- GRAMMAR_BEGIN -- 1028 //VolatileStatement: 1029 // volatile ScopeNonEmptyStatement 1030 class VolatileStatement : Statement 1031 { 1032 mixin SequenceNode!(ast.VolatileStatement, TOK_volatile, ScopeNonEmptyStatement); 1033 } 1034 1035 1036 //-- GRAMMAR_BEGIN -- 1037 //TryStatement: 1038 // try ScopeNonEmptyStatement Catches 1039 // try ScopeNonEmptyStatement Catches FinallyStatement 1040 // try ScopeNonEmptyStatement FinallyStatement 1041 // 1042 //Catches: 1043 // LastCatch 1044 // Catch 1045 // Catch Catches 1046 // 1047 //LastCatch: 1048 // catch NoScopeNonEmptyStatement 1049 // 1050 //FinallyStatement: 1051 // finally NoScopeNonEmptyStatement 1052 class TryStatement : Statement 1053 { 1054 mixin stateAppendClass!(FinallyStatement, Parser.forward) stateFinally; 1055 1056 static Action reduceLastCatch(Parser p) 1057 { 1058 p.popAppendTopNode!(ast.Catch, ast.Statement)(); 1059 p.popAppendTopNode!(ast.TryStatement, ast.Catch)(); 1060 switch(p.tok.id) 1061 { 1062 case TOK_finally: 1063 return stateFinally.shift(p); 1064 default: 1065 return Forward; 1066 } 1067 } 1068 1069 static Action reduceCatch(Parser p) 1070 { 1071 p.popAppendTopNode!(ast.TryStatement, ast.Catch)(); 1072 return stateCatches_shift(p); 1073 } 1074 1075 static Action shiftCatch(Parser p) 1076 { 1077 switch(p.tok.id) 1078 { 1079 case TOK_lparen: 1080 p.pushState(&reduceCatch); 1081 return Catch.enterAfterCatch(p); 1082 default: 1083 p.pushState(&reduceLastCatch); 1084 p.pushNode(new ast.Catch(p.tok)); 1085 return NoScopeNonEmptyStatement.enter(p); 1086 } 1087 } 1088 1089 static Action stateCatches_shift(Parser p) 1090 { 1091 switch(p.tok.id) 1092 { 1093 case TOK_catch: 1094 p.pushState(&shiftCatch); 1095 return Accept; 1096 case TOK_finally: 1097 return stateFinally.shift(p); 1098 default: 1099 if(p.topNode!(ast.TryStatement).members.length < 2) 1100 return p.parseError("catch or finally expected"); 1101 return Forward; 1102 } 1103 } 1104 1105 mixin stateAppendClass!(ScopeNonEmptyStatement, stateCatches_shift) stateTryStatement; 1106 1107 mixin stateEnterToken!(TOK_try, ast.TryStatement, stateTryStatement.shift); 1108 } 1109 1110 //-- GRAMMAR_BEGIN -- 1111 //Catch: 1112 // catch ( CatchParameter ) NoScopeNonEmptyStatement 1113 // 1114 //CatchParameter: 1115 // BasicType Identifier 1116 class Catch 1117 { 1118 mixin SequenceNode!(ast.Catch, TOK_catch, TOK_lparen, BasicType, Opt!(Identifier, TOK_Identifier), TOK_rparen, NoScopeNonEmptyStatement); 1119 1120 static Action enterAfterCatch(Parser p) 1121 { 1122 p.pushNode(new ast.Catch(p.tok)); 1123 return shift1.shift(p); 1124 } 1125 } 1126 1127 class FinallyStatement 1128 { 1129 mixin SequenceNode!(ast.FinallyStatement, TOK_finally, NoScopeNonEmptyStatement); 1130 } 1131 1132 //-- GRAMMAR_BEGIN -- 1133 //ThrowStatement: 1134 // throw Expression ; 1135 class ThrowStatement : Statement 1136 { 1137 mixin SequenceNode!(ast.ThrowStatement, TOK_throw, Expression, TOK_semicolon); 1138 } 1139 1140 //-- GRAMMAR_BEGIN -- 1141 //ScopeGuardStatement: 1142 // scope ( "exit" ) ScopeNonEmptyStatement 1143 // scope ( "success" ) ScopeNonEmptyStatement 1144 // scope ( "failure" ) ScopeNonEmptyStatement 1145 class ScopeGuardStatement : Statement 1146 { 1147 mixin SequenceNode!(ast.ScopeGuardStatement, TOK_scope, TOK_lparen, ScopeGuardIdentifier, TOK_rparen, ScopeNonEmptyStatement); 1148 1149 static Action enterAfterScope(Parser p) 1150 { 1151 p.pushNode(new ast.ScopeGuardStatement(p.tok)); 1152 return shift1.shift(p); 1153 } 1154 } 1155 1156 class ScopeGuardIdentifier 1157 { 1158 static Action enter(Parser p) 1159 { 1160 if(p.tok.id != TOK_Identifier) 1161 return p.parseError("identifier expected"); 1162 if(!isIn(p.tok.txt, "exit", "success", "failure")) 1163 return p.parseError("one of exit, success and failure expected in scope guard statement"); 1164 1165 p.pushNode(new ast.Identifier(p.tok)); 1166 return Accept; 1167 } 1168 } 1169 1170 //-- GRAMMAR_BEGIN -- 1171 //AsmStatement: 1172 // asm { } 1173 // asm { AsmInstructionList } 1174 // 1175 //AsmInstructionList: 1176 // AsmInstruction ; 1177 // AsmInstruction ; AsmInstructionList 1178 class AsmStatement : Statement 1179 { 1180 mixin SequenceNode!(ast.AsmStatement, TOK_asm, TOK_lcurly, AsmInstructionList, TOK_rcurly); 1181 } 1182 1183 class AsmInstructionList 1184 { 1185 mixin ListNode!(ast.AsmInstructionList, AsmInstruction, TOK_semicolon, true); 1186 } 1187 1188 //-- GRAMMAR_BEGIN -- 1189 //PragmaStatement: 1190 // Pragma NoScopeStatement 1191 class PragmaStatement : Statement 1192 { 1193 mixin SequenceNode!(ast.PragmaStatement, Pragma, NoScopeStatement); 1194 } 1195 1196 //-- GRAMMAR_BEGIN -- 1197 //MixinStatement: 1198 // mixin ( AssignExpression ) ; 1199 class MixinStatement : Statement 1200 { 1201 mixin SequenceNode!(ast.MixinStatement, TOK_mixin, TOK_lparen, AssignExpression, TOK_rparen); 1202 1203 static Action enterAfterMixin(Parser p) 1204 { 1205 p.pushNode(new ast.MixinStatement(p.tok)); 1206 return shift1.shift(p); 1207 } 1208 }