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.expr;
10 
11 import vdc.util;
12 import vdc.lexer;
13 import vdc.parser.engine;
14 import vdc.parser.decl;
15 import vdc.parser.tmpl;
16 import vdc.parser.misc;
17 import vdc.parser.aggr;
18 import ast = vdc.ast.all;
19 
20 alias ast.PREC PREC;
21 
22 ////////////////////////////////////////////////////////////////
23 //-- GRAMMAR_BEGIN --
24 //Expression:
25 //    CommaExpression
26 class Expression
27 {
28     static Action enter(Parser p)
29     {
30         return CommaExpression.enter(p);
31     }
32 }
33 
34 class BinaryExpression : Expression
35 {
36 }
37 
38 mixin template BinaryExpr(ASTNodeType, PREC prec, string recursion, SubType, ops...)
39 {
40     shared static this()
41     {
42         foreach(o; ops)
43         {
44             ast.precedence[o] = prec;
45             ast.recursion[o] = recursion[0];
46         }
47     }
48 
49     mixin BinaryNode!(ASTNodeType, recursion, SubType, ops);
50 }
51 
52 //-- GRAMMAR_BEGIN --
53 //CommaExpression:
54 //    AssignExpression
55 //    AssignExpression , CommaExpression
56 class CommaExpression : BinaryExpression
57 {
58     mixin BinaryExpr!(ast.CommaExpression, PREC.expr, "R", AssignExpression, TOK_comma);
59 }
60 
61 //-- GRAMMAR_BEGIN --
62 //AssignExpression:
63 //    ConditionalExpression
64 //    ConditionalExpression = AssignExpression
65 //    ConditionalExpression += AssignExpression
66 //    ConditionalExpression -= AssignExpression
67 //    ConditionalExpression *= AssignExpression
68 //    ConditionalExpression /= AssignExpression
69 //    ConditionalExpression %= AssignExpression
70 //    ConditionalExpression &= AssignExpression
71 //    ConditionalExpression |= AssignExpression
72 //    ConditionalExpression ^= AssignExpression
73 //    ConditionalExpression ~= AssignExpression
74 //    ConditionalExpression <<= AssignExpression
75 //    ConditionalExpression >>= AssignExpression
76 //    ConditionalExpression >>>= AssignExpression
77 //    ConditionalExpression ^^= AssignExpression
78 class AssignExpression : BinaryExpression
79 {
80     mixin BinaryExpr!(ast.AssignExpression, PREC.assign, "R", ConditionalExpression,
81                       TOK_assign, TOK_addass, TOK_minass, TOK_mulass, TOK_divass, TOK_modass,
82                       TOK_andass, TOK_orass, TOK_xorass, TOK_catass, TOK_shlass, TOK_shrass,
83                       TOK_ushrass, TOK_powass);
84 }
85 
86 //-- GRAMMAR_BEGIN --
87 //ConditionalExpression:
88 //    OrOrExpression
89 //    OrOrExpression ? Expression : ConditionalExpression
90 class ConditionalExpression : Expression
91 {
92     mixin TernaryNode!(ast.ConditionalExpression, OrOrExpression, TOK_question, Expression, TOK_colon);
93 }
94 
95 //-- GRAMMAR_BEGIN --
96 //OrOrExpression:
97 //    AndAndExpression
98 //    OrOrExpression || AndAndExpression
99 class OrOrExpression : BinaryExpression
100 {
101     mixin BinaryExpr!(ast.OrOrExpression, PREC.oror, "L", AndAndExpression, TOK_oror);
102 }
103 
104 //-- GRAMMAR_BEGIN --
105 //AndAndExpression:
106 //    OrExpression
107 //    AndAndExpression && OrExpression
108 class AndAndExpression : BinaryExpression
109 {
110     mixin BinaryExpr!(ast.AndAndExpression, PREC.andand, "L", OrExpression, TOK_andand);
111 }
112 
113 //-- GRAMMAR_BEGIN --
114 //OrExpression:
115 //    XorExpression
116 //    OrExpression | XorExpression
117 class OrExpression : BinaryExpression
118 {
119     mixin BinaryExpr!(ast.OrExpression, PREC.or, "L", XorExpression, TOK_or);
120 }
121 
122 //-- GRAMMAR_BEGIN --
123 //XorExpression:
124 //    AndExpression
125 //    XorExpression ^ AndExpression
126 class XorExpression : BinaryExpression
127 {
128     mixin BinaryExpr!(ast.XorExpression, PREC.xor, "L", AndExpression, TOK_xor);
129 }
130 
131 //-- GRAMMAR_BEGIN --
132 //AndExpression:
133 //    CmpExpression
134 //    AndExpression & CmpExpression
135 class AndExpression : BinaryExpression
136 {
137     mixin BinaryExpr!(ast.AndExpression, PREC.and, "L", CmpExpression, TOK_and);
138 }
139 
140 //-- GRAMMAR_BEGIN --
141 //CmpExpression:
142 //    ShiftExpression
143 //    EqualExpression
144 //    IdentityExpression
145 //    RelExpression
146 //    InExpression
147 //
148 //EqualExpression:
149 //    ShiftExpression == ShiftExpression
150 //    ShiftExpression != ShiftExpression
151 //
152 //IdentityExpression:
153 //    ShiftExpression is ShiftExpression
154 //    ShiftExpression !is ShiftExpression
155 //
156 //RelExpression:
157 //    ShiftExpression < ShiftExpression
158 //    ShiftExpression <= ShiftExpression
159 //    ShiftExpression > ShiftExpression
160 //    ShiftExpression >= ShiftExpression
161 //    ShiftExpression !<>= ShiftExpression
162 //    ShiftExpression !<> ShiftExpression
163 //    ShiftExpression <> ShiftExpression
164 //    ShiftExpression <>= ShiftExpression
165 //    ShiftExpression !> ShiftExpression
166 //    ShiftExpression !>= ShiftExpression
167 //    ShiftExpression !< ShiftExpression
168 //    ShiftExpression !<= ShiftExpression
169 //
170 //InExpression:
171 //    ShiftExpression in ShiftExpression
172 //    ShiftExpression !in ShiftExpression
173 class CmpExpression : BinaryExpression
174 {
175     static if(!supportUnorderedCompareOps)
176         mixin BinaryExpr!(ast.CmpExpression, PREC.rel, "N", ShiftExpression,
177                           TOK_equal, TOK_notequal, TOK_is, TOK_notidentity,
178                           TOK_lt, TOK_le, TOK_gt, TOK_ge,
179                           // TOK_unord, TOK_ue, TOK_lg, TOK_leg, TOK_ule, TOK_ul, TOK_uge, TOK_ug,
180                           TOK_in, TOK_notcontains);
181     else
182         mixin BinaryExpr!(ast.CmpExpression, PREC.rel, "N", ShiftExpression,
183                           TOK_equal, TOK_notequal, TOK_is, TOK_notidentity,
184                           TOK_lt, TOK_le, TOK_gt, TOK_ge,
185                           // TOK_unord, TOK_ue, TOK_lg, TOK_leg, TOK_ule, TOK_ul, TOK_uge, TOK_ug,
186                           TOK_in, TOK_notcontains);
187 }
188 
189 //-- GRAMMAR_BEGIN --
190 //ShiftExpression:
191 //    AddExpression
192 //    ShiftExpression << AddExpression
193 //    ShiftExpression >> AddExpression
194 //    ShiftExpression >>> AddExpression
195 class ShiftExpression : BinaryExpression
196 {
197     mixin BinaryExpr!(ast.ShiftExpression, PREC.shift, "L", AddExpression, TOK_shl, TOK_shr, TOK_ushr);
198 }
199 
200 //-- GRAMMAR_BEGIN --
201 //AddExpression:
202 //    MulExpression
203 //    AddExpression + MulExpression
204 //    AddExpression - MulExpression
205 //    CatExpression:
206 //CatExpression:
207 //    AddExpression ~ MulExpression
208 class AddExpression : BinaryExpression
209 {
210     mixin BinaryExpr!(ast.AddExpression, PREC.add, "L", MulExpression, TOK_add, TOK_min, TOK_tilde);
211 }
212 
213 //-- GRAMMAR_BEGIN --
214 //MulExpression:
215 //    SignExpression
216 //    MulExpression * SignExpression
217 //    MulExpression / SignExpression
218 //    MulExpression % SignExpression
219 class MulExpression : BinaryExpression
220 {
221     mixin BinaryExpr!(ast.MulExpression, PREC.mul, "L", SignExpression, TOK_mul, TOK_div, TOK_mod);
222 }
223 
224 //-- GRAMMAR_BEGIN --
225 //SignExpression:
226 //    PowExpression
227 //    + SignExpression
228 //    - SignExpression
229 class SignExpression : Expression
230 {
231     static Action enter(Parser p)
232     {
233         switch(p.tok.id)
234         {
235             case TOK_min:
236             case TOK_add:
237                 auto expr = new ast.UnaryExpression(p.tok);
238                 p.pushNode(expr);
239                 p.pushState(&shift);
240                 p.pushState(&enter);
241                 return Accept;
242             default:
243                 return PowExpression.enter(p);
244         }
245     }
246 
247     static Action shift(Parser p)
248     {
249         p.popAppendTopNode!(ast.UnaryExpression)();
250         return Forward;
251     }
252 }
253 
254 //-- GRAMMAR_BEGIN --
255 //PowExpression:
256 //    UnaryExpression
257 //    UnaryExpression ^^ SignExpression
258 class PowExpression : BinaryExpression
259 {
260     static Action shiftExponent(Parser p)
261     {
262         p.popAppendTopNode!(ast.PowExpression)();
263         return Forward;
264     }
265 
266     static Action shiftPow(Parser p)
267     {
268         switch(p.tok.id)
269         {
270             case TOK_pow:
271                 auto pe = new ast.PowExpression(p.tok);
272                 p.appendReplaceTopNode(pe);
273                 p.pushState(&shiftExponent);
274                 p.pushState(&SignExpression.enter);
275                 return Accept;
276             default:
277                 return Forward;
278         }
279     }
280     mixin stateEnterClass!(UnaryExpression, NoASTNode, shiftPow);
281 }
282 
283 //-- GRAMMAR_BEGIN --
284 //UnaryExpression:
285 //    PostfixExpression
286 //    & UnaryExpression
287 //    ++ UnaryExpression
288 //    -- UnaryExpression
289 //    * UnaryExpression
290 //    - UnaryExpression
291 //    + UnaryExpression
292 //    ! UnaryExpression
293 //    ~ UnaryExpression
294 //    NewExpression
295 //    DeleteExpression
296 //    CastExpression
297 //    /*NewAnonClassExpression*/
298 //
299 // DeleteExpression:
300 //     delete UnaryExpression
301 class UnaryExpression : Expression
302 {
303     static Action enter(Parser p)
304     {
305         switch(p.tok.id)
306         {
307             case TOK_and:
308             case TOK_plusplus:
309             case TOK_minusminus:
310             case TOK_mul:
311             case TOK_min:
312             case TOK_add:
313             case TOK_not:
314             case TOK_tilde:
315             case TOK_delete:
316                 auto expr = new ast.UnaryExpression(p.tok);
317                 p.pushNode(expr);
318                 p.pushState(&shift);
319                 p.pushState(&enter);
320                 return Accept;
321             case TOK_new:
322                 return NewExpression.enter(p);
323             case TOK_cast:
324                 return CastExpression.enter(p);
325             default:
326                 return PostfixExpression.enter(p);
327         }
328     }
329 
330     static Action shift(Parser p)
331     {
332         p.popAppendTopNode!(ast.UnaryExpression)();
333         return Forward;
334     }
335 }
336 
337 //-- GRAMMAR_BEGIN --
338 //NewExpression:
339 //    NewArguments Type [ AssignExpression ]
340 //    NewArguments Type ( ArgumentList )
341 //    NewArguments Type
342 //    NewArguments ClassArguments BaseClassList_opt { DeclDefs_opt }
343 //
344 //NewArguments:
345 //    new ( ArgumentList )
346 //    new ( )
347 //    new
348 //
349 //ClassArguments:
350 //    class ( ArgumentList )
351 //    class ( )
352 //    class
353 class NewExpression : UnaryExpression
354 {
355     static Action enter(Parser p)
356     {
357         p.pushNode(new ast.NewExpression(p.tok));
358         switch(p.tok.id)
359         {
360             case TOK_new:
361                 p.pushState(&shiftNew);
362                 return Accept;
363             default:
364                 return p.parseError("new expected");
365         }
366     }
367 
368     static Action shiftNew(Parser p)
369     {
370         switch(p.tok.id)
371         {
372             case TOK_lparen:
373                 p.pushState(&shiftNewLparen);
374                 return Accept;
375             case TOK_class:
376                 p.pushState(&shiftClass);
377                 return AnonymousClass.enter(p);
378             default:
379                 p.pushState(&shiftType);
380                 return Type.enter(p);
381         }
382     }
383 
384     static Action shiftType(Parser p)
385     {
386         p.popAppendTopNode!(ast.NewExpression);
387         switch(p.tok.id)
388         {
389             // [] are parsed as part of the type
390             case TOK_lparen:
391                 p.pushState(&shiftTypeLparen);
392                 return Accept;
393             default:
394                 return Forward;
395         }
396     }
397 
398     static Action shiftTypeLparen(Parser p)
399     {
400         switch(p.tok.id)
401         {
402             case TOK_rparen:
403                 return Accept; // empty argument list as good as none
404             default:
405                 p.pushState(&shiftArgumentList);
406                 return ArgumentList.enter(p);
407         }
408     }
409     static Action shiftArgumentList(Parser p)
410     {
411         switch(p.tok.id)
412         {
413             // [] are parsed as part of the type
414             case TOK_rparen:
415                 p.popAppendTopNode!(ast.NewExpression);
416                 return Accept;
417             default:
418                 return p.parseError("')' expected");
419         }
420     }
421 
422     static Action shiftNewLparen(Parser p)
423     {
424         p.pushState(&shiftNewArgumentList);
425         return ArgumentList.enter(p);
426     }
427 
428     static Action shiftNewArgumentList(Parser p)
429     {
430         p.popAppendTopNode!(ast.NewExpression);
431         p.topNode!(ast.NewExpression).hasNewArgs = true;
432 
433         switch(p.tok.id)
434         {
435             case TOK_rparen:
436                 p.pushState(&shiftRparen);
437                 return Accept;
438             default:
439                 return p.parseError("')' expected for new argument list");
440         }
441     }
442 
443     static Action shiftRparen(Parser p)
444     {
445         switch(p.tok.id)
446         {
447             case TOK_class:
448                 p.pushState(&shiftClass);
449                 return AnonymousClass.enter(p);
450             default:
451                 p.pushState(&shiftType);
452                 return Type.enter(p);
453         }
454     }
455 
456     static Action shiftClass(Parser p)
457     {
458         p.popAppendTopNode!(ast.NewExpression);
459         return Forward;
460     }
461 }
462 
463 //-- GRAMMAR_BEGIN --
464 // AnonymousClass:
465 //     ClassArguments BaseClassList_opt { DeclDefs_opt }
466 class AnonymousClass
467 {
468     static Action enter(Parser p)
469     {
470         switch(p.tok.id)
471         {
472             case TOK_class:
473                 p.pushNode(new ast.AnonymousClassType(p.tok));
474                 p.pushState(&shiftClass);
475                 return Accept;
476             default:
477                 return p.parseError("class expected");
478         }
479     }
480     static Action shiftClass(Parser p)
481     {
482         switch(p.tok.id)
483         {
484             case TOK_lparen:
485                 p.pushState(&shiftLparen);
486                 return Accept;
487             default:
488                 p.pushState(&shiftClassDeclaration);
489                 return AggregateDeclaration.enterAnonymousClass(p);
490         }
491     }
492 
493     static Action shiftLparen(Parser p)
494     {
495         switch(p.tok.id)
496         {
497             case TOK_rparen:
498                 p.topNode!(ast.AnonymousClassType).addMember(new ast.ArgumentList(p.tok));
499                 p.pushState(&shiftClassDeclaration);
500                 p.pushState(&AggregateDeclaration.enterAnonymousClass);
501                 return Accept;
502             default:
503                 p.pushState(&shiftArgumentList);
504                 return ArgumentList.enter(p);
505         }
506     }
507 
508     static Action shiftClassDeclaration(Parser p)
509     {
510         p.popAppendTopNode!(ast.AnonymousClassType);
511         return Forward;
512     }
513 
514     static Action shiftArgumentList(Parser p)
515     {
516         switch(p.tok.id)
517         {
518             case TOK_rparen:
519                 p.popAppendTopNode!(ast.AnonymousClassType);
520                 p.pushState(&shiftClassDeclaration);
521                 p.pushState(&AggregateDeclaration.enterAnonymousClass);
522                 return Accept;
523             default:
524                 return p.parseError("')' expected");
525         }
526     }
527 }
528 
529 //-- GRAMMAR_BEGIN --
530 //CastExpression:
531 //    cast ( Type )         UnaryExpression
532 //    cast ( )              UnaryExpression
533 //    cast ( const )        UnaryExpression
534 //    cast ( const shared ) UnaryExpression
535 //    cast ( immutable )    UnaryExpression
536 //    cast ( inout )        UnaryExpression
537 //    cast ( inout shared ) UnaryExpression
538 //    cast ( shared )       UnaryExpression
539 //    cast ( shared const ) UnaryExpression
540 //    cast ( shared inout ) UnaryExpression
541 class CastExpression : UnaryExpression
542 {
543     mixin stateAppendClass!(UnaryExpression, Parser.forward) stateExpression;
544 
545     static Action shiftType(Parser p)
546     {
547         p.popAppendTopNode!(ast.CastExpression)();
548         switch(p.tok.id)
549         {
550             case TOK_rparen:
551                 p.pushState(&stateExpression.shift);
552                 return Accept;
553             default:
554                 return p.parseError("')' expected");
555         }
556     }
557 
558     mixin stateShiftToken!(TOK_rparen, stateExpression.shift) stateRparen;
559 
560     static Action shiftModifier(Parser p)
561     {
562         Token tok;
563         switch(p.tok.id)
564         {
565             case TOK_rparen:
566                 tok = p.popToken();
567                 p.topNode!(ast.CastExpression)().attr = tokenToAttribute(tok.id);
568                 p.pushState(&stateExpression.shift);
569                 return Accept;
570 
571             case TOK_const:
572             case TOK_inout:
573                 tok = p.topToken();
574                 if(tok.id != TOK_shared)
575                     goto default;
576             L_combineAttr:
577                 tok = p.popToken();
578                 auto attr = tokenToAttribute(tok.id);
579                 p.combineAttributes(attr, tokenToAttribute(p.tok.id));
580                 p.topNode!(ast.CastExpression)().attr = attr;
581                 p.pushState(&stateRparen.shift);
582                 return Accept;
583 
584             case TOK_shared:
585                 tok = p.topToken();
586                 if(tok.id != TOK_inout && tok.id != TOK_const)
587                     goto default;
588                 goto L_combineAttr;
589 
590             default:
591                 p.pushState(&shiftType);
592                 return Type.enterTypeModifier(p);
593         }
594     }
595 
596     static Action stateType(Parser p)
597     {
598         switch(p.tok.id)
599         {
600             case TOK_rparen:
601                 p.pushState(&stateExpression.shift);
602                 return Accept;
603             case TOK_const:
604             case TOK_immutable:
605             case TOK_inout:
606             case TOK_shared:
607                 p.pushToken(p.tok);
608                 p.pushState(&shiftModifier);
609                 return Accept;
610             default:
611                 p.pushState(&shiftType);
612                 return Type.enter(p);
613         }
614     }
615 
616     mixin stateShiftToken!(TOK_lparen, stateType) stateLparen;
617 
618     mixin stateEnterToken!(TOK_cast, ast.CastExpression, stateLparen.shift);
619 }
620 
621 //-- GRAMMAR_BEGIN --
622 //PostfixExpression:
623 //    PrimaryExpression
624 //    PostfixExpression . IdentifierOrTemplateInstance
625 //    PostfixExpression . NewExpression
626 //    PostfixExpression ++
627 //    PostfixExpression --
628 //    PostfixExpression ( )
629 //    PostfixExpression ( ArgumentList )
630 //    IndexExpression
631 //    SliceExpression
632 //
633 //IndexExpression:
634 //    PostfixExpression [ ArgumentList ]
635 //
636 //SliceExpression:
637 //    PostfixExpression [ ]
638 //    PostfixExpression [ AssignExpression .. AssignExpression ]
639 class PostfixExpression : Expression
640 {
641     static Action enter(Parser p)
642     {
643         p.pushState(&shift);
644         return PrimaryExpression.enter(p);
645     }
646 
647     static Action shift(Parser p)
648     {
649         switch(p.tok.id)
650         {
651             case TOK_plusplus:
652             case TOK_minusminus:
653                 p.appendReplaceTopNode(new ast.PostfixExpression(p.tok));
654                 return Accept;
655 
656             case TOK_dot:
657                 p.pushState(&shiftDot);
658                 p.appendReplaceTopNode(new ast.DotExpression(p.tok));
659                 return Accept;
660 
661             case TOK_lparen:
662                 p.pushState(&shiftLParen);
663                 p.appendReplaceTopNode(new ast.PostfixExpression(p.tok));
664                 return Accept;
665 
666             case TOK_lbracket:
667                 p.pushState(&shiftLBracket);
668                 p.appendReplaceTopNode(new ast.PostfixExpression(p.tok));
669                 return Accept;
670 
671             default:
672                 return Forward;
673         }
674     }
675 
676     static Action shiftDot(Parser p)
677     {
678         switch(p.tok.id)
679         {
680             case TOK_Identifier:
681                 auto expr = p.topNode!(ast.DotExpression)();
682                 expr.id = TOK_dot;
683                 p.pushState(&shiftIdentifierOrTemplateInstance);
684                 return IdentifierOrTemplateInstance.enter(p);
685 
686             case TOK_RECOVER:
687                 auto expr = p.topNode!(ast.DotExpression)();
688                 expr.id = TOK_dot;
689                 auto id = new ast.Identifier(p.tok);
690                 expr.addMember(id);
691                 return Forward;
692 
693             case TOK_new:
694                 p.pushState(&shiftNewExpression);
695                 return NewExpression.enter(p);
696 
697             default:
698                 return p.parseError("identifier or new expected after '.'");
699         }
700     }
701 
702     static Action shiftIdentifierOrTemplateInstance(Parser p)
703     {
704         p.popAppendTopNode!(ast.PostfixExpression, ast.Identifier)();
705         return shift(p);
706     }
707 
708     static Action shiftLParen(Parser p)
709     {
710         if(p.tok.id == TOK_rparen)
711         {
712             p.pushState(&shift);
713             return Accept;
714         }
715 
716         p.pushState(&shiftRParen);
717         return ArgumentList.enter(p); // ArgumentList also starts with AssignExpression
718     }
719 
720     static Action shiftRParen(Parser p)
721     {
722         if(p.tok.id != TOK_rparen)
723             return p.parseError("closing parenthesis expected");
724 
725         p.popAppendTopNode!(ast.PostfixExpression)();
726         p.pushState(&shift);
727         return Accept;
728     }
729 
730     static Action shiftLBracket(Parser p)
731     {
732         if(p.tok.id == TOK_rbracket)
733         {
734             p.pushState(&shift);
735             return Accept;
736         }
737 
738         p.pushState(&shiftRBracket);
739         return ArgumentList.enter(p);
740     }
741 
742     static Action shiftRBracket(Parser p)
743     {
744         if(p.tok.id == TOK_slice)
745         {
746             // throw away the argument list, just use the expression
747             ast.Node arglist = p.popNode();
748             if (arglist.members.length != 1)
749                 return p.parseError("a single expression is expected before ..");
750 
751             p.topNode().addMember(arglist.removeMember(0));
752             p.pushState(&shiftSlice);
753             p.pushState(&AssignExpression.enter);
754             return Accept;
755         }
756         else if(p.tok.id != TOK_rbracket)
757             return p.parseError("closing bracket or .. expected");
758 
759         p.popAppendTopNode!(ast.PostfixExpression)();
760         p.pushState(&shift);
761         return Accept;
762     }
763 
764     static Action shiftSlice(Parser p)
765     {
766         if(p.tok.id != TOK_rbracket)
767             return p.parseError("closing bracket expected");
768 
769         p.popAppendTopNode!(ast.PostfixExpression)();
770         p.pushState(&shift);
771         return Accept;
772     }
773 
774     static Action shiftNewExpression(Parser p)
775     {
776         p.popAppendTopNode!(ast.PostfixExpression)();
777         auto expr = p.topNode!(ast.PostfixExpression)();
778         expr.id = TOK_new;
779         return Forward;
780     }
781 }
782 
783 //-- GRAMMAR_BEGIN --
784 //ArgumentList:
785 //    AssignExpression
786 //    AssignExpression ,
787 //    AssignExpression , ArgumentList
788 class ArgumentList
789 {
790     mixin ListNode!(ast.ArgumentList, AssignExpression, TOK_comma, true);
791 }
792 
793 //-- GRAMMAR_BEGIN --
794 //Arguments:
795 //    ( )
796 //    ( ArgumentList )
797 class Arguments
798 {
799     mixin SequenceNode!(NoASTNode, TOK_lparen, EmptyArgumentList, TOK_rparen);
800 }
801 
802 class EmptyArgumentList
803 {
804     mixin ListNode!(ast.ArgumentList, AssignExpression, TOK_comma, false, true);
805 }
806 
807 //-- GRAMMAR_BEGIN --
808 //PrimaryExpression:
809 //    IdentifierOrTemplateInstance
810 //    . IdentifierOrTemplateInstance
811 //    this
812 //    super
813 //    null
814 //    true
815 //    false
816 //    $
817 //    __FILE__
818 //    __LINE__
819 //    IntegerLiteral
820 //    FloatLiteral
821 //    CharacterLiteral
822 //    StringLiteral
823 //    ArrayLiteral
824 //    AssocArrayLiteral
825 //    Lambda
826 //    FunctionLiteral
827 //    StructLiteral            // deprecated
828 //    AssertExpression
829 //    MixinExpression
830 //    ImportExpression
831 //    TypeidExpression
832 //    IsExpression
833 //    ( Expression )
834 //    BasicType . IdentifierOrTemplateInstance
835 //    Typeof    . IdentifierOrTemplateInstance
836 //    ( Type )  . IdentifierOrTemplateInstance
837 //    BasicType Arguments
838 //    Typeof    Arguments
839 //    ( Type )  Arguments
840 //    TraitsExpression
841 
842 class PrimaryExpression : Expression
843 {
844     static Action enter(Parser p)
845     {
846         switch(p.tok.id)
847         {
848             case TOK_typeid:
849                 return TypeIdExpression.enter(p);
850             case TOK_is:
851                 return IsExpression.enter(p);
852             case TOK_notidentity:
853                 return IsExpression.enterNotIs(p);
854             case TOK_import:
855                 return ImportExpression.enter(p);
856             case TOK_mixin:
857                 return MixinExpression.enter(p);
858             case TOK_assert:
859                 return AssertExpression.enter(p);
860             case TOK___traits:
861                 return TraitsExpression.enter(p);
862 
863             case TOK_this:
864             case TOK_super:
865             case TOK_null:
866             case TOK_true:
867             case TOK_false:
868             case TOK_dollar:
869             case TOK___FILE__:
870             case TOK___LINE__:
871             case TOK___FUNCTION__:
872             case TOK___PRETTY_FUNCTION__:
873             case TOK___MODULE__:
874                 auto expr = new ast.PrimaryExpression(p.tok);
875                 p.pushNode(expr);
876                 return Accept;
877 
878             case TOK_typeof: // cannot make this part of Type, because it will also eat the property
879                 p.pushState(&shiftType);
880                 return Typeof.enter(p);
881 
882             case TOK___vector:
883             mixin(case_TOKs_TypeModifier);
884             mixin(case_TOKs_BasicTypeX);
885                 p.pushState(&shiftType);
886                 return Type.enter(p);
887 
888             case TOK_dot:
889                 p.pushState(&shiftDot);
890                 return Accept;
891             case TOK_Identifier:
892                 p.pushToken(p.tok);
893                 p.pushState(&shiftIdentifier);
894                 return Accept;
895 
896             case TOK_IntegerLiteral:
897                 p.pushNode(new ast.IntegerLiteralExpression(p.tok));
898                 return Accept;
899             case TOK_FloatLiteral:
900                 p.pushNode(new ast.FloatLiteralExpression(p.tok));
901                 return Accept;
902             case TOK_CharacterLiteral:
903                 p.pushNode(new ast.CharacterLiteralExpression(p.tok));
904                 return Accept;
905             case TOK_StringLiteral:
906                 p.pushNode(new ast.StringLiteralExpression(p.tok));
907                 p.pushState(&shiftStringLiteral);
908                 return Accept;
909 
910             case TOK_lbracket:
911                 return ArrayLiteral.enter(p);
912 
913             case TOK_delegate:
914             case TOK_function:
915                 return FunctionLiteral!true.enter(p); // SPEC: allowing lambda not in the language spec
916             case TOK_lcurly:
917                 p.pushRollback(&rollbackFunctionLiteralFailure);
918                 p.pushState(&shiftFunctionLiteral);
919                 return FunctionLiteral!false.enter(p);
920 
921             case TOK_lparen:
922                 p.pushRollback(&rollbackExpressionFailure);
923                 p.pushState(&shiftLparenExpr);
924                 p.pushState(&Expression.enter);
925                 return Accept;
926 
927             default:
928                 return p.parseError("primary expression expected");
929         }
930     }
931 
932     static Action shiftIdentifier(Parser p)
933     {
934         switch(p.tok.id)
935         {
936             case TOK_lambda:
937                 // id => expr
938                 auto tok = p.popToken();
939                 auto lambda = new ast.Lambda(p.tok);
940                 auto pdecl = new ast.ParameterDeclarator;
941                 auto type = new ast.AutoType;
942                 auto id = new ast.Declarator(tok);
943                 pdecl.addMember(type);
944                 pdecl.addMember(id);
945                 auto pl = new ast.ParameterList;
946                 pl.addMember(pdecl);
947                 lambda.addMember(pl);
948                 p.pushNode(lambda);
949                 p.pushState(&shiftLambda);
950                 p.pushState(&AssignExpression.enter);
951                 return Accept;
952 
953             default:
954                 auto tok = p.topToken();
955                 p.pushNode(new ast.IdentifierExpression(tok));
956                 p.pushState(&shiftIdentifierOrTemplateInstance);
957                 return IdentifierOrTemplateInstance.enterIdentifier(p);
958         }
959     }
960 
961     static Action shiftLambda(Parser p)
962     {
963         p.popAppendTopNode!(ast.Lambda)();
964         return Forward;
965     }
966 
967     // ( Expression )
968     // ( Type ) . Identifier
969     // FunctionLiteral: ParameterAttributes FunctionBody
970     static Action shiftLparenExpr(Parser p)
971     {
972         if(p.tok.id != TOK_rparen)
973             return p.parseError("closing parenthesis expected");
974 
975         p.pushState(&shiftRparenExpr);
976         return Accept;
977     }
978     static Action shiftRparenExpr(Parser p)
979     {
980         if(p.tok.id == TOK_lcurly || p.tok.id == TOK_lambda)
981             return Reject;
982 
983         p.popRollback();
984         return Forward;
985     }
986 
987 
988     static Action rollbackExpressionFailure(Parser p)
989     {
990         assert(p.tok.id == TOK_lparen);
991         p.pushRollback(&rollbackTypeFailure);
992         p.pushState(&shiftLparenType);
993         p.pushState(&Type.enter);
994         return Accept;
995     }
996 
997     static Action rollbackFunctionLiteralFailure(Parser p)
998     {
999         assert(p.tok.id == TOK_lcurly || p.tok.id == TOK_lambda);
1000         return StructLiteral.enter(p);
1001     }
1002 
1003     static Action shiftFunctionLiteral(Parser p)
1004     {
1005         p.popRollback();
1006         return Forward;
1007     }
1008 
1009     static Action shiftLparenType(Parser p)
1010     {
1011         if(p.tok.id != TOK_rparen)
1012             return p.parseError("closing parenthesis expected");
1013         p.pushState(&shiftLparenTypeDot);
1014         return Accept;
1015     }
1016     static Action shiftLparenTypeDot(Parser p)
1017     {
1018         switch(p.tok.id)
1019         {
1020             case TOK_dot:
1021                 p.popRollback();
1022                 p.appendReplaceTopNode(new ast.TypeProperty(p.tok));
1023                 p.pushState(&shiftTypeDot);
1024                 p.pushState(&IdentifierOrTemplateInstance.enter);
1025                 return Accept;
1026             case TOK_lparen:
1027                 p.popRollback();
1028                 p.appendReplaceTopNode(new ast.StructConstructor(p.tok));
1029                 p.pushState(&shiftStructArguments);
1030                 return Arguments.enter(p);
1031             default:
1032                 return p.parseError("'.' expected for type property");
1033         }
1034     }
1035 
1036     static Action rollbackTypeFailure(Parser p)
1037     {
1038         assert(p.tok.id == TOK_lparen);
1039         return FunctionLiteral!true.enter(p);
1040     }
1041 
1042     static Action shiftDot(Parser p)
1043     {
1044         if(p.tok.id != TOK_Identifier)
1045             return p.parseError("identifier expected");
1046 
1047         auto id = new ast.IdentifierExpression(p.tok);
1048         id.global = true;
1049         p.pushNode(id);
1050 
1051         p.pushState(&shiftIdentifierOrTemplateInstance);
1052         return IdentifierOrTemplateInstance.enter(p);
1053     }
1054 
1055     static Action shiftIdentifierOrTemplateInstance(Parser p)
1056     {
1057         p.popAppendTopNode!(ast.IdentifierExpression, ast.Identifier)();
1058         return Forward;
1059     }
1060 
1061     // BasicType . Identifier
1062     static Action shiftType(Parser p)
1063     {
1064         switch(p.tok.id)
1065         {
1066             case TOK_dot:
1067                 p.appendReplaceTopNode(new ast.TypeProperty(p.tok));
1068                 p.pushState(&shiftTypeDot);
1069                 p.pushState(&IdentifierOrTemplateInstance.enter);
1070                 return Accept;
1071             case TOK_lparen:
1072                 p.appendReplaceTopNode(new ast.StructConstructor(p.tok));
1073                 p.pushState(&shiftStructArguments);
1074                 return Arguments.enter(p);
1075             default:
1076                 return p.parseError("'.' expected for type property");
1077         }
1078     }
1079 
1080     static Action shiftTypeDot(Parser p)
1081     {
1082         p.popAppendTopNode!(ast.TypeProperty)();
1083         return Forward;
1084     }
1085 
1086     static Action shiftStructArguments(Parser p)
1087     {
1088         p.popAppendTopNode!(ast.StructConstructor)();
1089         return Forward;
1090     }
1091 
1092     static Action shiftStringLiteral(Parser p)
1093     {
1094         switch(p.tok.id)
1095         {
1096             case TOK_StringLiteral:
1097                 p.topNode!(ast.StringLiteralExpression).addText(p.tok);
1098                 p.pushState(&shiftStringLiteral);
1099                 return Accept;
1100             default:
1101                 return Forward;
1102         }
1103     }
1104 }
1105 
1106 //-- GRAMMAR_BEGIN --
1107 //VoidInitializer:
1108 //    void
1109 //
1110 //ArrayLiteral:
1111 //    [ ArgumentList ]
1112 //
1113 //AssocArrayLiteral:
1114 //    [ KeyValuePairs ]
1115 class ArrayLiteral : Expression
1116 {
1117     // combines all array literals, has to be disambiguated when assigned
1118     mixin SequenceNode!(ast.ArrayLiteral, TOK_lbracket, ArrayValueList, TOK_rbracket);
1119 }
1120 
1121 //-- GRAMMAR_BEGIN --
1122 //ArrayValueList:
1123 //    ArrayValue
1124 //    ArrayValue , ArrayValue
1125 class ArrayValueList
1126 {
1127     mixin ListNode!(ast.ArgumentList, ArrayValue, TOK_comma, true, true);
1128 }
1129 
1130 //-- GRAMMAR_BEGIN --
1131 //ArrayValue:
1132 //    AssignExpression
1133 //    AssignExpression : AssignExpression
1134 class ArrayValue : BinaryExpression
1135 {
1136     mixin stateAppendClass!(AssignExpression, Parser.forward) stateValue;
1137 
1138     static Action statePrepareValue(Parser p)
1139     {
1140         auto kp = new ast.KeyValuePair(p.tok);
1141         p.appendReplaceTopNode(kp);
1142         return stateValue.shift(p);
1143     }
1144 
1145     mixin stateShiftToken!(TOK_colon, statePrepareValue, -1) stateColon;
1146     mixin stateEnterClass!(AssignExpression, NoASTNode, stateColon.shift);
1147 }
1148 
1149 //-- GRAMMAR_BEGIN --
1150 //FunctionLiteral:
1151 //    function Type_opt ParameterAttributes_opt FunctionBody
1152 //    delegate Type_opt ParameterAttributes_opt FunctionBody
1153 //    ParameterAttributes FunctionBody
1154 //    FunctionBody
1155 //
1156 //ParameterAttributes:
1157 //    Parameters
1158 //    Parameters FunctionAttributes
1159 class FunctionLiteral(bool allowLambda) : Expression
1160 {
1161     static Action enter(Parser p)
1162     {
1163         auto lit = new ast.FunctionLiteral(0, p.tok.span);
1164         p.pushNode(lit);
1165 
1166         switch(p.tok.id)
1167         {
1168             case TOK_function:
1169             case TOK_delegate:
1170                 lit.id = p.tok.id;
1171                 p.pushState(&shiftFunctionDelegate);
1172                 return Accept;
1173 
1174             case TOK_lcurly:
1175                 lit.addMember(new ast.ParameterList(p.tok));
1176                 p.pushState(&shiftFunctionBody);
1177                 return FunctionBody.enter(p);
1178 
1179             case TOK_lparen:
1180                 p.pushState(&shiftParameters);
1181                 return Parameters.enter(p);
1182 
1183             default:
1184                 return p.parseError("unexpected token for function/delegate literal");
1185         }
1186     }
1187 
1188     static Action shiftFunctionDelegate(Parser p)
1189     {
1190         switch(p.tok.id)
1191         {
1192             case TOK_lcurly:
1193                 auto lit = p.topNode!(ast.FunctionLiteral)();
1194                 lit.addMember(new ast.ParameterList(p.tok));
1195                 p.pushState(&shiftFunctionBody);
1196                 return FunctionBody.enter(p);
1197 
1198             case TOK_lparen:
1199                 p.pushState(&shiftParameters);
1200                 return Parameters.enter(p);
1201 
1202             default:
1203                 p.pushState(&shiftType);
1204                 return Type.enter(p);
1205         }
1206     }
1207 
1208     static Action shiftType(Parser p)
1209     {
1210         p.popAppendTopNode!(ast.FunctionLiteral);
1211         switch(p.tok.id)
1212         {
1213             case TOK_lcurly:
1214                 auto lit = p.topNode!(ast.FunctionLiteral)();
1215                 lit.addMember(new ast.ParameterList(p.tok));
1216                 p.pushState(&shiftFunctionBody);
1217                 return FunctionBody.enter(p);
1218 
1219             case TOK_lparen:
1220                 p.pushState(&shiftParameters);
1221                 return Parameters.enter(p);
1222 
1223             default:
1224                 return p.parseError("'(' or '{' expected in function literal");
1225         }
1226     }
1227 
1228     static Action shiftParameters(Parser p)
1229     {
1230         p.popAppendTopNode!(ast.FunctionLiteral)();
1231         return shiftFunctionAttribute(p);
1232     }
1233 
1234     static Action shiftFunctionAttribute(Parser p)
1235     {
1236         switch(p.tok.id)
1237         {
1238             case TOK_lcurly:
1239                 p.pushState(&shiftFunctionBody);
1240                 return FunctionBody.enter(p);
1241 
1242             static if(allowLambda)
1243             {
1244             case TOK_lambda:
1245                 p.pushState(&shiftLambda);
1246                 p.pushState(&AssignExpression.enter);
1247                 return Accept;
1248             }
1249             mixin(case_TOKs_FunctionAttribute);
1250                 auto lit = p.topNode!(ast.FunctionLiteral)();
1251                 p.combineAttributes(lit.attr, tokenToAttribute(p.tok.id));
1252                 p.combineAnnotations(lit.annotation, tokenToAnnotation(p.tok.id));
1253                 p.pushState(&shiftFunctionAttribute);
1254                 return Accept;
1255 
1256             default:
1257                 return p.parseError("'{' expected in function literal");
1258         }
1259     }
1260 
1261     static Action shiftFunctionBody(Parser p)
1262     {
1263         p.popAppendTopNode!(ast.FunctionLiteral);
1264         return Forward;
1265     }
1266 
1267     static Action shiftLambda(Parser p)
1268     {
1269         auto expr = p.popNode!(ast.Expression)();
1270         auto ret = new ast.ReturnStatement;
1271         ret.addMember(expr);
1272         auto blk = new ast.BlockStatement;
1273         blk.addMember(ret);
1274         auto bdy = new ast.FunctionBody;
1275         bdy.addMember(blk);
1276         bdy.bodyStatement = blk;
1277 
1278         auto lit = p.topNode!(ast.FunctionLiteral)();
1279         lit.addMember(bdy);
1280         return Forward;
1281     }
1282 }
1283 
1284 //-- GRAMMAR_BEGIN --
1285 //StructLiteral:
1286 //    { ArrayValueList }
1287 class StructLiteral : Expression
1288 {
1289     mixin SequenceNode!(ast.StructLiteral, TOK_lcurly, ArrayValueList, TOK_rcurly);
1290 
1291 }
1292 
1293 //-- GRAMMAR_BEGIN --
1294 //AssertExpression:
1295 //    assert ( AssignExpression )
1296 //    assert ( AssignExpression , AssignExpression )
1297 class AssertExpression : Expression
1298 {
1299     // assert ( AssignExpression , AssignExpression $ )
1300     mixin stateShiftToken!(TOK_rparen, Parser.forward) stateRparen;
1301 
1302     // assert ( AssignExpression , $ AssignExpression )
1303     mixin stateAppendClass!(AssignExpression, stateRparen.shift) stateMessage;
1304 
1305     // assert ( AssignExpression $ )
1306     // assert ( AssignExpression $ , AssignExpression )
1307     mixin stateShiftToken!(TOK_rparen, Parser.forward,
1308                            TOK_comma, stateMessage.shift) stateRparenComma;
1309 
1310     // assert ( $ AssignExpression , AssignExpression )
1311     mixin stateAppendClass!(AssignExpression, stateRparenComma.shift) stateExpression;
1312 
1313     // assert $ ( AssignExpression , AssignExpression )
1314     mixin stateShiftToken!(TOK_lparen, stateExpression.shift) stateLparen;
1315 
1316     // $ assert ( AssignExpression , AssignExpression )
1317     mixin stateEnterToken!(TOK_assert, ast.AssertExpression, stateLparen.shift);
1318 }
1319 
1320 //-- GRAMMAR_BEGIN --
1321 //MixinExpression:
1322 //    mixin ( AssignExpression )
1323 class MixinExpression : Expression
1324 {
1325     mixin SequenceNode!(ast.MixinExpression, TOK_mixin, TOK_lparen, AssignExpression, TOK_rparen);
1326 }
1327 
1328 //-- GRAMMAR_BEGIN --
1329 //ImportExpression:
1330 //    import ( AssignExpression )
1331 class ImportExpression : Expression
1332 {
1333     mixin SequenceNode!(ast.ImportExpression, TOK_import, TOK_lparen, AssignExpression, TOK_rparen);
1334 }
1335 
1336 //-- GRAMMAR_BEGIN --
1337 //TypeidExpression:
1338 //    typeid ( Type )
1339 //    typeid ( Expression )
1340 class TypeIdExpression : Expression
1341 {
1342     mixin SequenceNode!(ast.TypeIdExpression, TOK_typeid, TOK_lparen, TypeOrExpression!TOK_rparen, TOK_rparen);
1343 }
1344 
1345 class TypeOrExpression(ops...)
1346 {
1347     static Action enter(Parser p)
1348     {
1349         p.pushRollback(&rollbackTypeFailure);
1350         p.pushState(&shiftType);
1351         return Type.enter(p);
1352     }
1353 
1354     static Action shiftType(Parser p)
1355     {
1356         if(!isInOps!(ops)(p.tok.id))
1357             return p.parseError("not a type!");
1358 
1359         p.popRollback();
1360         return Forward;
1361     }
1362 
1363     static Action rollbackTypeFailure(Parser p)
1364     {
1365         return AssignExpression.enter(p);
1366     }
1367 }
1368 
1369 //-- GRAMMAR_BEGIN --
1370 //IsExpression:
1371 //    is ( Type )
1372 //    is ( Type : TypeSpecialization )
1373 //    is ( Type == TypeSpecialization )
1374 //    is ( Type Identifier )
1375 //    is ( Type Identifier : TypeSpecialization )
1376 //    is ( Type Identifier == TypeSpecialization )
1377 //    is ( Type Identifier : TypeSpecialization , TemplateParameterList )
1378 //    is ( Type Identifier == TypeSpecialization , TemplateParameterList )
1379 //
1380 //TypeSpecialization:
1381 //    TypeWithModifier
1382 //    struct
1383 //    union
1384 //    class
1385 //    interface
1386 //    enum
1387 //    function
1388 //    delegate
1389 //    super
1390 //    const
1391 //    immutable
1392 //    inout
1393 //    shared
1394 //    return
1395 //    __parameters
1396 //    __argTypes
1397 //
1398 // !is specially treated, because it's a token to the lexer
1399 class IsExpression : Expression
1400 {
1401     // is ( Type Identifier == TypeSpecialization , TemplateParameterList $ )
1402     mixin stateShiftToken!(TOK_rparen, Parser.forward) stateRparen;
1403 
1404     // is ( Type Identifier == TypeSpecialization , $ TemplateParameterList )
1405     mixin stateAppendClass!(TemplateParameterList, stateRparen.shift) stateTemplateParameterList;
1406 
1407     // is ( Type : TypeSpecialization $ )
1408     // ...
1409     // is ( Type Identifier == TypeSpecialization $ , TemplateParameterList )
1410     mixin stateShiftToken!(TOK_rparen, Parser.forward,
1411                            TOK_comma, stateTemplateParameterList.shift) stateRparenComma;
1412 
1413     // is ( Type : $ TypeSpecialization )
1414     // is ( Type == $ TypeSpecialization )
1415     mixin stateAppendClass!(TypeSpecialization, stateRparenComma.shift) stateTypeSpecialization;
1416 
1417     static Action rememberColon(Parser p)
1418     {
1419         p.topNode!(ast.IsExpression).kind = TOK_colon;
1420         return stateTypeSpecialization.shift(p);
1421     }
1422     static Action rememberAssign(Parser p)
1423     {
1424         p.topNode!(ast.IsExpression).kind = TOK_equal;
1425         return stateTypeSpecialization.shift(p);
1426     }
1427     mixin stateShiftToken!(TOK_rparen, Parser.forward,
1428                            TOK_colon, rememberColon,
1429                            TOK_equal, rememberAssign) stateAfterIdentifier;
1430 
1431     static Action rememberIdentifier(Parser p)
1432     {
1433         switch(p.tok.id)
1434         {
1435             case TOK_Identifier:
1436                 p.topNode!(ast.IsExpression).ident = p.tok.txt;
1437                 p.pushState(&stateAfterIdentifier.shift);
1438                 return Accept;
1439             default:
1440                 return p.parseError("')', ':', '==' or identifier expected");
1441         }
1442     }
1443 
1444     // is ( Type $ )
1445     // is ( Type $ : TypeSpecialization )
1446     // is ( Type $ == TypeSpecialization )
1447     // is ( Type $ Identifier == TypeSpecialization , TemplateParameterList )
1448     mixin stateShiftToken!(TOK_rparen, Parser.forward,
1449                            TOK_colon, rememberColon,
1450                            TOK_equal, rememberAssign,
1451                            -1, rememberIdentifier) stateIdentifier;
1452 
1453     // is ( $ Type Identifier == TypeSpecialization , TemplateParameterList )
1454     mixin stateAppendClass!(Type, stateIdentifier.shift) stateType;
1455 
1456     // is $ ( Type Identifier == TypeSpecialization , TemplateParameterList )
1457     mixin stateShiftToken!(TOK_lparen, stateType.shift) stateLparen;
1458 
1459     // $ is ( Type Identifier == TypeSpecialization , TemplateParameterList )
1460     mixin stateEnterToken!(TOK_is, ast.IsExpression, stateLparen.shift);
1461 
1462     static Action enterNotIs(Parser p)
1463     {
1464         p.pushNode(new ast.UnaryExpression(TOK_not, p.tok.span));
1465         p.pushNode(new ast.IsExpression(p.tok));
1466         p.pushState(&shiftNotIsExpression);
1467         p.pushState(&stateLparen.shift);
1468         return Accept;
1469     }
1470 
1471     static Action shiftNotIsExpression(Parser p)
1472     {
1473         p.popAppendTopNode!(ast.UnaryExpression)();
1474         return Forward;
1475     }
1476 }
1477 
1478 class TypeSpecialization
1479 {
1480     static Action enter(Parser p)
1481     {
1482         switch(p.tok.id)
1483         {
1484             case TOK_struct:
1485             case TOK_union:
1486             case TOK_class:
1487             case TOK_interface:
1488             case TOK_enum:
1489             case TOK_function:
1490             case TOK_delegate:
1491             case TOK_super:
1492             case TOK_return:
1493             case TOK_typedef:
1494             case TOK___parameters:
1495             case TOK___argTypes:
1496                 p.pushNode(new ast.TypeSpecialization(p.tok));
1497                 return Accept;
1498             case TOK_const:
1499             case TOK_immutable:
1500             case TOK_inout:
1501             case TOK_shared:
1502                 p.pushToken(p.tok);
1503                 p.pushState(&shiftModifier);
1504                 return Accept;
1505             default:
1506                 p.pushNode(new ast.TypeSpecialization(0, p.tok.span));
1507                 p.pushState(&shiftType);
1508                 return Type.enter(p);
1509         }
1510     }
1511 
1512     static Action shiftModifier(Parser p)
1513     {
1514         switch(p.tok.id)
1515         {
1516             case TOK_lparen:
1517                 p.pushNode(new ast.TypeSpecialization(0, p.tok.span));
1518                 p.pushState(&shiftType);
1519                 return Type.enterTypeModifier(p);
1520             case TOK_rparen:
1521             case TOK_comma:
1522                 auto tok = p.popToken();
1523                 p.pushNode(new ast.TypeSpecialization(tok));
1524                 return Forward;
1525             default:
1526                 p.pushNode(new ast.TypeSpecialization(0, p.tok.span));
1527                 p.pushState(&shiftType);
1528                 return TypeWithModifier.shiftModifier(p);
1529         }
1530     }
1531 
1532     static Action shiftType(Parser p)
1533     {
1534         p.popAppendTopNode!(ast.TypeSpecialization)();
1535         return Forward;
1536     }
1537 }
1538 
1539 //-- GRAMMAR_BEGIN --
1540 //TraitsExpression:
1541 //    __traits ( TraitsKeyword , TraitsArguments )
1542 //
1543 //TraitsKeyword:
1544 //    "isAbstractClass"
1545 //    "isArithmetic"
1546 //    "isAssociativeArray"
1547 //    "isFinalClass"
1548 //    "isFloating"
1549 //    "isIntegral"
1550 //    "isScalar"
1551 //    "isStaticArray"
1552 //    "isUnsigned"
1553 //    "isVirtualFunction"
1554 //    "isAbstractFunction"
1555 //    "isFinalFunction"
1556 //    "isStaticFunction"
1557 //    "isRef"
1558 //    "isOut"
1559 //    "isLazy"
1560 //    "hasMember"
1561 //    "identifier"
1562 //    "getMember"
1563 //    "getOverloads"
1564 //    "getVirtualFunctions"
1565 //    "classInstanceSize"
1566 //    "allMembers"
1567 //    "derivedMembers"
1568 //    "isSame"
1569 //    "compiles"
1570 class TraitsExpression : Expression
1571 {
1572     mixin stateShiftToken!(TOK_rparen, Parser.forward) stateRparen;
1573 
1574     mixin stateAppendClass!(TraitsArguments, stateRparen.shift) stateArguments;
1575 
1576     mixin stateShiftToken!(TOK_comma, stateArguments.shift,
1577                            TOK_rparen, Parser.forward) stateComma;
1578 
1579     mixin stateAppendClass!(Identifier, stateComma.shift) stateIdentifier;
1580 
1581     mixin stateShiftToken!(TOK_lparen, stateIdentifier.shift) stateLparen;
1582 
1583     mixin stateEnterToken!(TOK___traits, ast.TraitsExpression, stateLparen.shift);
1584 }
1585 
1586 //-- GRAMMAR_BEGIN --
1587 //TraitsArguments:
1588 //    TraitsArgument
1589 //    TraitsArgument , TraitsArguments
1590 //
1591 //TraitsArgument:
1592 //    AssignExpression
1593 //    Type
1594 class TraitsArguments
1595 {
1596     mixin ListNode!(ast.TraitsArguments, TypeOrExpression!(TOK_comma, TOK_rparen), TOK_comma, false, false);
1597 }