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 }