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.misc; 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.stmt; 17 import vdc.parser.mod; 18 19 import ast = vdc.ast.all; 20 21 import stdext.util; 22 23 //-- GRAMMAR_BEGIN -- 24 //EnumDeclaration: 25 // enum EnumTag EnumBody 26 // enum EnumBody 27 // enum EnumTag : EnumBaseType EnumBody 28 // enum : EnumBaseType EnumBody 29 // enum EnumTag ; 30 // enum EnumInitializers ; 31 // enum Type EnumInitializers ; 32 // 33 //EnumTag: 34 // Identifier 35 // 36 //EnumBaseType: 37 // Type 38 // 39 //EnumInitializers: 40 // EnumInitializer 41 // EnumInitializers , EnumInitializer 42 // 43 //EnumInitializer: 44 // Identifier = AssignExpression 45 class EnumDeclaration 46 { 47 static Action enter(Parser p) 48 { 49 if(p.tok.id != TOK_enum) 50 return p.parseError("enum expected"); 51 52 p.pushNode(new ast.EnumDeclaration(p.tok)); 53 p.pushState(&shiftEnum); 54 return Accept; 55 } 56 57 static Action shiftEnum(Parser p) 58 { 59 switch(p.tok.id) 60 { 61 case TOK_lcurly: 62 p.pushState(&shiftEnumBody); 63 return EnumBody.enter(p); 64 case TOK_colon: 65 p.pushState(&shiftColon); 66 return Accept; 67 case TOK_Identifier: 68 p.pushToken(p.tok); 69 p.pushState(&shiftIdentifier); 70 return Accept; 71 default: 72 p.pushState(&shiftType); 73 return Type.enter(p); 74 } 75 } 76 77 static Action shiftColon(Parser p) 78 { 79 p.pushState(&shiftBaseType); 80 return Type.enter(p); 81 } 82 83 static Action shiftType(Parser p) 84 { 85 p.popAppendTopNode!(ast.EnumDeclaration)(); 86 switch(p.tok.id) 87 { 88 case TOK_Identifier: 89 p.topNode!(ast.EnumDeclaration)().ident = p.tok.txt; 90 p.pushState(&shiftAssignAfterType); 91 return Accept; 92 default: 93 return p.parseError("identifier expected after enum type"); 94 } 95 } 96 97 // assumes token on stack 98 static Action shiftIdentifier(Parser p) 99 { 100 switch(p.tok.id) 101 { 102 case TOK_colon: 103 p.topNode!(ast.EnumDeclaration)().ident = p.popToken().txt; 104 p.pushState(&shiftColon); 105 return Accept; 106 case TOK_semicolon: 107 p.topNode!(ast.EnumDeclaration)().ident = p.popToken().txt; 108 return Accept; 109 case TOK_assign: 110 p.topNode!(ast.EnumDeclaration)().ident = p.popToken().txt; 111 p.pushState(&shiftAssign); 112 return Accept; 113 case TOK_lcurly: 114 p.topNode!(ast.EnumDeclaration)().ident = p.popToken().txt; 115 p.pushState(&shiftEnumBody); 116 return EnumBody.enter(p); 117 default: 118 p.pushState(&shiftType); 119 return Type.enterIdentifier(p); 120 } 121 } 122 123 static Action shiftBaseType(Parser p) 124 { 125 p.popAppendTopNode!(ast.EnumDeclaration)(); 126 p.pushState(&shiftEnumBody); 127 return EnumBody.enter(p); 128 } 129 130 static Action shiftEnumBody(Parser p) 131 { 132 p.popAppendTopNode!(ast.EnumDeclaration)(); 133 return Forward; 134 } 135 136 static Action shiftAssignAfterType(Parser p) 137 { 138 switch(p.tok.id) 139 { 140 case TOK_assign: 141 p.pushState(&shiftAssign); 142 return Accept; 143 default: 144 return p.parseError("'=' expected to initialize enum"); 145 } 146 } 147 148 static Action shiftAssign(Parser p) 149 { 150 p.pushState(&shiftExpression); 151 return AssignExpression.enter(p); 152 } 153 154 static Action shiftExpression(Parser p) 155 { 156 auto expr = p.popNode(); 157 auto ed = p.topNode!(ast.EnumDeclaration)(); 158 159 // rebuild as anonymous enum with single member 160 auto b = new ast.EnumBody(TOK_lcurly, ed.span); 161 auto m = new ast.EnumMembers(TOK_Identifier, ed.span); 162 auto e = new ast.EnumMember(TOK_Identifier, ed.span); 163 e.addMember(expr); 164 e.ident = ed.ident; 165 m.addMember(e); 166 b.addMember(m); 167 168 ed.ident = null; 169 ed.isDecl = true; 170 ed.addMember(b); 171 172 switch(p.tok.id) 173 { 174 case TOK_semicolon: 175 return Accept; 176 case TOK_comma: 177 p.pushState(&shiftNextIdentifier); 178 return Accept; 179 default: 180 return p.parseError("';' expected after single line enum"); 181 } 182 } 183 184 static Action shiftNextIdentifier(Parser p) 185 { 186 switch(p.tok.id) 187 { 188 case TOK_Identifier: 189 auto e = new ast.EnumMember(p.tok); 190 e.ident = p.tok.txt; 191 p.pushNode(e); 192 p.pushState(&shiftAssignAfterNextIdentifier); 193 return Accept; 194 default: 195 return p.parseError("identifier expected after enum type"); 196 } 197 } 198 199 static Action shiftAssignAfterNextIdentifier(Parser p) 200 { 201 switch(p.tok.id) 202 { 203 case TOK_assign: 204 p.pushState(&shiftNextAssign); 205 return Accept; 206 default: 207 return p.parseError("'=' expected to initialize enum"); 208 } 209 } 210 211 static Action shiftNextAssign(Parser p) 212 { 213 p.pushState(&shiftNextExpression); 214 return AssignExpression.enter(p); 215 } 216 217 static Action shiftNextExpression(Parser p) 218 { 219 p.popAppendTopNode!(ast.EnumMember)(); 220 auto m = p.popNode!(ast.EnumMember)(); 221 auto ed = p.topNode!(ast.EnumDeclaration)(); 222 auto eb = ed.getBody(); 223 auto em = static_cast!(ast.EnumMembers)(eb.getMember(0)); 224 em.addMember(m); 225 226 switch(p.tok.id) 227 { 228 case TOK_semicolon: 229 return Accept; 230 case TOK_comma: 231 p.pushState(&shiftNextIdentifier); 232 return Accept; 233 default: 234 return p.parseError("';' expected after single line enum"); 235 } 236 } 237 } 238 239 //-- GRAMMAR_BEGIN -- 240 // forward declaration not needed with proper handling 241 //EnumBody: 242 // ; 243 // { EnumMembers } 244 class EnumBody 245 { 246 mixin SequenceNode!(ast.EnumBody, TOK_lcurly, EnumMembersRecover, TOK_rcurly); 247 } 248 class EnumMembersRecover 249 { 250 static Action enter(Parser p) 251 { 252 p.pushNode(new ast.EnumMembers(p.tok)); 253 254 // recover code inserted into EnumMembers.enter 255 p.pushRecoverState(&recover); 256 p.pushState(&Parser.keepRecover); // add a "guard" state to avoid popping recover 257 p.pushState(&verifyCurly); 258 259 p.pushState(&EnumMembers.shift); 260 return EnumMember.enter(p); 261 } 262 263 static Action verifyCurly(Parser p) 264 { 265 if(p.tok.id != TOK_rcurly) 266 return p.parseError("'}' expected after enum"); 267 return Forward; 268 } 269 270 static Action recover(Parser p) 271 { 272 return Parser.recoverSemiCurly(p); 273 } 274 } 275 276 //-- GRAMMAR_BEGIN -- 277 //EnumMembers: 278 // EnumMember 279 // EnumMember , 280 // EnumMember , EnumMembers 281 class EnumMembers 282 { 283 mixin ListNode!(ast.EnumMembers, EnumMember, TOK_comma, true); 284 } 285 286 //-- GRAMMAR_BEGIN -- 287 //EnumMember: 288 // Identifier 289 // Identifier = AssignExpression 290 // Type Identifier = AssignExpression 291 class EnumMember 292 { 293 static Action enter(Parser p) 294 { 295 p.pushNode(new ast.EnumMember(p.tok)); 296 297 if(p.tok.id != TOK_Identifier) 298 { 299 p.pushState(&shiftType); 300 return Type.enter(p); 301 } 302 p.pushState(&shiftIdentifierOrType); 303 p.pushToken(p.tok); 304 return Accept; 305 } 306 307 static Action shiftIdentifierOrType(Parser p) 308 { 309 if(p.tok.id != TOK_assign && p.tok.id != TOK_comma && p.tok.id != TOK_rcurly) 310 { 311 p.pushState(&shiftType); 312 return Type.enterIdentifier(p); 313 } 314 Token tok = p.popToken(); 315 ast.EnumMember em = p.topNode!(ast.EnumMember)(); 316 em.ident = tok.txt; 317 return shiftIdentifier(p); 318 } 319 320 static Action shiftAssign(Parser p) 321 { 322 p.pushState(&shiftExpression); 323 return AssignExpression.enter(p); 324 } 325 326 static Action shiftExpression(Parser p) 327 { 328 p.popAppendTopNode!(ast.EnumMember, ast.Expression)(); 329 return Forward; 330 } 331 332 static Action shiftType(Parser p) 333 { 334 if(p.tok.id != TOK_Identifier) 335 return p.parseError("identifier expected after type in enum"); 336 337 p.popAppendTopNode!(ast.EnumMember, ast.Type)(); 338 auto em = p.topNode!(ast.EnumMember)(); 339 em.ident = p.tok.txt; 340 341 p.pushState(&shiftIdentifier); 342 return Accept; 343 } 344 345 static Action shiftIdentifier(Parser p) 346 { 347 if(p.tok.id != TOK_assign) 348 return Forward; 349 350 p.pushState(&shiftAssign); 351 return Accept; 352 } 353 } 354 355 //////////////////////////////////////////////////////////////// 356 //-- GRAMMAR_BEGIN -- 357 //FunctionBody: 358 // BlockStatement 359 // BodyStatement 360 // InStatement BodyStatement 361 // OutStatement BodyStatement 362 // InStatement OutStatement BodyStatement 363 // OutStatement InStatement BodyStatement 364 // 365 //InStatement: 366 // in BlockStatement 367 // 368 //OutStatement: 369 // out BlockStatement 370 // out ( Identifier ) BlockStatement 371 // 372 //BodyStatement: 373 // body BlockStatement 374 // 375 // body statement might be missing in interface contracts 376 // 377 class FunctionBody 378 { 379 static bool isInitTerminal(Token tok) 380 { 381 switch(tok.id) 382 { 383 case TOK_lcurly: 384 case TOK_body: 385 case TOK_in: 386 case TOK_out: 387 return true; 388 default: 389 return false; 390 } 391 } 392 393 static Action enter(Parser p) 394 { 395 ast.FunctionBody fb = new ast.FunctionBody(p.tok); 396 p.pushNode(fb); 397 398 if(p.tok.id == TOK_lcurly) 399 { 400 p.pushState(&shiftBodyStatement); 401 return BlockStatement.enter(p); 402 } 403 return shiftStatement(p); 404 } 405 406 static Action shiftBodyStatement(Parser p) 407 { 408 auto bodyStmt = p.topNode!(ast.BlockStatement)(); 409 p.popAppendTopNode(); 410 p.topNode!(ast.FunctionBody)().bodyStatement = bodyStmt; 411 return Forward; 412 } 413 414 static Action shiftInStatement(Parser p) 415 { 416 auto inStmt = p.topNode!(ast.BlockStatement)(); 417 p.popAppendTopNode(); 418 p.topNode!(ast.FunctionBody)().inStatement = inStmt; 419 return shiftStatement(p); 420 } 421 422 static Action shiftOutStatement(Parser p) 423 { 424 auto outStmt = p.topNode!(ast.BlockStatement)(); 425 p.popAppendTopNode(); 426 p.topNode!(ast.FunctionBody)().outStatement = outStmt; 427 return shiftStatement(p); 428 } 429 430 static Action shiftStatement(Parser p) 431 { 432 switch(p.tok.id) 433 { 434 case TOK_body: 435 p.pushState(&shiftBodyStatement); 436 p.pushState(&BlockStatement.enter); 437 return Accept; 438 case TOK_in: 439 if(p.topNode!(ast.FunctionBody)().inStatement) 440 return p.parseError("duplicate in block"); 441 p.pushState(&shiftInStatement); 442 p.pushState(&BlockStatement.enter); 443 return Accept; 444 case TOK_out: 445 if(p.topNode!(ast.FunctionBody)().outStatement) 446 return p.parseError("duplicate out block"); 447 p.pushState(&shiftOut); 448 return Accept; 449 default: 450 return Forward; // p.parseError("expected body or in or out block"); 451 } 452 } 453 454 static Action shiftOut(Parser p) 455 { 456 if(p.tok.id == TOK_lparen) 457 { 458 p.pushState(&shiftLparen); 459 return Accept; 460 } 461 p.pushState(&shiftOutStatement); 462 return BlockStatement.enter(p); 463 } 464 465 static Action shiftLparen(Parser p) 466 { 467 if(p.tok.id != TOK_Identifier) 468 return p.parseError("identifier expected for return value in out contract"); 469 470 auto outid = new ast.OutIdentifier(p.tok); 471 p.topNode!(ast.FunctionBody)().addMember(outid); 472 p.topNode!(ast.FunctionBody)().outIdentifier = outid; 473 p.pushState(&shiftOutIdentifier); 474 return Accept; 475 } 476 477 static Action shiftOutIdentifier(Parser p) 478 { 479 if(p.tok.id != TOK_rparen) 480 return p.parseError("closing parenthesis expected in out contract"); 481 p.pushState(&shiftOutStatement); 482 p.pushState(&BlockStatement.enter); 483 return Accept; 484 } 485 } 486 487 //////////////////////////////////////////////////////////////// 488 // disambiguate between VersionCondition and VersionSpecification 489 class VersionCondOrSpec 490 { 491 static Action enter(Parser p) 492 { 493 assert(p.tok.id == TOK_version); 494 p.pushState(&shiftVersion); 495 return Accept; 496 } 497 498 static Action shiftVersion(Parser p) 499 { 500 switch(p.tok.id) 501 { 502 case TOK_assign: 503 return VersionSpecification.enterAfterVersion(p); 504 case TOK_lparen: 505 return ConditionalDeclaration.enterAfterVersion(p); 506 default: 507 return p.parseError("'=' or '(' expected after version"); 508 } 509 } 510 } 511 512 //-- GRAMMAR_BEGIN -- 513 //ConditionalDeclaration: 514 // Condition DeclarationBlock 515 // Condition DeclarationBlock else DeclarationBlock 516 // Condition: DeclDefs_opt 517 class ConditionalDeclaration 518 { 519 // Condition DeclarationBlock else $ DeclarationBlock 520 mixin stateAppendClass!(DeclarationBlock, Parser.forward) stateElseDecl; 521 522 // Condition DeclarationBlock $ else DeclarationBlock 523 mixin stateShiftToken!(TOK_else, stateElseDecl.shift, 524 -1, Parser.forward) stateElse; 525 526 // Condition $ DeclarationBlock else DeclarationBlock 527 mixin stateAppendClass!(DeclarationBlock, stateElse.shift) stateThenDecl; 528 529 static Action shiftCondition(Parser p) 530 { 531 switch(p.tok.id) 532 { 533 case TOK_colon: 534 auto declblk = new ast.DeclarationBlock(p.tok); 535 p.topNode!(ast.ConditionalDeclaration).id = TOK_colon; 536 p.pushNode(declblk); 537 p.pushState(&enterDeclarationBlock); 538 return Accept; 539 default: 540 return stateThenDecl.shift(p); 541 } 542 } 543 static Action enterDeclarationBlock(Parser p) 544 { 545 switch(p.tok.id) 546 { 547 case TOK_rcurly: 548 case TOK_EOF: 549 return shiftDeclarationBlock(p); 550 default: 551 p.pushState(&shiftDeclarationBlock); 552 return DeclDefs.enter(p); 553 } 554 } 555 556 static Action shiftDeclarationBlock(Parser p) 557 { 558 p.popAppendTopNode!(ast.ConditionalDeclaration,ast.DeclarationBlock)(); 559 return Forward; 560 } 561 562 // $ Condition DeclarationBlock else DeclarationBlock 563 mixin stateEnterClass!(Condition, ast.ConditionalDeclaration, shiftCondition); 564 565 static Action enterAfterVersion(Parser p) 566 { 567 p.pushNode(new ast.ConditionalDeclaration(p.tok)); 568 p.pushState(&enterReduce); 569 return VersionCondition.enterAfterVersion(p); 570 } 571 static Action enterAfterDebug(Parser p) 572 { 573 p.pushNode(new ast.ConditionalDeclaration(p.tok)); 574 p.pushState(&enterReduce); 575 return DebugCondition.enterAfterDebug(p); 576 } 577 static Action enterAfterStatic(Parser p) 578 { 579 p.pushNode(new ast.ConditionalDeclaration(p.tok)); 580 p.pushState(&enterReduce); 581 return StaticIfCondition.enterAfterStatic(p); 582 } 583 } 584 585 //-- GRAMMAR_BEGIN -- 586 //ConditionalStatement: 587 // Condition NoScopeNonEmptyStatement 588 // Condition NoScopeNonEmptyStatement else NoScopeNonEmptyStatement 589 class ConditionalStatement 590 { 591 // Condition $ NoScopeNonEmptyStatement else NoScopeNonEmptyStatement 592 mixin stateAppendClass!(NoScopeNonEmptyStatement, Parser.forward) stateElseStmt; 593 594 mixin stateShiftToken!(TOK_else, stateElseStmt.shift, 595 -1, Parser.forward) stateElse; 596 597 // Condition $ NoScopeNonEmptyStatement else NoScopeNonEmptyStatement 598 mixin stateAppendClass!(NoScopeNonEmptyStatement, stateElse.shift) stateThenStmt; 599 600 // $ Condition NoScopeNonEmptyStatement else NoScopeNonEmptyStatement 601 mixin stateEnterClass!(Condition, ast.ConditionalStatement, stateThenStmt.shift); 602 603 static Action enterAfterStatic(Parser p) 604 { 605 p.pushNode(new ast.ConditionalStatement(p.tok)); 606 p.pushState(&enterReduce); 607 return StaticIfCondition.enterAfterStatic(p); 608 } 609 } 610 611 //-- GRAMMAR_BEGIN -- 612 //Condition: 613 // VersionCondition 614 // DebugCondition 615 // StaticIfCondition 616 class Condition 617 { 618 static Action enter(Parser p) 619 { 620 switch(p.tok.id) 621 { 622 case TOK_version: 623 return VersionCondition.enter(p); 624 case TOK_debug: 625 return DebugCondition.enter(p); 626 case TOK_static: 627 return StaticIfCondition.enter(p); 628 default: 629 return p.parseError("version, debug or static if expected"); 630 } 631 } 632 } 633 634 //-- GRAMMAR_BEGIN -- 635 //VersionCondition: 636 // version ( Integer ) 637 // version ( Identifier ) 638 // version ( unittest ) 639 // version ( assert ) 640 class VersionCondition 641 { 642 // version ( Integer $ ) 643 mixin stateShiftToken!(TOK_rparen, Parser.forward) stateRparen; 644 645 // version ( $ Integer ) 646 mixin stateAppendClass!(IdentifierOrInteger, stateRparen.shift) stateArgument2; 647 648 static Action shiftUnittest(Parser p) 649 { 650 p.topNode!(ast.VersionCondition).id = TOK_unittest; 651 return stateRparen.shift(p); 652 } 653 654 static Action shiftAssert(Parser p) 655 { 656 p.topNode!(ast.VersionCondition).id = TOK_assert; 657 return stateRparen.shift(p); 658 } 659 660 mixin stateShiftToken!(TOK_unittest, shiftUnittest, 661 TOK_assert, shiftAssert, 662 -1, stateArgument2.shift) stateArgument; 663 664 // version $ ( Integer ) 665 mixin stateShiftToken!(TOK_lparen, stateArgument.shift) stateLparen; 666 667 // $ version ( Integer ) 668 mixin stateEnterToken!(TOK_version, ast.VersionCondition, stateLparen.shift); 669 670 static Action enterAfterVersion(Parser p) 671 { 672 p.pushNode(new ast.VersionCondition(p.tok)); 673 return stateLparen.shift(p); 674 } 675 } 676 677 //-- GRAMMAR_BEGIN -- 678 //VersionSpecification: 679 // version = Identifier ; 680 // version = Integer ; 681 class VersionSpecification 682 { 683 mixin stateShiftToken!(TOK_semicolon, Parser.forward) stateSemi; 684 685 mixin stateAppendClass!(IdentifierOrInteger, stateSemi.shift) stateArgument; 686 687 mixin stateShiftToken!(TOK_assign, stateArgument.shift) stateAssign; 688 689 mixin stateEnterToken!(TOK_version, ast.VersionSpecification, stateAssign.shift); 690 691 static Action enterAfterVersion(Parser p) 692 { 693 p.pushNode(new ast.VersionSpecification(p.tok)); 694 return stateAssign.shift(p); 695 } 696 } 697 698 // disambiguate between DebugCondition and DebugSpecification 699 class DebugCondOrSpec 700 { 701 static Action enter(Parser p) 702 { 703 assert(p.tok.id == TOK_debug); 704 p.pushState(&shiftDebug); 705 return Accept; 706 } 707 708 static Action shiftDebug(Parser p) 709 { 710 switch(p.tok.id) 711 { 712 case TOK_assign: 713 return DebugSpecification.enterAfterDebug(p); 714 default: 715 return ConditionalDeclaration.enterAfterDebug(p); 716 } 717 } 718 } 719 720 //-- GRAMMAR_BEGIN -- 721 //DebugCondition: 722 // debug 723 // debug ( Integer ) 724 // debug ( Identifier ) 725 class DebugCondition 726 { 727 // debug ( Integer $ ) 728 mixin stateShiftToken!(TOK_rparen, Parser.forward) stateRparen; 729 730 // debug ( $ Integer ) 731 mixin stateAppendClass!(IdentifierOrInteger, stateRparen.shift) stateArgument; 732 733 // debug $ ( Integer ) 734 mixin stateShiftToken!(TOK_lparen, stateArgument.shift, 735 -1, Parser.forward) stateLparen; 736 737 // $ debug ( Integer ) 738 mixin stateEnterToken!(TOK_debug, ast.DebugCondition, stateLparen.shift); 739 740 static Action enterAfterDebug(Parser p) 741 { 742 p.pushNode(new ast.DebugCondition(p.tok)); 743 return stateLparen.shift(p); 744 } 745 } 746 747 //-- GRAMMAR_BEGIN -- 748 //DebugSpecification: 749 // debug = Identifier ; 750 // debug = Integer ; 751 class DebugSpecification 752 { 753 // debug = Integer $ ; 754 mixin stateShiftToken!(TOK_semicolon, Parser.forward) stateSemi; 755 756 // debug = $ Integer ; 757 mixin stateAppendClass!(IdentifierOrInteger, stateSemi.shift) stateArgument; 758 759 // debug $ = Integer ; 760 mixin stateShiftToken!(TOK_assign, stateArgument.shift) stateAssign; 761 762 // $ debug = Integer ; 763 mixin stateEnterToken!(TOK_debug, ast.DebugSpecification, stateAssign.shift); 764 765 static Action enterAfterDebug(Parser p) 766 { 767 p.pushNode(new ast.DebugSpecification(p.tok)); 768 return stateAssign.shift(p); 769 } 770 } 771 772 class IdentifierOrInteger 773 { 774 static Action enter(Parser p) 775 { 776 switch(p.tok.id) 777 { 778 case TOK_IntegerLiteral: 779 p.pushNode(new ast.IntegerLiteralExpression(p.tok)); 780 return Accept; 781 case TOK_Identifier: 782 p.pushNode(new ast.Identifier(p.tok)); 783 return Accept; 784 default: 785 return p.parseError("integer or identifier expected"); 786 } 787 } 788 } 789 790 //-- GRAMMAR_BEGIN -- 791 //StaticIfCondition: 792 // static if ( AssignExpression ) 793 class StaticIfCondition 794 { 795 mixin SequenceNode!(ast.StaticIfCondition, TOK_static, TOK_if, TOK_lparen, AssignExpression, TOK_rparen); 796 797 static Action enterAfterStatic(Parser p) 798 { 799 p.pushNode(new ast.StaticIfCondition(p.tok)); 800 return shift1.shift(p); // jump into sequence before TOK_if 801 } 802 } 803 804 //-- GRAMMAR_BEGIN -- 805 //StaticAssert: 806 // static assert ( AssignExpression ) ; 807 // static assert ( AssignExpression , AssignExpression ) ; 808 class StaticAssert 809 { 810 mixin SequenceNode!(ast.StaticAssert, TOK_static, TOK_assert, TOK_lparen, ArgumentList, TOK_rparen, TOK_semicolon); 811 812 static Action enterAfterStatic(Parser p) 813 { 814 p.pushNode(new ast.StaticAssert(p.tok)); 815 return shift1.shift(p); // jump into sequence before TOK_assert 816 } 817 }