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.mod; 10 11 import vdc.util; 12 import vdc.lexer; 13 import vdc.parser.engine; 14 import vdc.parser.decl; 15 import vdc.parser.expr; 16 import vdc.parser.misc; 17 import vdc.parser.aggr; 18 import vdc.parser.tmpl; 19 import vdc.parser.stmt; 20 21 import ast = vdc.ast.mod; 22 23 import std.conv; 24 25 //////////////////////////////////////////////////////////////// 26 27 //-- GRAMMAR_BEGIN -- 28 //Module: 29 // ModuleDeclaration DeclDefs_opt 30 // DeclDefs_opt 31 // 32 class Module 33 { 34 static Action enter(Parser p) 35 { 36 p.pushNode(new ast.Module(p.tok)); 37 38 if(p.tok.id == TOK_module) 39 { 40 p.pushRecoverState(&recoverModuleDeclaration); 41 42 p.pushState(&shiftModuleDeclaration); 43 return ModuleDeclaration.enter(p); 44 } 45 46 if(p.tok.id == TOK_EOF) 47 return Accept; 48 49 p.pushState(&shiftModuleDeclDefs); 50 return DeclDefs.enter(p); 51 } 52 53 static Action shiftModuleDeclaration(Parser p) 54 { 55 p.popAppendTopNode!(ast.Module)(); 56 if(p.tok.id == TOK_EOF) 57 return Accept; 58 59 p.pushState(&shiftModuleDeclDefs); 60 return DeclDefs.enter(p); 61 } 62 63 static Action shiftModuleDeclDefs(Parser p) 64 { 65 if(p.tok.id != TOK_EOF) 66 { 67 // recover by assuming the mismatched braces, trying to add more declarations to the module 68 p.pushRecoverState(&recoverModuleDeclaration); 69 70 return p.parseError("EOF expected"); 71 } 72 return Accept; 73 } 74 75 static Action recoverModuleDeclaration(Parser p) 76 { 77 p.pushState(&afterRecover); 78 return Parser.recoverSemiCurly(p); 79 } 80 81 static Action recoverDeclDef(Parser p) 82 { 83 p.pushState(&afterRecover); 84 return Parser.recoverSemiCurly(p); 85 } 86 87 static Action afterRecover(Parser p) 88 { 89 if(p.tok.id == TOK_EOF) 90 return Accept; 91 92 if(p.tok.id == TOK_rcurly) 93 { 94 // eat pending '}' 95 p.pushState(&afterRecover); 96 return Accept; 97 } 98 p.pushState(&shiftModuleDeclDefs); 99 return DeclDefs.enter(p); 100 } 101 } 102 103 //-- GRAMMAR_BEGIN -- 104 //ModuleDeclaration: 105 // module ModuleFullyQualifiedName ; 106 class ModuleDeclaration 107 { 108 static Action enter(Parser p) 109 { 110 if(p.tok.id != TOK_module) 111 return p.parseError("module expected"); 112 113 p.pushNode(new ast.ModuleDeclaration(p.tok)); 114 115 p.pushState(&shiftName); 116 p.pushState(&ModuleFullyQualifiedName.enter); 117 return Accept; 118 } 119 120 static Action shiftName(Parser p) 121 { 122 if(p.tok.id != TOK_semicolon) 123 return p.parseError("semicolon expected"); 124 p.popAppendTopNode!(ast.ModuleDeclaration)(); 125 return Accept; 126 } 127 } 128 129 //-- GRAMMAR_BEGIN -- 130 //ModuleFullyQualifiedName: 131 // ModuleName 132 // Packages . ModuleName 133 // 134 //ModuleName: 135 // Identifier 136 // 137 //Packages: 138 // PackageName 139 // Packages . PackageName 140 // 141 //PackageName: 142 // Identifier 143 class ModuleFullyQualifiedName 144 { 145 mixin ListNode!(ast.ModuleFullyQualifiedName, Identifier, TOK_dot); 146 } 147 148 /* might also be empty, but the grammar reflects this by the _opt suffix where used */ 149 //-- GRAMMAR_BEGIN -- 150 //DeclDefs: 151 // DeclDef 152 // DeclDef DeclDefs 153 class DeclDefs 154 { 155 enum doNotPopNode = true; 156 157 // does not create new Node, but inserts DeclDef into module or block 158 static Action enter(Parser p) 159 { 160 if(p.tok.id == TOK_rcurly || p.tok.id == TOK_EOF) 161 return Forward; 162 163 p.pushRecoverState(&recover); 164 p.pushState(&Parser.keepRecover); // add a "guard" state to avoid popping recover 165 166 p.pushState(&shiftDeclDef); 167 return DeclDef.enter(p); 168 } 169 170 static Action next(Parser p) 171 { 172 if(p.tok.id == TOK_rcurly || p.tok.id == TOK_EOF || p.tok.id == TOK_RECOVER) 173 return Forward; 174 175 p.pushState(&shiftDeclDef); 176 return DeclDef.enter(p); 177 } 178 179 static Action shiftDeclDef(Parser p) 180 { 181 p.popAppendTopNode(); 182 return next(p); 183 } 184 185 static Action recover(Parser p) 186 { 187 auto node = new ast.ParseRecoverNode(p.tok); 188 if(p.nodeStack.depth) 189 node.fulspan.start = p.topNode().fulspan.end; // record span of removed text 190 p.pushNode(node); 191 p.pushState(&afterRecover); 192 return Parser.recoverSemiCurly(p); 193 } 194 195 static Action afterRecover(Parser p) 196 { 197 p.popAppendTopNode!(ast.Node, ast.ParseRecoverNode)(); 198 199 p.pushRecoverState(&recover); 200 p.pushState(&Parser.keepRecover); // add a "guard" state to avoid popping recover 201 202 return next(p); 203 } 204 } 205 206 //-- GRAMMAR_BEGIN -- 207 //DeclDef: 208 // AttributeSpecifier 209 // PragmaSpecifier 210 // ImportDeclaration 211 // EnumDeclaration 212 // ClassDeclaration 213 // InterfaceDeclaration 214 // AggregateDeclaration 215 // Declaration 216 // Constructor 217 // Destructor 218 // Invariant 219 // UnitTest 220 // StaticConstructor 221 // StaticDestructor 222 // SharedStaticConstructor 223 // SharedStaticDestructor 224 // DebugSpecification 225 // VersionSpecification 226 // ConditionalDeclaration 227 // StaticAssert 228 // TemplateDeclaration 229 // TemplateMixinDeclaration 230 // TemplateMixin 231 // MixinDeclaration 232 // ClassAllocator 233 // ClassDeallocator 234 // ; 235 class DeclDef 236 { 237 // does not create new Node, but inserts DeclDef into module or block 238 static Action enter(Parser p) 239 { 240 switch(p.tok.id) 241 { 242 case TOK_pragma: 243 return Pragma.enter(p); 244 case TOK_mixin: 245 p.pushState(&shiftMixin); 246 return Accept; 247 case TOK_import: 248 return ImportDeclaration.enter(p); 249 case TOK_enum: 250 return EnumDeclaration.enter(p); 251 252 case TOK_struct: 253 case TOK_union: 254 case TOK_class: 255 case TOK_interface: 256 return AggregateDeclaration.enter(p); 257 258 case TOK_this: 259 return Constructor.enter(p); 260 case TOK_tilde: 261 return Destructor.enter(p); 262 case TOK_invariant: 263 return Invariant.enter(p); 264 case TOK_unittest: 265 return Unittest.enter(p); 266 case TOK_debug: 267 return DebugCondOrSpec.enter(p); 268 case TOK_version: 269 return VersionCondOrSpec.enter(p); 270 case TOK_template: 271 return TemplateDeclaration.enter(p); 272 case TOK_new: 273 return ClassAllocator.enter(p); 274 case TOK_delete: 275 return ClassDeallocator.enter(p); 276 277 case TOK_semicolon: 278 p.pushNode(new ast.EmptyDeclDef(p.tok)); 279 return Accept; 280 281 case TOK_static: 282 p.pushToken(p.tok); 283 p.pushState(&shiftStatic); 284 return Accept; 285 286 default: 287 if(AttributeSpecifier.tryenter(p) == Accept) 288 return Accept; 289 return Declaration.enter(p); 290 } 291 } 292 293 static Action shiftStatic(Parser p) 294 { 295 switch(p.tok.id) 296 { 297 case TOK_if: // only after static 298 p.popToken(); 299 return ConditionalDeclaration.enterAfterStatic(p); 300 case TOK_assert: // only after static 301 p.popToken(); 302 return StaticAssert.enterAfterStatic(p); 303 default: 304 return AttributeSpecifier.enterAfterStatic(p); 305 } 306 } 307 308 static Action shiftMixin(Parser p) 309 { 310 switch(p.tok.id) 311 { 312 case TOK_template: 313 return TemplateMixinDeclaration.enterAfterMixin(p); 314 case TOK_lparen: 315 return MixinDeclaration.enterAfterMixin(p); 316 default: 317 return TemplateMixin.enterAfterMixin(p); 318 } 319 } 320 } 321 322 //-- GRAMMAR_BEGIN -- 323 //AttributeSpecifier: 324 // Attribute : 325 // Attribute DeclarationBlock 326 // 327 //Attribute: 328 // LinkageAttribute 329 // AlignAttribute 330 // AttributeOrStorageClass 331 // ProtectionAttribute 332 // @disable 333 // @property 334 // @safe 335 // @system 336 // @trusted 337 class AttributeSpecifier 338 { 339 // no members means "Attribute:" 340 341 static Action enter(Parser p) 342 { 343 if(tryenter(p) != Accept) 344 return p.parseError("attribute specifier expected"); 345 return Accept; 346 } 347 348 static Action tryenter(Parser p) 349 { 350 switch(p.tok.id) 351 { 352 case TOK_align: 353 p.pushState(&shiftAttribute); 354 return AlignAttribute.enter(p); 355 case TOK_extern: 356 p.pushState(&shiftAttribute); 357 return LinkageAttribute.enter(p); 358 case TOK_Identifier: 359 if(p.tok.txt[0] != '@') 360 return Forward; 361 return UserAttributeSpecifier.enter(p); 362 case TOK_deprecated: 363 return UserAttributeSpecifier.enter(p); 364 365 default: 366 if(tokenToAnnotation(p.tok.id) == 0 && 367 tokenToProtection(p.tok.id) == 0 && 368 tokenToAttribute(p.tok.id) == 0) 369 return Forward; 370 371 p.pushToken(p.tok); 372 p.pushState(&shiftColonOrLcurly); 373 return Accept; 374 } 375 } 376 377 // assumes attribute on the token stack 378 static Action enterAfterStatic(Parser p) 379 { 380 return shiftColonOrLcurly(p); 381 } 382 383 static ast.AttributeSpecifier createFromToken(Token tok) 384 { 385 TokenId id = tok.id; 386 ast.AttributeSpecifier n; 387 Annotation annot = tokenToAnnotation(id); 388 if(annot == 0) 389 annot = tokenToProtection(id); 390 if(annot != 0) 391 { 392 n = new ast.AttributeSpecifier(tok); 393 n.annotation = annot; 394 } 395 else 396 { 397 Attribute attr = tokenToAttribute(id); 398 if(attr != 0) 399 { 400 n = new ast.AttributeSpecifier(tok); 401 n.attr = attr; 402 } 403 } 404 assert(n); 405 return n; 406 } 407 408 static Action shiftColonOrLcurly(Parser p) 409 { 410 switch(p.tok.id) 411 { 412 case TOK_lparen: 413 if(isTypeModifier(p.topToken().id)) 414 // running into a type instead of an attribute, so switch to Declaration 415 return Decl!true.enterAttributeSpecifier(p); 416 goto default; 417 default: 418 Token tok = p.popToken(); 419 auto attr = createFromToken(tok); 420 p.pushNode(attr); 421 return shiftAttribute(p); 422 } 423 } 424 425 static Action shiftAttribute(Parser p) 426 { 427 auto attr = p.topNode!(ast.AttributeSpecifier); 428 switch(p.tok.id) 429 { 430 case TOK_colon: 431 attr.id = TOK_colon; 432 return Accept; 433 434 case TOK_lcurly: 435 attr.id = TOK_lcurly; 436 p.pushState(&shiftRcurly); 437 p.pushState(&DeclDefs.enter); 438 p.pushNode(new ast.DeclarationBlock(p.tok)); 439 return Accept; 440 441 case TOK_Identifier: 442 // identifier can be basic type or identifier of an AutoDeclaration 443 p.pushToken(p.tok); 444 p.pushState(&shiftIdentifier); 445 return Accept; 446 447 case TOK_alias: 448 case TOK_typedef: 449 p.pushState(&shiftDeclDef); 450 return Declaration.enter(p); 451 452 case TOK_align: 453 p.pushState(&shiftDeclDef); 454 p.pushState(&shiftAttribute); 455 return AlignAttribute.enter(p); 456 case TOK_extern: 457 p.pushState(&shiftDeclDef); 458 p.pushState(&shiftAttribute); 459 return LinkageAttribute.enter(p); 460 461 case TOK_pragma: 462 case TOK_mixin: 463 case TOK_import: 464 case TOK_enum: 465 case TOK_struct: 466 case TOK_union: 467 case TOK_class: 468 case TOK_interface: 469 case TOK_this: 470 case TOK_tilde: 471 case TOK_invariant: 472 case TOK_unittest: 473 case TOK_debug: 474 case TOK_version: 475 case TOK_template: 476 case TOK_semicolon: 477 case TOK_static: 478 p.pushState(&shiftDeclDef); 479 return DeclDef.enter(p); 480 default: 481 if(isTypeModifier(p.tok.id)) 482 { 483 p.pushState(&shiftDeclDef); 484 p.pushToken(p.tok); 485 p.pushState(&shiftColonOrLcurly); 486 return Accept; 487 } 488 int annot = tokenToAnnotation(p.tok.id) | tokenToProtection(p.tok.id); 489 int attrib = tokenToAttribute(p.tok.id); 490 if(annot || attrib) 491 { 492 p.combineAnnotations(attr.annotation, annot); 493 p.combineAttributes(attr.attr, attrib); 494 p.pushState(&shiftAttribute); 495 return Accept; 496 } 497 p.pushState(&shiftDeclDef); 498 return Decl!true.enter(p); 499 } 500 } 501 502 static Action shiftRcurly(Parser p) 503 { 504 if(p.tok.id != TOK_rcurly) 505 return p.parseError("closing brace expected for declaration block"); 506 507 p.popAppendTopNode!(ast.AttributeSpecifier)(); 508 return Accept; 509 } 510 511 static Action shiftDeclDef(Parser p) 512 { 513 p.popAppendTopNode!(ast.AttributeSpecifier)(); 514 return Forward; 515 } 516 517 static Action shiftIdentifier(Parser p) 518 { 519 switch(p.tok.id) 520 { 521 case TOK_assign: 522 p.pushState(&shiftDeclDef); 523 return Decl!true.enterIdentifier(p); 524 case TOK_lparen: 525 p.pushState(&shiftDeclDef); 526 return Decl!true.enterAutoReturn(p); 527 default: 528 p.pushState(&shiftDeclDef); 529 return Decl!true.enterTypeIdentifier(p); 530 } 531 } 532 } 533 534 //-- GRAMMAR_BEGIN -- 535 //UserAttributeSpecifier: 536 // deprectated 537 // @identifier 538 // deprecated ( ArgumentList ) 539 // @identifier ( ArgumentList ) 540 class UserAttributeSpecifier 541 { 542 static Action enter(Parser p) 543 { 544 switch(p.tok.id) 545 { 546 case TOK_deprecated: 547 case TOK_Identifier: 548 auto attr = new ast.UserAttributeSpecifier(p.tok); 549 attr.ident = p.tok.txt; 550 p.pushNode(attr); 551 p.pushState(&shiftIdentifier); 552 return Accept; 553 default: 554 return p.parseError("@identifier expected in user attribute"); 555 } 556 } 557 558 static Action shiftIdentifier(Parser p) 559 { 560 switch(p.tok.id) 561 { 562 case TOK_lparen: 563 p.pushState(&shiftArgumentList); 564 return Arguments.enter(p); 565 default: 566 return Forward; 567 } 568 } 569 570 static Action shiftArgumentList(Parser p) 571 { 572 p.popAppendTopNode!(ast.UserAttributeSpecifier, ast.ArgumentList)(); 573 return Forward; 574 } 575 } 576 577 //-- GRAMMAR_BEGIN -- 578 //DeclarationBlock: 579 // DeclDef 580 // { DeclDefs_opt } 581 class DeclarationBlock 582 { 583 static Action enter(Parser p) 584 { 585 switch(p.tok.id) 586 { 587 case TOK_lcurly: 588 auto decl = new ast.DeclarationBlock(p.tok); 589 p.pushNode(decl); 590 p.pushState(&shiftLcurly); 591 return Accept; 592 default: 593 return DeclDef.enter(p); 594 } 595 } 596 static Action shiftLcurly(Parser p) 597 { 598 switch(p.tok.id) 599 { 600 case TOK_rcurly: 601 return Accept; 602 default: 603 p.pushState(&shiftDeclDefs); 604 return DeclDefs.enter(p); 605 } 606 } 607 608 static Action shiftDeclDefs(Parser p) 609 { 610 switch(p.tok.id) 611 { 612 case TOK_rcurly: 613 return Accept; 614 default: 615 return p.parseError("'}' expected"); 616 } 617 } 618 } 619 620 621 //-- GRAMMAR_BEGIN -- 622 //LinkageAttribute: 623 // extern ( LinkageType ) 624 // 625 //LinkageType: 626 // "C" 627 // "C" ++ 628 // "D" 629 // "Windows" 630 // "System" 631 class LinkageAttribute 632 { 633 static Action enter(Parser p) 634 { 635 if(p.tok.id != TOK_extern) 636 return p.parseError("extern expected"); 637 p.pushState(&shiftLparen); 638 return Accept; 639 } 640 641 static Action shiftLparen(Parser p) 642 { 643 switch(p.tok.id) 644 { 645 case TOK_lparen: 646 p.pushNode(new ast.LinkageAttribute(p.tok)); 647 p.pushState(&shiftLinkageType); 648 return Accept; 649 default: 650 auto attr = new ast.AttributeSpecifier(p.tok); 651 attr.attr = Attr_Extern; 652 p.pushNode(attr); 653 return Forward; 654 } 655 } 656 657 static Action shiftLinkageType(Parser p) 658 { 659 Attribute attr = tokenToLinkageType(p.tok); 660 if(attr == 0) 661 return p.parseError("linkage type expected in extern"); 662 p.topNode!(ast.LinkageAttribute)().attr = attr; 663 664 p.pushState(&shiftRParen); 665 return Accept; 666 } 667 668 static Action shiftRParen(Parser p) 669 { 670 assert(cast(ast.LinkageAttribute)p.topNode()); 671 if(p.tok.id == TOK_rparen) 672 return Accept; 673 674 if(p.topNode().attr != Attr_ExternC || p.tok.id != TOK_plusplus) 675 return p.parseError("closing parenthesis expected after linkage type"); 676 677 p.topNode().attr = Attr_ExternCPP; 678 p.pushState(&shiftRParen); 679 return Accept; 680 } 681 } 682 683 Attribute tokenToLinkageType(Token tok) 684 { 685 if(tok.id != TOK_Identifier) 686 return 0; 687 688 switch(tok.txt) 689 { 690 case "C": return Attr_ExternC; 691 case "D": return Attr_ExternD; 692 case "Windows": return Attr_ExternWindows; 693 case "System": return Attr_ExternSystem; 694 default: return 0; 695 } 696 } 697 698 //-- GRAMMAR_BEGIN -- 699 //AlignAttribute: 700 // align 701 // align ( Integer ) 702 class AlignAttribute 703 { 704 static Action enter(Parser p) 705 { 706 if(p.tok.id != TOK_align) 707 return p.parseError("align expected"); 708 709 p.pushNode(new ast.AlignAttribute(p.tok)); 710 p.pushState(&shiftLparen); 711 return Accept; 712 } 713 714 static Action shiftLparen(Parser p) 715 { 716 if(p.tok.id != TOK_lparen) 717 return Forward; 718 719 p.pushState(&shiftInteger); 720 return Accept; 721 } 722 723 static Action shiftInteger(Parser p) 724 { 725 if(p.tok.id != TOK_IntegerLiteral) 726 return p.parseError("integer expected in align"); 727 int algn = parse!int(p.tok.txt); 728 Attribute attr = alignmentToAttribute(algn); 729 if(attr == 0) 730 return p.parseError("alignment not supported: " ~ p.tok.txt); 731 732 p.topNode!(ast.AlignAttribute)().attr = attr; 733 p.pushState(&shiftRParen); 734 return Accept; 735 } 736 737 static Action shiftRParen(Parser p) 738 { 739 assert(cast(ast.AlignAttribute)p.topNode()); 740 if(p.tok.id != TOK_rparen) 741 return p.parseError("closing parenthesis expected after align"); 742 return Accept; 743 } 744 } 745 746 Attribute alignmentToAttribute(int algn) 747 { 748 switch(algn) 749 { 750 case 1: return Attr_Align1; 751 case 2: return Attr_Align2; 752 case 4: return Attr_Align4; 753 case 8: return Attr_Align8; 754 case 16: return Attr_Align16; 755 default: return 0; 756 } 757 } 758 759 //-- GRAMMAR_BEGIN -- 760 //ProtectionAttribute: 761 // private 762 // package 763 // protected 764 // public 765 // export 766 767 //PragmaSpecifier: 768 // Pragma DeclDef 769 //Pragma: 770 // pragma ( Identifier ) 771 // pragma ( Identifier , TemplateArgumentList ) 772 class Pragma 773 { 774 static Action enter(Parser p) 775 { 776 if(p.tok.id != TOK_pragma) 777 return p.parseError("pragma expected"); 778 779 p.pushNode(new ast.Pragma(p.tok)); 780 p.pushState(&shiftLparen); 781 return Accept; 782 } 783 784 static Action shiftLparen(Parser p) 785 { 786 if(p.tok.id != TOK_lparen) 787 return Forward; 788 789 p.pushState(&shiftIdentifier); 790 return Accept; 791 } 792 793 static Action shiftIdentifier(Parser p) 794 { 795 if(p.tok.id != TOK_Identifier) 796 return p.parseError("integer expected in align"); 797 798 p.topNode!(ast.Pragma)().ident = p.tok.txt; 799 800 p.pushState(&shiftCommaOrRParen); 801 return Accept; 802 } 803 804 static Action shiftCommaOrRParen(Parser p) 805 { 806 if(p.tok.id == TOK_comma) 807 { 808 p.pushState(&shiftArgumentList); 809 p.pushState(&TemplateArgumentList.enter); 810 return Accept; 811 } 812 return shiftRParen(p); 813 } 814 815 static Action shiftRParen(Parser p) 816 { 817 assert(cast(ast.Pragma)p.topNode()); 818 if(p.tok.id != TOK_rparen) 819 return p.parseError("closing parenthesis expected for pragma"); 820 return Accept; 821 } 822 823 static Action shiftArgumentList(Parser p) 824 { 825 p.popAppendTopNode!(ast.Pragma)(); 826 return shiftRParen(p); 827 } 828 } 829 830 831 //-- GRAMMAR_BEGIN -- 832 //ImportDeclaration: 833 // import ImportList ; 834 class ImportDeclaration 835 { 836 mixin SequenceNode!(ast.ImportDeclaration, TOK_import, ImportList, TOK_semicolon); 837 } 838 839 //-- GRAMMAR_BEGIN -- 840 //ImportList: 841 // Import 842 // ImportBindings 843 // Import , ImportList 844 // 845 //ImportBindings: 846 // Import : ImportBindList 847 848 class ImportList 849 { 850 static Action enter(Parser p) 851 { 852 p.pushNode(new ast.ImportList(p.tok)); 853 p.pushState(&shiftImport); 854 return Import.enter(p); 855 } 856 857 static Action shiftImport(Parser p) 858 { 859 if(p.tok.id == TOK_colon) 860 { 861 p.pushState(&shiftImportBindList); 862 p.pushState(&ImportBindList.enter); 863 return Accept; 864 } 865 p.popAppendTopNode!(ast.ImportList)(); 866 867 if(p.tok.id == TOK_comma) 868 { 869 p.pushState(&shiftImport); 870 p.pushState(&Import.enter); 871 return Accept; 872 } 873 return Forward; 874 } 875 876 static Action shiftImportBindList(Parser p) 877 { 878 p.popAppendTopNode!(ast.Import)(); 879 p.popAppendTopNode!(ast.ImportList)(); 880 return Forward; 881 } 882 } 883 884 //-- GRAMMAR_BEGIN -- 885 //Import: 886 // ModuleFullyQualifiedName 887 // ModuleAliasIdentifier = ModuleFullyQualifiedName 888 // 889 //ModuleAliasIdentifier: 890 // Identifier 891 class Import 892 { 893 static Action enter(Parser p) 894 { 895 if(p.tok.id != TOK_Identifier) 896 return p.parseError("identifier expected in import"); 897 898 p.pushToken(p.tok); 899 p.pushNode(new ast.Import(p.tok)); 900 p.pushState(&shiftIdentifier); 901 return Accept; 902 } 903 904 static Action shiftIdentifier(Parser p) 905 { 906 p.pushState(&shiftFullyQualifiedName); 907 908 if(p.tok.id == TOK_assign) 909 { 910 p.topNode!(ast.Import)().aliasIdent = p.popToken().txt; 911 p.pushState(&ModuleFullyQualifiedName.enter); 912 return Accept; 913 } 914 915 // delegate into ModuleFullyQualifiedName 916 p.pushNode(new ast.ModuleFullyQualifiedName(p.tok)); 917 auto id = new ast.Identifier(p.popToken()); 918 p.pushNode(id); 919 return ModuleFullyQualifiedName.shift(p); 920 } 921 922 static Action shiftFullyQualifiedName(Parser p) 923 { 924 p.popAppendTopNode!(ast.Import)(); 925 return Forward; 926 } 927 } 928 929 //-- GRAMMAR_BEGIN -- 930 //ImportBindList: 931 // ImportBind 932 // ImportBind , ImportBindList 933 class ImportBindList 934 { 935 mixin ListNode!(ast.ImportBindList, ImportBind, TOK_comma); 936 } 937 938 939 //-- GRAMMAR_BEGIN -- 940 //ImportBind: 941 // Identifier 942 // Identifier = Identifier 943 class ImportBind 944 { 945 mixin OptionalNode!(ast.ImportBind, Identifier, TOK_assign, Identifier); 946 } 947 948 //-- GRAMMAR_BEGIN -- 949 //MixinDeclaration: 950 // mixin ( AssignExpression ) ; 951 class MixinDeclaration 952 { 953 mixin SequenceNode!(ast.MixinDeclaration, TOK_mixin, TOK_lparen, AssignExpression, TOK_rparen, TOK_semicolon); 954 955 static Action enterAfterMixin(Parser p) 956 { 957 p.pushNode(new ast.MixinDeclaration(p.tok)); 958 return shift1.shift(p); 959 } 960 } 961 962 //-- GRAMMAR_BEGIN -- 963 //Unittest: 964 // unittest BlockStatement 965 class Unittest 966 { 967 mixin SequenceNode!(ast.Unittest, TOK_unittest, BlockStatement); 968 }