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.decl;
10 
11 import vdc.util;
12 import vdc.lexer;
13 import vdc.parser.engine;
14 import vdc.parser.expr;
15 import vdc.parser.misc;
16 import vdc.parser.tmpl;
17 import vdc.parser.mod;
18 
19 import ast = vdc.ast.all;
20 
21 import stdext.util;
22 
23 //-- GRAMMAR_BEGIN --
24 //Declaration:
25 //    alias LinkageAttribute_opt Decl
26 //    typedef Decl /* for legacy code */
27 //    Decl
28 //    alias Identifier this
29 //    alias this = Identifier
30 class Declaration
31 {
32     static Action enter(Parser p)
33     {
34         switch(p.tok.id)
35         {
36             case TOK_alias:
37                 p.pushState(&shiftAlias);
38                 return Accept;
39 
40             case TOK_typedef:
41                 p.pushState(&shiftTypedef);
42                 p.pushState(&Decl!true.enter);
43                 return Accept;
44             default:
45                 return Decl!true.enter(p);
46         }
47     }
48 
49     static Action shiftAlias(Parser p)
50     {
51         switch(p.tok.id)
52         {
53             case TOK_extern:
54                 p.pushState(&shiftAliasLinkage);
55                 p.pushState(&Decl!true.enter);
56                 return LinkageAttribute.enter(p);
57 
58             case TOK_Identifier:
59                 p.pushToken(p.tok);
60                 p.pushState(&shiftAliasIdentifier);
61                 return Accept;
62 
63             case TOK_this:
64                 p.pushState(&shiftThis);
65                 return Accept;
66 
67             default:
68                 p.pushState(&shiftTypedef);
69                 return Decl!true.enter(p);
70         }
71     }
72 
73     static Action shiftAliasLinkage(Parser p)
74     {
75         auto decl = p.popNode!(ast.Decl)();
76         auto link = p.popNode!(ast.AttributeSpecifier)();
77         p.combineAttributes(decl.attr, link.attr);
78         p.pushNode(decl);
79         return Forward;
80     }
81 
82     // assumes identifier token on the info stack
83     static Action shiftAliasIdentifier(Parser p)
84     {
85         switch(p.tok.id)
86         {
87             case TOK_this:
88                 auto tok = p.popToken();
89                 p.pushNode(new ast.AliasThis(tok));
90                 p.pushState(&shiftAliasThis);
91                 return Accept;
92             case TOK_assign:
93                 p.pushState(&shiftAliasAssign);
94                 p.pushState(&Type.enter);
95                 return Accept;
96             default:
97                 p.pushState(&shiftTypedef);
98                 return Decl!true.enterTypeIdentifier(p);
99         }
100     }
101 
102     static Action shiftThis(Parser p)
103     {
104         switch(p.tok.id)
105         {
106             case TOK_assign:
107                 p.pushState(&shiftThisAssign);
108                 return Accept;
109             default:
110                 return p.parseError("'=' expected after alias this");
111         }
112     }
113 
114     static Action shiftThisAssign(Parser p)
115     {
116         switch(p.tok.id)
117         {
118             case TOK_Identifier:
119                 p.pushNode(new ast.AliasThis(p.tok));
120                 p.pushState(&shiftAliasThis);
121                 return Accept;
122             default:
123                 return p.parseError("identifier expected after alias this =");
124         }
125     }
126 
127     static Action shiftAliasThis(Parser p)
128     {
129         switch(p.tok.id)
130         {
131             case TOK_semicolon:
132                 return Accept;
133             default:
134                 return p.parseError("semicolon expected after alias this;");
135         }
136     }
137 
138     // assumes identifier token on the info stack
139     static Action shiftAliasAssign(Parser p)
140     {
141         auto type = static_cast!(ast.Type)(p.popNode());
142 
143         auto tok = p.popToken();
144         auto decl = new ast.Decl(type.id, type.span);
145         auto decls = new ast.Declarators(tok);
146         decls.addMember(new ast.Declarator(tok));
147         // insert type before declarator identifier
148         decl.addMember(type);
149         decl.addMember(decls);
150         decl.isAlias = true;
151         decl.hasSemi = true;
152         p.pushNode(decl);
153 
154         switch(p.tok.id)
155         {
156             case TOK_semicolon:
157                 return Accept;
158             case TOK_comma:
159             default:
160                 return p.parseError("semicolon expected after alias identifier = type");
161         }
162     }
163 
164     static Action shiftTypedef(Parser p)
165     {
166         //p.appendReplaceTopNode(new ast.AliasDeclaration(p.tok));
167         p.topNode!(ast.Decl)().isAlias = true;
168         return Forward;
169     }
170 }
171 
172 //-- GRAMMAR_BEGIN --
173 //Decl:
174 //    StorageClasses Decl
175 //    BasicType BasicTypes2_opt Declarators ;
176 //    BasicType BasicTypes2_opt Declarator FunctionBody
177 //    AutoDeclaration
178 //
179 //AutoDeclaration:
180 //    StorageClasses Identifier = AssignExpression ;
181 class Decl(bool checkSemi = true)
182 {
183     // storage class stored in Decl.attr, first child is Type (TOK_auto if not present)
184     static Action enter(Parser p)
185     {
186         auto decl = new ast.Decl(p.tok);
187         decl.hasSemi = checkSemi;
188         p.pushNode(decl);
189 
190         if(isTypeModifier(p.tok.id))
191         {
192             // could be storage class or BasicType
193             p.pushToken(p.tok);
194             p.pushState(&shiftTypeModifier);
195             return Accept;
196         }
197         if(isStorageClass(p.tok.id))
198         {
199             p.combineAttributes(decl.attr, tokenToAttribute(p.tok.id));
200             p.combineAnnotations(decl.annotation, tokenToAnnotation(p.tok.id));
201             p.pushState(&shiftStorageClass);
202             return Accept;
203         }
204         p.pushState(&shiftBasicType);
205         return BasicType.enter(p);
206     }
207 
208     // switch here from AttributeSpecifier when detecting a '(' after const,etc
209     // assumes modifier token on the info stack
210     static Action enterAttributeSpecifier(Parser p)
211     {
212         assert(p.tok.id == TOK_lparen);
213 
214         auto decl = new ast.Decl(p.tok);
215         decl.hasSemi = checkSemi;
216         p.pushNode(decl);
217         p.pushState(&shiftBasicType);
218         return BasicType.shiftTypeModifier(p);
219     }
220 
221     // disambiguate "const x" and "const(int) x"
222     // assumes modifier token on the info stack
223     static Action shiftTypeModifier(Parser p)
224     {
225         if(p.tok.id == TOK_lparen)
226         {
227             p.pushState(&shiftBasicType);
228             return BasicType.shiftTypeModifier(p);
229         }
230 
231         auto decl = p.topNode!(ast.Decl)();
232         Token tok = p.popToken();
233         p.combineAttributes(decl.attr, tokenToAttribute(tok.id));
234         return shiftStorageClass(p);
235     }
236 
237     static Action enterAfterStorageClass(Parser p, TokenId storage)
238     {
239         auto decl = new ast.Decl(p.tok);
240         decl.hasSemi = checkSemi;
241         p.pushNode(decl);
242         decl.attr = tokenToAttribute(storage);
243         return shiftStorageClass(p);
244     }
245 
246     static Action shiftStorageClass(Parser p)
247     {
248         if(p.tok.id == TOK_Identifier)
249         {
250             p.pushToken(p.tok);
251             p.pushState(&shiftIdentifier);
252             return Accept;
253         }
254         if(isTypeModifier(p.tok.id))
255         {
256             // could be storage class or BasicType
257             p.pushToken(p.tok);
258             p.pushState(&shiftTypeModifier);
259             return Accept;
260         }
261         if(isStorageClass(p.tok.id))
262         {
263             auto decl = p.topNode!(ast.Decl)();
264             p.combineAttributes(decl.attr, tokenToAttribute(p.tok.id));
265             p.combineAnnotations(decl.annotation, tokenToAnnotation(p.tok.id));
266             p.pushState(&shiftStorageClass);
267             return Accept;
268         }
269         p.pushState(&shiftBasicType);
270         return BasicType.enter(p);
271     }
272 
273     // switch here from Statement when detecting a declaration after an identifier
274     // assumes identifier token on the info stack
275     static Action enterTypeIdentifier(Parser p)
276     {
277         auto decl = new ast.Decl(p.tok);
278         decl.hasSemi = checkSemi;
279         p.pushNode(decl);
280 
281         p.pushState(&shiftBasicType);
282         return BasicType.enterIdentifier(p);
283     }
284 
285     // assumes identifier token on the info stack
286     static Action enterIdentifier(Parser p)
287     {
288         auto decl = new ast.Decl(p.tok);
289         decl.hasSemi = checkSemi;
290         p.pushNode(decl);
291 
292         return shiftIdentifier(p);
293     }
294 
295     // assumes identifier token on the info stack
296     static Action shiftIdentifier(Parser p)
297     {
298         switch(p.tok.id)
299         {
300             case TOK_assign:
301                 auto bt = new ast.AutoType(TOK_auto, p.topToken().span);
302                 p.topNode!(ast.Decl)().addMember(bt);
303 
304                 p.pushState(&shiftDeclarators);
305                 return Declarators.enterAfterIdentifier(p);
306             case TOK_lparen:
307                 // storageclass identifier(... must be function with auto return
308                 auto bt = new ast.AutoType(TOK_auto, p.topToken().span);
309                 p.topNode!(ast.Decl).addMember(bt);
310                 p.pushState(&shiftDeclarators);
311                 return Declarators.enterAfterIdentifier(p);
312             default:
313                 p.pushState(&shiftBasicType);
314                 return BasicType.enterIdentifier(p);
315         }
316     }
317 
318     // assumes identifier token on the info stack
319     static Action enterAutoReturn(Parser p)
320     {
321         assert(p.tok.id == TOK_lparen);
322 
323         auto decl = new ast.Decl(p.topToken());
324         decl.hasSemi = checkSemi;
325         p.pushNode(decl);
326 
327         auto bt = new ast.AutoType(TOK_auto, p.topToken().span);
328         decl.addMember(bt);
329 
330         p.pushState(&shiftDeclarators);
331         return Declarators.enterAfterIdentifier(p);
332     }
333 
334     static Action shiftBasicType(Parser p)
335     {
336         switch(p.tok.id)
337         {
338             mixin(BasicType2.case_TOKs);
339                 p.pushState(&shiftBasicTypes2);
340                 return BasicTypes2.enter(p);
341             default:
342                 return shiftBasicTypes2(p);
343         }
344     }
345 
346     static Action shiftBasicTypes2(Parser p)
347     {
348         p.popAppendTopNode!(ast.Decl, ast.Type)();
349         p.pushState(&shiftDeclarators);
350         return Declarators.enter(p);
351     }
352 
353     static Action shiftDeclarators(Parser p)
354     {
355         p.popAppendTopNode!(ast.Decl)();
356         static if(checkSemi)
357         {
358             if(p.tok.id == TOK_RECOVER)
359                 return Forward;
360             auto decl = p.topNode!(ast.Decl)();
361             if(decl.members.length == 2 && // BasicType and Declarators
362                decl.members[1].members.length == 1 && // only one declarator
363                FunctionBody.isInitTerminal(p.tok))
364             {
365                 decl.hasSemi = false;
366                 p.pushState(&shiftFunctionBody);
367                 return FunctionBody.enter(p);
368             }
369             if(p.tok.id != TOK_semicolon)
370                 return p.parseError("semicolon expected after declaration");
371             return Accept;
372         }
373         else
374         {
375             return Forward;
376         }
377     }
378 
379     static Action shiftFunctionBody(Parser p)
380     {
381         p.popAppendTopNode!(ast.Decl)();
382         return Forward;
383     }
384 }
385 
386 //-- GRAMMAR_BEGIN --
387 //Declarators:
388 //    DeclaratorInitializer
389 //    DeclaratorInitializer , DeclaratorIdentifierList
390 class Declarators
391 {
392     mixin ListNode!(ast.Declarators, DeclaratorInitializer, TOK_comma);
393 
394     // assumes identifier token on the info stack
395     static Action enterAfterIdentifier(Parser p)
396     {
397         p.pushNode(new ast.Declarators(p.tok));
398         p.pushState(&shift);
399         return DeclaratorInitializer.enterAfterIdentifier(p);
400     }
401 }
402 
403 //-- GRAMMAR_BEGIN --
404 //DeclaratorInitializer:
405 //    Declarator
406 //    Declarator = Initializer
407 class DeclaratorInitializer
408 {
409     mixin OptionalNode!(ast.DeclaratorInitializer, Declarator, TOK_assign, Initializer);
410 
411     // assumes identifier token on the info stack
412     static Action enterAfterIdentifier(Parser p)
413     {
414         switch(p.tok.id)
415         {
416             case TOK_assign:
417                 auto tok = p.popToken();
418                 p.pushNode(new ast.Declarator(tok));
419                 return shiftSubType1(p);
420             default:
421                 p.pushState(&shiftSubType1);
422                 return Declarator.enterAfterIdentifier(p);
423         }
424     }
425 }
426 
427 //-- GRAMMAR_BEGIN --
428 //DeclaratorIdentifierList:
429 //    DeclaratorIdentifier
430 //    DeclaratorIdentifier , DeclaratorIdentifierList
431 class DeclaratorIdentifierList
432 {
433     mixin ListNode!(ast.DeclaratorIdentifierList, DeclaratorIdentifier, TOK_comma);
434 }
435 
436 //-- GRAMMAR_BEGIN --
437 //DeclaratorIdentifier:
438 //    Identifier
439 //    Identifier = Initializer
440 class DeclaratorIdentifier
441 {
442     mixin OptionalNode!(ast.DeclaratorIdentifier, Identifier, TOK_assign, Initializer);
443 }
444 
445 //-- GRAMMAR_BEGIN --
446 //Initializer:
447 //    VoidInitializer
448 //    NonVoidInitializer
449 //
450 //NonVoidInitializer:
451 //    AssignExpression
452 //    ArrayInitializer  /* same as ArrayLiteral? */
453 //    StructInitializer
454 class Initializer
455 {
456     static Action enter(Parser p)
457     {
458         if(p.tok.id == TOK_void)
459         {
460             p.pushRollback(&rollbackVoid);
461             p.pushState(&shiftVoid);
462             return Accept;
463         }
464         // StructInitializer not implemented
465         return AssignExpression.enter(p);
466     }
467 
468     static Action shiftVoid(Parser p)
469     {
470         switch(p.tok.id)
471         {
472             case TOK_dot:
473                 return p.parseError("unexpected '.' in void initializer");
474             default:
475                 p.popRollback();
476                 p.pushNode(new ast.VoidInitializer(p.tok));
477                 return Forward;
478         }
479     }
480 
481     static Action rollbackVoid(Parser p)
482     {
483         return AssignExpression.enter(p);
484     }
485 }
486 
487 //-- GRAMMAR_BEGIN --
488 //BasicType:
489 //    BasicTypeX
490 //    . IdentifierList
491 //    IdentifierList
492 //    Typeof
493 //    Typeof . IdentifierList
494 //    ModifiedType
495 //    VectorType
496 //
497 //ModifiedType:
498 //    const ( Type )
499 //    immutable ( Type )
500 //    shared ( Type )
501 //    inout ( Type )
502 class BasicType
503 {
504     static Action enter(Parser p)
505     {
506         switch(p.tok.id)
507         {
508             case TOK_dot:
509             case TOK_Identifier:
510                 p.pushNode(new ast.IdentifierType(p.tok));
511                 p.pushState(&shiftIdentifierList);
512                 return GlobalIdentifierList.enter(p);
513             case TOK_typeof:
514                 p.pushState(&shiftTypeof);
515                 return Typeof.enter(p);
516 
517             mixin(case_TOKs_BasicTypeX);
518                 p.pushNode(new ast.BasicType(p.tok));
519                 return Accept;
520 
521             mixin(case_TOKs_TypeModifier);
522                 p.pushToken(p.tok);
523                 p.pushState(&shiftTypeModifier);
524                 return Accept;
525 
526             case TOK___vector:
527                 return VectorType.enter(p);
528 
529             default:
530                 return p.parseError("unexpected token in BasicType");
531         }
532     }
533 
534     // assumes modifier token on the info stack
535     static Action shiftTypeModifier(Parser p)
536     {
537         Token tok = p.popToken();
538         p.pushNode(new ast.ModifiedType(tok));
539 
540         switch(p.tok.id)
541         {
542             case TOK_lparen:
543                 p.pushState(&shiftParenType);
544                 p.pushState(&Type.enter);
545                 return Accept;
546             default:
547                 p.pushState(&shiftType);
548                 return Type.enter(p);
549         }
550     }
551 
552     static Action shiftParenType(Parser p)
553     {
554         if(p.tok.id != TOK_rparen)
555             return p.parseError("closing parenthesis expected");
556         p.popAppendTopNode();
557         return Accept;
558     }
559 
560     static Action shiftType(Parser p)
561     {
562         p.popAppendTopNode();
563         return Forward;
564     }
565 
566     // entry point on token after identifier
567     // assumes identifier token on the info stack
568     static Action enterIdentifier(Parser p)
569     {
570         p.pushNode(new ast.IdentifierType(p.topToken()));
571         p.pushState(&shiftIdentifierList);
572         return IdentifierList.enterAfterIdentifier(p);
573     }
574 
575     static Action shiftIdentifierList(Parser p)
576     {
577         p.popAppendTopNode!(ast.IdentifierType)();
578         return Forward;
579     }
580 
581     static Action shiftTypeof(Parser p)
582     {
583         if(p.tok.id != TOK_dot)
584             return Forward;
585 
586         p.pushState(&shiftTypeofIdentifierList);
587         p.pushState(&IdentifierList.enter);
588         return Accept;
589     }
590 
591     static Action shiftTypeofIdentifierList(Parser p)
592     {
593         p.popAppendTopNode!(ast.Typeof, ast.IdentifierList)();
594         return Forward;
595     }
596 
597 }
598 
599 enum case_TOKs_TypeModifier = q{
600         case TOK_const:
601         case TOK_shared:
602         case TOK_immutable:
603         case TOK_inout:
604 };
605 
606 bool isTypeModifier(TokenId tok)
607 {
608     switch(tok)
609     {
610         mixin(case_TOKs_TypeModifier);
611             return true;
612         default:
613             return false;
614     }
615 }
616 
617 //-- GRAMMAR_BEGIN --
618 //BasicTypeX:
619 //    bool
620 //    byte
621 //    ubyte
622 //    short
623 //    ushort
624 //    int
625 //    uint
626 //    long
627 //    ulong
628 //    char
629 //    wchar
630 //    dchar
631 //    float
632 //    double
633 //    real
634 //    ifloat
635 //    idouble
636 //    ireal
637 //    cfloat
638 //    cdouble
639 //    creal
640 //    void
641 
642 bool isBasicTypeX(TokenId tok)
643 {
644     switch(tok)
645     {
646         mixin(case_TOKs_BasicTypeX);
647             return true;
648         default:
649             return false;
650     }
651 }
652 
653 //-- GRAMMAR_BEGIN --
654 //VectorType:
655 //    __vector ( Type )
656 class VectorType
657 {
658     mixin SequenceNode!(ast.VectorType, TOK___vector, TOK_lparen, Type, TOK_rparen);
659 }
660 
661 //-- GRAMMAR_BEGIN --
662 //Typeof:
663 //    typeof ( Expression )
664 //    typeof ( return )
665 class Typeof
666 {
667     static Action enter(Parser p)
668     {
669         if(p.tok.id != TOK_typeof)
670             return p.parseError("typeof expected");
671         p.pushNode(new ast.Typeof(p.tok));
672         p.pushState(&shiftLparen);
673         return Accept;
674     }
675 
676     static Action shiftLparen(Parser p)
677     {
678         if(p.tok.id != TOK_lparen)
679             return p.parseError("opening parenthesis expected");
680         p.pushState(&shiftArgument);
681         return Accept;
682     }
683 
684     static Action shiftArgument(Parser p)
685     {
686         if(p.tok.id == TOK_return)
687         {
688             p.topNode!(ast.Typeof).id = TOK_return;
689             p.pushState(&shiftRparen);
690             return Accept;
691         }
692         p.pushState(&shiftExpression);
693         return Expression.enter(p);
694     }
695 
696     static Action shiftExpression(Parser p)
697     {
698         if(p.tok.id != TOK_rparen)
699             return p.parseError("closing parenthesis expected");
700         p.popAppendTopNode!(ast.Typeof)();
701         return Accept;
702     }
703 
704     static Action shiftRparen(Parser p)
705     {
706         if(p.tok.id != TOK_rparen)
707             return p.parseError("closing parenthesis expected");
708         return Accept;
709     }
710 }
711 
712 //-- GRAMMAR_BEGIN --
713 //Declarator:
714 //    Identifier DeclaratorSuffixes_opt
715 class Declarator
716 {
717     static Action enter(Parser p)
718     {
719         switch(p.tok.id)
720         {
721             case TOK_Identifier:
722                 p.pushNode(new ast.Declarator(p.tok));
723                 p.pushState(&shiftIdentifier);
724                 return Accept;
725 
726             default:
727                 return p.parseError("unexpected token in Declarator");
728         }
729     }
730 
731     static Action shiftIdentifier(Parser p)
732     {
733         switch(p.tok.id)
734         {
735             case TOK_lparen:
736             case TOK_lbracket:
737                 return DeclaratorSuffixes.enter(p); // appends to Declarator
738             default:
739                 return Forward;
740         }
741     }
742 
743     // assumes identifier token on the info stack
744     static Action enterAfterIdentifier(Parser p)
745     {
746         auto tok = p.popToken();
747         p.pushNode(new ast.Declarator(tok));
748         return shiftIdentifier(p);
749     }
750 }
751 
752 //-- GRAMMAR_BEGIN --
753 // always optional
754 //BasicType2:
755 //    *
756 //    [ ]
757 //    [ AssignExpression ]
758 //    [ AssignExpression .. AssignExpression ]
759 //    [ Type ]
760 //    delegate Parameters FunctionAttributes_opt
761 //    function Parameters FunctionAttributes_opt
762 class BasicType2
763 {
764     enum case_TOKs = q{
765             case TOK_mul:
766             case TOK_lbracket:
767             case TOK_delegate:
768             case TOK_function:
769     };
770 
771     static Action enter(Parser p)
772     {
773         assert(p.topNode!(ast.Type));
774         switch(p.tok.id)
775         {
776             case TOK_mul:
777                 p.appendReplaceTopNode(new ast.TypePointer(p.tok));
778                 return Accept;
779             case TOK_lbracket:
780                 p.pushState(&shiftLbracket);
781                 return Accept;
782 
783             case TOK_delegate:
784                 p.appendReplaceTopNode(new ast.TypeDelegate(p.tok));
785                 p.pushState(&shiftParameters);
786                 p.pushState(&Parameters.enter);
787                 return Accept;
788 
789             case TOK_function:
790                 p.appendReplaceTopNode(new ast.TypeFunction(p.tok));
791                 p.pushState(&shiftParameters);
792                 p.pushState(&Parameters.enter);
793                 return Accept;
794             default:
795                 return p.parseError("unexpected token in BasicType2");
796         }
797     }
798 
799     static Action shiftLbracket(Parser p)
800     {
801         switch(p.tok.id)
802         {
803             case TOK_rbracket:
804                 p.appendReplaceTopNode(new ast.TypeDynamicArray(p.tok));
805                 return Accept;
806             default:
807                 p.pushState(&shiftTypeOrExpression);
808                 return TypeOrExpression!TOK_rbracket.enter(p);
809         }
810     }
811 
812     static Action shiftTypeOrExpression(Parser p)
813     {
814         if(cast(ast.Type) p.topNode())
815         {
816             auto keyType = p.popNode!(ast.Type);
817             p.appendReplaceTopNode(new ast.TypeAssocArray(p.tok));
818             p.topNode().addMember(keyType);
819             if(p.tok.id != TOK_rbracket)
820                 return p.parseError("']' expected");
821             return Accept;
822         }
823 
824         switch(p.tok.id)
825         {
826             case TOK_rbracket:
827                 auto dim = p.popNode!(ast.Expression);
828                 p.appendReplaceTopNode(new ast.TypeStaticArray(p.tok));
829                 p.topNode().addMember(dim);
830                 return Accept;
831             case TOK_slice:
832                 auto low = p.popNode!(ast.Expression);
833                 p.appendReplaceTopNode(new ast.TypeArraySlice(p.tok));
834                 p.topNode().addMember(low);
835                 p.pushState(&shiftSliceUpper);
836                 p.pushState(&AssignExpression.enter);
837                 return Accept;
838             default:
839                 return p.parseError("']' expected");
840         }
841     }
842 
843     static Action shiftSliceUpper(Parser p)
844     {
845         p.popAppendTopNode!(ast.TypeArraySlice)();
846         switch(p.tok.id)
847         {
848             case TOK_rbracket:
849                 return Accept;
850             default:
851                 return p.parseError("']' expected");
852         }
853     }
854 
855     static Action shiftParameters(Parser p)
856     {
857         p.popAppendTopNode();
858         return shiftAttributes(p);
859     }
860 
861     static Action shiftAttributes(Parser p)
862     {
863         switch(p.tok.id)
864         {
865             mixin(case_TOKs_MemberFunctionAttribute); // no member attributes?
866                 {
867                     auto type = p.topNode!(ast.Type);
868                     p.combineAttributes(type.attr, tokenToAttribute(p.tok.id));
869                     p.pushState(&shiftAttributes);
870                 }
871                 return Accept;
872             default:
873                 return Forward;
874         }
875     }
876 }
877 
878 //-- GRAMMAR_BEGIN --
879 //BasicTypes2:
880 //    BasicType2
881 //    BasicType2 BasicTypes2
882 class BasicTypes2
883 {
884     static Action enter(Parser p)
885     {
886         assert(p.topNode!(ast.Type));
887         switch(p.tok.id)
888         {
889             mixin(BasicType2.case_TOKs);
890                 p.pushState(&shiftBasicType);
891                 return BasicType2.enter(p);
892             default:
893                 return p.parseError("unexpected token in BasicType2");
894         }
895     }
896 
897     static Action shiftBasicType(Parser p)
898     {
899         switch(p.tok.id)
900         {
901             mixin(BasicType2.case_TOKs);
902                 p.pushState(&shiftBasicType);
903                 return BasicType2.enter(p);
904             default:
905                 return Forward;
906         }
907     }
908 }
909 
910 //-- GRAMMAR_BEGIN --
911 //DeclaratorSuffixes:
912 //    DeclaratorSuffix
913 //    DeclaratorSuffix DeclaratorSuffixes
914 //
915 // obsolete C-style?
916 //DeclaratorSuffix:
917 //    TemplateParameterList_opt Parameters MemberFunctionAttributes_opt Constraint_opt
918 //    [ ]
919 //    [ AssignExpression ]
920 //    [ Type ]
921 class DeclaratorSuffixes
922 {
923     static Action enter(Parser p)
924     {
925         switch(p.tok.id)
926         {
927             case TOK_lparen:
928                 p.pushRollback(&rollbackParametersFailure);
929                 p.pushState(&shiftParameters);
930                 return Parameters.enter(p);
931             case TOK_lbracket:
932                 p.pushState(&shiftLbracket);
933                 return Accept;
934             default:
935                 return p.parseError("opening parenthesis or bracket expected");
936         }
937     }
938 
939     static Action nextSuffix(Parser p)
940     {
941         switch(p.tok.id)
942         {
943             case TOK_lbracket:
944                 p.pushState(&shiftLbracket);
945                 return Accept;
946             default:
947                 return Forward;
948         }
949     }
950 
951     static Action shiftLbracket(Parser p)
952     {
953         switch(p.tok.id)
954         {
955             case TOK_rbracket:
956                 p.topNode().addMember(new ast.SuffixDynamicArray(p.tok));
957                 p.pushState(&nextSuffix);
958                 return Accept;
959             default:
960                 p.pushState(&shiftTypeOrExpression);
961                 return TypeOrExpression!(TOK_rbracket).enter(p);
962         }
963         // return p.notImplementedError("C style declarators");
964     }
965 
966     static Action shiftTypeOrExpression(Parser p)
967     {
968         switch(p.tok.id)
969         {
970             case TOK_rbracket:
971                 auto node = p.popNode();
972                 ast.Node n = new ast.SuffixArray(p.tok);
973                 n.addMember(node);
974                 p.topNode().addMember(n);
975                 p.pushState(&nextSuffix);
976                 return Accept;
977             default:
978                 return p.parseError("']' expected in C style declarator");
979         }
980     }
981 
982     static Action shiftParameters(Parser p)
983     {
984         switch(p.tok.id)
985         {
986             case TOK_lparen:
987                 // somehow made it through the parameters, but another parameters list follow...
988                 return Reject; // so rollback to retry with template parameter list
989 
990             mixin(case_TOKs_MemberFunctionAttribute);
991                 p.popRollback();
992                 auto param = p.topNode!(ast.ParameterList);
993                 p.combineAttributes(param.attr, tokenToAttribute(p.tok.id));
994                 p.pushState(&shiftMemberFunctionAttribute);
995                 return Accept;
996             case TOK_if:
997                 p.popRollback();
998                 p.popAppendTopNode!(ast.Declarator, ast.ParameterList)();
999                 p.pushState(&shiftConstraint);
1000                 return Constraint.enter(p);
1001             default:
1002                 p.popRollback();
1003                 p.popAppendTopNode!(ast.Declarator, ast.ParameterList)();
1004                 return Forward;
1005         }
1006     }
1007 
1008     static Action shiftMemberFunctionAttribute(Parser p)
1009     {
1010         switch(p.tok.id)
1011         {
1012             mixin(case_TOKs_MemberFunctionAttribute);
1013                 {
1014                     auto param = p.topNode!(ast.ParameterList);
1015                     p.combineAttributes(param.attr, tokenToAttribute(p.tok.id));
1016                     p.pushState(&shiftMemberFunctionAttribute);
1017                 }
1018                 return Accept;
1019             case TOK_if:
1020                 p.popAppendTopNode!(ast.Declarator, ast.ParameterList)();
1021                 p.pushState(&shiftConstraint);
1022                 return Constraint.enter(p);
1023             default:
1024                 p.popAppendTopNode!(ast.Declarator, ast.ParameterList)();
1025                 return Forward;
1026         }
1027     }
1028 
1029     static Action shiftConstraint(Parser p)
1030     {
1031         p.popAppendTopNode!(ast.Declarator, ast.Constraint)();
1032         return Forward;
1033     }
1034 
1035     static Action rollbackParametersFailure(Parser p)
1036     {
1037         p.pushState(&shiftTemplateParameterList);
1038         return TemplateParameters.enter(p);
1039     }
1040 
1041     static Action shiftTemplateParameterList(Parser p)
1042     {
1043         p.popAppendTopNode(); // append to declarator
1044         switch(p.tok.id)
1045         {
1046             case TOK_lparen:
1047                 p.pushState(&shiftParametersAfterTempl);
1048                 return Parameters.enter(p);
1049             default:
1050                 return p.parseError("parameter list expected after template arguments");
1051         }
1052     }
1053 
1054     static Action shiftParametersAfterTempl(Parser p)
1055     {
1056         return shiftMemberFunctionAttribute(p);
1057     }
1058 }
1059 
1060 //-- GRAMMAR_BEGIN --
1061 //GlobalIdentifierList:
1062 //    IdentifierList
1063 //    . IdentifierList
1064 class GlobalIdentifierList
1065 {
1066     static Action enter(Parser p)
1067     {
1068         switch(p.tok.id)
1069         {
1070             case TOK_dot:
1071                 return IdentifierList.enterGlobal(p);
1072             default:
1073                 return IdentifierList.enter(p);
1074         }
1075     }
1076 
1077 }
1078 
1079 //-- GRAMMAR_BEGIN --
1080 //IdentifierList:
1081 //    Identifier
1082 //    Identifier . IdentifierList
1083 //    TemplateInstance
1084 //    TemplateInstance . IdentifierList
1085 //
1086 // using IdentifierOrTemplateInstance
1087 class IdentifierList
1088 {
1089     mixin ListNode!(ast.IdentifierList, IdentifierOrTemplateInstance, TOK_dot);
1090 
1091     // if preceded by '.', enter here fore global scope
1092     static Action enterGlobal(Parser p)
1093     {
1094         assert(p.tok.id == TOK_dot);
1095 
1096         auto list = new ast.IdentifierList(p.tok);
1097         list.global = true;
1098         p.pushNode(list);
1099         p.pushState(&shift);
1100         p.pushState(&IdentifierOrTemplateInstance.enter);
1101         return Accept;
1102     }
1103 
1104     // assumes identifier token on the info stack
1105     static Action enterAfterIdentifier(Parser p)
1106     {
1107         auto list = new ast.IdentifierList(p.topToken());
1108         p.pushNode(list);
1109         p.pushState(&shift);
1110         return IdentifierOrTemplateInstance.enterIdentifier(p);
1111     }
1112 }
1113 
1114 class Identifier
1115 {
1116     static Action enter(Parser p)
1117     {
1118         if(p.tok.id != TOK_Identifier)
1119             return p.parseError("identifier expected");
1120 
1121         p.pushNode(new ast.Identifier(p.tok));
1122         return Accept;
1123     }
1124 }
1125 
1126 //-- GRAMMAR_BEGIN --
1127 //StorageClasses:
1128 //    StorageClass
1129 //    StorageClass StorageClasses
1130 //
1131 //StorageClass:
1132 //    AttributeOrStorageClass
1133 //    extern
1134 //    nothrow
1135 //    pure
1136 //    synchronized
1137 bool isStorageClass(TokenId tok)
1138 {
1139     switch(tok)
1140     {
1141         case TOK_extern:
1142         case TOK_synchronized:
1143         mixin(case_TOKs_FunctionAttribute);
1144         mixin(case_TOKs_AttributeOrStorageClass);
1145             return true;
1146         default:
1147             return false;
1148     }
1149 }
1150 
1151 //-- GRAMMAR_BEGIN --
1152 //AttributeOrStorageClass:
1153 //    deprecated
1154 //    static
1155 //    final
1156 //    override
1157 //    abstract
1158 //    const
1159 //    auto
1160 //    scope
1161 //  __gshared
1162 //  __thread
1163 //    shared
1164 //    immutable
1165 //    inout
1166 //    ref
1167 enum case_TOKs_AttributeOrStorageClass = q{
1168         case TOK_deprecated:
1169         case TOK_static:
1170         case TOK_final:
1171         case TOK_override:
1172         case TOK_abstract:
1173         case TOK_const:
1174         case TOK_auto:
1175         case TOK_scope:
1176         case TOK_volatile:
1177         case TOK___gshared:
1178         case TOK___thread:
1179         case TOK_shared:
1180         case TOK_immutable:
1181         case TOK_inout:
1182         case TOK_ref:
1183 };
1184 bool isAttributeOrStorageClass(TokenId tok)
1185 {
1186     switch(tok)
1187     {
1188         mixin(case_TOKs_AttributeOrStorageClass);
1189             return true;
1190         default:
1191             return false;
1192     }
1193 }
1194 
1195 //-- GRAMMAR_BEGIN --
1196 //Type:
1197 //    BasicType
1198 //    BasicType Declarator2
1199 //
1200 //Declarator2:
1201 //    BasicType2 Declarator2
1202 //    ( Declarator2 )
1203 //    ( Declarator2 ) DeclaratorSuffixes
1204 //
1205 class Type
1206 {
1207     static Action enter(Parser p)
1208     {
1209         p.pushState(&shiftBasicType);
1210         return BasicType.enter(p);
1211     }
1212 
1213     static Action shiftBasicType(Parser p)
1214     {
1215         switch(p.tok.id)
1216         {
1217             mixin(BasicType2.case_TOKs);
1218                 p.pushState(&shiftBasicType);
1219                 return BasicType2.enter(p);
1220 
1221             case TOK_lparen:
1222 // not implemented, better forward, it might also be constructor arguments
1223 //                p.pushState(&shiftDeclarator2);
1224 //                return Accept;
1225 
1226             default:
1227                 return Forward;
1228         }
1229     }
1230 
1231     // entry point from EnumMember: Type Identifier = AssignExpression
1232     // and             ForeachType: ref_opt Type_opt Identifier
1233     // assumes identifier pushed onto token stack
1234     static Action enterIdentifier(Parser p)
1235     {
1236         p.pushState(&shiftBasicType);
1237         return BasicType.enterIdentifier(p);
1238     }
1239 
1240     // assumes modifier token on the info stack
1241     static Action enterTypeModifier(Parser p)
1242     {
1243         p.pushState(&shiftBasicType);
1244         return BasicType.shiftTypeModifier(p);
1245     }
1246 
1247     static Action shiftDeclarator2(Parser p)
1248     {
1249         return p.notImplementedError();
1250     }
1251 
1252 }
1253 
1254 //-- GRAMMAR_BEGIN --
1255 //TypeWithModifier:
1256 //    Type
1257 //    const TypeWithModifier
1258 //    immutable TypeWithModifier
1259 //    inout TypeWithModifier
1260 //    shared TypeWithModifier
1261 class TypeWithModifier
1262 {
1263     static Action enter(Parser p)
1264     {
1265         switch(p.tok.id)
1266         {
1267             case TOK_const:
1268             case TOK_immutable:
1269             case TOK_inout:
1270             case TOK_shared:
1271                 p.pushToken(p.tok);
1272                 p.pushState(&shiftModifier);
1273                 return Accept;
1274             default:
1275                 return Type.enter(p);
1276         }
1277     }
1278 
1279     static Action shiftModifier(Parser p)
1280     {
1281         switch(p.tok.id)
1282         {
1283             case TOK_lparen:
1284                 return Type.enterTypeModifier(p);
1285 
1286             default:
1287                 auto tok = p.popToken();
1288                 p.pushNode(new ast.ModifiedType(tok));
1289                 p.pushState(&shiftModifiedType);
1290                 return enter(p);
1291         }
1292     }
1293 
1294     static Action shiftModifiedType(Parser p)
1295     {
1296         p.popAppendTopNode!(ast.ModifiedType)();
1297         return Forward;
1298     }
1299 }
1300 
1301 //-- GRAMMAR_BEGIN --
1302 //Parameters:
1303 //    ( ParameterList )
1304 //    ( )
1305 class Parameters
1306 {
1307     static Action enter(Parser p)
1308     {
1309         switch(p.tok.id)
1310         {
1311             case TOK_lparen:
1312                 p.pushState(&shiftLparen);
1313                 return Accept;
1314             default:
1315                 return p.parseError("opening parenthesis expected in parameter list");
1316         }
1317     }
1318 
1319     static Action shiftLparen(Parser p)
1320     {
1321         if(p.tok.id == TOK_rparen)
1322         {
1323             p.pushNode(new ast.ParameterList(p.tok));
1324             return Accept;
1325         }
1326         p.pushState(&shiftParameterList);
1327         return ParameterList.enter(p);
1328     }
1329 
1330     static Action shiftParameterList(Parser p)
1331     {
1332         if(p.tok.id != TOK_rparen)
1333             return p.parseError("closing parenthesis expected for parameter list");
1334         return Accept;
1335     }
1336 }
1337 
1338 //-- GRAMMAR_BEGIN --
1339 //ParameterList:
1340 //    Parameter
1341 //    Parameter , ParameterList
1342 //    Parameter ...
1343 //    ...
1344 class ParameterList
1345 {
1346     static Action enter(Parser p)
1347     {
1348         p.pushNode(new ast.ParameterList(p.tok));
1349         return shift(p);
1350     }
1351 
1352     static Action shift(Parser p)
1353     {
1354         switch(p.tok.id)
1355         {
1356             case TOK_dotdotdot:
1357                 p.topNode!(ast.ParameterList)().anonymous_varargs = true;
1358                 return Accept;
1359             default:
1360                 p.pushState(&shiftParameter);
1361                 return Parameter.enter(p);
1362         }
1363     }
1364 
1365     static Action shiftParameter(Parser p)
1366     {
1367         p.popAppendTopNode!(ast.ParameterList)();
1368 
1369         switch(p.tok.id)
1370         {
1371             case TOK_dotdotdot:
1372                 p.topNode!(ast.ParameterList)().varargs = true;
1373                 return Accept;
1374             case TOK_comma:
1375                 p.pushState(&shift);
1376                 return Accept;
1377             default:
1378                 return Forward;
1379         }
1380     }
1381 }
1382 
1383 //-- GRAMMAR_BEGIN --
1384 ///* Declarator replaced with ParameterDeclarator */
1385 //Parameter:
1386 //    InOut_opt ParameterDeclarator DefaultInitializerExpression_opt
1387 //
1388 //DefaultInitializerExpression:
1389 //    = AssignExpression
1390 //    = __FILE__ // already in primary expression
1391 //    = __LINE__ // already in primary expression
1392 class Parameter
1393 {
1394     static Action enter(Parser p)
1395     {
1396         p.pushNode(new ast.Parameter(p.tok));
1397         p.pushState(&shiftParameterDeclarator);
1398 
1399         if(isInOut(p.tok.id))
1400         {
1401             p.topNode!(ast.Parameter)().io = p.tok.id;
1402             p.pushState(&ParameterDeclarator.enter);
1403             return Accept;
1404         }
1405         return ParameterDeclarator.enter(p);
1406     }
1407 
1408     static Action shiftParameterDeclarator(Parser p)
1409     {
1410         p.popAppendTopNode!(ast.Parameter)();
1411         if(p.tok.id != TOK_assign)
1412             return Forward;
1413         p.pushState(&shiftInitializer);
1414         p.pushState(&AssignExpression.enter);
1415         return Accept;
1416     }
1417 
1418     static Action shiftInitializer(Parser p)
1419     {
1420         p.popAppendTopNode!(ast.Parameter)();
1421         return Forward;
1422     }
1423 }
1424 
1425 //-- GRAMMAR_BEGIN --
1426 //ParameterDeclarator:
1427 //    StorageClasses_opt BasicType BasicTypes2_opt Declarator_opt
1428 // /*Identifier DeclaratorSuffixes_opt*/
1429 class ParameterDeclarator
1430 {
1431     // very similar to Decl, combine?
1432     // differences: no auto, single Declarator only
1433     static Action enter(Parser p)
1434     {
1435         auto decl = new ast.ParameterDeclarator(p.tok);
1436         p.pushNode(decl);
1437         return shift(p);
1438     }
1439 
1440     static Action shift(Parser p)
1441     {
1442         if(isTypeModifier(p.tok.id))
1443         {
1444             // could be storage class or BasicType
1445             p.pushToken(p.tok);
1446             p.pushState(&shiftTypeModifier);
1447             return Accept;
1448         }
1449         if(isStorageClass(p.tok.id))
1450         {
1451             auto decl = p.topNode!(ast.ParameterDeclarator)();
1452             p.combineAttributes(decl.attr, tokenToAttribute(p.tok.id));
1453             p.combineAnnotations(decl.annotation, tokenToAnnotation(p.tok.id));
1454             p.pushState(&shiftStorageClass);
1455             return Accept;
1456         }
1457         p.pushState(&shiftBasicType);
1458         return BasicType.enter(p);
1459     }
1460 
1461     // disambiguate "const x" and "const(int) x"
1462     // assumes modifier token on the info stack
1463     static Action shiftTypeModifier(Parser p)
1464     {
1465         if(p.tok.id == TOK_lparen)
1466         {
1467             p.pushState(&shiftBasicType);
1468             return BasicType.shiftTypeModifier(p);
1469         }
1470 
1471         auto decl = p.topNode!(ast.ParameterDeclarator)();
1472         Token tok = p.popToken();
1473         p.combineAttributes(decl.attr, tokenToAttribute(tok.id));
1474         return shift(p);
1475     }
1476 
1477     static Action shiftStorageClass(Parser p)
1478     {
1479         if(isTypeModifier(p.tok.id))
1480         {
1481             // could be storage class or BasicType
1482             p.pushToken(p.tok);
1483             p.pushState(&shiftTypeModifier);
1484             return Accept;
1485         }
1486         if(isStorageClass(p.tok.id))
1487         {
1488             auto decl = p.topNode!(ast.ParameterDeclarator)();
1489             p.combineAttributes(decl.attr, tokenToAttribute(p.tok.id));
1490             p.combineAnnotations(decl.annotation, tokenToAnnotation(p.tok.id));
1491             p.pushState(&shiftStorageClass);
1492             return Accept;
1493         }
1494         p.pushState(&shiftBasicType);
1495         return BasicType.enter(p);
1496     }
1497 
1498     // switch here from TemplateValueParameter when detecting a declaration after an identifier
1499     // assumes identifier token on the info stack
1500     static Action enterTypeIdentifier(Parser p)
1501     {
1502         auto decl = new ast.ParameterDeclarator(p.tok);
1503         p.pushNode(decl);
1504 
1505         p.pushState(&shiftBasicType);
1506         return BasicType.enterIdentifier(p);
1507     }
1508 
1509     static Action shiftBasicType(Parser p)
1510     {
1511         switch(p.tok.id)
1512         {
1513             mixin(BasicType2.case_TOKs);
1514                 p.pushState(&shiftBasicTypes2);
1515                 return BasicTypes2.enter(p);
1516             default:
1517                 return shiftBasicTypes2(p);
1518         }
1519     }
1520 
1521     static Action shiftBasicTypes2(Parser p)
1522     {
1523         p.popAppendTopNode!(ast.ParameterDeclarator, ast.Type)();
1524         if(p.tok.id != TOK_Identifier)
1525             return Forward;
1526         p.pushState(&shiftDeclarator);
1527         return Declarator.enter(p);
1528     }
1529 
1530     static Action shiftDeclarator(Parser p)
1531     {
1532         p.popAppendTopNode!(ast.ParameterDeclarator)();
1533         return Forward;
1534     }
1535 
1536 }
1537 
1538 //-- GRAMMAR_BEGIN --
1539 //InOut:
1540 //    in
1541 //    out
1542 //    ref
1543 //    lazy
1544 //    scope /* ? */
1545 enum case_TOKs_InOut = q{
1546         case TOK_in:
1547         case TOK_out:
1548         case TOK_ref:
1549         case TOK_lazy:
1550         case TOK_scope:
1551 };
1552 bool isInOut(TokenId tok)
1553 {
1554     switch(tok)
1555     {
1556         mixin(case_TOKs_InOut);
1557             return true;
1558         default:
1559             return false;
1560     }
1561 }
1562 
1563 //-- GRAMMAR_BEGIN --
1564 //FunctionAttributes:
1565 //    FunctionAttribute
1566 //    FunctionAttribute FunctionAttributes
1567 //
1568 //FunctionAttribute:
1569 //    nothrow
1570 //    pure
1571 enum case_TOKs_FunctionAttribute = q{
1572         case TOK_nothrow:
1573         case TOK_pure:
1574         case TOK_safe:
1575         case TOK_system:
1576         case TOK_trusted:
1577         case TOK_property:
1578         case TOK_disable:
1579         case TOK_nogc:
1580 };
1581 
1582 bool isFunctionAttribute(TokenId tok)
1583 {
1584     switch(tok)
1585     {
1586         mixin(case_TOKs_FunctionAttribute);
1587             return true;
1588         default:
1589             return false;
1590     }
1591 }
1592 
1593 //-- GRAMMAR_BEGIN --
1594 //MemberFunctionAttributes:
1595 //    MemberFunctionAttribute
1596 //    MemberFunctionAttribute MemberFunctionAttributes
1597 //
1598 //MemberFunctionAttribute:
1599 //    const
1600 //    immutable
1601 //    inout
1602 //    shared
1603 //    FunctionAttribute
1604 //
1605 enum case_TOKs_MemberFunctionAttribute = q{
1606         case TOK_const:
1607         case TOK_immutable:
1608         case TOK_inout:
1609         case TOK_shared:
1610 } ~ case_TOKs_FunctionAttribute;
1611 
1612 bool isMemberFunctionAttribute(TokenId tok)
1613 {
1614     switch(tok)
1615     {
1616         mixin(case_TOKs_MemberFunctionAttribute);
1617             return true;
1618         default:
1619             return false;
1620     }
1621 }