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 }