1 /**
2  * Compiler implementation of the
3  * $(LINK2 http://www.dlang.org, D programming language).
4  *
5  * Copyright:   Copyright (c) 1999-2016 by Digital Mars, All Rights Reserved
6  * Authors:     $(LINK2 http://www.digitalmars.com, Walter Bright)
7  * License:     $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
8  * Source:      $(DMDSRC _parse.d)
9  */
10 
11 module ddmd.parse;
12 
13 import core.stdc.stdio;
14 import core.stdc..string;
15 import ddmd.aggregate;
16 import ddmd.aliasthis;
17 import ddmd.arraytypes;
18 import ddmd.attrib;
19 import ddmd.cond;
20 import ddmd.dclass;
21 import ddmd.declaration;
22 import ddmd.denum;
23 import ddmd.dimport;
24 import ddmd.dmodule;
25 import ddmd.dstruct;
26 import ddmd.dsymbol;
27 import ddmd.dtemplate;
28 import ddmd.dversion;
29 import ddmd.errors;
30 import ddmd.expression;
31 import ddmd.func;
32 import ddmd.globals;
33 import ddmd.hdrgen;
34 import ddmd.id;
35 import ddmd.identifier;
36 import ddmd.init;
37 import ddmd.lexer;
38 import ddmd.mtype;
39 import ddmd.nspace;
40 import ddmd.root.filename;
41 import ddmd.root.outbuffer;
42 import ddmd.root.rmem;
43 import ddmd.root.rootobject;
44 import ddmd.statement;
45 import ddmd.staticassert;
46 import ddmd.tokens;
47 
48 // How multiple declarations are parsed.
49 // If 1, treat as C.
50 // If 0, treat:
51 //      int *p, i;
52 // as:
53 //      int* p;
54 //      int* i;
55 enum CDECLSYNTAX = 0;
56 
57 // Support C cast syntax:
58 //      (type)(expression)
59 enum CCASTSYNTAX = 1;
60 
61 // Support postfix C array declarations, such as
62 //      int a[3][4];
63 enum CARRAYDECL = 1;
64 
65 /**********************************
66  * Set operator precedence for each operator.
67  */
68 __gshared PREC[TOKMAX] precedence =
69 [
70     TOKtype : PREC.expr,
71     TOKerror : PREC.expr,
72 
73     TOKtypeof : PREC.primary,
74     TOKmixin : PREC.primary,
75 
76     TOKimport : PREC.primary,
77     TOKdotvar : PREC.primary,
78     TOKscope : PREC.primary,
79     TOKidentifier : PREC.primary,
80     TOKthis : PREC.primary,
81     TOKsuper : PREC.primary,
82     TOKint64 : PREC.primary,
83     TOKfloat64 : PREC.primary,
84     TOKcomplex80 : PREC.primary,
85     TOKnull : PREC.primary,
86     TOKstring : PREC.primary,
87     TOKarrayliteral : PREC.primary,
88     TOKassocarrayliteral : PREC.primary,
89     TOKclassreference : PREC.primary,
90     TOKfile : PREC.primary,
91     TOKfilefullpath : PREC.primary,
92     TOKline : PREC.primary,
93     TOKmodulestring : PREC.primary,
94     TOKfuncstring : PREC.primary,
95     TOKprettyfunc : PREC.primary,
96     TOKtypeid : PREC.primary,
97     TOKis : PREC.primary,
98     TOKassert : PREC.primary,
99     TOKhalt : PREC.primary,
100     TOKtemplate : PREC.primary,
101     TOKdsymbol : PREC.primary,
102     TOKfunction : PREC.primary,
103     TOKvar : PREC.primary,
104     TOKsymoff : PREC.primary,
105     TOKstructliteral : PREC.primary,
106     TOKarraylength : PREC.primary,
107     TOKdelegateptr : PREC.primary,
108     TOKdelegatefuncptr : PREC.primary,
109     TOKremove : PREC.primary,
110     TOKtuple : PREC.primary,
111     TOKtraits : PREC.primary,
112     TOKdefault : PREC.primary,
113     TOKoverloadset : PREC.primary,
114     TOKvoid : PREC.primary,
115 
116     // post
117     TOKdotti : PREC.primary,
118     TOKdotid : PREC.primary,
119     TOKdottd : PREC.primary,
120     TOKdot : PREC.primary,
121     TOKdottype : PREC.primary,
122     TOKplusplus : PREC.primary,
123     TOKminusminus : PREC.primary,
124     TOKpreplusplus : PREC.primary,
125     TOKpreminusminus : PREC.primary,
126     TOKcall : PREC.primary,
127     TOKslice : PREC.primary,
128     TOKarray : PREC.primary,
129     TOKindex : PREC.primary,
130 
131     TOKdelegate : PREC.unary,
132     TOKaddress : PREC.unary,
133     TOKstar : PREC.unary,
134     TOKneg : PREC.unary,
135     TOKuadd : PREC.unary,
136     TOKnot : PREC.unary,
137     TOKtilde : PREC.unary,
138     TOKdelete : PREC.unary,
139     TOKnew : PREC.unary,
140     TOKnewanonclass : PREC.unary,
141     TOKcast : PREC.unary,
142 
143     TOKvector : PREC.unary,
144     TOKpow : PREC.pow,
145 
146     TOKmul : PREC.mul,
147     TOKdiv : PREC.mul,
148     TOKmod : PREC.mul,
149 
150     TOKadd : PREC.add,
151     TOKmin : PREC.add,
152     TOKcat : PREC.add,
153 
154     TOKshl : PREC.shift,
155     TOKshr : PREC.shift,
156     TOKushr : PREC.shift,
157 
158     TOKlt : PREC.rel,
159     TOKle : PREC.rel,
160     TOKgt : PREC.rel,
161     TOKge : PREC.rel,
162     TOKunord : PREC.rel,
163     TOKlg : PREC.rel,
164     TOKleg : PREC.rel,
165     TOKule : PREC.rel,
166     TOKul : PREC.rel,
167     TOKuge : PREC.rel,
168     TOKug : PREC.rel,
169     TOKue : PREC.rel,
170     TOKin : PREC.rel,
171 
172     /* Note that we changed precedence, so that < and != have the same
173      * precedence. This change is in the parser, too.
174      */
175     TOKequal : PREC.rel,
176     TOKnotequal : PREC.rel,
177     TOKidentity : PREC.rel,
178     TOKnotidentity : PREC.rel,
179 
180     TOKand : PREC.and,
181     TOKxor : PREC.xor,
182     TOKor : PREC.or,
183 
184     TOKandand : PREC.andand,
185     TOKoror : PREC.oror,
186 
187     TOKquestion : PREC.cond,
188 
189     TOKassign : PREC.assign,
190     TOKconstruct : PREC.assign,
191     TOKblit : PREC.assign,
192     TOKaddass : PREC.assign,
193     TOKminass : PREC.assign,
194     TOKcatass : PREC.assign,
195     TOKmulass : PREC.assign,
196     TOKdivass : PREC.assign,
197     TOKmodass : PREC.assign,
198     TOKpowass : PREC.assign,
199     TOKshlass : PREC.assign,
200     TOKshrass : PREC.assign,
201     TOKushrass : PREC.assign,
202     TOKandass : PREC.assign,
203     TOKorass : PREC.assign,
204     TOKxorass : PREC.assign,
205 
206     TOKcomma : PREC.expr,
207     TOKdeclaration : PREC.expr,
208 
209     TOKinterval : PREC.assign,
210 ];
211 
212 enum ParseStatementFlags : int
213 {
214     PSsemi          = 1,        // empty ';' statements are allowed, but deprecated
215     PSscope         = 2,        // start a new scope
216     PScurly         = 4,        // { } statement is required
217     PScurlyscope    = 8,        // { } starts a new scope
218     PSsemi_ok       = 0x10,     // empty ';' are really ok
219 }
220 
221 alias PSsemi = ParseStatementFlags.PSsemi;
222 alias PSscope = ParseStatementFlags.PSscope;
223 alias PScurly = ParseStatementFlags.PScurly;
224 alias PScurlyscope = ParseStatementFlags.PScurlyscope;
225 alias PSsemi_ok = ParseStatementFlags.PSsemi_ok;
226 
227 struct PrefixAttributes
228 {
229     StorageClass storageClass;
230     Expression depmsg;
231     LINK link;
232     Prot protection;
233     bool setAlignment;
234     Expression ealign;
235     Expressions* udas;
236     const(char)* comment;
237 }
238 
239 /*****************************
240  * Destructively extract storage class from pAttrs.
241  */
242 private StorageClass getStorageClass(PrefixAttributes* pAttrs)
243 {
244     StorageClass stc = STCundefined;
245     if (pAttrs)
246     {
247         stc = pAttrs.storageClass;
248         pAttrs.storageClass = STCundefined;
249     }
250     return stc;
251 }
252 
253 /***********************************************************
254  */
255 final class Parser : Lexer
256 {
257     Module mod;
258     ModuleDeclaration* md;
259     LINK linkage;
260     CPPMANGLE cppmangle;
261     Loc endloc; // set to location of last right curly
262     int inBrackets; // inside [] of array index or slice
263     Loc lookingForElse; // location of lonely if looking for an else
264 
265     /*********************
266      * Use this constructor for string mixins.
267      * Input:
268      *      loc     location in source file of mixin
269      */
270     extern (D) this(Loc loc, Module _module, const(char)[] input, bool doDocComment)
271     {
272         super(_module ? _module.srcfile.toChars() : null, input.ptr, 0, input.length, doDocComment, false);
273 
274         //printf("Parser::Parser()\n");
275         scanloc = loc;
276 
277         if (loc.filename)
278         {
279             /* Create a pseudo-filename for the mixin string, as it may not even exist
280              * in the source file.
281              */
282             char* filename = cast(char*)mem.xmalloc(strlen(loc.filename) + 7 + (loc.linnum).sizeof * 3 + 1);
283             sprintf(filename, "%s-mixin-%d", loc.filename, cast(int)loc.linnum);
284             scanloc.filename = filename;
285         }
286 
287         mod = _module;
288         linkage = LINKd;
289         //nextToken();              // start up the scanner
290     }
291 
292     extern (D) this(Module _module, const(char)[] input, bool doDocComment)
293     {
294         super(_module ? _module.srcfile.toChars() : null, input.ptr, 0, input.length, doDocComment, false);
295 
296         //printf("Parser::Parser()\n");
297         mod = _module;
298         linkage = LINKd;
299         //nextToken();              // start up the scanner
300     }
301 
302     Dsymbols* parseModule()
303     {
304         const comment = token.blockComment;
305         bool isdeprecated = false;
306         Expression msg = null;
307         Expressions* udas = null;
308         Dsymbols* decldefs;
309         Dsymbol lastDecl = mod; // for attaching ddoc unittests to module decl
310 
311         Token* tk;
312         if (skipAttributes(&token, &tk) && tk.value == TOKmodule)
313         {
314             while (token.value != TOKmodule)
315             {
316                 switch (token.value)
317                 {
318                 case TOKdeprecated:
319                     {
320                         // deprecated (...) module ...
321                         if (isdeprecated)
322                         {
323                             error("there is only one deprecation attribute allowed for module declaration");
324                         }
325                         else
326                         {
327                             isdeprecated = true;
328                         }
329                         nextToken();
330                         if (token.value == TOKlparen)
331                         {
332                             check(TOKlparen);
333                             msg = parseAssignExp();
334                             check(TOKrparen);
335                         }
336                         break;
337                     }
338                 case TOKat:
339                     {
340                         Expressions* exps = null;
341                         const stc = parseAttribute(&exps);
342                         if (stc == STCproperty || stc == STCnogc || stc == STCdisable || stc == STCsafe || stc == STCtrusted || stc == STCsystem)
343                         {
344                             error("@%s attribute for module declaration is not supported", token.toChars());
345                         }
346                         else
347                         {
348                             udas = UserAttributeDeclaration.concat(udas, exps);
349                         }
350                         if (stc)
351                             nextToken();
352                         break;
353                     }
354                 default:
355                     {
356                         error("'module' expected instead of %s", token.toChars());
357                         nextToken();
358                         break;
359                     }
360                 }
361             }
362         }
363 
364         if (udas)
365         {
366             auto a = new Dsymbols();
367             auto udad = new UserAttributeDeclaration(udas, a);
368             mod.userAttribDecl = udad;
369         }
370 
371         // ModuleDeclation leads off
372         if (token.value == TOKmodule)
373         {
374             const loc = token.loc;
375 
376             nextToken();
377             if (token.value != TOKidentifier)
378             {
379                 error("identifier expected following module");
380                 goto Lerr;
381             }
382             else
383             {
384                 Identifiers* a = null;
385                 Identifier id = token.ident;
386 
387                 while (nextToken() == TOKdot)
388                 {
389                     if (!a)
390                         a = new Identifiers();
391                     a.push(id);
392                     nextToken();
393                     if (token.value != TOKidentifier)
394                     {
395                         error("identifier expected following package");
396                         goto Lerr;
397                     }
398                     id = token.ident;
399                 }
400 
401                 md = new ModuleDeclaration(loc, a, id, msg, isdeprecated);
402 
403                 if (token.value != TOKsemicolon)
404                     error("';' expected following module declaration instead of %s", token.toChars());
405                 nextToken();
406                 addComment(mod, comment);
407             }
408         }
409 
410         decldefs = parseDeclDefs(0, &lastDecl);
411         if (token.value != TOKeof)
412         {
413             error(token.loc, "unrecognized declaration");
414             goto Lerr;
415         }
416         return decldefs;
417 
418     Lerr:
419         while (token.value != TOKsemicolon && token.value != TOKeof)
420             nextToken();
421         nextToken();
422         return new Dsymbols();
423     }
424 
425     Dsymbols* parseDeclDefs(int once, Dsymbol* pLastDecl = null, PrefixAttributes* pAttrs = null)
426     {
427         Dsymbol lastDecl = null; // used to link unittest to its previous declaration
428         if (!pLastDecl)
429             pLastDecl = &lastDecl;
430 
431         const linksave = linkage; // save global state
432 
433         //printf("Parser::parseDeclDefs()\n");
434         auto decldefs = new Dsymbols();
435         do
436         {
437             // parse result
438             Dsymbol s = null;
439             Dsymbols* a = null;
440 
441             PrefixAttributes attrs;
442             if (!once || !pAttrs)
443             {
444                 pAttrs = &attrs;
445                 pAttrs.comment = token.blockComment;
446             }
447             PROTKIND prot;
448             StorageClass stc;
449             Condition condition;
450 
451             linkage = linksave;
452 
453             switch (token.value)
454             {
455             case TOKenum:
456                 {
457                     /* Determine if this is a manifest constant declaration,
458                      * or a conventional enum.
459                      */
460                     Token* t = peek(&token);
461                     if (t.value == TOKlcurly || t.value == TOKcolon)
462                         s = parseEnum();
463                     else if (t.value != TOKidentifier)
464                         goto Ldeclaration;
465                     else
466                     {
467                         t = peek(t);
468                         if (t.value == TOKlcurly || t.value == TOKcolon || t.value == TOKsemicolon)
469                             s = parseEnum();
470                         else
471                             goto Ldeclaration;
472                     }
473                     break;
474                 }
475             case TOKimport:
476                 a = parseImport();
477                 // keep pLastDecl
478                 break;
479 
480             case TOKtemplate:
481                 s = cast(Dsymbol)parseTemplateDeclaration();
482                 break;
483 
484             case TOKmixin:
485                 {
486                     const loc = token.loc;
487                     switch (peekNext())
488                     {
489                     case TOKlparen:
490                         {
491                             // mixin(string)
492                             nextToken();
493                             check(TOKlparen, "mixin");
494                             Expression e = parseAssignExp();
495                             check(TOKrparen);
496                             check(TOKsemicolon);
497                             s = new CompileDeclaration(loc, e);
498                             break;
499                         }
500                     case TOKtemplate:
501                         // mixin template
502                         nextToken();
503                         s = cast(Dsymbol)parseTemplateDeclaration(true);
504                         break;
505 
506                     default:
507                         s = parseMixin();
508                         break;
509                     }
510                     break;
511                 }
512             case TOKwchar:
513             case TOKdchar:
514             case TOKbool:
515             case TOKchar:
516             case TOKint8:
517             case TOKuns8:
518             case TOKint16:
519             case TOKuns16:
520             case TOKint32:
521             case TOKuns32:
522             case TOKint64:
523             case TOKuns64:
524             case TOKint128:
525             case TOKuns128:
526             case TOKfloat32:
527             case TOKfloat64:
528             case TOKfloat80:
529             case TOKimaginary32:
530             case TOKimaginary64:
531             case TOKimaginary80:
532             case TOKcomplex32:
533             case TOKcomplex64:
534             case TOKcomplex80:
535             case TOKvoid:
536             case TOKalias:
537             case TOKidentifier:
538             case TOKsuper:
539             case TOKtypeof:
540             case TOKdot:
541             case TOKvector:
542             case TOKstruct:
543             case TOKunion:
544             case TOKclass:
545             case TOKinterface:
546             Ldeclaration:
547                 a = parseDeclarations(false, pAttrs, pAttrs.comment);
548                 if (a && a.dim)
549                     *pLastDecl = (*a)[a.dim - 1];
550                 break;
551 
552             case TOKthis:
553                 if (peekNext() == TOKdot)
554                     goto Ldeclaration;
555                 else
556                     s = parseCtor(pAttrs);
557                 break;
558 
559             case TOKtilde:
560                 s = parseDtor(pAttrs);
561                 break;
562 
563             case TOKinvariant:
564                 {
565                     Token* t = peek(&token);
566                     if (t.value == TOKlparen && peek(t).value == TOKrparen || t.value == TOKlcurly)
567                     {
568                         // invariant {}
569                         // invariant() {}
570                         s = parseInvariant(pAttrs);
571                     }
572                     else
573                     {
574                         error("invariant body expected, not '%s'", token.toChars());
575                         goto Lerror;
576                     }
577                     break;
578                 }
579             case TOKunittest:
580                 if (global.params.useUnitTests || global.params.doDocComments || global.params.doHdrGeneration)
581                 {
582                     s = parseUnitTest(pAttrs);
583                     if (*pLastDecl)
584                         (*pLastDecl).ddocUnittest = cast(UnitTestDeclaration)s;
585                 }
586                 else
587                 {
588                     // Skip over unittest block by counting { }
589                     Loc loc = token.loc;
590                     int braces = 0;
591                     while (1)
592                     {
593                         nextToken();
594                         switch (token.value)
595                         {
596                         case TOKlcurly:
597                             ++braces;
598                             continue;
599 
600                         case TOKrcurly:
601                             if (--braces)
602                                 continue;
603                             nextToken();
604                             break;
605 
606                         case TOKeof:
607                             /* { */
608                             error(loc, "closing } of unittest not found before end of file");
609                             goto Lerror;
610 
611                         default:
612                             continue;
613                         }
614                         break;
615                     }
616                     // Workaround 14894. Add an empty unittest declaration to keep
617                     // the number of symbols in this scope independent of -unittest.
618                     s = new UnitTestDeclaration(loc, token.loc, STCundefined, null);
619                 }
620                 break;
621 
622             case TOKnew:
623                 s = parseNew(pAttrs);
624                 break;
625 
626             case TOKdelete:
627                 s = parseDelete(pAttrs);
628                 break;
629 
630             case TOKcolon:
631             case TOKlcurly:
632                 error("declaration expected, not '%s'", token.toChars());
633                 goto Lerror;
634 
635             case TOKrcurly:
636             case TOKeof:
637                 if (once)
638                     error("declaration expected, not '%s'", token.toChars());
639                 return decldefs;
640 
641             case TOKstatic:
642                 {
643                     const next = peekNext();
644                     if (next == TOKthis)
645                         s = parseStaticCtor(pAttrs);
646                     else if (next == TOKtilde)
647                         s = parseStaticDtor(pAttrs);
648                     else if (next == TOKassert)
649                         s = parseStaticAssert();
650                     else if (next == TOKif)
651                     {
652                         condition = parseStaticIfCondition();
653                         Dsymbols* athen;
654                         if (token.value == TOKcolon)
655                             athen = parseBlock(pLastDecl);
656                         else
657                         {
658                             const lookingForElseSave = lookingForElse;
659                             lookingForElse = token.loc;
660                             athen = parseBlock(pLastDecl);
661                             lookingForElse = lookingForElseSave;
662                         }
663                         Dsymbols* aelse = null;
664                         if (token.value == TOKelse)
665                         {
666                             const elseloc = token.loc;
667                             nextToken();
668                             aelse = parseBlock(pLastDecl);
669                             checkDanglingElse(elseloc);
670                         }
671                         s = new StaticIfDeclaration(condition, athen, aelse);
672                     }
673                     else if (next == TOKimport)
674                     {
675                         a = parseImport();
676                         // keep pLastDecl
677                     }
678                     else
679                     {
680                         stc = STCstatic;
681                         goto Lstc;
682                     }
683                     break;
684                 }
685             case TOKconst:
686                 if (peekNext() == TOKlparen)
687                     goto Ldeclaration;
688                 stc = STCconst;
689                 goto Lstc;
690 
691             case TOKimmutable:
692                 if (peekNext() == TOKlparen)
693                     goto Ldeclaration;
694                 stc = STCimmutable;
695                 goto Lstc;
696 
697             case TOKshared:
698                 {
699                     const next = peekNext();
700                     if (next == TOKlparen)
701                         goto Ldeclaration;
702                     if (next == TOKstatic)
703                     {
704                         TOK next2 = peekNext2();
705                         if (next2 == TOKthis)
706                         {
707                             s = parseSharedStaticCtor(pAttrs);
708                             break;
709                         }
710                         if (next2 == TOKtilde)
711                         {
712                             s = parseSharedStaticDtor(pAttrs);
713                             break;
714                         }
715                     }
716                     stc = STCshared;
717                     goto Lstc;
718                 }
719             case TOKwild:
720                 if (peekNext() == TOKlparen)
721                     goto Ldeclaration;
722                 stc = STCwild;
723                 goto Lstc;
724 
725             case TOKfinal:
726                 stc = STCfinal;
727                 goto Lstc;
728 
729             case TOKauto:
730                 stc = STCauto;
731                 goto Lstc;
732 
733             case TOKscope:
734                 stc = STCscope;
735                 goto Lstc;
736 
737             case TOKoverride:
738                 stc = STCoverride;
739                 goto Lstc;
740 
741             case TOKabstract:
742                 stc = STCabstract;
743                 goto Lstc;
744 
745             case TOKsynchronized:
746                 stc = STCsynchronized;
747                 goto Lstc;
748 
749             case TOKnothrow:
750                 stc = STCnothrow;
751                 goto Lstc;
752 
753             case TOKpure:
754                 stc = STCpure;
755                 goto Lstc;
756 
757             case TOKref:
758                 stc = STCref;
759                 goto Lstc;
760 
761             case TOKgshared:
762                 stc = STCgshared;
763                 goto Lstc;
764 
765             //case TOKmanifest:   stc = STCmanifest;     goto Lstc;
766 
767             case TOKat:
768                 {
769                     Expressions* exps = null;
770                     stc = parseAttribute(&exps);
771                     if (stc)
772                         goto Lstc; // it's a predefined attribute
773                     // no redundant/conflicting check for UDAs
774                     pAttrs.udas = UserAttributeDeclaration.concat(pAttrs.udas, exps);
775                     goto Lautodecl;
776                 }
777             Lstc:
778                 pAttrs.storageClass = appendStorageClass(pAttrs.storageClass, stc);
779                 nextToken();
780 
781             Lautodecl:
782                 Token* tk;
783 
784                 /* Look for auto initializers:
785                  *      storage_class identifier = initializer;
786                  *      storage_class identifier(...) = initializer;
787                  */
788                 if (token.value == TOKidentifier && skipParensIf(peek(&token), &tk) && tk.value == TOKassign)
789                 {
790                     a = parseAutoDeclarations(getStorageClass(pAttrs), pAttrs.comment);
791                     if (a && a.dim)
792                         *pLastDecl = (*a)[a.dim - 1];
793                     if (pAttrs.udas)
794                     {
795                         s = new UserAttributeDeclaration(pAttrs.udas, a);
796                         pAttrs.udas = null;
797                     }
798                     break;
799                 }
800 
801                 /* Look for return type inference for template functions.
802                  */
803                 if (token.value == TOKidentifier && skipParens(peek(&token), &tk) && skipAttributes(tk, &tk) && (tk.value == TOKlparen || tk.value == TOKlcurly || tk.value == TOKin || tk.value == TOKout || tk.value == TOKbody))
804                 {
805                     a = parseDeclarations(true, pAttrs, pAttrs.comment);
806                     if (a && a.dim)
807                         *pLastDecl = (*a)[a.dim - 1];
808                     if (pAttrs.udas)
809                     {
810                         s = new UserAttributeDeclaration(pAttrs.udas, a);
811                         pAttrs.udas = null;
812                     }
813                     break;
814                 }
815 
816                 a = parseBlock(pLastDecl, pAttrs);
817                 auto stc2 = getStorageClass(pAttrs);
818                 if (stc2 != STCundefined)
819                 {
820                     s = new StorageClassDeclaration(stc2, a);
821                 }
822                 if (pAttrs.udas)
823                 {
824                     if (s)
825                     {
826                         a = new Dsymbols();
827                         a.push(s);
828                     }
829                     s = new UserAttributeDeclaration(pAttrs.udas, a);
830                     pAttrs.udas = null;
831                 }
832                 break;
833 
834             case TOKdeprecated:
835                 {
836                     if (peek(&token).value != TOKlparen)
837                     {
838                         stc = STCdeprecated;
839                         goto Lstc;
840                     }
841                     nextToken();
842                     check(TOKlparen);
843                     Expression e = parseAssignExp();
844                     check(TOKrparen);
845                     if (pAttrs.depmsg)
846                     {
847                         error("conflicting storage class 'deprecated(%s)' and 'deprecated(%s)'", pAttrs.depmsg.toChars(), e.toChars());
848                     }
849                     pAttrs.depmsg = e;
850                     a = parseBlock(pLastDecl, pAttrs);
851                     if (pAttrs.depmsg)
852                     {
853                         s = new DeprecatedDeclaration(pAttrs.depmsg, a);
854                         pAttrs.depmsg = null;
855                     }
856                     break;
857                 }
858             case TOKlbracket:
859                 {
860                     if (peekNext() == TOKrbracket)
861                         error("empty attribute list is not allowed");
862                     error("use @(attributes) instead of [attributes]");
863                     Expressions* exps = parseArguments();
864                     // no redundant/conflicting check for UDAs
865 
866                     pAttrs.udas = UserAttributeDeclaration.concat(pAttrs.udas, exps);
867                     a = parseBlock(pLastDecl, pAttrs);
868                     if (pAttrs.udas)
869                     {
870                         s = new UserAttributeDeclaration(pAttrs.udas, a);
871                         pAttrs.udas = null;
872                     }
873                     break;
874                 }
875             case TOKextern:
876                 {
877                     if (peek(&token).value != TOKlparen)
878                     {
879                         stc = STCextern;
880                         goto Lstc;
881                     }
882 
883                     const linkLoc = token.loc;
884                     Identifiers* idents = null;
885                     CPPMANGLE cppmangle;
886                     const link = parseLinkage(&idents, cppmangle);
887                     if (pAttrs.link != LINKdefault)
888                     {
889                         if (pAttrs.link != link)
890                         {
891                             error("conflicting linkage extern (%s) and extern (%s)", linkageToChars(pAttrs.link), linkageToChars(link));
892                         }
893                         else if (idents)
894                         {
895                             // Allow:
896                             //      extern(C++, foo) extern(C++, bar) void foo();
897                             // to be equivalent with:
898                             //      extern(C++, foo.bar) void foo();
899                         }
900                         else
901                             error("redundant linkage extern (%s)", linkageToChars(pAttrs.link));
902                     }
903                     pAttrs.link = link;
904                     this.linkage = link;
905                     a = parseBlock(pLastDecl, pAttrs);
906                     if (idents)
907                     {
908                         assert(link == LINKcpp);
909                         assert(idents.dim);
910                         for (size_t i = idents.dim; i;)
911                         {
912                             Identifier id = (*idents)[--i];
913                             if (s)
914                             {
915                                 a = new Dsymbols();
916                                 a.push(s);
917                             }
918                             s = new Nspace(linkLoc, id, a);
919                         }
920                         pAttrs.link = LINKdefault;
921                     }
922                     else if (cppmangle != CPPMANGLE.def)
923                     {
924                         assert(link == LINKcpp);
925                         s = new CPPMangleDeclaration(cppmangle, a);
926                     }
927                     else if (pAttrs.link != LINKdefault)
928                     {
929                         s = new LinkDeclaration(pAttrs.link, a);
930                         pAttrs.link = LINKdefault;
931                     }
932                     break;
933                 }
934 
935             case TOKprivate:
936                 prot = PROTprivate;
937                 goto Lprot;
938 
939             case TOKpackage:
940                 prot = PROTpackage;
941                 goto Lprot;
942 
943             case TOKprotected:
944                 prot = PROTprotected;
945                 goto Lprot;
946 
947             case TOKpublic:
948                 prot = PROTpublic;
949                 goto Lprot;
950 
951             case TOKexport:
952                 prot = PROTexport;
953                 goto Lprot;
954             Lprot:
955                 {
956                     if (pAttrs.protection.kind != PROTundefined)
957                     {
958                         if (pAttrs.protection.kind != prot)
959                             error("conflicting protection attribute '%s' and '%s'", protectionToChars(pAttrs.protection.kind), protectionToChars(prot));
960                         else
961                             error("redundant protection attribute '%s'", protectionToChars(prot));
962                     }
963                     pAttrs.protection.kind = prot;
964 
965                     nextToken();
966 
967                     // optional qualified package identifier to bind
968                     // protection to
969                     Identifiers* pkg_prot_idents = null;
970                     if (pAttrs.protection.kind == PROTpackage && token.value == TOKlparen)
971                     {
972                         pkg_prot_idents = parseQualifiedIdentifier("protection package");
973                         if (pkg_prot_idents)
974                             check(TOKrparen);
975                         else
976                         {
977                             while (token.value != TOKsemicolon && token.value != TOKeof)
978                                 nextToken();
979                             nextToken();
980                             break;
981                         }
982                     }
983 
984                     const attrloc = token.loc;
985                     a = parseBlock(pLastDecl, pAttrs);
986                     if (pAttrs.protection.kind != PROTundefined)
987                     {
988                         if (pAttrs.protection.kind == PROTpackage && pkg_prot_idents)
989                             s = new ProtDeclaration(attrloc, pkg_prot_idents, a);
990                         else
991                             s = new ProtDeclaration(attrloc, pAttrs.protection, a);
992 
993                         pAttrs.protection = Prot(PROTundefined);
994                     }
995                     break;
996                 }
997             case TOKalign:
998                 {
999                     const attrLoc = token.loc;
1000 
1001                     nextToken();
1002 
1003                     Expression e = null; // default
1004                     if (token.value == TOKlparen)
1005                     {
1006                         nextToken();
1007                         e = parseAssignExp();
1008                         check(TOKrparen);
1009                     }
1010 
1011                     if (pAttrs.setAlignment)
1012                     {
1013                         if (e)
1014                             error("redundant alignment attribute align(%s)", e.toChars());
1015                         else
1016                             error("redundant alignment attribute align");
1017                     }
1018 
1019                     pAttrs.setAlignment = true;
1020                     pAttrs.ealign = e;
1021                     a = parseBlock(pLastDecl, pAttrs);
1022                     if (pAttrs.setAlignment)
1023                     {
1024                         s = new AlignDeclaration(attrLoc, pAttrs.ealign, a);
1025                         pAttrs.setAlignment = false;
1026                         pAttrs.ealign = null;
1027                     }
1028                     break;
1029                 }
1030             case TOKpragma:
1031                 {
1032                     Expressions* args = null;
1033                     const loc = token.loc;
1034 
1035                     nextToken();
1036                     check(TOKlparen);
1037                     if (token.value != TOKidentifier)
1038                     {
1039                         error("pragma(identifier) expected");
1040                         goto Lerror;
1041                     }
1042                     Identifier ident = token.ident;
1043                     nextToken();
1044                     if (token.value == TOKcomma && peekNext() != TOKrparen)
1045                         args = parseArguments(); // pragma(identifier, args...)
1046                     else
1047                         check(TOKrparen); // pragma(identifier)
1048 
1049                     Dsymbols* a2 = null;
1050                     if (token.value == TOKsemicolon)
1051                     {
1052                         /* Bugzilla 2354: Accept single semicolon as an empty
1053                          * DeclarationBlock following attribute.
1054                          *
1055                          * Attribute DeclarationBlock
1056                          * Pragma    DeclDef
1057                          *           ;
1058                          */
1059                         nextToken();
1060                     }
1061                     else
1062                         a2 = parseBlock(pLastDecl);
1063                     s = new PragmaDeclaration(loc, ident, args, a2);
1064                     break;
1065                 }
1066             case TOKdebug:
1067                 nextToken();
1068                 if (token.value == TOKassign)
1069                 {
1070                     nextToken();
1071                     if (token.value == TOKidentifier)
1072                         s = new DebugSymbol(token.loc, token.ident);
1073                     else if (token.value == TOKint32v || token.value == TOKint64v)
1074                         s = new DebugSymbol(token.loc, cast(uint)token.uns64value);
1075                     else
1076                     {
1077                         error("identifier or integer expected, not %s", token.toChars());
1078                         s = null;
1079                     }
1080                     nextToken();
1081                     if (token.value != TOKsemicolon)
1082                         error("semicolon expected");
1083                     nextToken();
1084                     break;
1085                 }
1086 
1087                 condition = parseDebugCondition();
1088                 goto Lcondition;
1089 
1090             case TOKversion:
1091                 nextToken();
1092                 if (token.value == TOKassign)
1093                 {
1094                     nextToken();
1095                     if (token.value == TOKidentifier)
1096                         s = new VersionSymbol(token.loc, token.ident);
1097                     else if (token.value == TOKint32v || token.value == TOKint64v)
1098                         s = new VersionSymbol(token.loc, cast(uint)token.uns64value);
1099                     else
1100                     {
1101                         error("identifier or integer expected, not %s", token.toChars());
1102                         s = null;
1103                     }
1104                     nextToken();
1105                     if (token.value != TOKsemicolon)
1106                         error("semicolon expected");
1107                     nextToken();
1108                     break;
1109                 }
1110                 condition = parseVersionCondition();
1111                 goto Lcondition;
1112 
1113             Lcondition:
1114                 {
1115                     Dsymbols* athen;
1116                     if (token.value == TOKcolon)
1117                         athen = parseBlock(pLastDecl);
1118                     else
1119                     {
1120                         const lookingForElseSave = lookingForElse;
1121                         lookingForElse = token.loc;
1122                         athen = parseBlock(pLastDecl);
1123                         lookingForElse = lookingForElseSave;
1124                     }
1125                     Dsymbols* aelse = null;
1126                     if (token.value == TOKelse)
1127                     {
1128                         const elseloc = token.loc;
1129                         nextToken();
1130                         aelse = parseBlock(pLastDecl);
1131                         checkDanglingElse(elseloc);
1132                     }
1133                     s = new ConditionalDeclaration(condition, athen, aelse);
1134                     break;
1135                 }
1136             case TOKsemicolon:
1137                 // empty declaration
1138                 //error("empty declaration");
1139                 nextToken();
1140                 continue;
1141 
1142             default:
1143                 error("declaration expected, not '%s'", token.toChars());
1144             Lerror:
1145                 while (token.value != TOKsemicolon && token.value != TOKeof)
1146                     nextToken();
1147                 nextToken();
1148                 s = null;
1149                 continue;
1150             }
1151 
1152             if (s)
1153             {
1154                 if (!s.isAttribDeclaration())
1155                     *pLastDecl = s;
1156                 decldefs.push(s);
1157                 addComment(s, pAttrs.comment);
1158             }
1159             else if (a && a.dim)
1160             {
1161                 decldefs.append(a);
1162             }
1163         }
1164         while (!once);
1165 
1166         linkage = linksave;
1167 
1168         return decldefs;
1169     }
1170 
1171     /*****************************************
1172      * Parse auto declarations of the form:
1173      *   storageClass ident = init, ident = init, ... ;
1174      * and return the array of them.
1175      * Starts with token on the first ident.
1176      * Ends with scanner past closing ';'
1177      */
1178     Dsymbols* parseAutoDeclarations(StorageClass storageClass, const(char)* comment)
1179     {
1180         //printf("parseAutoDeclarations\n");
1181         Token* tk;
1182         auto a = new Dsymbols();
1183 
1184         while (1)
1185         {
1186             const loc = token.loc;
1187             Identifier ident = token.ident;
1188             nextToken(); // skip over ident
1189 
1190             TemplateParameters* tpl = null;
1191             if (token.value == TOKlparen)
1192                 tpl = parseTemplateParameterList();
1193 
1194             check(TOKassign);   // skip over '='
1195             Initializer _init = parseInitializer();
1196             auto v = new VarDeclaration(loc, null, ident, _init, storageClass);
1197 
1198             Dsymbol s = v;
1199             if (tpl)
1200             {
1201                 auto a2 = new Dsymbols();
1202                 a2.push(v);
1203                 auto tempdecl = new TemplateDeclaration(loc, ident, tpl, null, a2, 0);
1204                 s = tempdecl;
1205             }
1206             a.push(s);
1207             switch (token.value)
1208             {
1209             case TOKsemicolon:
1210                 nextToken();
1211                 addComment(s, comment);
1212                 break;
1213 
1214             case TOKcomma:
1215                 nextToken();
1216                 if (!(token.value == TOKidentifier && skipParensIf(peek(&token), &tk) && tk.value == TOKassign))
1217                 {
1218                     error("identifier expected following comma");
1219                     break;
1220                 }
1221                 addComment(s, comment);
1222                 continue;
1223 
1224             default:
1225                 error("semicolon expected following auto declaration, not '%s'", token.toChars());
1226                 break;
1227             }
1228             break;
1229         }
1230         return a;
1231     }
1232 
1233     /********************************************
1234      * Parse declarations after an align, protection, or extern decl.
1235      */
1236     Dsymbols* parseBlock(Dsymbol* pLastDecl, PrefixAttributes* pAttrs = null)
1237     {
1238         Dsymbols* a = null;
1239 
1240         //printf("parseBlock()\n");
1241         switch (token.value)
1242         {
1243         case TOKsemicolon:
1244             error("declaration expected following attribute, not ';'");
1245             nextToken();
1246             break;
1247 
1248         case TOKeof:
1249             error("declaration expected following attribute, not EOF");
1250             break;
1251 
1252         case TOKlcurly:
1253             {
1254                 const lookingForElseSave = lookingForElse;
1255                 lookingForElse = Loc();
1256 
1257                 nextToken();
1258                 a = parseDeclDefs(0, pLastDecl);
1259                 if (token.value != TOKrcurly)
1260                 {
1261                     /* { */
1262                     error("matching '}' expected, not %s", token.toChars());
1263                 }
1264                 else
1265                     nextToken();
1266                 lookingForElse = lookingForElseSave;
1267                 break;
1268             }
1269         case TOKcolon:
1270             nextToken();
1271             a = parseDeclDefs(0, pLastDecl); // grab declarations up to closing curly bracket
1272             break;
1273 
1274         default:
1275             a = parseDeclDefs(1, pLastDecl, pAttrs);
1276             break;
1277         }
1278         return a;
1279     }
1280 
1281     /*********************************************
1282      * Give error on redundant/conflicting storage class.
1283      *
1284      * TODO: remove deprecation in 2.068 and keep only error
1285      */
1286     StorageClass appendStorageClass(StorageClass storageClass, StorageClass stc, bool deprec = false)
1287     {
1288         if ((storageClass & stc) || (storageClass & STCin && stc & (STCconst | STCscope)) || (stc & STCin && storageClass & (STCconst | STCscope)))
1289         {
1290             OutBuffer buf;
1291             stcToBuffer(&buf, stc);
1292             if (deprec)
1293                 deprecation("redundant attribute '%s'", buf.peekString());
1294             else
1295                 error("redundant attribute '%s'", buf.peekString());
1296             return storageClass | stc;
1297         }
1298 
1299         storageClass |= stc;
1300 
1301         if (stc & (STCconst | STCimmutable | STCmanifest))
1302         {
1303             StorageClass u = storageClass & (STCconst | STCimmutable | STCmanifest);
1304             if (u & (u - 1))
1305                 error("conflicting attribute '%s'", Token.toChars(token.value));
1306         }
1307         if (stc & (STCgshared | STCshared | STCtls))
1308         {
1309             StorageClass u = storageClass & (STCgshared | STCshared | STCtls);
1310             if (u & (u - 1))
1311                 error("conflicting attribute '%s'", Token.toChars(token.value));
1312         }
1313         if (stc & (STCsafe | STCsystem | STCtrusted))
1314         {
1315             StorageClass u = storageClass & (STCsafe | STCsystem | STCtrusted);
1316             if (u & (u - 1))
1317                 error("conflicting attribute '@%s'", token.toChars());
1318         }
1319 
1320         return storageClass;
1321     }
1322 
1323     /***********************************************
1324      * Parse attribute, lexer is on '@'.
1325      * Input:
1326      *      pudas           array of UDAs to append to
1327      * Returns:
1328      *      storage class   if a predefined attribute; also scanner remains on identifier.
1329      *      0               if not a predefined attribute
1330      *      *pudas          set if user defined attribute, scanner is past UDA
1331      *      *pudas          NULL if not a user defined attribute
1332      */
1333     StorageClass parseAttribute(Expressions** pudas)
1334     {
1335         nextToken();
1336         Expressions* udas = null;
1337         StorageClass stc = 0;
1338         if (token.value == TOKidentifier)
1339         {
1340             if (token.ident == Id.property)
1341                 stc = STCproperty;
1342             else if (token.ident == Id.nogc)
1343                 stc = STCnogc;
1344             else if (token.ident == Id.safe)
1345                 stc = STCsafe;
1346             else if (token.ident == Id.trusted)
1347                 stc = STCtrusted;
1348             else if (token.ident == Id.system)
1349                 stc = STCsystem;
1350             else if (token.ident == Id.disable)
1351                 stc = STCdisable;
1352             else
1353             {
1354                 // Allow identifier, template instantiation, or function call
1355                 Expression exp = parsePrimaryExp();
1356                 if (token.value == TOKlparen)
1357                 {
1358                     const loc = token.loc;
1359                     exp = new CallExp(loc, exp, parseArguments());
1360                 }
1361 
1362                 udas = new Expressions();
1363                 udas.push(exp);
1364             }
1365         }
1366         else if (token.value == TOKlparen)
1367         {
1368             // @( ArgumentList )
1369             // Concatenate with existing
1370             if (peekNext() == TOKrparen)
1371                 error("empty attribute list is not allowed");
1372             udas = parseArguments();
1373         }
1374         else
1375         {
1376             error("@identifier or @(ArgumentList) expected, not @%s", token.toChars());
1377         }
1378 
1379         if (stc)
1380         {
1381         }
1382         else if (udas)
1383         {
1384             *pudas = UserAttributeDeclaration.concat(*pudas, udas);
1385         }
1386         else
1387             error("valid attributes are @property, @safe, @trusted, @system, @disable, @nogc");
1388         return stc;
1389     }
1390 
1391     /***********************************************
1392      * Parse const/immutable/shared/inout/nothrow/pure postfix
1393      */
1394     StorageClass parsePostfix(StorageClass storageClass, Expressions** pudas)
1395     {
1396         while (1)
1397         {
1398             StorageClass stc;
1399             switch (token.value)
1400             {
1401             case TOKconst:
1402                 stc = STCconst;
1403                 break;
1404 
1405             case TOKimmutable:
1406                 stc = STCimmutable;
1407                 break;
1408 
1409             case TOKshared:
1410                 stc = STCshared;
1411                 break;
1412 
1413             case TOKwild:
1414                 stc = STCwild;
1415                 break;
1416 
1417             case TOKnothrow:
1418                 stc = STCnothrow;
1419                 break;
1420 
1421             case TOKpure:
1422                 stc = STCpure;
1423                 break;
1424 
1425             case TOKreturn:
1426                 stc = STCreturn;
1427                 break;
1428 
1429             case TOKscope:
1430                 stc = STCscope;
1431                 break;
1432 
1433             case TOKat:
1434                 {
1435                     Expressions* udas = null;
1436                     stc = parseAttribute(&udas);
1437                     if (udas)
1438                     {
1439                         if (pudas)
1440                             *pudas = UserAttributeDeclaration.concat(*pudas, udas);
1441                         else
1442                         {
1443                             // Disallow:
1444                             //      void function() @uda fp;
1445                             //      () @uda { return 1; }
1446                             error("user defined attributes cannot appear as postfixes");
1447                         }
1448                         continue;
1449                     }
1450                     break;
1451                 }
1452             default:
1453                 return storageClass;
1454             }
1455             storageClass = appendStorageClass(storageClass, stc, true);
1456             nextToken();
1457         }
1458     }
1459 
1460     StorageClass parseTypeCtor()
1461     {
1462         StorageClass storageClass = STCundefined;
1463 
1464         while (1)
1465         {
1466             if (peek(&token).value == TOKlparen)
1467                 return storageClass;
1468 
1469             StorageClass stc;
1470             switch (token.value)
1471             {
1472             case TOKconst:
1473                 stc = STCconst;
1474                 break;
1475 
1476             case TOKimmutable:
1477                 stc = STCimmutable;
1478                 break;
1479 
1480             case TOKshared:
1481                 stc = STCshared;
1482                 break;
1483 
1484             case TOKwild:
1485                 stc = STCwild;
1486                 break;
1487 
1488             default:
1489                 return storageClass;
1490             }
1491             storageClass = appendStorageClass(storageClass, stc);
1492             nextToken();
1493         }
1494     }
1495 
1496     /**************************************
1497      * Parse constraint.
1498      * Constraint is of the form:
1499      *      if ( ConstraintExpression )
1500      */
1501     Expression parseConstraint()
1502     {
1503         Expression e = null;
1504         if (token.value == TOKif)
1505         {
1506             nextToken(); // skip over 'if'
1507             check(TOKlparen);
1508             e = parseExpression();
1509             check(TOKrparen);
1510         }
1511         return e;
1512     }
1513 
1514     /**************************************
1515      * Parse a TemplateDeclaration.
1516      */
1517     TemplateDeclaration parseTemplateDeclaration(bool ismixin = false)
1518     {
1519         TemplateDeclaration tempdecl;
1520         Identifier id;
1521         TemplateParameters* tpl;
1522         Dsymbols* decldefs;
1523         Expression constraint = null;
1524         const loc = token.loc;
1525 
1526         nextToken();
1527         if (token.value != TOKidentifier)
1528         {
1529             error("identifier expected following template");
1530             goto Lerr;
1531         }
1532         id = token.ident;
1533         nextToken();
1534         tpl = parseTemplateParameterList();
1535         if (!tpl)
1536             goto Lerr;
1537 
1538         constraint = parseConstraint();
1539 
1540         if (token.value != TOKlcurly)
1541         {
1542             error("members of template declaration expected");
1543             goto Lerr;
1544         }
1545         else
1546         {
1547             nextToken();
1548             decldefs = parseDeclDefs(0);
1549             if (token.value != TOKrcurly)
1550             {
1551                 error("template member expected");
1552                 goto Lerr;
1553             }
1554             nextToken();
1555         }
1556 
1557         tempdecl = new TemplateDeclaration(loc, id, tpl, constraint, decldefs, ismixin);
1558         return tempdecl;
1559 
1560     Lerr:
1561         return null;
1562     }
1563 
1564     /******************************************
1565      * Parse template parameter list.
1566      * Input:
1567      *      flag    0: parsing "( list )"
1568      *              1: parsing non-empty "list $(RPAREN)"
1569      */
1570     TemplateParameters* parseTemplateParameterList(int flag = 0)
1571     {
1572         auto tpl = new TemplateParameters();
1573 
1574         if (!flag && token.value != TOKlparen)
1575         {
1576             error("parenthesized TemplateParameterList expected following TemplateIdentifier");
1577             goto Lerr;
1578         }
1579         nextToken();
1580 
1581         // Get array of TemplateParameters
1582         if (flag || token.value != TOKrparen)
1583         {
1584             int isvariadic = 0;
1585             while (token.value != TOKrparen)
1586             {
1587                 TemplateParameter tp;
1588                 Loc loc;
1589                 Identifier tp_ident = null;
1590                 Type tp_spectype = null;
1591                 Type tp_valtype = null;
1592                 Type tp_defaulttype = null;
1593                 Expression tp_specvalue = null;
1594                 Expression tp_defaultvalue = null;
1595                 Token* t;
1596 
1597                 // Get TemplateParameter
1598 
1599                 // First, look ahead to see if it is a TypeParameter or a ValueParameter
1600                 t = peek(&token);
1601                 if (token.value == TOKalias)
1602                 {
1603                     // AliasParameter
1604                     nextToken();
1605                     loc = token.loc; // todo
1606                     Type spectype = null;
1607                     if (isDeclaration(&token, NeedDeclaratorId.must, TOKreserved, null))
1608                     {
1609                         spectype = parseType(&tp_ident);
1610                     }
1611                     else
1612                     {
1613                         if (token.value != TOKidentifier)
1614                         {
1615                             error("identifier expected for template alias parameter");
1616                             goto Lerr;
1617                         }
1618                         tp_ident = token.ident;
1619                         nextToken();
1620                     }
1621                     RootObject spec = null;
1622                     if (token.value == TOKcolon) // : Type
1623                     {
1624                         nextToken();
1625                         if (isDeclaration(&token, NeedDeclaratorId.no, TOKreserved, null))
1626                             spec = parseType();
1627                         else
1628                             spec = parseCondExp();
1629                     }
1630                     RootObject def = null;
1631                     if (token.value == TOKassign) // = Type
1632                     {
1633                         nextToken();
1634                         if (isDeclaration(&token, NeedDeclaratorId.no, TOKreserved, null))
1635                             def = parseType();
1636                         else
1637                             def = parseCondExp();
1638                     }
1639                     tp = new TemplateAliasParameter(loc, tp_ident, spectype, spec, def);
1640                 }
1641                 else if (t.value == TOKcolon || t.value == TOKassign || t.value == TOKcomma || t.value == TOKrparen)
1642                 {
1643                     // TypeParameter
1644                     if (token.value != TOKidentifier)
1645                     {
1646                         error("identifier expected for template type parameter");
1647                         goto Lerr;
1648                     }
1649                     loc = token.loc;
1650                     tp_ident = token.ident;
1651                     nextToken();
1652                     if (token.value == TOKcolon) // : Type
1653                     {
1654                         nextToken();
1655                         tp_spectype = parseType();
1656                     }
1657                     if (token.value == TOKassign) // = Type
1658                     {
1659                         nextToken();
1660                         tp_defaulttype = parseType();
1661                     }
1662                     tp = new TemplateTypeParameter(loc, tp_ident, tp_spectype, tp_defaulttype);
1663                 }
1664                 else if (token.value == TOKidentifier && t.value == TOKdotdotdot)
1665                 {
1666                     // ident...
1667                     if (isvariadic)
1668                         error("variadic template parameter must be last");
1669                     isvariadic = 1;
1670                     loc = token.loc;
1671                     tp_ident = token.ident;
1672                     nextToken();
1673                     nextToken();
1674                     tp = new TemplateTupleParameter(loc, tp_ident);
1675                 }
1676                 else if (token.value == TOKthis)
1677                 {
1678                     // ThisParameter
1679                     nextToken();
1680                     if (token.value != TOKidentifier)
1681                     {
1682                         error("identifier expected for template this parameter");
1683                         goto Lerr;
1684                     }
1685                     loc = token.loc;
1686                     tp_ident = token.ident;
1687                     nextToken();
1688                     if (token.value == TOKcolon) // : Type
1689                     {
1690                         nextToken();
1691                         tp_spectype = parseType();
1692                     }
1693                     if (token.value == TOKassign) // = Type
1694                     {
1695                         nextToken();
1696                         tp_defaulttype = parseType();
1697                     }
1698                     tp = new TemplateThisParameter(loc, tp_ident, tp_spectype, tp_defaulttype);
1699                 }
1700                 else
1701                 {
1702                     // ValueParameter
1703                     loc = token.loc; // todo
1704                     tp_valtype = parseType(&tp_ident);
1705                     if (!tp_ident)
1706                     {
1707                         error("identifier expected for template value parameter");
1708                         tp_ident = Identifier.idPool("error");
1709                     }
1710                     if (token.value == TOKcolon) // : CondExpression
1711                     {
1712                         nextToken();
1713                         tp_specvalue = parseCondExp();
1714                     }
1715                     if (token.value == TOKassign) // = CondExpression
1716                     {
1717                         nextToken();
1718                         tp_defaultvalue = parseDefaultInitExp();
1719                     }
1720                     tp = new TemplateValueParameter(loc, tp_ident, tp_valtype, tp_specvalue, tp_defaultvalue);
1721                 }
1722                 tpl.push(tp);
1723                 if (token.value != TOKcomma)
1724                     break;
1725                 nextToken();
1726             }
1727         }
1728         check(TOKrparen);
1729 
1730     Lerr:
1731         return tpl;
1732     }
1733 
1734     /******************************************
1735      * Parse template mixin.
1736      *      mixin Foo;
1737      *      mixin Foo!(args);
1738      *      mixin a.b.c!(args).Foo!(args);
1739      *      mixin Foo!(args) identifier;
1740      *      mixin typeof(expr).identifier!(args);
1741      */
1742     Dsymbol parseMixin()
1743     {
1744         TemplateMixin tm;
1745         Identifier id;
1746         Objects* tiargs;
1747 
1748         //printf("parseMixin()\n");
1749         const locMixin = token.loc;
1750         nextToken(); // skip 'mixin'
1751 
1752         auto loc = token.loc;
1753         TypeQualified tqual = null;
1754         if (token.value == TOKdot)
1755         {
1756             id = Id.empty;
1757         }
1758         else
1759         {
1760             if (token.value == TOKtypeof)
1761             {
1762                 tqual = parseTypeof();
1763                 check(TOKdot);
1764             }
1765             if (token.value != TOKidentifier)
1766             {
1767                 error("identifier expected, not %s", token.toChars());
1768                 id = Id.empty;
1769             }
1770             else
1771                 id = token.ident;
1772             nextToken();
1773         }
1774 
1775         while (1)
1776         {
1777             tiargs = null;
1778             if (token.value == TOKnot)
1779             {
1780                 tiargs = parseTemplateArguments();
1781             }
1782 
1783             if (tiargs && token.value == TOKdot)
1784             {
1785                 auto tempinst = new TemplateInstance(loc, id, tiargs);
1786                 if (!tqual)
1787                     tqual = new TypeInstance(loc, tempinst);
1788                 else
1789                     tqual.addInst(tempinst);
1790                 tiargs = null;
1791             }
1792             else
1793             {
1794                 if (!tqual)
1795                     tqual = new TypeIdentifier(loc, id);
1796                 else
1797                     tqual.addIdent(id);
1798             }
1799 
1800             if (token.value != TOKdot)
1801                 break;
1802 
1803             nextToken();
1804             if (token.value != TOKidentifier)
1805             {
1806                 error("identifier expected following '.' instead of '%s'", token.toChars());
1807                 break;
1808             }
1809             loc = token.loc;
1810             id = token.ident;
1811             nextToken();
1812         }
1813 
1814         if (token.value == TOKidentifier)
1815         {
1816             id = token.ident;
1817             nextToken();
1818         }
1819         else
1820             id = null;
1821 
1822         tm = new TemplateMixin(locMixin, id, tqual, tiargs);
1823         if (token.value != TOKsemicolon)
1824             error("';' expected after mixin");
1825         nextToken();
1826 
1827         return tm;
1828     }
1829 
1830     /******************************************
1831      * Parse template arguments.
1832      * Input:
1833      *      current token is opening '!'
1834      * Output:
1835      *      current token is one after closing '$(RPAREN)'
1836      */
1837     Objects* parseTemplateArguments()
1838     {
1839         Objects* tiargs;
1840 
1841         nextToken();
1842         if (token.value == TOKlparen)
1843         {
1844             // ident!(template_arguments)
1845             tiargs = parseTemplateArgumentList();
1846         }
1847         else
1848         {
1849             // ident!template_argument
1850             tiargs = parseTemplateSingleArgument();
1851         }
1852         if (token.value == TOKnot)
1853         {
1854             TOK tok = peekNext();
1855             if (tok != TOKis && tok != TOKin)
1856             {
1857                 error("multiple ! arguments are not allowed");
1858             Lagain:
1859                 nextToken();
1860                 if (token.value == TOKlparen)
1861                     parseTemplateArgumentList();
1862                 else
1863                     parseTemplateSingleArgument();
1864                 if (token.value == TOKnot && (tok = peekNext()) != TOKis && tok != TOKin)
1865                     goto Lagain;
1866             }
1867         }
1868         return tiargs;
1869     }
1870 
1871     /******************************************
1872      * Parse template argument list.
1873      * Input:
1874      *      current token is opening '$(LPAREN)',
1875      *          or ',' for __traits
1876      * Output:
1877      *      current token is one after closing '$(RPAREN)'
1878      */
1879     Objects* parseTemplateArgumentList()
1880     {
1881         //printf("Parser::parseTemplateArgumentList()\n");
1882         auto tiargs = new Objects();
1883         TOK endtok = TOKrparen;
1884         assert(token.value == TOKlparen || token.value == TOKcomma);
1885         nextToken();
1886 
1887         // Get TemplateArgumentList
1888         while (token.value != endtok)
1889         {
1890             // See if it is an Expression or a Type
1891             if (isDeclaration(&token, NeedDeclaratorId.no, TOKreserved, null))
1892             {
1893                 // Template argument is a type
1894                 Type ta = parseType();
1895                 tiargs.push(ta);
1896             }
1897             else
1898             {
1899                 // Template argument is an expression
1900                 Expression ea = parseAssignExp();
1901                 tiargs.push(ea);
1902             }
1903             if (token.value != TOKcomma)
1904                 break;
1905             nextToken();
1906         }
1907         check(endtok, "template argument list");
1908         return tiargs;
1909     }
1910 
1911     /*****************************
1912      * Parse single template argument, to support the syntax:
1913      *      foo!arg
1914      * Input:
1915      *      current token is the arg
1916      */
1917     Objects* parseTemplateSingleArgument()
1918     {
1919         //printf("parseTemplateSingleArgument()\n");
1920         auto tiargs = new Objects();
1921         Type ta;
1922         switch (token.value)
1923         {
1924         case TOKidentifier:
1925             ta = new TypeIdentifier(token.loc, token.ident);
1926             goto LabelX;
1927 
1928         case TOKvector:
1929             ta = parseVector();
1930             goto LabelX;
1931 
1932         case TOKvoid:
1933             ta = Type.tvoid;
1934             goto LabelX;
1935 
1936         case TOKint8:
1937             ta = Type.tint8;
1938             goto LabelX;
1939 
1940         case TOKuns8:
1941             ta = Type.tuns8;
1942             goto LabelX;
1943 
1944         case TOKint16:
1945             ta = Type.tint16;
1946             goto LabelX;
1947 
1948         case TOKuns16:
1949             ta = Type.tuns16;
1950             goto LabelX;
1951 
1952         case TOKint32:
1953             ta = Type.tint32;
1954             goto LabelX;
1955 
1956         case TOKuns32:
1957             ta = Type.tuns32;
1958             goto LabelX;
1959 
1960         case TOKint64:
1961             ta = Type.tint64;
1962             goto LabelX;
1963 
1964         case TOKuns64:
1965             ta = Type.tuns64;
1966             goto LabelX;
1967 
1968         case TOKint128:
1969             ta = Type.tint128;
1970             goto LabelX;
1971 
1972         case TOKuns128:
1973             ta = Type.tuns128;
1974             goto LabelX;
1975 
1976         case TOKfloat32:
1977             ta = Type.tfloat32;
1978             goto LabelX;
1979 
1980         case TOKfloat64:
1981             ta = Type.tfloat64;
1982             goto LabelX;
1983 
1984         case TOKfloat80:
1985             ta = Type.tfloat80;
1986             goto LabelX;
1987 
1988         case TOKimaginary32:
1989             ta = Type.timaginary32;
1990             goto LabelX;
1991 
1992         case TOKimaginary64:
1993             ta = Type.timaginary64;
1994             goto LabelX;
1995 
1996         case TOKimaginary80:
1997             ta = Type.timaginary80;
1998             goto LabelX;
1999 
2000         case TOKcomplex32:
2001             ta = Type.tcomplex32;
2002             goto LabelX;
2003 
2004         case TOKcomplex64:
2005             ta = Type.tcomplex64;
2006             goto LabelX;
2007 
2008         case TOKcomplex80:
2009             ta = Type.tcomplex80;
2010             goto LabelX;
2011 
2012         case TOKbool:
2013             ta = Type.tbool;
2014             goto LabelX;
2015 
2016         case TOKchar:
2017             ta = Type.tchar;
2018             goto LabelX;
2019 
2020         case TOKwchar:
2021             ta = Type.twchar;
2022             goto LabelX;
2023 
2024         case TOKdchar:
2025             ta = Type.tdchar;
2026             goto LabelX;
2027         LabelX:
2028             tiargs.push(ta);
2029             nextToken();
2030             break;
2031 
2032         case TOKint32v:
2033         case TOKuns32v:
2034         case TOKint64v:
2035         case TOKuns64v:
2036         case TOKint128v:
2037         case TOKuns128v:
2038         case TOKfloat32v:
2039         case TOKfloat64v:
2040         case TOKfloat80v:
2041         case TOKimaginary32v:
2042         case TOKimaginary64v:
2043         case TOKimaginary80v:
2044         case TOKnull:
2045         case TOKtrue:
2046         case TOKfalse:
2047         case TOKcharv:
2048         case TOKwcharv:
2049         case TOKdcharv:
2050         case TOKstring:
2051         case TOKxstring:
2052         case TOKfile:
2053         case TOKfilefullpath:
2054         case TOKline:
2055         case TOKmodulestring:
2056         case TOKfuncstring:
2057         case TOKprettyfunc:
2058         case TOKthis:
2059             {
2060                 // Template argument is an expression
2061                 Expression ea = parsePrimaryExp();
2062                 tiargs.push(ea);
2063                 break;
2064             }
2065         default:
2066             error("template argument expected following !");
2067             break;
2068         }
2069         return tiargs;
2070     }
2071 
2072     /**********************************
2073      * Parse a static assertion.
2074      * Current token is 'static'.
2075      */
2076     StaticAssert parseStaticAssert()
2077     {
2078         const loc = token.loc;
2079         Expression exp;
2080         Expression msg = null;
2081 
2082         //printf("parseStaticAssert()\n");
2083         nextToken();
2084         nextToken();
2085         check(TOKlparen);
2086         exp = parseAssignExp();
2087         if (token.value == TOKcomma)
2088         {
2089             nextToken();
2090             if (token.value != TOKrparen)
2091             {
2092                 msg = parseAssignExp();
2093                 if (token.value == TOKcomma)
2094                     nextToken();
2095             }
2096         }
2097         check(TOKrparen);
2098         check(TOKsemicolon);
2099         return new StaticAssert(loc, exp, msg);
2100     }
2101 
2102     /***********************************
2103      * Parse typeof(expression).
2104      * Current token is on the 'typeof'.
2105      */
2106     TypeQualified parseTypeof()
2107     {
2108         TypeQualified t;
2109         const loc = token.loc;
2110 
2111         nextToken();
2112         check(TOKlparen);
2113         if (token.value == TOKreturn) // typeof(return)
2114         {
2115             nextToken();
2116             t = new TypeReturn(loc);
2117         }
2118         else
2119         {
2120             Expression exp = parseExpression(); // typeof(expression)
2121             t = new TypeTypeof(loc, exp);
2122         }
2123         check(TOKrparen);
2124         return t;
2125     }
2126 
2127     /***********************************
2128      * Parse __vector(type).
2129      * Current token is on the '__vector'.
2130      */
2131     Type parseVector()
2132     {
2133         const loc = token.loc;
2134         nextToken();
2135         check(TOKlparen);
2136         Type tb = parseType();
2137         check(TOKrparen);
2138         return new TypeVector(loc, tb);
2139     }
2140 
2141     /***********************************
2142      * Parse:
2143      *      extern (linkage)
2144      *      extern (C++, namespaces)
2145      * The parser is on the 'extern' token.
2146      */
2147     LINK parseLinkage(Identifiers** pidents, out CPPMANGLE cppmangle)
2148     {
2149         Identifiers* idents = null;
2150         cppmangle = CPPMANGLE.def;
2151         LINK link = LINKdefault;
2152         nextToken();
2153         assert(token.value == TOKlparen);
2154         nextToken();
2155         if (token.value == TOKidentifier)
2156         {
2157             Identifier id = token.ident;
2158             nextToken();
2159             if (id == Id.Windows)
2160                 link = LINKwindows;
2161             else if (id == Id.Pascal)
2162                 link = LINKpascal;
2163             else if (id == Id.D)
2164                 link = LINKd;
2165             else if (id == Id.C)
2166             {
2167                 link = LINKc;
2168                 if (token.value == TOKplusplus)
2169                 {
2170                     link = LINKcpp;
2171                     nextToken();
2172                     if (token.value == TOKcomma) // , namespaces or class or struct
2173                     {
2174                         nextToken();
2175                         if (token.value == TOKclass || token.value == TOKstruct)
2176                         {
2177                             cppmangle = token.value == TOKclass ? CPPMANGLE.asClass : CPPMANGLE.asStruct;
2178                             nextToken();
2179                         }
2180                         else
2181                         {
2182                             idents = new Identifiers();
2183                             while (1)
2184                             {
2185                                 if (token.value == TOKidentifier)
2186                                 {
2187                                     Identifier idn = token.ident;
2188                                     idents.push(idn);
2189                                     nextToken();
2190                                     if (token.value == TOKdot)
2191                                     {
2192                                         nextToken();
2193                                         continue;
2194                                     }
2195                                 }
2196                                 else
2197                                     error("identifier expected for C++ namespace");
2198                                 break;
2199                             }
2200                         }
2201                     }
2202                 }
2203             }
2204             else if (id == Id.Objective) // Looking for tokens "Objective-C"
2205             {
2206                 if (token.value == TOKmin)
2207                 {
2208                     nextToken();
2209                     if (token.ident == Id.C)
2210                     {
2211                         link = LINKobjc;
2212                         nextToken();
2213                     }
2214                     else
2215                         goto LinvalidLinkage;
2216                 }
2217                 else
2218                     goto LinvalidLinkage;
2219             }
2220             else if (id == Id.System)
2221             {
2222                 link = global.params.isWindows ? LINKwindows : LINKc;
2223             }
2224             else
2225             {
2226             LinvalidLinkage:
2227                 error("valid linkage identifiers are D, C, C++, Objective-C, Pascal, Windows, System");
2228                 link = LINKd;
2229             }
2230         }
2231         else
2232         {
2233             link = LINKd; // default
2234         }
2235         check(TOKrparen);
2236         *pidents = idents;
2237         return link;
2238     }
2239 
2240     /***********************************
2241      * Parse ident1.ident2.ident3
2242      *
2243      * Params:
2244      *  entity = what qualified identifier is expected to resolve into.
2245      *     Used only for better error message
2246      *
2247      * Returns:
2248      *     array of identifiers with actual qualified one stored last
2249      */
2250     Identifiers* parseQualifiedIdentifier(const(char)* entity)
2251     {
2252         Identifiers* qualified = null;
2253 
2254         do
2255         {
2256             nextToken();
2257             if (token.value != TOKidentifier)
2258             {
2259                 error("%s expected as dot-separated identifiers, got '%s'", entity, token.toChars());
2260                 return null;
2261             }
2262 
2263             Identifier id = token.ident;
2264             if (!qualified)
2265                 qualified = new Identifiers();
2266             qualified.push(id);
2267 
2268             nextToken();
2269         }
2270         while (token.value == TOKdot);
2271 
2272         return qualified;
2273     }
2274 
2275     /**************************************
2276      * Parse a debug conditional
2277      */
2278     Condition parseDebugCondition()
2279     {
2280         uint level = 1;
2281         Identifier id = null;
2282 
2283         if (token.value == TOKlparen)
2284         {
2285             nextToken();
2286 
2287             if (token.value == TOKidentifier)
2288                 id = token.ident;
2289             else if (token.value == TOKint32v || token.value == TOKint64v)
2290                 level = cast(uint)token.uns64value;
2291             else
2292                 error("identifier or integer expected inside debug(...), not %s", token.toChars());
2293             nextToken();
2294             check(TOKrparen);
2295         }
2296         return new DebugCondition(mod, level, id);
2297     }
2298 
2299     /**************************************
2300      * Parse a version conditional
2301      */
2302     Condition parseVersionCondition()
2303     {
2304         uint level = 1;
2305         Identifier id = null;
2306 
2307         if (token.value == TOKlparen)
2308         {
2309             nextToken();
2310             /* Allow:
2311              *    version (unittest)
2312              *    version (assert)
2313              * even though they are keywords
2314              */
2315             if (token.value == TOKidentifier)
2316                 id = token.ident;
2317             else if (token.value == TOKint32v || token.value == TOKint64v)
2318                 level = cast(uint)token.uns64value;
2319             else if (token.value == TOKunittest)
2320                 id = Identifier.idPool(Token.toString(TOKunittest));
2321             else if (token.value == TOKassert)
2322                 id = Identifier.idPool(Token.toString(TOKassert));
2323             else
2324                 error("identifier or integer expected inside version(...), not %s", token.toChars());
2325             nextToken();
2326             check(TOKrparen);
2327         }
2328         else
2329             error("(condition) expected following version");
2330         return new VersionCondition(mod, level, id);
2331     }
2332 
2333     /***********************************************
2334      *      static if (expression)
2335      *          body
2336      *      else
2337      *          body
2338      * Current token is 'static'.
2339      */
2340     Condition parseStaticIfCondition()
2341     {
2342         Expression exp;
2343         Condition condition;
2344         const loc = token.loc;
2345 
2346         nextToken();
2347         nextToken();
2348         if (token.value == TOKlparen)
2349         {
2350             nextToken();
2351             exp = parseAssignExp();
2352             check(TOKrparen);
2353         }
2354         else
2355         {
2356             error("(expression) expected following static if");
2357             exp = null;
2358         }
2359         condition = new StaticIfCondition(loc, exp);
2360         return condition;
2361     }
2362 
2363     /*****************************************
2364      * Parse a constructor definition:
2365      *      this(parameters) { body }
2366      * or postblit:
2367      *      this(this) { body }
2368      * or constructor template:
2369      *      this(templateparameters)(parameters) { body }
2370      * Current token is 'this'.
2371      */
2372     Dsymbol parseCtor(PrefixAttributes* pAttrs)
2373     {
2374         Expressions* udas = null;
2375         const loc = token.loc;
2376         StorageClass stc = getStorageClass(pAttrs);
2377 
2378         nextToken();
2379         if (token.value == TOKlparen && peekNext() == TOKthis && peekNext2() == TOKrparen)
2380         {
2381             // this(this) { ... }
2382             nextToken();
2383             nextToken();
2384             check(TOKrparen);
2385 
2386             stc = parsePostfix(stc, &udas);
2387             if (stc & STCstatic)
2388                 error(loc, "postblit cannot be static");
2389 
2390             auto f = new PostBlitDeclaration(loc, Loc(), stc, Id.postblit);
2391             Dsymbol s = parseContracts(f);
2392             if (udas)
2393             {
2394                 auto a = new Dsymbols();
2395                 a.push(f);
2396                 s = new UserAttributeDeclaration(udas, a);
2397             }
2398             return s;
2399         }
2400 
2401         /* Look ahead to see if:
2402          *   this(...)(...)
2403          * which is a constructor template
2404          */
2405         TemplateParameters* tpl = null;
2406         if (token.value == TOKlparen && peekPastParen(&token).value == TOKlparen)
2407         {
2408             tpl = parseTemplateParameterList();
2409         }
2410 
2411         /* Just a regular constructor
2412          */
2413         int varargs;
2414         Parameters* parameters = parseParameters(&varargs);
2415         stc = parsePostfix(stc, &udas);
2416         if (varargs != 0 || Parameter.dim(parameters) != 0)
2417         {
2418             if (stc & STCstatic)
2419                 error(loc, "constructor cannot be static");
2420         }
2421         else if (StorageClass ss = stc & (STCshared | STCstatic)) // this()
2422         {
2423             if (ss == STCstatic)
2424                 error(loc, "use 'static this()' to declare a static constructor");
2425             else if (ss == (STCshared | STCstatic))
2426                 error(loc, "use 'shared static this()' to declare a shared static constructor");
2427         }
2428 
2429         Expression constraint = tpl ? parseConstraint() : null;
2430 
2431         Type tf = new TypeFunction(parameters, null, varargs, linkage, stc); // RetrunType -> auto
2432         tf = tf.addSTC(stc);
2433 
2434         auto f = new CtorDeclaration(loc, Loc(), stc, tf);
2435         Dsymbol s = parseContracts(f);
2436         if (udas)
2437         {
2438             auto a = new Dsymbols();
2439             a.push(f);
2440             s = new UserAttributeDeclaration(udas, a);
2441         }
2442 
2443         if (tpl)
2444         {
2445             // Wrap a template around it
2446             auto decldefs = new Dsymbols();
2447             decldefs.push(s);
2448             s = new TemplateDeclaration(loc, f.ident, tpl, constraint, decldefs);
2449         }
2450 
2451         return s;
2452     }
2453 
2454     /*****************************************
2455      * Parse a destructor definition:
2456      *      ~this() { body }
2457      * Current token is '~'.
2458      */
2459     Dsymbol parseDtor(PrefixAttributes* pAttrs)
2460     {
2461         Expressions* udas = null;
2462         const loc = token.loc;
2463         StorageClass stc = getStorageClass(pAttrs);
2464 
2465         nextToken();
2466         check(TOKthis);
2467         check(TOKlparen);
2468         check(TOKrparen);
2469 
2470         stc = parsePostfix(stc, &udas);
2471         if (StorageClass ss = stc & (STCshared | STCstatic))
2472         {
2473             if (ss == STCstatic)
2474                 error(loc, "use 'static ~this()' to declare a static destructor");
2475             else if (ss == (STCshared | STCstatic))
2476                 error(loc, "use 'shared static ~this()' to declare a shared static destructor");
2477         }
2478 
2479         auto f = new DtorDeclaration(loc, Loc(), stc, Id.dtor);
2480         Dsymbol s = parseContracts(f);
2481         if (udas)
2482         {
2483             auto a = new Dsymbols();
2484             a.push(f);
2485             s = new UserAttributeDeclaration(udas, a);
2486         }
2487         return s;
2488     }
2489 
2490     /*****************************************
2491      * Parse a static constructor definition:
2492      *      static this() { body }
2493      * Current token is 'static'.
2494      */
2495     Dsymbol parseStaticCtor(PrefixAttributes* pAttrs)
2496     {
2497         //Expressions *udas = NULL;
2498         const loc = token.loc;
2499         StorageClass stc = getStorageClass(pAttrs);
2500 
2501         nextToken();
2502         nextToken();
2503         check(TOKlparen);
2504         check(TOKrparen);
2505 
2506         stc = parsePostfix(stc & ~STC_TYPECTOR, null) | stc;
2507         if (stc & STCshared)
2508             error(loc, "use 'shared static this()' to declare a shared static constructor");
2509         else if (stc & STCstatic)
2510             appendStorageClass(stc, STCstatic); // complaint for the redundancy
2511         else if (StorageClass modStc = stc & STC_TYPECTOR)
2512         {
2513             OutBuffer buf;
2514             stcToBuffer(&buf, modStc);
2515             error(loc, "static constructor cannot be %s", buf.peekString());
2516         }
2517         stc &= ~(STCstatic | STC_TYPECTOR);
2518 
2519         auto f = new StaticCtorDeclaration(loc, Loc(), stc);
2520         Dsymbol s = parseContracts(f);
2521         return s;
2522     }
2523 
2524     /*****************************************
2525      * Parse a static destructor definition:
2526      *      static ~this() { body }
2527      * Current token is 'static'.
2528      */
2529     Dsymbol parseStaticDtor(PrefixAttributes* pAttrs)
2530     {
2531         Expressions* udas = null;
2532         const loc = token.loc;
2533         StorageClass stc = getStorageClass(pAttrs);
2534 
2535         nextToken();
2536         nextToken();
2537         check(TOKthis);
2538         check(TOKlparen);
2539         check(TOKrparen);
2540 
2541         stc = parsePostfix(stc & ~STC_TYPECTOR, &udas) | stc;
2542         if (stc & STCshared)
2543             error(loc, "use 'shared static ~this()' to declare a shared static destructor");
2544         else if (stc & STCstatic)
2545             appendStorageClass(stc, STCstatic); // complaint for the redundancy
2546         else if (StorageClass modStc = stc & STC_TYPECTOR)
2547         {
2548             OutBuffer buf;
2549             stcToBuffer(&buf, modStc);
2550             error(loc, "static destructor cannot be %s", buf.peekString());
2551         }
2552         stc &= ~(STCstatic | STC_TYPECTOR);
2553 
2554         auto f = new StaticDtorDeclaration(loc, Loc(), stc);
2555         Dsymbol s = parseContracts(f);
2556         if (udas)
2557         {
2558             auto a = new Dsymbols();
2559             a.push(f);
2560             s = new UserAttributeDeclaration(udas, a);
2561         }
2562         return s;
2563     }
2564 
2565     /*****************************************
2566      * Parse a shared static constructor definition:
2567      *      shared static this() { body }
2568      * Current token is 'shared'.
2569      */
2570     Dsymbol parseSharedStaticCtor(PrefixAttributes* pAttrs)
2571     {
2572         //Expressions *udas = NULL;
2573         const loc = token.loc;
2574         StorageClass stc = getStorageClass(pAttrs);
2575 
2576         nextToken();
2577         nextToken();
2578         nextToken();
2579         check(TOKlparen);
2580         check(TOKrparen);
2581 
2582         stc = parsePostfix(stc & ~STC_TYPECTOR, null) | stc;
2583         if (StorageClass ss = stc & (STCshared | STCstatic))
2584             appendStorageClass(stc, ss); // complaint for the redundancy
2585         else if (StorageClass modStc = stc & STC_TYPECTOR)
2586         {
2587             OutBuffer buf;
2588             stcToBuffer(&buf, modStc);
2589             error(loc, "shared static constructor cannot be %s", buf.peekString());
2590         }
2591         stc &= ~(STCstatic | STC_TYPECTOR);
2592 
2593         auto f = new SharedStaticCtorDeclaration(loc, Loc(), stc);
2594         Dsymbol s = parseContracts(f);
2595         return s;
2596     }
2597 
2598     /*****************************************
2599      * Parse a shared static destructor definition:
2600      *      shared static ~this() { body }
2601      * Current token is 'shared'.
2602      */
2603     Dsymbol parseSharedStaticDtor(PrefixAttributes* pAttrs)
2604     {
2605         Expressions* udas = null;
2606         const loc = token.loc;
2607         StorageClass stc = getStorageClass(pAttrs);
2608 
2609         nextToken();
2610         nextToken();
2611         nextToken();
2612         check(TOKthis);
2613         check(TOKlparen);
2614         check(TOKrparen);
2615 
2616         stc = parsePostfix(stc & ~STC_TYPECTOR, &udas) | stc;
2617         if (StorageClass ss = stc & (STCshared | STCstatic))
2618             appendStorageClass(stc, ss); // complaint for the redundancy
2619         else if (StorageClass modStc = stc & STC_TYPECTOR)
2620         {
2621             OutBuffer buf;
2622             stcToBuffer(&buf, modStc);
2623             error(loc, "shared static destructor cannot be %s", buf.peekString());
2624         }
2625         stc &= ~(STCstatic | STC_TYPECTOR);
2626 
2627         auto f = new SharedStaticDtorDeclaration(loc, Loc(), stc);
2628         Dsymbol s = parseContracts(f);
2629         if (udas)
2630         {
2631             auto a = new Dsymbols();
2632             a.push(f);
2633             s = new UserAttributeDeclaration(udas, a);
2634         }
2635         return s;
2636     }
2637 
2638     /*****************************************
2639      * Parse an invariant definition:
2640      *      invariant() { body }
2641      * Current token is 'invariant'.
2642      */
2643     Dsymbol parseInvariant(PrefixAttributes* pAttrs)
2644     {
2645         const loc = token.loc;
2646         StorageClass stc = getStorageClass(pAttrs);
2647 
2648         nextToken();
2649         if (token.value == TOKlparen) // optional ()
2650         {
2651             nextToken();
2652             check(TOKrparen);
2653         }
2654 
2655         auto fbody = parseStatement(PScurly);
2656         auto f = new InvariantDeclaration(loc, token.loc, stc, null, fbody);
2657         return f;
2658     }
2659 
2660     /*****************************************
2661      * Parse a unittest definition:
2662      *      unittest { body }
2663      * Current token is 'unittest'.
2664      */
2665     Dsymbol parseUnitTest(PrefixAttributes* pAttrs)
2666     {
2667         const loc = token.loc;
2668         StorageClass stc = getStorageClass(pAttrs);
2669 
2670         nextToken();
2671 
2672         const(char)* begPtr = token.ptr + 1; // skip '{'
2673         const(char)* endPtr = null;
2674         Statement sbody = parseStatement(PScurly, &endPtr);
2675 
2676         /** Extract unittest body as a string. Must be done eagerly since memory
2677          will be released by the lexer before doc gen. */
2678         char* docline = null;
2679         if (global.params.doDocComments && endPtr > begPtr)
2680         {
2681             /* Remove trailing whitespaces */
2682             for (const(char)* p = endPtr - 1; begPtr <= p && (*p == ' ' || *p == '\r' || *p == '\n' || *p == '\t'); --p)
2683             {
2684                 endPtr = p;
2685             }
2686 
2687             size_t len = endPtr - begPtr;
2688             if (len > 0)
2689             {
2690                 docline = cast(char*)mem.xmalloc(len + 2);
2691                 memcpy(docline, begPtr, len);
2692                 docline[len] = '\n'; // Terminate all lines by LF
2693                 docline[len + 1] = '\0';
2694             }
2695         }
2696 
2697         auto f = new UnitTestDeclaration(loc, token.loc, stc, docline);
2698         f.fbody = sbody;
2699         return f;
2700     }
2701 
2702     /*****************************************
2703      * Parse a new definition:
2704      *      new(parameters) { body }
2705      * Current token is 'new'.
2706      */
2707     Dsymbol parseNew(PrefixAttributes* pAttrs)
2708     {
2709         const loc = token.loc;
2710         StorageClass stc = getStorageClass(pAttrs);
2711 
2712         nextToken();
2713 
2714         int varargs;
2715         Parameters* parameters = parseParameters(&varargs);
2716         auto f = new NewDeclaration(loc, Loc(), stc, parameters, varargs);
2717         Dsymbol s = parseContracts(f);
2718         return s;
2719     }
2720 
2721     /*****************************************
2722      * Parse a delete definition:
2723      *      delete(parameters) { body }
2724      * Current token is 'delete'.
2725      */
2726     Dsymbol parseDelete(PrefixAttributes* pAttrs)
2727     {
2728         const loc = token.loc;
2729         StorageClass stc = getStorageClass(pAttrs);
2730 
2731         nextToken();
2732 
2733         int varargs;
2734         Parameters* parameters = parseParameters(&varargs);
2735         if (varargs)
2736             error("... not allowed in delete function parameter list");
2737         auto f = new DeleteDeclaration(loc, Loc(), stc, parameters);
2738         Dsymbol s = parseContracts(f);
2739         return s;
2740     }
2741 
2742     /**********************************************
2743      * Parse parameter list.
2744      */
2745     Parameters* parseParameters(int* pvarargs, TemplateParameters** tpl = null)
2746     {
2747         auto parameters = new Parameters();
2748         int varargs = 0;
2749         int hasdefault = 0;
2750 
2751         check(TOKlparen);
2752         while (1)
2753         {
2754             Identifier ai = null;
2755             Type at;
2756             StorageClass storageClass = 0;
2757             StorageClass stc;
2758             Expression ae;
2759 
2760             for (; 1; nextToken())
2761             {
2762                 switch (token.value)
2763                 {
2764                 case TOKrparen:
2765                     break;
2766 
2767                 case TOKdotdotdot:
2768                     varargs = 1;
2769                     nextToken();
2770                     break;
2771 
2772                 case TOKconst:
2773                     if (peek(&token).value == TOKlparen)
2774                         goto Ldefault;
2775                     stc = STCconst;
2776                     goto L2;
2777 
2778                 case TOKimmutable:
2779                     if (peek(&token).value == TOKlparen)
2780                         goto Ldefault;
2781                     stc = STCimmutable;
2782                     goto L2;
2783 
2784                 case TOKshared:
2785                     if (peek(&token).value == TOKlparen)
2786                         goto Ldefault;
2787                     stc = STCshared;
2788                     goto L2;
2789 
2790                 case TOKwild:
2791                     if (peek(&token).value == TOKlparen)
2792                         goto Ldefault;
2793                     stc = STCwild;
2794                     goto L2;
2795 
2796                 case TOKin:
2797                     stc = STCin;
2798                     goto L2;
2799 
2800                 case TOKout:
2801                     stc = STCout;
2802                     goto L2;
2803 
2804                 case TOKref:
2805                     stc = STCref;
2806                     goto L2;
2807 
2808                 case TOKlazy:
2809                     stc = STClazy;
2810                     goto L2;
2811 
2812                 case TOKscope:
2813                     stc = STCscope;
2814                     goto L2;
2815 
2816                 case TOKfinal:
2817                     stc = STCfinal;
2818                     goto L2;
2819 
2820                 case TOKauto:
2821                     stc = STCauto;
2822                     goto L2;
2823 
2824                 case TOKreturn:
2825                     stc = STCreturn;
2826                     goto L2;
2827                 L2:
2828                     storageClass = appendStorageClass(storageClass, stc);
2829                     continue;
2830 
2831                     version (none)
2832                     {
2833                     case TOKstatic:
2834                         stc = STCstatic;
2835                         goto L2;
2836 
2837                     case TOKauto:
2838                         storageClass = STCauto;
2839                         goto L4;
2840 
2841                     case TOKalias:
2842                         storageClass = STCalias;
2843                         goto L4;
2844                     L4:
2845                         nextToken();
2846                         if (token.value == TOKidentifier)
2847                         {
2848                             ai = token.ident;
2849                             nextToken();
2850                         }
2851                         else
2852                             ai = null;
2853                         at = null; // no type
2854                         ae = null; // no default argument
2855                         if (token.value == TOKassign) // = defaultArg
2856                         {
2857                             nextToken();
2858                             ae = parseDefaultInitExp();
2859                             hasdefault = 1;
2860                         }
2861                         else
2862                         {
2863                             if (hasdefault)
2864                                 error("default argument expected for alias %s", ai ? ai.toChars() : "");
2865                         }
2866                         goto L3;
2867                     }
2868                 default:
2869                 Ldefault:
2870                     {
2871                         stc = storageClass & (STCin | STCout | STCref | STClazy);
2872                         // if stc is not a power of 2
2873                         if (stc & (stc - 1) && !(stc == (STCin | STCref)))
2874                             error("incompatible parameter storage classes");
2875                         if ((storageClass & STCscope) && (storageClass & (STCref | STCout)))
2876                             error("scope cannot be ref or out");
2877 
2878                         Token* t;
2879                         if (tpl && token.value == TOKidentifier && (t = peek(&token), (t.value == TOKcomma || t.value == TOKrparen || t.value == TOKdotdotdot)))
2880                         {
2881                             Identifier id = Identifier.generateId("__T");
2882                             const loc = token.loc;
2883                             at = new TypeIdentifier(loc, id);
2884                             if (!*tpl)
2885                                 *tpl = new TemplateParameters();
2886                             TemplateParameter tp = new TemplateTypeParameter(loc, id, null, null);
2887                             (*tpl).push(tp);
2888 
2889                             ai = token.ident;
2890                             nextToken();
2891                         }
2892                         else
2893                             at = parseType(&ai);
2894                         ae = null;
2895                         if (token.value == TOKassign) // = defaultArg
2896                         {
2897                             nextToken();
2898                             ae = parseDefaultInitExp();
2899                             hasdefault = 1;
2900                         }
2901                         else
2902                         {
2903                             if (hasdefault)
2904                                 error("default argument expected for %s", ai ? ai.toChars() : at.toChars());
2905                         }
2906                         if (token.value == TOKdotdotdot)
2907                         {
2908                             /* This is:
2909                              *      at ai ...
2910                              */
2911                             if (storageClass & (STCout | STCref))
2912                                 error("variadic argument cannot be out or ref");
2913                             varargs = 2;
2914                             parameters.push(new Parameter(storageClass, at, ai, ae));
2915                             nextToken();
2916                             break;
2917                         }
2918                         parameters.push(new Parameter(storageClass, at, ai, ae));
2919                         if (token.value == TOKcomma)
2920                         {
2921                             nextToken();
2922                             goto L1;
2923                         }
2924                         break;
2925                     }
2926                 }
2927                 break;
2928             }
2929             break;
2930 
2931         L1:
2932         }
2933         check(TOKrparen);
2934         *pvarargs = varargs;
2935         return parameters;
2936     }
2937 
2938     /*************************************
2939      */
2940     EnumDeclaration parseEnum()
2941     {
2942         EnumDeclaration e;
2943         Identifier id;
2944         Type memtype;
2945         auto loc = token.loc;
2946 
2947         //printf("Parser::parseEnum()\n");
2948         nextToken();
2949         if (token.value == TOKidentifier)
2950         {
2951             id = token.ident;
2952             nextToken();
2953         }
2954         else
2955             id = null;
2956 
2957         if (token.value == TOKcolon)
2958         {
2959             nextToken();
2960             int alt = 0;
2961             const typeLoc = token.loc;
2962             memtype = parseBasicType();
2963             memtype = parseDeclarator(memtype, &alt, null);
2964             checkCstyleTypeSyntax(typeLoc, memtype, alt, null);
2965         }
2966         else
2967             memtype = null;
2968 
2969         e = new EnumDeclaration(loc, id, memtype);
2970         if (token.value == TOKsemicolon && id)
2971             nextToken();
2972         else if (token.value == TOKlcurly)
2973         {
2974             //printf("enum definition\n");
2975             e.members = new Dsymbols();
2976             nextToken();
2977             const(char)* comment = token.blockComment;
2978             while (token.value != TOKrcurly)
2979             {
2980                 /* Can take the following forms:
2981                  *  1. ident
2982                  *  2. ident = value
2983                  *  3. type ident = value
2984                  */
2985                 loc = token.loc;
2986 
2987                 Type type = null;
2988                 Identifier ident = null;
2989                 Token* tp = peek(&token);
2990                 if (token.value == TOKidentifier && (tp.value == TOKassign || tp.value == TOKcomma || tp.value == TOKrcurly))
2991                 {
2992                     ident = token.ident;
2993                     type = null;
2994                     nextToken();
2995                 }
2996                 else
2997                 {
2998                     type = parseType(&ident, null);
2999                     if (!ident)
3000                         error("no identifier for declarator %s", type.toChars());
3001                     if (id || memtype)
3002                         error("type only allowed if anonymous enum and no enum type");
3003                 }
3004 
3005                 Expression value;
3006                 if (token.value == TOKassign)
3007                 {
3008                     nextToken();
3009                     value = parseAssignExp();
3010                 }
3011                 else
3012                 {
3013                     value = null;
3014                     if (type)
3015                         error("if type, there must be an initializer");
3016                 }
3017 
3018                 auto em = new EnumMember(loc, ident, value, type);
3019                 e.members.push(em);
3020 
3021                 if (token.value == TOKrcurly)
3022                 {
3023                 }
3024                 else
3025                 {
3026                     addComment(em, comment);
3027                     comment = null;
3028                     check(TOKcomma);
3029                 }
3030                 addComment(em, comment);
3031                 comment = token.blockComment;
3032 
3033                 if (token.value == TOKeof)
3034                 {
3035                     error("premature end of file");
3036                     break;
3037                 }
3038             }
3039             nextToken();
3040         }
3041         else
3042             error("enum declaration is invalid");
3043 
3044         //printf("-parseEnum() %s\n", e->toChars());
3045         return e;
3046     }
3047 
3048     /********************************
3049      * Parse struct, union, interface, class.
3050      */
3051     Dsymbol parseAggregate()
3052     {
3053         TemplateParameters* tpl = null;
3054         Expression constraint;
3055         const loc = token.loc;
3056         TOK tok = token.value;
3057 
3058         //printf("Parser::parseAggregate()\n");
3059         nextToken();
3060         Identifier id;
3061         if (token.value != TOKidentifier)
3062         {
3063             id = null;
3064         }
3065         else
3066         {
3067             id = token.ident;
3068             nextToken();
3069 
3070             if (token.value == TOKlparen)
3071             {
3072                 // struct/class template declaration.
3073                 tpl = parseTemplateParameterList();
3074                 constraint = parseConstraint();
3075             }
3076         }
3077 
3078         // Collect base class(es)
3079         BaseClasses* baseclasses = null;
3080         if (token.value == TOKcolon)
3081         {
3082             if (tok != TOKinterface && tok != TOKclass)
3083                 error("base classes are not allowed for %s, did you mean ';'?", Token.toChars(tok));
3084             nextToken();
3085             baseclasses = parseBaseClasses();
3086         }
3087 
3088         if (token.value == TOKif)
3089         {
3090             if (constraint)
3091                 error("template constraints appear both before and after BaseClassList, put them before");
3092             constraint = parseConstraint();
3093         }
3094         if (constraint)
3095         {
3096             if (!id)
3097                 error("template constraints not allowed for anonymous %s", Token.toChars(tok));
3098             if (!tpl)
3099                 error("template constraints only allowed for templates");
3100         }
3101 
3102         Dsymbols* members = null;
3103         if (token.value == TOKlcurly)
3104         {
3105             //printf("aggregate definition\n");
3106             const lookingForElseSave = lookingForElse;
3107             lookingForElse = Loc();
3108             nextToken();
3109             members = parseDeclDefs(0);
3110             lookingForElse = lookingForElseSave;
3111             if (token.value != TOKrcurly)
3112             {
3113                 /* { */
3114                 error("} expected following members in %s declaration at %s",
3115                     Token.toChars(tok), loc.toChars());
3116             }
3117             nextToken();
3118         }
3119         else if (token.value == TOKsemicolon && id)
3120         {
3121             if (baseclasses || constraint)
3122                 error("members expected");
3123             nextToken();
3124         }
3125         else
3126         {
3127             error("{ } expected following %s declaration", Token.toChars(tok));
3128         }
3129 
3130         AggregateDeclaration a;
3131         switch (tok)
3132         {
3133         case TOKinterface:
3134             if (!id)
3135                 error(loc, "anonymous interfaces not allowed");
3136             a = new InterfaceDeclaration(loc, id, baseclasses);
3137             a.members = members;
3138             break;
3139 
3140         case TOKclass:
3141             if (!id)
3142                 error(loc, "anonymous classes not allowed");
3143             bool inObject = md && !md.packages && md.id == Id.object;
3144             a = new ClassDeclaration(loc, id, baseclasses, members, inObject);
3145             break;
3146 
3147         case TOKstruct:
3148             if (id)
3149             {
3150                 a = new StructDeclaration(loc, id);
3151                 a.members = members;
3152             }
3153             else
3154             {
3155                 /* Anonymous structs/unions are more like attributes.
3156                  */
3157                 assert(!tpl);
3158                 return new AnonDeclaration(loc, false, members);
3159             }
3160             break;
3161 
3162         case TOKunion:
3163             if (id)
3164             {
3165                 a = new UnionDeclaration(loc, id);
3166                 a.members = members;
3167             }
3168             else
3169             {
3170                 /* Anonymous structs/unions are more like attributes.
3171                  */
3172                 assert(!tpl);
3173                 return new AnonDeclaration(loc, true, members);
3174             }
3175             break;
3176 
3177         default:
3178             assert(0);
3179         }
3180 
3181         if (tpl)
3182         {
3183             // Wrap a template around the aggregate declaration
3184             auto decldefs = new Dsymbols();
3185             decldefs.push(a);
3186             auto tempdecl = new TemplateDeclaration(loc, id, tpl, constraint, decldefs);
3187             return tempdecl;
3188         }
3189         return a;
3190     }
3191 
3192     /*******************************************
3193      */
3194     BaseClasses* parseBaseClasses()
3195     {
3196         auto baseclasses = new BaseClasses();
3197 
3198         for (; 1; nextToken())
3199         {
3200             auto b = new BaseClass(parseBasicType());
3201             baseclasses.push(b);
3202             if (token.value != TOKcomma)
3203                 break;
3204         }
3205         return baseclasses;
3206     }
3207 
3208     Dsymbols* parseImport()
3209     {
3210         auto decldefs = new Dsymbols();
3211         Identifier aliasid = null;
3212 
3213         int isstatic = token.value == TOKstatic;
3214         if (isstatic)
3215             nextToken();
3216 
3217         //printf("Parser::parseImport()\n");
3218         do
3219         {
3220         L1:
3221             nextToken();
3222             if (token.value != TOKidentifier)
3223             {
3224                 error("identifier expected following import");
3225                 break;
3226             }
3227 
3228             const loc = token.loc;
3229             Identifier id = token.ident;
3230             Identifiers* a = null;
3231             nextToken();
3232             if (!aliasid && token.value == TOKassign)
3233             {
3234                 aliasid = id;
3235                 goto L1;
3236             }
3237             while (token.value == TOKdot)
3238             {
3239                 if (!a)
3240                     a = new Identifiers();
3241                 a.push(id);
3242                 nextToken();
3243                 if (token.value != TOKidentifier)
3244                 {
3245                     error("identifier expected following package");
3246                     break;
3247                 }
3248                 id = token.ident;
3249                 nextToken();
3250             }
3251 
3252             auto s = new Import(loc, a, id, aliasid, isstatic);
3253             decldefs.push(s);
3254 
3255             /* Look for
3256              *      : alias=name, alias=name;
3257              * syntax.
3258              */
3259             if (token.value == TOKcolon)
3260             {
3261                 do
3262                 {
3263                     nextToken();
3264                     if (token.value != TOKidentifier)
3265                     {
3266                         error("identifier expected following :");
3267                         break;
3268                     }
3269                     Identifier _alias = token.ident;
3270                     Identifier name;
3271                     nextToken();
3272                     if (token.value == TOKassign)
3273                     {
3274                         nextToken();
3275                         if (token.value != TOKidentifier)
3276                         {
3277                             error("identifier expected following %s=", _alias.toChars());
3278                             break;
3279                         }
3280                         name = token.ident;
3281                         nextToken();
3282                     }
3283                     else
3284                     {
3285                         name = _alias;
3286                         _alias = null;
3287                     }
3288                     s.addAlias(name, _alias);
3289                 }
3290                 while (token.value == TOKcomma);
3291                 break; // no comma-separated imports of this form
3292             }
3293             aliasid = null;
3294         }
3295         while (token.value == TOKcomma);
3296 
3297         if (token.value == TOKsemicolon)
3298             nextToken();
3299         else
3300         {
3301             error("';' expected");
3302             nextToken();
3303         }
3304 
3305         return decldefs;
3306     }
3307 
3308     Type parseType(Identifier* pident = null, TemplateParameters** ptpl = null)
3309     {
3310         /* Take care of the storage class prefixes that
3311          * serve as type attributes:
3312          *               const type
3313          *           immutable type
3314          *              shared type
3315          *               inout type
3316          *         inout const type
3317          *        shared const type
3318          *        shared inout type
3319          *  shared inout const type
3320          */
3321         StorageClass stc = 0;
3322         while (1)
3323         {
3324             switch (token.value)
3325             {
3326             case TOKconst:
3327                 if (peekNext() == TOKlparen)
3328                     break; // const as type constructor
3329                 stc |= STCconst; // const as storage class
3330                 nextToken();
3331                 continue;
3332 
3333             case TOKimmutable:
3334                 if (peekNext() == TOKlparen)
3335                     break;
3336                 stc |= STCimmutable;
3337                 nextToken();
3338                 continue;
3339 
3340             case TOKshared:
3341                 if (peekNext() == TOKlparen)
3342                     break;
3343                 stc |= STCshared;
3344                 nextToken();
3345                 continue;
3346 
3347             case TOKwild:
3348                 if (peekNext() == TOKlparen)
3349                     break;
3350                 stc |= STCwild;
3351                 nextToken();
3352                 continue;
3353 
3354             default:
3355                 break;
3356             }
3357             break;
3358         }
3359 
3360         const typeLoc = token.loc;
3361 
3362         Type t;
3363         t = parseBasicType();
3364 
3365         int alt = 0;
3366         t = parseDeclarator(t, &alt, pident, ptpl);
3367         checkCstyleTypeSyntax(typeLoc, t, alt, pident ? *pident : null);
3368 
3369         t = t.addSTC(stc);
3370         return t;
3371     }
3372 
3373     Type parseBasicType(bool dontLookDotIdents = false)
3374     {
3375         Type t;
3376         Loc loc;
3377         Identifier id;
3378         //printf("parseBasicType()\n");
3379         switch (token.value)
3380         {
3381         case TOKvoid:
3382             t = Type.tvoid;
3383             goto LabelX;
3384 
3385         case TOKint8:
3386             t = Type.tint8;
3387             goto LabelX;
3388 
3389         case TOKuns8:
3390             t = Type.tuns8;
3391             goto LabelX;
3392 
3393         case TOKint16:
3394             t = Type.tint16;
3395             goto LabelX;
3396 
3397         case TOKuns16:
3398             t = Type.tuns16;
3399             goto LabelX;
3400 
3401         case TOKint32:
3402             t = Type.tint32;
3403             goto LabelX;
3404 
3405         case TOKuns32:
3406             t = Type.tuns32;
3407             goto LabelX;
3408 
3409         case TOKint64:
3410             t = Type.tint64;
3411             goto LabelX;
3412 
3413         case TOKuns64:
3414             t = Type.tuns64;
3415             goto LabelX;
3416 
3417         case TOKint128:
3418             t = Type.tint128;
3419             goto LabelX;
3420 
3421         case TOKuns128:
3422             t = Type.tuns128;
3423             goto LabelX;
3424 
3425         case TOKfloat32:
3426             t = Type.tfloat32;
3427             goto LabelX;
3428 
3429         case TOKfloat64:
3430             t = Type.tfloat64;
3431             goto LabelX;
3432 
3433         case TOKfloat80:
3434             t = Type.tfloat80;
3435             goto LabelX;
3436 
3437         case TOKimaginary32:
3438             t = Type.timaginary32;
3439             goto LabelX;
3440 
3441         case TOKimaginary64:
3442             t = Type.timaginary64;
3443             goto LabelX;
3444 
3445         case TOKimaginary80:
3446             t = Type.timaginary80;
3447             goto LabelX;
3448 
3449         case TOKcomplex32:
3450             t = Type.tcomplex32;
3451             goto LabelX;
3452 
3453         case TOKcomplex64:
3454             t = Type.tcomplex64;
3455             goto LabelX;
3456 
3457         case TOKcomplex80:
3458             t = Type.tcomplex80;
3459             goto LabelX;
3460 
3461         case TOKbool:
3462             t = Type.tbool;
3463             goto LabelX;
3464 
3465         case TOKchar:
3466             t = Type.tchar;
3467             goto LabelX;
3468 
3469         case TOKwchar:
3470             t = Type.twchar;
3471             goto LabelX;
3472 
3473         case TOKdchar:
3474             t = Type.tdchar;
3475             goto LabelX;
3476         LabelX:
3477             nextToken();
3478             break;
3479 
3480         case TOKthis:
3481         case TOKsuper:
3482         case TOKidentifier:
3483             loc = token.loc;
3484             id = token.ident;
3485             nextToken();
3486             if (token.value == TOKnot)
3487             {
3488                 // ident!(template_arguments)
3489                 auto tempinst = new TemplateInstance(loc, id, parseTemplateArguments());
3490                 t = parseBasicTypeStartingAt(new TypeInstance(loc, tempinst), dontLookDotIdents);
3491             }
3492             else
3493             {
3494                 t = parseBasicTypeStartingAt(new TypeIdentifier(loc, id), dontLookDotIdents);
3495             }
3496             break;
3497 
3498         case TOKdot:
3499             // Leading . as in .foo
3500             t = parseBasicTypeStartingAt(new TypeIdentifier(token.loc, Id.empty), dontLookDotIdents);
3501             break;
3502 
3503         case TOKtypeof:
3504             // typeof(expression)
3505             t = parseBasicTypeStartingAt(parseTypeof(), dontLookDotIdents);
3506             break;
3507 
3508         case TOKvector:
3509             t = parseVector();
3510             break;
3511 
3512         case TOKconst:
3513             // const(type)
3514             nextToken();
3515             check(TOKlparen);
3516             t = parseType().addSTC(STCconst);
3517             check(TOKrparen);
3518             break;
3519 
3520         case TOKimmutable:
3521             // immutable(type)
3522             nextToken();
3523             check(TOKlparen);
3524             t = parseType().addSTC(STCimmutable);
3525             check(TOKrparen);
3526             break;
3527 
3528         case TOKshared:
3529             // shared(type)
3530             nextToken();
3531             check(TOKlparen);
3532             t = parseType().addSTC(STCshared);
3533             check(TOKrparen);
3534             break;
3535 
3536         case TOKwild:
3537             // wild(type)
3538             nextToken();
3539             check(TOKlparen);
3540             t = parseType().addSTC(STCwild);
3541             check(TOKrparen);
3542             break;
3543 
3544         default:
3545             error("basic type expected, not %s", token.toChars());
3546             t = Type.terror;
3547             break;
3548         }
3549         return t;
3550     }
3551 
3552     Type parseBasicTypeStartingAt(TypeQualified tid, bool dontLookDotIdents)
3553     {
3554         Type maybeArray = null;
3555         // See https://issues.dlang.org/show_bug.cgi?id=1215
3556         // A basic type can look like MyType (typical case), but also:
3557         //  MyType.T -> A type
3558         //  MyType[expr] -> Either a static array of MyType or a type (iif MyType is a Ttuple)
3559         //  MyType[expr].T -> A type.
3560         //  MyType[expr].T[expr] ->  Either a static array of MyType[expr].T or a type
3561         //                           (iif MyType[expr].T is a Ttuple)
3562         while (1)
3563         {
3564             switch (token.value)
3565             {
3566             case TOKdot:
3567                 {
3568                     nextToken();
3569                     if (token.value != TOKidentifier)
3570                     {
3571                         error("identifier expected following '.' instead of '%s'", token.toChars());
3572                         break;
3573                     }
3574                     if (maybeArray)
3575                     {
3576                         // This is actually a TypeTuple index, not an {a/s}array.
3577                         // We need to have a while loop to unwind all index taking:
3578                         // T[e1][e2].U   ->  T, addIndex(e1), addIndex(e2)
3579                         Objects dimStack;
3580                         Type t = maybeArray;
3581                         while (true)
3582                         {
3583                             if (t.ty == Tsarray)
3584                             {
3585                                 // The index expression is an Expression.
3586                                 TypeSArray a = cast(TypeSArray)t;
3587                                 dimStack.push(a.dim.syntaxCopy());
3588                                 t = a.next.syntaxCopy();
3589                             }
3590                             else if (t.ty == Taarray)
3591                             {
3592                                 // The index expression is a Type. It will be interpreted as an expression at semantic time.
3593                                 TypeAArray a = cast(TypeAArray)t;
3594                                 dimStack.push(a.index.syntaxCopy());
3595                                 t = a.next.syntaxCopy();
3596                             }
3597                             else
3598                             {
3599                                 break;
3600                             }
3601                         }
3602                         assert(dimStack.dim > 0);
3603                         // We're good. Replay indices in the reverse order.
3604                         tid = cast(TypeQualified)t;
3605                         while (dimStack.dim)
3606                         {
3607                             tid.addIndex(dimStack.pop());
3608                         }
3609                         maybeArray = null;
3610                     }
3611                     const loc = token.loc;
3612                     Identifier id = token.ident;
3613                     nextToken();
3614                     if (token.value == TOKnot)
3615                     {
3616                         auto tempinst = new TemplateInstance(loc, id, parseTemplateArguments());
3617                         tid.addInst(tempinst);
3618                     }
3619                     else
3620                         tid.addIdent(id);
3621                     continue;
3622                 }
3623             case TOKlbracket:
3624                 {
3625                     if (dontLookDotIdents) // workaround for Bugzilla 14911
3626                         goto Lend;
3627 
3628                     nextToken();
3629                     Type t = maybeArray ? maybeArray : cast(Type)tid;
3630                     if (token.value == TOKrbracket)
3631                     {
3632                         // It's a dynamic array, and we're done:
3633                         // T[].U does not make sense.
3634                         t = new TypeDArray(t);
3635                         nextToken();
3636                         return t;
3637                     }
3638                     else if (isDeclaration(&token, NeedDeclaratorId.no, TOKrbracket, null))
3639                     {
3640                         // This can be one of two things:
3641                         //  1 - an associative array declaration, T[type]
3642                         //  2 - an associative array declaration, T[expr]
3643                         // These  can only be disambiguated later.
3644                         Type index = parseType(); // [ type ]
3645                         maybeArray = new TypeAArray(t, index);
3646                         check(TOKrbracket);
3647                     }
3648                     else
3649                     {
3650                         // This can be one of three things:
3651                         //  1 - an static array declaration, T[expr]
3652                         //  2 - a slice, T[expr .. expr]
3653                         //  3 - a template parameter pack index expression, T[expr].U
3654                         // 1 and 3 can only be disambiguated later.
3655                         //printf("it's type[expression]\n");
3656                         inBrackets++;
3657                         Expression e = parseAssignExp(); // [ expression ]
3658                         if (token.value == TOKslice)
3659                         {
3660                             // It's a slice, and we're done.
3661                             nextToken();
3662                             Expression e2 = parseAssignExp(); // [ exp .. exp ]
3663                             t = new TypeSlice(t, e, e2);
3664                             inBrackets--;
3665                             check(TOKrbracket);
3666                             return t;
3667                         }
3668                         else
3669                         {
3670                             maybeArray = new TypeSArray(t, e);
3671                             inBrackets--;
3672                             check(TOKrbracket);
3673                             continue;
3674                         }
3675                     }
3676                     break;
3677                 }
3678             default:
3679                 goto Lend;
3680             }
3681         }
3682     Lend:
3683         return maybeArray ? maybeArray : cast(Type)tid;
3684     }
3685 
3686     /******************************************
3687      * Parse things that follow the initial type t.
3688      *      t *
3689      *      t []
3690      *      t [type]
3691      *      t [expression]
3692      *      t [expression .. expression]
3693      *      t function
3694      *      t delegate
3695      */
3696     Type parseBasicType2(Type t)
3697     {
3698         //printf("parseBasicType2()\n");
3699         while (1)
3700         {
3701             switch (token.value)
3702             {
3703             case TOKmul:
3704                 t = new TypePointer(t);
3705                 nextToken();
3706                 continue;
3707 
3708             case TOKlbracket:
3709                 // Handle []. Make sure things like
3710                 //     int[3][1] a;
3711                 // is (array[1] of array[3] of int)
3712                 nextToken();
3713                 if (token.value == TOKrbracket)
3714                 {
3715                     t = new TypeDArray(t); // []
3716                     nextToken();
3717                 }
3718                 else if (isDeclaration(&token, NeedDeclaratorId.no, TOKrbracket, null))
3719                 {
3720                     // It's an associative array declaration
3721                     //printf("it's an associative array\n");
3722                     Type index = parseType(); // [ type ]
3723                     t = new TypeAArray(t, index);
3724                     check(TOKrbracket);
3725                 }
3726                 else
3727                 {
3728                     //printf("it's type[expression]\n");
3729                     inBrackets++;
3730                     Expression e = parseAssignExp(); // [ expression ]
3731                     if (token.value == TOKslice)
3732                     {
3733                         nextToken();
3734                         Expression e2 = parseAssignExp(); // [ exp .. exp ]
3735                         t = new TypeSlice(t, e, e2);
3736                     }
3737                     else
3738                     {
3739                         t = new TypeSArray(t, e);
3740                     }
3741                     inBrackets--;
3742                     check(TOKrbracket);
3743                 }
3744                 continue;
3745 
3746             case TOKdelegate:
3747             case TOKfunction:
3748                 {
3749                     // Handle delegate declaration:
3750                     //      t delegate(parameter list) nothrow pure
3751                     //      t function(parameter list) nothrow pure
3752                     TOK save = token.value;
3753                     nextToken();
3754 
3755                     int varargs;
3756                     Parameters* parameters = parseParameters(&varargs);
3757 
3758                     StorageClass stc = parsePostfix(STCundefined, null);
3759                     auto tf = new TypeFunction(parameters, t, varargs, linkage, stc);
3760                     if (stc & (STCconst | STCimmutable | STCshared | STCwild | STCreturn))
3761                     {
3762                         if (save == TOKfunction)
3763                             error("const/immutable/shared/inout/return attributes are only valid for non-static member functions");
3764                         else
3765                             tf = cast(TypeFunction)tf.addSTC(stc);
3766                     }
3767 
3768                     if (save == TOKdelegate)
3769                         t = new TypeDelegate(tf);
3770                     else
3771                         t = new TypePointer(tf); // pointer to function
3772                     continue;
3773                 }
3774             default:
3775                 return t;
3776             }
3777             assert(0);
3778         }
3779         assert(0);
3780     }
3781 
3782     Type parseDeclarator(Type t, int* palt, Identifier* pident, TemplateParameters** tpl = null, StorageClass storageClass = 0, int* pdisable = null, Expressions** pudas = null)
3783     {
3784         //printf("parseDeclarator(tpl = %p)\n", tpl);
3785         t = parseBasicType2(t);
3786         Type ts;
3787         switch (token.value)
3788         {
3789         case TOKidentifier:
3790             if (pident)
3791                 *pident = token.ident;
3792             else
3793                 error("unexpected identifer '%s' in declarator", token.ident.toChars());
3794             ts = t;
3795             nextToken();
3796             break;
3797 
3798         case TOKlparen:
3799             {
3800                 // like: T (*fp)();
3801                 // like: T ((*fp))();
3802                 if (peekNext() == TOKmul || peekNext() == TOKlparen)
3803                 {
3804                     /* Parse things with parentheses around the identifier, like:
3805                      *  int (*ident[3])[]
3806                      * although the D style would be:
3807                      *  int[]*[3] ident
3808                      */
3809                     *palt |= 1;
3810                     nextToken();
3811                     ts = parseDeclarator(t, palt, pident);
3812                     check(TOKrparen);
3813                     break;
3814                 }
3815                 ts = t;
3816 
3817                 Token* peekt = &token;
3818                 /* Completely disallow C-style things like:
3819                  *   T (a);
3820                  * Improve error messages for the common bug of a missing return type
3821                  * by looking to see if (a) looks like a parameter list.
3822                  */
3823                 if (isParameters(&peekt))
3824                 {
3825                     error("function declaration without return type. (Note that constructors are always named 'this')");
3826                 }
3827                 else
3828                     error("unexpected ( in declarator");
3829                 break;
3830             }
3831         default:
3832             ts = t;
3833             break;
3834         }
3835 
3836         // parse DeclaratorSuffixes
3837         while (1)
3838         {
3839             switch (token.value)
3840             {
3841                 static if (CARRAYDECL)
3842                 {
3843                     /* Support C style array syntax:
3844                      *   int ident[]
3845                      * as opposed to D-style:
3846                      *   int[] ident
3847                      */
3848                 case TOKlbracket:
3849                     {
3850                         // This is the old C-style post [] syntax.
3851                         TypeNext ta;
3852                         nextToken();
3853                         if (token.value == TOKrbracket)
3854                         {
3855                             // It's a dynamic array
3856                             ta = new TypeDArray(t); // []
3857                             nextToken();
3858                             *palt |= 2;
3859                         }
3860                         else if (isDeclaration(&token, NeedDeclaratorId.no, TOKrbracket, null))
3861                         {
3862                             // It's an associative array
3863                             //printf("it's an associative array\n");
3864                             Type index = parseType(); // [ type ]
3865                             check(TOKrbracket);
3866                             ta = new TypeAArray(t, index);
3867                             *palt |= 2;
3868                         }
3869                         else
3870                         {
3871                             //printf("It's a static array\n");
3872                             Expression e = parseAssignExp(); // [ expression ]
3873                             ta = new TypeSArray(t, e);
3874                             check(TOKrbracket);
3875                             *palt |= 2;
3876                         }
3877 
3878                         /* Insert ta into
3879                          *   ts -> ... -> t
3880                          * so that
3881                          *   ts -> ... -> ta -> t
3882                          */
3883                         Type* pt;
3884                         for (pt = &ts; *pt != t; pt = &(cast(TypeNext)*pt).next)
3885                         {
3886                         }
3887                         *pt = ta;
3888                         continue;
3889                     }
3890                 }
3891             case TOKlparen:
3892                 {
3893                     if (tpl)
3894                     {
3895                         Token* tk = peekPastParen(&token);
3896                         if (tk.value == TOKlparen)
3897                         {
3898                             /* Look ahead to see if this is (...)(...),
3899                              * i.e. a function template declaration
3900                              */
3901                             //printf("function template declaration\n");
3902 
3903                             // Gather template parameter list
3904                             *tpl = parseTemplateParameterList();
3905                         }
3906                         else if (tk.value == TOKassign)
3907                         {
3908                             /* or (...) =,
3909                              * i.e. a variable template declaration
3910                              */
3911                             //printf("variable template declaration\n");
3912                             *tpl = parseTemplateParameterList();
3913                             break;
3914                         }
3915                     }
3916 
3917                     int varargs;
3918                     Parameters* parameters = parseParameters(&varargs);
3919 
3920                     /* Parse const/immutable/shared/inout/nothrow/pure/return postfix
3921                      */
3922                     // merge prefix storage classes
3923                     StorageClass stc = parsePostfix(storageClass, pudas);
3924 
3925                     Type tf = new TypeFunction(parameters, t, varargs, linkage, stc);
3926                     tf = tf.addSTC(stc);
3927                     if (pdisable)
3928                         *pdisable = stc & STCdisable ? 1 : 0;
3929 
3930                     /* Insert tf into
3931                      *   ts -> ... -> t
3932                      * so that
3933                      *   ts -> ... -> tf -> t
3934                      */
3935                     Type* pt;
3936                     for (pt = &ts; *pt != t; pt = &(cast(TypeNext)*pt).next)
3937                     {
3938                     }
3939                     *pt = tf;
3940                     break;
3941                 }
3942             default:
3943                 break;
3944             }
3945             break;
3946         }
3947         return ts;
3948     }
3949 
3950     void parseStorageClasses(ref StorageClass storage_class, ref LINK link,
3951         ref bool setAlignment, ref Expression ealign, ref Expressions* udas)
3952     {
3953         StorageClass stc;
3954         bool sawLinkage = false; // seen a linkage declaration
3955 
3956         while (1)
3957         {
3958             switch (token.value)
3959             {
3960             case TOKconst:
3961                 if (peek(&token).value == TOKlparen)
3962                     break; // const as type constructor
3963                 stc = STCconst; // const as storage class
3964                 goto L1;
3965 
3966             case TOKimmutable:
3967                 if (peek(&token).value == TOKlparen)
3968                     break;
3969                 stc = STCimmutable;
3970                 goto L1;
3971 
3972             case TOKshared:
3973                 if (peek(&token).value == TOKlparen)
3974                     break;
3975                 stc = STCshared;
3976                 goto L1;
3977 
3978             case TOKwild:
3979                 if (peek(&token).value == TOKlparen)
3980                     break;
3981                 stc = STCwild;
3982                 goto L1;
3983 
3984             case TOKstatic:
3985                 stc = STCstatic;
3986                 goto L1;
3987 
3988             case TOKfinal:
3989                 stc = STCfinal;
3990                 goto L1;
3991 
3992             case TOKauto:
3993                 stc = STCauto;
3994                 goto L1;
3995 
3996             case TOKscope:
3997                 stc = STCscope;
3998                 goto L1;
3999 
4000             case TOKoverride:
4001                 stc = STCoverride;
4002                 goto L1;
4003 
4004             case TOKabstract:
4005                 stc = STCabstract;
4006                 goto L1;
4007 
4008             case TOKsynchronized:
4009                 stc = STCsynchronized;
4010                 goto L1;
4011 
4012             case TOKdeprecated:
4013                 stc = STCdeprecated;
4014                 goto L1;
4015 
4016             case TOKnothrow:
4017                 stc = STCnothrow;
4018                 goto L1;
4019 
4020             case TOKpure:
4021                 stc = STCpure;
4022                 goto L1;
4023 
4024             case TOKref:
4025                 stc = STCref;
4026                 goto L1;
4027 
4028             case TOKgshared:
4029                 stc = STCgshared;
4030                 goto L1;
4031 
4032             case TOKenum:
4033                 stc = STCmanifest;
4034                 goto L1;
4035 
4036             case TOKat:
4037                 {
4038                     stc = parseAttribute(&udas);
4039                     if (stc)
4040                         goto L1;
4041                     continue;
4042                 }
4043             L1:
4044                 storage_class = appendStorageClass(storage_class, stc);
4045                 nextToken();
4046                 continue;
4047 
4048             case TOKextern:
4049                 {
4050                     if (peek(&token).value != TOKlparen)
4051                     {
4052                         stc = STCextern;
4053                         goto L1;
4054                     }
4055 
4056                     if (sawLinkage)
4057                         error("redundant linkage declaration");
4058                     sawLinkage = true;
4059                     Identifiers* idents = null;
4060                     CPPMANGLE cppmangle;
4061                     link = parseLinkage(&idents, cppmangle);
4062                     if (idents)
4063                     {
4064                         error("C++ name spaces not allowed here");
4065                     }
4066                     if (cppmangle != CPPMANGLE.def)
4067                     {
4068                         error("C++ mangle declaration not allowed here");
4069                     }
4070                     continue;
4071                 }
4072             case TOKalign:
4073                 {
4074                     nextToken();
4075                     setAlignment = true;
4076                     if (token.value == TOKlparen)
4077                     {
4078                         nextToken();
4079                         ealign = parseExpression();
4080                         check(TOKrparen);
4081                     }
4082                     continue;
4083                 }
4084             default:
4085                 break;
4086             }
4087             break;
4088         }
4089     }
4090 
4091     /**********************************
4092      * Parse Declarations.
4093      * These can be:
4094      *      1. declarations at global/class level
4095      *      2. declarations at statement level
4096      * Return array of Declaration *'s.
4097      */
4098     Dsymbols* parseDeclarations(bool autodecl, PrefixAttributes* pAttrs, const(char)* comment)
4099     {
4100         StorageClass storage_class = STCundefined;
4101         Type ts;
4102         Type t;
4103         Type tfirst;
4104         Identifier ident;
4105         TOK tok = TOKreserved;
4106         LINK link = linkage;
4107         bool setAlignment = false;
4108         Expression ealign;
4109         auto loc = token.loc;
4110         Expressions* udas = null;
4111         Token* tk;
4112 
4113         //printf("parseDeclarations() %s\n", token.toChars());
4114         if (!comment)
4115             comment = token.blockComment;
4116 
4117         if (autodecl)
4118         {
4119             ts = null; // infer type
4120             goto L2;
4121         }
4122 
4123         if (token.value == TOKalias)
4124         {
4125             tok = token.value;
4126             nextToken();
4127 
4128             /* Look for:
4129              *   alias identifier this;
4130              */
4131             if (token.value == TOKidentifier && peekNext() == TOKthis)
4132             {
4133                 auto s = new AliasThis(loc, token.ident);
4134                 nextToken();
4135                 check(TOKthis);
4136                 check(TOKsemicolon);
4137                 auto a = new Dsymbols();
4138                 a.push(s);
4139                 addComment(s, comment);
4140                 return a;
4141             }
4142             version (none)
4143             {
4144                 /* Look for:
4145                  *  alias this = identifier;
4146                  */
4147                 if (token.value == TOKthis && peekNext() == TOKassign && peekNext2() == TOKidentifier)
4148                 {
4149                     check(TOKthis);
4150                     check(TOKassign);
4151                     auto s = new AliasThis(loc, token.ident);
4152                     nextToken();
4153                     check(TOKsemicolon);
4154                     auto a = new Dsymbols();
4155                     a.push(s);
4156                     addComment(s, comment);
4157                     return a;
4158                 }
4159             }
4160             /* Look for:
4161              *  alias identifier = type;
4162              *  alias identifier(...) = type;
4163              */
4164             if (token.value == TOKidentifier && skipParensIf(peek(&token), &tk) && tk.value == TOKassign)
4165             {
4166                 auto a = new Dsymbols();
4167                 while (1)
4168                 {
4169                     ident = token.ident;
4170                     nextToken();
4171                     TemplateParameters* tpl = null;
4172                     if (token.value == TOKlparen)
4173                         tpl = parseTemplateParameterList();
4174                     check(TOKassign);
4175 
4176                     Declaration v;
4177                     if (token.value == TOKfunction ||
4178                         token.value == TOKdelegate ||
4179                         token.value == TOKlparen &&
4180                             skipAttributes(peekPastParen(&token), &tk) &&
4181                             (tk.value == TOKgoesto || tk.value == TOKlcurly) ||
4182                         token.value == TOKlcurly ||
4183                         token.value == TOKidentifier && peekNext() == TOKgoesto
4184                        )
4185                     {
4186                         // function (parameters) { statements... }
4187                         // delegate (parameters) { statements... }
4188                         // (parameters) { statements... }
4189                         // (parameters) => expression
4190                         // { statements... }
4191                         // identifier => expression
4192 
4193                         Dsymbol s = parseFunctionLiteral();
4194                         v = new AliasDeclaration(loc, ident, s);
4195                     }
4196                     else
4197                     {
4198                         // StorageClasses type
4199 
4200                         storage_class = STCundefined;
4201                         link = linkage;
4202                         setAlignment = false;
4203                         ealign = null;
4204                         udas = null;
4205                         parseStorageClasses(storage_class, link, setAlignment, ealign, udas);
4206 
4207                         if (udas)
4208                             error("user defined attributes not allowed for %s declarations", Token.toChars(tok));
4209 
4210                         t = parseType();
4211                         v = new AliasDeclaration(loc, ident, t);
4212                     }
4213                     v.storage_class = storage_class;
4214 
4215                     Dsymbol s = v;
4216                     if (tpl)
4217                     {
4218                         auto a2 = new Dsymbols();
4219                         a2.push(s);
4220                         auto tempdecl = new TemplateDeclaration(loc, ident, tpl, null, a2);
4221                         s = tempdecl;
4222                     }
4223                     if (link != linkage)
4224                     {
4225                         auto a2 = new Dsymbols();
4226                         a2.push(s);
4227                         s = new LinkDeclaration(link, a2);
4228                     }
4229                     a.push(s);
4230 
4231                     switch (token.value)
4232                     {
4233                     case TOKsemicolon:
4234                         nextToken();
4235                         addComment(s, comment);
4236                         break;
4237 
4238                     case TOKcomma:
4239                         nextToken();
4240                         addComment(s, comment);
4241                         if (token.value != TOKidentifier)
4242                         {
4243                             error("identifier expected following comma, not %s", token.toChars());
4244                             break;
4245                         }
4246                         if (peekNext() != TOKassign && peekNext() != TOKlparen)
4247                         {
4248                             error("= expected following identifier");
4249                             nextToken();
4250                             break;
4251                         }
4252                         continue;
4253 
4254                     default:
4255                         error("semicolon expected to close %s declaration", Token.toChars(tok));
4256                         break;
4257                     }
4258                     break;
4259                 }
4260                 return a;
4261             }
4262 
4263             // alias StorageClasses type ident;
4264         }
4265 
4266         parseStorageClasses(storage_class, link, setAlignment, ealign, udas);
4267 
4268         if (token.value == TOKstruct ||
4269             token.value == TOKunion ||
4270             token.value == TOKclass ||
4271             token.value == TOKinterface)
4272         {
4273             Dsymbol s = parseAggregate();
4274             auto a = new Dsymbols();
4275             a.push(s);
4276 
4277             if (storage_class)
4278             {
4279                 s = new StorageClassDeclaration(storage_class, a);
4280                 a = new Dsymbols();
4281                 a.push(s);
4282             }
4283             if (setAlignment)
4284             {
4285                 s = new AlignDeclaration(s.loc, ealign, a);
4286                 a = new Dsymbols();
4287                 a.push(s);
4288             }
4289             if (link != linkage)
4290             {
4291                 s = new LinkDeclaration(link, a);
4292                 a = new Dsymbols();
4293                 a.push(s);
4294             }
4295             if (udas)
4296             {
4297                 s = new UserAttributeDeclaration(udas, a);
4298                 a = new Dsymbols();
4299                 a.push(s);
4300             }
4301 
4302             addComment(s, comment);
4303             return a;
4304         }
4305 
4306         /* Look for auto initializers:
4307          *  storage_class identifier = initializer;
4308          *  storage_class identifier(...) = initializer;
4309          */
4310         if ((storage_class || udas) && token.value == TOKidentifier && skipParensIf(peek(&token), &tk) && tk.value == TOKassign)
4311         {
4312             Dsymbols* a = parseAutoDeclarations(storage_class, comment);
4313             if (udas)
4314             {
4315                 Dsymbol s = new UserAttributeDeclaration(udas, a);
4316                 a = new Dsymbols();
4317                 a.push(s);
4318             }
4319             return a;
4320         }
4321 
4322         /* Look for return type inference for template functions.
4323          */
4324         if ((storage_class || udas) && token.value == TOKidentifier && skipParens(peek(&token), &tk) && skipAttributes(tk, &tk) && (tk.value == TOKlparen || tk.value == TOKlcurly || tk.value == TOKin || tk.value == TOKout || tk.value == TOKbody))
4325         {
4326             ts = null;
4327         }
4328         else
4329         {
4330             ts = parseBasicType();
4331             ts = parseBasicType2(ts);
4332         }
4333 
4334     L2:
4335         tfirst = null;
4336         auto a = new Dsymbols();
4337 
4338         if (pAttrs)
4339         {
4340             storage_class |= pAttrs.storageClass;
4341             //pAttrs->storageClass = STCundefined;
4342         }
4343 
4344         while (1)
4345         {
4346             TemplateParameters* tpl = null;
4347             int disable;
4348             int alt = 0;
4349 
4350             loc = token.loc;
4351             ident = null;
4352             t = parseDeclarator(ts, &alt, &ident, &tpl, storage_class, &disable, &udas);
4353             assert(t);
4354             if (!tfirst)
4355                 tfirst = t;
4356             else if (t != tfirst)
4357                 error("multiple declarations must have the same type, not %s and %s", tfirst.toChars(), t.toChars());
4358 
4359             bool isThis = (t.ty == Tident && (cast(TypeIdentifier)t).ident == Id.This && token.value == TOKassign);
4360             if (ident)
4361                 checkCstyleTypeSyntax(loc, t, alt, ident);
4362             else if (!isThis)
4363                 error("no identifier for declarator %s", t.toChars());
4364 
4365             if (tok == TOKalias)
4366             {
4367                 Declaration v;
4368                 Initializer _init = null;
4369 
4370                 /* Aliases can no longer have multiple declarators, storage classes,
4371                  * linkages, or auto declarations.
4372                  * These never made any sense, anyway.
4373                  * The code below needs to be fixed to reject them.
4374                  * The grammar has already been fixed to preclude them.
4375                  */
4376 
4377                 if (udas)
4378                     error("user defined attributes not allowed for %s declarations", Token.toChars(tok));
4379 
4380                 if (token.value == TOKassign)
4381                 {
4382                     nextToken();
4383                     _init = parseInitializer();
4384                 }
4385                 if (_init)
4386                 {
4387                     if (isThis)
4388                         error("cannot use syntax 'alias this = %s', use 'alias %s this' instead", _init.toChars(), _init.toChars());
4389                     else
4390                         error("alias cannot have initializer");
4391                 }
4392                 v = new AliasDeclaration(loc, ident, t);
4393 
4394                 v.storage_class = storage_class;
4395                 if (pAttrs)
4396                 {
4397                     /* AliasDeclaration distinguish @safe, @system, @trusted atttributes
4398                      * on prefix and postfix.
4399                      *   @safe alias void function() FP1;
4400                      *   alias @safe void function() FP2;    // FP2 is not @safe
4401                      *   alias void function() @safe FP3;
4402                      */
4403                     pAttrs.storageClass &= (STCsafe | STCsystem | STCtrusted);
4404                 }
4405                 Dsymbol s = v;
4406 
4407                 if (link != linkage)
4408                 {
4409                     auto ax = new Dsymbols();
4410                     ax.push(v);
4411                     s = new LinkDeclaration(link, ax);
4412                 }
4413                 a.push(s);
4414                 switch (token.value)
4415                 {
4416                 case TOKsemicolon:
4417                     nextToken();
4418                     addComment(s, comment);
4419                     break;
4420 
4421                 case TOKcomma:
4422                     nextToken();
4423                     addComment(s, comment);
4424                     continue;
4425 
4426                 default:
4427                     error("semicolon expected to close %s declaration", Token.toChars(tok));
4428                     break;
4429                 }
4430             }
4431             else if (t.ty == Tfunction)
4432             {
4433                 Expression constraint = null;
4434                 version (none)
4435                 {
4436                     TypeFunction tf = cast(TypeFunction)t;
4437                     if (Parameter.isTPL(tf.parameters))
4438                     {
4439                         if (!tpl)
4440                             tpl = new TemplateParameters();
4441                     }
4442                 }
4443 
4444                 //printf("%s funcdecl t = %s, storage_class = x%lx\n", loc.toChars(), t->toChars(), storage_class);
4445                 auto f = new FuncDeclaration(loc, Loc(), ident, storage_class | (disable ? STCdisable : 0), t);
4446                 if (pAttrs)
4447                     pAttrs.storageClass = STCundefined;
4448                 if (tpl)
4449                     constraint = parseConstraint();
4450                 Dsymbol s = parseContracts(f);
4451                 auto tplIdent = s.ident;
4452 
4453                 if (link != linkage)
4454                 {
4455                     auto ax = new Dsymbols();
4456                     ax.push(s);
4457                     s = new LinkDeclaration(link, ax);
4458                 }
4459                 if (udas)
4460                 {
4461                     auto ax = new Dsymbols();
4462                     ax.push(s);
4463                     s = new UserAttributeDeclaration(udas, ax);
4464                 }
4465 
4466                 /* A template parameter list means it's a function template
4467                  */
4468                 if (tpl)
4469                 {
4470                     // Wrap a template around the function declaration
4471                     auto decldefs = new Dsymbols();
4472                     decldefs.push(s);
4473                     auto tempdecl = new TemplateDeclaration(loc, tplIdent, tpl, constraint, decldefs);
4474                     s = tempdecl;
4475 
4476                     if (storage_class & STCstatic)
4477                     {
4478                         assert(f.storage_class & STCstatic);
4479                         f.storage_class &= ~STCstatic;
4480                         auto ax = new Dsymbols();
4481                         ax.push(s);
4482                         s = new StorageClassDeclaration(STCstatic, ax);
4483                     }
4484                 }
4485                 a.push(s);
4486                 addComment(s, comment);
4487             }
4488             else if (ident)
4489             {
4490                 Initializer _init = null;
4491                 if (token.value == TOKassign)
4492                 {
4493                     nextToken();
4494                     _init = parseInitializer();
4495                 }
4496 
4497                 auto v = new VarDeclaration(loc, t, ident, _init);
4498                 v.storage_class = storage_class;
4499                 if (pAttrs)
4500                     pAttrs.storageClass = STCundefined;
4501 
4502                 Dsymbol s = v;
4503 
4504                 if (tpl && _init)
4505                 {
4506                     auto a2 = new Dsymbols();
4507                     a2.push(s);
4508                     auto tempdecl = new TemplateDeclaration(loc, ident, tpl, null, a2, 0);
4509                     s = tempdecl;
4510                 }
4511                 if (setAlignment)
4512                 {
4513                     auto ax = new Dsymbols();
4514                     ax.push(s);
4515                     s = new AlignDeclaration(v.loc, ealign, ax);
4516                 }
4517                 if (link != linkage)
4518                 {
4519                     auto ax = new Dsymbols();
4520                     ax.push(s);
4521                     s = new LinkDeclaration(link, ax);
4522                 }
4523                 if (udas)
4524                 {
4525                     auto ax = new Dsymbols();
4526                     ax.push(s);
4527                     s = new UserAttributeDeclaration(udas, ax);
4528                 }
4529                 a.push(s);
4530                 switch (token.value)
4531                 {
4532                 case TOKsemicolon:
4533                     nextToken();
4534                     addComment(s, comment);
4535                     break;
4536 
4537                 case TOKcomma:
4538                     nextToken();
4539                     addComment(s, comment);
4540                     continue;
4541 
4542                 default:
4543                     error("semicolon expected, not '%s'", token.toChars());
4544                     break;
4545                 }
4546             }
4547             break;
4548         }
4549         return a;
4550     }
4551 
4552     Dsymbol parseFunctionLiteral()
4553     {
4554         const loc = token.loc;
4555         TemplateParameters* tpl = null;
4556         Parameters* parameters = null;
4557         int varargs = 0;
4558         Type tret = null;
4559         StorageClass stc = 0;
4560         TOK save = TOKreserved;
4561 
4562         switch (token.value)
4563         {
4564         case TOKfunction:
4565         case TOKdelegate:
4566             save = token.value;
4567             nextToken();
4568             if (token.value != TOKlparen && token.value != TOKlcurly)
4569             {
4570                 // function type (parameters) { statements... }
4571                 // delegate type (parameters) { statements... }
4572                 tret = parseBasicType();
4573                 tret = parseBasicType2(tret); // function return type
4574             }
4575 
4576             if (token.value == TOKlparen)
4577             {
4578                 // function (parameters) { statements... }
4579                 // delegate (parameters) { statements... }
4580             }
4581             else
4582             {
4583                 // function { statements... }
4584                 // delegate { statements... }
4585                 break;
4586             }
4587             goto case TOKlparen;
4588 
4589         case TOKlparen:
4590             {
4591                 // (parameters) => expression
4592                 // (parameters) { statements... }
4593                 parameters = parseParameters(&varargs, &tpl);
4594                 stc = parsePostfix(STCundefined, null);
4595                 if (StorageClass modStc = stc & STC_TYPECTOR)
4596                 {
4597                     if (save == TOKfunction)
4598                     {
4599                         OutBuffer buf;
4600                         stcToBuffer(&buf, modStc);
4601                         error("function literal cannot be %s", buf.peekString());
4602                     }
4603                     else
4604                         save = TOKdelegate;
4605                 }
4606                 break;
4607             }
4608         case TOKlcurly:
4609             // { statements... }
4610             break;
4611 
4612         case TOKidentifier:
4613             {
4614                 // identifier => expression
4615                 parameters = new Parameters();
4616                 Identifier id = Identifier.generateId("__T");
4617                 Type t = new TypeIdentifier(loc, id);
4618                 parameters.push(new Parameter(0, t, token.ident, null));
4619 
4620                 tpl = new TemplateParameters();
4621                 TemplateParameter tp = new TemplateTypeParameter(loc, id, null, null);
4622                 tpl.push(tp);
4623 
4624                 nextToken();
4625                 break;
4626             }
4627         default:
4628             assert(0);
4629         }
4630 
4631         if (!parameters)
4632             parameters = new Parameters();
4633         auto tf = new TypeFunction(parameters, tret, varargs, linkage, stc);
4634         tf = cast(TypeFunction)tf.addSTC(stc);
4635         auto fd = new FuncLiteralDeclaration(loc, Loc(), tf, save, null);
4636 
4637         if (token.value == TOKgoesto)
4638         {
4639             check(TOKgoesto);
4640             const returnloc = token.loc;
4641             Expression ae = parseAssignExp();
4642             fd.fbody = new ReturnStatement(returnloc, ae);
4643             fd.endloc = token.loc;
4644         }
4645         else
4646         {
4647             parseContracts(fd);
4648         }
4649 
4650         if (tpl)
4651         {
4652             // Wrap a template around function fd
4653             auto decldefs = new Dsymbols();
4654             decldefs.push(fd);
4655             return new TemplateDeclaration(fd.loc, fd.ident, tpl, null, decldefs, false, true);
4656         }
4657         else
4658             return fd;
4659     }
4660 
4661     /*****************************************
4662      * Parse contracts following function declaration.
4663      */
4664     FuncDeclaration parseContracts(FuncDeclaration f)
4665     {
4666         LINK linksave = linkage;
4667 
4668         bool literal = f.isFuncLiteralDeclaration() !is null;
4669 
4670         // The following is irrelevant, as it is overridden by sc->linkage in
4671         // TypeFunction::semantic
4672         linkage = LINKd; // nested functions have D linkage
4673     L1:
4674         switch (token.value)
4675         {
4676         case TOKlcurly:
4677             if (f.frequire || f.fensure)
4678                 error("missing body { ... } after in or out");
4679             f.fbody = parseStatement(PSsemi);
4680             f.endloc = endloc;
4681             break;
4682 
4683         case TOKbody:
4684             nextToken();
4685             f.fbody = parseStatement(PScurly);
4686             f.endloc = endloc;
4687             break;
4688 
4689             version (none)
4690             {
4691                 // Do we want this for function declarations, so we can do:
4692                 // int x, y, foo(), z;
4693             case TOKcomma:
4694                 nextToken();
4695                 continue;
4696             }
4697 
4698             version (none)
4699             {
4700                 // Dumped feature
4701             case TOKthrow:
4702                 if (!f.fthrows)
4703                     f.fthrows = new Types();
4704                 nextToken();
4705                 check(TOKlparen);
4706                 while (1)
4707                 {
4708                     Type tb = parseBasicType();
4709                     f.fthrows.push(tb);
4710                     if (token.value == TOKcomma)
4711                     {
4712                         nextToken();
4713                         continue;
4714                     }
4715                     break;
4716                 }
4717                 check(TOKrparen);
4718                 goto L1;
4719             }
4720 
4721         case TOKin:
4722             nextToken();
4723             if (f.frequire)
4724                 error("redundant 'in' statement");
4725             f.frequire = parseStatement(PScurly | PSscope);
4726             goto L1;
4727 
4728         case TOKout:
4729             // parse: out (identifier) { statement }
4730             nextToken();
4731             if (token.value != TOKlcurly)
4732             {
4733                 check(TOKlparen);
4734                 if (token.value != TOKidentifier)
4735                     error("(identifier) following 'out' expected, not %s", token.toChars());
4736                 f.outId = token.ident;
4737                 nextToken();
4738                 check(TOKrparen);
4739             }
4740             if (f.fensure)
4741                 error("redundant 'out' statement");
4742             f.fensure = parseStatement(PScurly | PSscope);
4743             goto L1;
4744 
4745         case TOKsemicolon:
4746             if (!literal)
4747             {
4748                 // Bugzilla 15799: Semicolon becomes a part of function declaration
4749                 // only when neither of contracts exists.
4750                 if (!f.frequire && !f.fensure)
4751                     nextToken();
4752                 break;
4753             }
4754             goto default;
4755 
4756         default:
4757             if (literal)
4758             {
4759                 const(char)* sbody = (f.frequire || f.fensure) ? "body " : "";
4760                 error("missing %s{ ... } for function literal", sbody);
4761             }
4762             else if (!f.frequire && !f.fensure) // allow these even with no body
4763             {
4764                 error("semicolon expected following function declaration");
4765             }
4766             break;
4767         }
4768         if (literal && !f.fbody)
4769         {
4770             // Set empty function body for error recovery
4771             f.fbody = new CompoundStatement(Loc(), cast(Statement)null);
4772         }
4773 
4774         linkage = linksave;
4775 
4776         return f;
4777     }
4778 
4779     /*****************************************
4780      */
4781     void checkDanglingElse(Loc elseloc)
4782     {
4783         if (token.value != TOKelse && token.value != TOKcatch && token.value != TOKfinally && lookingForElse.linnum != 0)
4784         {
4785             warning(elseloc, "else is dangling, add { } after condition at %s", lookingForElse.toChars());
4786         }
4787     }
4788 
4789     void checkCstyleTypeSyntax(Loc loc, Type t, int alt, Identifier ident)
4790     {
4791         if (!alt)
4792             return;
4793 
4794         const(char)* sp = !ident ? "" : " ";
4795         const(char)* s = !ident ? "" : ident.toChars();
4796         if (alt & 1) // contains C-style function pointer syntax
4797             error(loc, "instead of C-style syntax, use D-style '%s%s%s'", t.toChars(), sp, s);
4798         else
4799             .deprecation(loc, "instead of C-style syntax, use D-style syntax '%s%s%s'", t.toChars(), sp, s);
4800     }
4801 
4802     /*****************************************
4803      * Input:
4804      *      flags   PSxxxx
4805      * Output:
4806      *      pEndloc if { ... statements ... }, store location of closing brace, otherwise loc of first token of next statement
4807      */
4808     Statement parseStatement(int flags, const(char)** endPtr = null, Loc* pEndloc = null)
4809     {
4810         Statement s;
4811         Condition cond;
4812         Statement ifbody;
4813         Statement elsebody;
4814         bool isfinal;
4815         const loc = token.loc;
4816 
4817         //printf("parseStatement()\n");
4818         if (flags & PScurly && token.value != TOKlcurly)
4819             error("statement expected to be { }, not %s", token.toChars());
4820 
4821         switch (token.value)
4822         {
4823         case TOKidentifier:
4824             {
4825                 /* A leading identifier can be a declaration, label, or expression.
4826                  * The easiest case to check first is label:
4827                  */
4828                 Token* t = peek(&token);
4829                 if (t.value == TOKcolon)
4830                 {
4831                     Token* nt = peek(t);
4832                     if (nt.value == TOKcolon)
4833                     {
4834                         // skip ident::
4835                         nextToken();
4836                         nextToken();
4837                         nextToken();
4838                         error("use '.' for member lookup, not '::'");
4839                         break;
4840                     }
4841                     // It's a label
4842                     Identifier ident = token.ident;
4843                     nextToken();
4844                     nextToken();
4845                     if (token.value == TOKrcurly)
4846                         s = null;
4847                     else if (token.value == TOKlcurly)
4848                         s = parseStatement(PScurly | PSscope);
4849                     else
4850                         s = parseStatement(PSsemi_ok);
4851                     s = new LabelStatement(loc, ident, s);
4852                     break;
4853                 }
4854                 goto case TOKdot;
4855             }
4856         case TOKdot:
4857         case TOKtypeof:
4858         case TOKvector:
4859             /* Bugzilla 15163: If tokens can be handled as
4860              * old C-style declaration or D expression, prefer the latter.
4861              */
4862             if (isDeclaration(&token, NeedDeclaratorId.mustIfDstyle, TOKreserved, null))
4863                 goto Ldeclaration;
4864             else
4865                 goto Lexp;
4866 
4867         case TOKassert:
4868         case TOKthis:
4869         case TOKsuper:
4870         case TOKint32v:
4871         case TOKuns32v:
4872         case TOKint64v:
4873         case TOKuns64v:
4874         case TOKint128v:
4875         case TOKuns128v:
4876         case TOKfloat32v:
4877         case TOKfloat64v:
4878         case TOKfloat80v:
4879         case TOKimaginary32v:
4880         case TOKimaginary64v:
4881         case TOKimaginary80v:
4882         case TOKcharv:
4883         case TOKwcharv:
4884         case TOKdcharv:
4885         case TOKnull:
4886         case TOKtrue:
4887         case TOKfalse:
4888         case TOKstring:
4889         case TOKxstring:
4890         case TOKlparen:
4891         case TOKcast:
4892         case TOKmul:
4893         case TOKmin:
4894         case TOKadd:
4895         case TOKtilde:
4896         case TOKnot:
4897         case TOKplusplus:
4898         case TOKminusminus:
4899         case TOKnew:
4900         case TOKdelete:
4901         case TOKdelegate:
4902         case TOKfunction:
4903         case TOKtypeid:
4904         case TOKis:
4905         case TOKlbracket:
4906         case TOKtraits:
4907         case TOKfile:
4908         case TOKfilefullpath:
4909         case TOKline:
4910         case TOKmodulestring:
4911         case TOKfuncstring:
4912         case TOKprettyfunc:
4913         Lexp:
4914             {
4915                 Expression exp = parseExpression();
4916                 check(TOKsemicolon, "statement");
4917                 s = new ExpStatement(loc, exp);
4918                 break;
4919             }
4920         case TOKstatic:
4921             {
4922                 // Look ahead to see if it's static assert() or static if()
4923                 Token* t = peek(&token);
4924                 if (t.value == TOKassert)
4925                 {
4926                     s = new StaticAssertStatement(parseStaticAssert());
4927                     break;
4928                 }
4929                 if (t.value == TOKif)
4930                 {
4931                     cond = parseStaticIfCondition();
4932                     goto Lcondition;
4933                 }
4934                 if (t.value == TOKimport)
4935                 {
4936                     Dsymbols* imports = parseImport();
4937                     s = new ImportStatement(loc, imports);
4938                     if (flags & PSscope)
4939                         s = new ScopeStatement(loc, s, token.loc);
4940                     break;
4941                 }
4942                 goto Ldeclaration;
4943             }
4944         case TOKfinal:
4945             if (peekNext() == TOKswitch)
4946             {
4947                 nextToken();
4948                 isfinal = true;
4949                 goto Lswitch;
4950             }
4951             goto Ldeclaration;
4952 
4953         case TOKwchar:
4954         case TOKdchar:
4955         case TOKbool:
4956         case TOKchar:
4957         case TOKint8:
4958         case TOKuns8:
4959         case TOKint16:
4960         case TOKuns16:
4961         case TOKint32:
4962         case TOKuns32:
4963         case TOKint64:
4964         case TOKuns64:
4965         case TOKint128:
4966         case TOKuns128:
4967         case TOKfloat32:
4968         case TOKfloat64:
4969         case TOKfloat80:
4970         case TOKimaginary32:
4971         case TOKimaginary64:
4972         case TOKimaginary80:
4973         case TOKcomplex32:
4974         case TOKcomplex64:
4975         case TOKcomplex80:
4976         case TOKvoid:
4977             // bug 7773: int.max is always a part of expression
4978             if (peekNext() == TOKdot)
4979                 goto Lexp;
4980             if (peekNext() == TOKlparen)
4981                 goto Lexp;
4982             goto case;
4983 
4984         case TOKalias:
4985         case TOKconst:
4986         case TOKauto:
4987         case TOKabstract:
4988         case TOKextern:
4989         case TOKalign:
4990         case TOKimmutable:
4991         case TOKshared:
4992         case TOKwild:
4993         case TOKdeprecated:
4994         case TOKnothrow:
4995         case TOKpure:
4996         case TOKref:
4997         case TOKgshared:
4998         case TOKat:
4999         case TOKstruct:
5000         case TOKunion:
5001         case TOKclass:
5002         case TOKinterface:
5003         Ldeclaration:
5004             {
5005                 Dsymbols* a = parseDeclarations(false, null, null);
5006                 if (a.dim > 1)
5007                 {
5008                     auto as = new Statements();
5009                     as.reserve(a.dim);
5010                     foreach (i; 0 .. a.dim)
5011                     {
5012                         Dsymbol d = (*a)[i];
5013                         s = new ExpStatement(loc, d);
5014                         as.push(s);
5015                     }
5016                     s = new CompoundDeclarationStatement(loc, as);
5017                 }
5018                 else if (a.dim == 1)
5019                 {
5020                     Dsymbol d = (*a)[0];
5021                     s = new ExpStatement(loc, d);
5022                 }
5023                 else
5024                     s = new ExpStatement(loc, cast(Expression)null);
5025                 if (flags & PSscope)
5026                     s = new ScopeStatement(loc, s, token.loc);
5027                 break;
5028             }
5029         case TOKenum:
5030             {
5031                 /* Determine if this is a manifest constant declaration,
5032                  * or a conventional enum.
5033                  */
5034                 Dsymbol d;
5035                 Token* t = peek(&token);
5036                 if (t.value == TOKlcurly || t.value == TOKcolon)
5037                     d = parseEnum();
5038                 else if (t.value != TOKidentifier)
5039                     goto Ldeclaration;
5040                 else
5041                 {
5042                     t = peek(t);
5043                     if (t.value == TOKlcurly || t.value == TOKcolon || t.value == TOKsemicolon)
5044                         d = parseEnum();
5045                     else
5046                         goto Ldeclaration;
5047                 }
5048                 s = new ExpStatement(loc, d);
5049                 if (flags & PSscope)
5050                     s = new ScopeStatement(loc, s, token.loc);
5051                 break;
5052             }
5053         case TOKmixin:
5054             {
5055                 Token* t = peek(&token);
5056                 if (t.value == TOKlparen)
5057                 {
5058                     // mixin(string)
5059                     Expression e = parseAssignExp();
5060                     check(TOKsemicolon);
5061                     if (e.op == TOKmixin)
5062                     {
5063                         CompileExp cpe = cast(CompileExp)e;
5064                         s = new CompileStatement(loc, cpe.e1);
5065                     }
5066                     else
5067                     {
5068                         s = new ExpStatement(loc, e);
5069                     }
5070                     break;
5071                 }
5072                 Dsymbol d = parseMixin();
5073                 s = new ExpStatement(loc, d);
5074                 if (flags & PSscope)
5075                     s = new ScopeStatement(loc, s, token.loc);
5076                 break;
5077             }
5078         case TOKlcurly:
5079             {
5080                 const lookingForElseSave = lookingForElse;
5081                 lookingForElse = Loc();
5082 
5083                 nextToken();
5084                 //if (token.value == TOKsemicolon)
5085                 //    error("use '{ }' for an empty statement, not a ';'");
5086                 auto statements = new Statements();
5087                 while (token.value != TOKrcurly && token.value != TOKeof)
5088                 {
5089                     statements.push(parseStatement(PSsemi | PScurlyscope));
5090                 }
5091                 if (endPtr)
5092                     *endPtr = token.ptr;
5093                 endloc = token.loc;
5094                 if (pEndloc)
5095                 {
5096                     *pEndloc = token.loc;
5097                     pEndloc = null; // don't set it again
5098                 }
5099                 s = new CompoundStatement(loc, statements);
5100                 if (flags & (PSscope | PScurlyscope))
5101                     s = new ScopeStatement(loc, s, token.loc);
5102                 check(TOKrcurly, "compound statement");
5103                 lookingForElse = lookingForElseSave;
5104                 break;
5105             }
5106         case TOKwhile:
5107             {
5108                 nextToken();
5109                 check(TOKlparen);
5110                 Expression condition = parseExpression();
5111                 check(TOKrparen);
5112                 Loc endloc;
5113                 Statement _body = parseStatement(PSscope, null, &endloc);
5114                 s = new WhileStatement(loc, condition, _body, endloc);
5115                 break;
5116             }
5117         case TOKsemicolon:
5118             if (!(flags & PSsemi_ok))
5119             {
5120                 if (flags & PSsemi)
5121                     warning(loc, "use '{ }' for an empty statement, not a ';'");
5122                 else
5123                     error("use '{ }' for an empty statement, not a ';'");
5124             }
5125             nextToken();
5126             s = new ExpStatement(loc, cast(Expression)null);
5127             break;
5128 
5129         case TOKdo:
5130             {
5131                 Statement _body;
5132                 Expression condition;
5133 
5134                 nextToken();
5135                 const lookingForElseSave = lookingForElse;
5136                 lookingForElse = Loc();
5137                 _body = parseStatement(PSscope);
5138                 lookingForElse = lookingForElseSave;
5139                 check(TOKwhile);
5140                 check(TOKlparen);
5141                 condition = parseExpression();
5142                 check(TOKrparen);
5143                 if (token.value == TOKsemicolon)
5144                     nextToken();
5145                 else
5146                     error("terminating ';' required after do-while statement");
5147                 s = new DoStatement(loc, _body, condition, token.loc);
5148                 break;
5149             }
5150         case TOKfor:
5151             {
5152                 Statement _init;
5153                 Expression condition;
5154                 Expression increment;
5155 
5156                 nextToken();
5157                 check(TOKlparen);
5158                 if (token.value == TOKsemicolon)
5159                 {
5160                     _init = null;
5161                     nextToken();
5162                 }
5163                 else
5164                 {
5165                     const lookingForElseSave = lookingForElse;
5166                     lookingForElse = Loc();
5167                     _init = parseStatement(0);
5168                     lookingForElse = lookingForElseSave;
5169                 }
5170                 if (token.value == TOKsemicolon)
5171                 {
5172                     condition = null;
5173                     nextToken();
5174                 }
5175                 else
5176                 {
5177                     condition = parseExpression();
5178                     check(TOKsemicolon, "for condition");
5179                 }
5180                 if (token.value == TOKrparen)
5181                 {
5182                     increment = null;
5183                     nextToken();
5184                 }
5185                 else
5186                 {
5187                     increment = parseExpression();
5188                     check(TOKrparen);
5189                 }
5190                 Loc endloc;
5191                 Statement _body = parseStatement(PSscope, null, &endloc);
5192                 s = new ForStatement(loc, _init, condition, increment, _body, endloc);
5193                 break;
5194             }
5195         case TOKforeach:
5196         case TOKforeach_reverse:
5197             {
5198                 TOK op = token.value;
5199 
5200                 nextToken();
5201                 check(TOKlparen);
5202 
5203                 auto parameters = new Parameters();
5204                 while (1)
5205                 {
5206                     Identifier ai = null;
5207                     Type at;
5208 
5209                     StorageClass storageClass = 0;
5210                     StorageClass stc = 0;
5211                 Lagain:
5212                     if (stc)
5213                     {
5214                         storageClass = appendStorageClass(storageClass, stc);
5215                         nextToken();
5216                     }
5217                     switch (token.value)
5218                     {
5219                     case TOKref:
5220                         stc = STCref;
5221                         goto Lagain;
5222 
5223                     case TOKconst:
5224                         if (peekNext() != TOKlparen)
5225                         {
5226                             stc = STCconst;
5227                             goto Lagain;
5228                         }
5229                         break;
5230 
5231                     case TOKimmutable:
5232                         if (peekNext() != TOKlparen)
5233                         {
5234                             stc = STCimmutable;
5235                             goto Lagain;
5236                         }
5237                         break;
5238 
5239                     case TOKshared:
5240                         if (peekNext() != TOKlparen)
5241                         {
5242                             stc = STCshared;
5243                             goto Lagain;
5244                         }
5245                         break;
5246 
5247                     case TOKwild:
5248                         if (peekNext() != TOKlparen)
5249                         {
5250                             stc = STCwild;
5251                             goto Lagain;
5252                         }
5253                         break;
5254 
5255                     default:
5256                         break;
5257                     }
5258                     if (token.value == TOKidentifier)
5259                     {
5260                         Token* t = peek(&token);
5261                         if (t.value == TOKcomma || t.value == TOKsemicolon)
5262                         {
5263                             ai = token.ident;
5264                             at = null; // infer argument type
5265                             nextToken();
5266                             goto Larg;
5267                         }
5268                     }
5269                     at = parseType(&ai);
5270                     if (!ai)
5271                         error("no identifier for declarator %s", at.toChars());
5272                 Larg:
5273                     auto p = new Parameter(storageClass, at, ai, null);
5274                     parameters.push(p);
5275                     if (token.value == TOKcomma)
5276                     {
5277                         nextToken();
5278                         continue;
5279                     }
5280                     break;
5281                 }
5282                 check(TOKsemicolon);
5283 
5284                 Expression aggr = parseExpression();
5285                 if (token.value == TOKslice && parameters.dim == 1)
5286                 {
5287                     Parameter p = (*parameters)[0];
5288                     nextToken();
5289                     Expression upr = parseExpression();
5290                     check(TOKrparen);
5291                     Loc endloc;
5292                     Statement _body = parseStatement(0, null, &endloc);
5293                     s = new ForeachRangeStatement(loc, op, p, aggr, upr, _body, endloc);
5294                 }
5295                 else
5296                 {
5297                     check(TOKrparen);
5298                     Loc endloc;
5299                     Statement _body = parseStatement(0, null, &endloc);
5300                     s = new ForeachStatement(loc, op, parameters, aggr, _body, endloc);
5301                 }
5302                 break;
5303             }
5304         case TOKif:
5305             {
5306                 Parameter param = null;
5307                 Expression condition;
5308 
5309                 nextToken();
5310                 check(TOKlparen);
5311 
5312                 StorageClass storageClass = 0;
5313                 StorageClass stc = 0;
5314             LagainStc:
5315                 if (stc)
5316                 {
5317                     storageClass = appendStorageClass(storageClass, stc);
5318                     nextToken();
5319                 }
5320                 switch (token.value)
5321                 {
5322                 case TOKref:
5323                     stc = STCref;
5324                     goto LagainStc;
5325 
5326                 case TOKauto:
5327                     stc = STCauto;
5328                     goto LagainStc;
5329 
5330                 case TOKconst:
5331                     if (peekNext() != TOKlparen)
5332                     {
5333                         stc = STCconst;
5334                         goto LagainStc;
5335                     }
5336                     break;
5337 
5338                 case TOKimmutable:
5339                     if (peekNext() != TOKlparen)
5340                     {
5341                         stc = STCimmutable;
5342                         goto LagainStc;
5343                     }
5344                     break;
5345 
5346                 case TOKshared:
5347                     if (peekNext() != TOKlparen)
5348                     {
5349                         stc = STCshared;
5350                         goto LagainStc;
5351                     }
5352                     break;
5353 
5354                 case TOKwild:
5355                     if (peekNext() != TOKlparen)
5356                     {
5357                         stc = STCwild;
5358                         goto LagainStc;
5359                     }
5360                     break;
5361 
5362                 default:
5363                     break;
5364                 }
5365                 if (storageClass != 0 && token.value == TOKidentifier && peek(&token).value == TOKassign)
5366                 {
5367                     Identifier ai = token.ident;
5368                     Type at = null; // infer parameter type
5369                     nextToken();
5370                     check(TOKassign);
5371                     param = new Parameter(storageClass, at, ai, null);
5372                 }
5373                 else if (isDeclaration(&token, NeedDeclaratorId.must, TOKassign, null))
5374                 {
5375                     Identifier ai;
5376                     Type at = parseType(&ai);
5377                     check(TOKassign);
5378                     param = new Parameter(storageClass, at, ai, null);
5379                 }
5380 
5381                 condition = parseExpression();
5382                 check(TOKrparen);
5383                 {
5384                     const lookingForElseSave = lookingForElse;
5385                     lookingForElse = loc;
5386                     ifbody = parseStatement(PSscope);
5387                     lookingForElse = lookingForElseSave;
5388                 }
5389                 if (token.value == TOKelse)
5390                 {
5391                     const elseloc = token.loc;
5392                     nextToken();
5393                     elsebody = parseStatement(PSscope);
5394                     checkDanglingElse(elseloc);
5395                 }
5396                 else
5397                     elsebody = null;
5398                 if (condition && ifbody)
5399                     s = new IfStatement(loc, param, condition, ifbody, elsebody, token.loc);
5400                 else
5401                     s = null; // don't propagate parsing errors
5402                 break;
5403             }
5404         case TOKscope:
5405             if (peek(&token).value != TOKlparen)
5406                 goto Ldeclaration; // scope used as storage class
5407             nextToken();
5408             check(TOKlparen);
5409             if (token.value != TOKidentifier)
5410             {
5411                 error("scope identifier expected");
5412                 goto Lerror;
5413             }
5414             else
5415             {
5416                 TOK t = TOKon_scope_exit;
5417                 Identifier id = token.ident;
5418                 if (id == Id.exit)
5419                     t = TOKon_scope_exit;
5420                 else if (id == Id.failure)
5421                     t = TOKon_scope_failure;
5422                 else if (id == Id.success)
5423                     t = TOKon_scope_success;
5424                 else
5425                     error("valid scope identifiers are exit, failure, or success, not %s", id.toChars());
5426                 nextToken();
5427                 check(TOKrparen);
5428                 Statement st = parseStatement(PScurlyscope);
5429                 s = new OnScopeStatement(loc, t, st);
5430                 break;
5431             }
5432 
5433         case TOKdebug:
5434             nextToken();
5435             if (token.value == TOKassign)
5436             {
5437                 error("debug conditions can only be declared at module scope");
5438                 nextToken();
5439                 nextToken();
5440                 goto Lerror;
5441             }
5442             cond = parseDebugCondition();
5443             goto Lcondition;
5444 
5445         case TOKversion:
5446             nextToken();
5447             if (token.value == TOKassign)
5448             {
5449                 error("version conditions can only be declared at module scope");
5450                 nextToken();
5451                 nextToken();
5452                 goto Lerror;
5453             }
5454             cond = parseVersionCondition();
5455             goto Lcondition;
5456 
5457         Lcondition:
5458             {
5459                 const lookingForElseSave = lookingForElse;
5460                 lookingForElse = loc;
5461                 ifbody = parseStatement(0);
5462                 lookingForElse = lookingForElseSave;
5463             }
5464             elsebody = null;
5465             if (token.value == TOKelse)
5466             {
5467                 const elseloc = token.loc;
5468                 nextToken();
5469                 elsebody = parseStatement(0);
5470                 checkDanglingElse(elseloc);
5471             }
5472             s = new ConditionalStatement(loc, cond, ifbody, elsebody);
5473             if (flags & PSscope)
5474                 s = new ScopeStatement(loc, s, token.loc);
5475             break;
5476 
5477         case TOKpragma:
5478             {
5479                 Identifier ident;
5480                 Expressions* args = null;
5481                 Statement _body;
5482 
5483                 nextToken();
5484                 check(TOKlparen);
5485                 if (token.value != TOKidentifier)
5486                 {
5487                     error("pragma(identifier) expected");
5488                     goto Lerror;
5489                 }
5490                 ident = token.ident;
5491                 nextToken();
5492                 if (token.value == TOKcomma && peekNext() != TOKrparen)
5493                     args = parseArguments(); // pragma(identifier, args...);
5494                 else
5495                     check(TOKrparen); // pragma(identifier);
5496                 if (token.value == TOKsemicolon)
5497                 {
5498                     nextToken();
5499                     _body = null;
5500                 }
5501                 else
5502                     _body = parseStatement(PSsemi);
5503                 s = new PragmaStatement(loc, ident, args, _body);
5504                 break;
5505             }
5506         case TOKswitch:
5507             isfinal = false;
5508             goto Lswitch;
5509 
5510         Lswitch:
5511             {
5512                 nextToken();
5513                 check(TOKlparen);
5514                 Expression condition = parseExpression();
5515                 check(TOKrparen);
5516                 Statement _body = parseStatement(PSscope);
5517                 s = new SwitchStatement(loc, condition, _body, isfinal);
5518                 break;
5519             }
5520         case TOKcase:
5521             {
5522                 Expression exp;
5523                 Expressions cases; // array of Expression's
5524                 Expression last = null;
5525 
5526                 while (1)
5527                 {
5528                     nextToken();
5529                     exp = parseAssignExp();
5530                     cases.push(exp);
5531                     if (token.value != TOKcomma)
5532                         break;
5533                 }
5534                 check(TOKcolon);
5535 
5536                 /* case exp: .. case last:
5537                  */
5538                 if (token.value == TOKslice)
5539                 {
5540                     if (cases.dim > 1)
5541                         error("only one case allowed for start of case range");
5542                     nextToken();
5543                     check(TOKcase);
5544                     last = parseAssignExp();
5545                     check(TOKcolon);
5546                 }
5547 
5548                 if (flags & PScurlyscope)
5549                 {
5550                     auto statements = new Statements();
5551                     while (token.value != TOKcase && token.value != TOKdefault && token.value != TOKeof && token.value != TOKrcurly)
5552                     {
5553                         statements.push(parseStatement(PSsemi | PScurlyscope));
5554                     }
5555                     s = new CompoundStatement(loc, statements);
5556                 }
5557                 else
5558                     s = parseStatement(PSsemi | PScurlyscope);
5559                 s = new ScopeStatement(loc, s, token.loc);
5560 
5561                 if (last)
5562                 {
5563                     s = new CaseRangeStatement(loc, exp, last, s);
5564                 }
5565                 else
5566                 {
5567                     // Keep cases in order by building the case statements backwards
5568                     for (size_t i = cases.dim; i; i--)
5569                     {
5570                         exp = cases[i - 1];
5571                         s = new CaseStatement(loc, exp, s);
5572                     }
5573                 }
5574                 break;
5575             }
5576         case TOKdefault:
5577             {
5578                 nextToken();
5579                 check(TOKcolon);
5580 
5581                 if (flags & PScurlyscope)
5582                 {
5583                     auto statements = new Statements();
5584                     while (token.value != TOKcase && token.value != TOKdefault && token.value != TOKeof && token.value != TOKrcurly)
5585                     {
5586                         statements.push(parseStatement(PSsemi | PScurlyscope));
5587                     }
5588                     s = new CompoundStatement(loc, statements);
5589                 }
5590                 else
5591                     s = parseStatement(PSsemi | PScurlyscope);
5592                 s = new ScopeStatement(loc, s, token.loc);
5593                 s = new DefaultStatement(loc, s);
5594                 break;
5595             }
5596         case TOKreturn:
5597             {
5598                 Expression exp;
5599                 nextToken();
5600                 if (token.value == TOKsemicolon)
5601                     exp = null;
5602                 else
5603                     exp = parseExpression();
5604                 check(TOKsemicolon, "return statement");
5605                 s = new ReturnStatement(loc, exp);
5606                 break;
5607             }
5608         case TOKbreak:
5609             {
5610                 Identifier ident;
5611                 nextToken();
5612                 if (token.value == TOKidentifier)
5613                 {
5614                     ident = token.ident;
5615                     nextToken();
5616                 }
5617                 else
5618                     ident = null;
5619                 check(TOKsemicolon, "break statement");
5620                 s = new BreakStatement(loc, ident);
5621                 break;
5622             }
5623         case TOKcontinue:
5624             {
5625                 Identifier ident;
5626                 nextToken();
5627                 if (token.value == TOKidentifier)
5628                 {
5629                     ident = token.ident;
5630                     nextToken();
5631                 }
5632                 else
5633                     ident = null;
5634                 check(TOKsemicolon, "continue statement");
5635                 s = new ContinueStatement(loc, ident);
5636                 break;
5637             }
5638         case TOKgoto:
5639             {
5640                 Identifier ident;
5641                 nextToken();
5642                 if (token.value == TOKdefault)
5643                 {
5644                     nextToken();
5645                     s = new GotoDefaultStatement(loc);
5646                 }
5647                 else if (token.value == TOKcase)
5648                 {
5649                     Expression exp = null;
5650                     nextToken();
5651                     if (token.value != TOKsemicolon)
5652                         exp = parseExpression();
5653                     s = new GotoCaseStatement(loc, exp);
5654                 }
5655                 else
5656                 {
5657                     if (token.value != TOKidentifier)
5658                     {
5659                         error("identifier expected following goto");
5660                         ident = null;
5661                     }
5662                     else
5663                     {
5664                         ident = token.ident;
5665                         nextToken();
5666                     }
5667                     s = new GotoStatement(loc, ident);
5668                 }
5669                 check(TOKsemicolon, "goto statement");
5670                 break;
5671             }
5672         case TOKsynchronized:
5673             {
5674                 Expression exp;
5675                 Statement _body;
5676 
5677                 Token* t = peek(&token);
5678                 if (skipAttributes(t, &t) && t.value == TOKclass)
5679                     goto Ldeclaration;
5680 
5681                 nextToken();
5682                 if (token.value == TOKlparen)
5683                 {
5684                     nextToken();
5685                     exp = parseExpression();
5686                     check(TOKrparen);
5687                 }
5688                 else
5689                     exp = null;
5690                 _body = parseStatement(PSscope);
5691                 s = new SynchronizedStatement(loc, exp, _body);
5692                 break;
5693             }
5694         case TOKwith:
5695             {
5696                 Expression exp;
5697                 Statement _body;
5698                 Loc endloc = loc;
5699 
5700                 nextToken();
5701                 check(TOKlparen);
5702                 exp = parseExpression();
5703                 check(TOKrparen);
5704                 _body = parseStatement(PSscope, null, &endloc);
5705                 s = new WithStatement(loc, exp, _body, endloc);
5706                 break;
5707             }
5708         case TOKtry:
5709             {
5710                 Statement _body;
5711                 Catches* catches = null;
5712                 Statement finalbody = null;
5713 
5714                 nextToken();
5715                 const lookingForElseSave = lookingForElse;
5716                 lookingForElse = Loc();
5717                 _body = parseStatement(PSscope);
5718                 lookingForElse = lookingForElseSave;
5719                 while (token.value == TOKcatch)
5720                 {
5721                     Statement handler;
5722                     Catch c;
5723                     Type t;
5724                     Identifier id;
5725                     const catchloc = token.loc;
5726 
5727                     nextToken();
5728                     if (token.value == TOKlcurly || token.value != TOKlparen)
5729                     {
5730                         t = null;
5731                         id = null;
5732                     }
5733                     else
5734                     {
5735                         check(TOKlparen);
5736                         id = null;
5737                         t = parseType(&id);
5738                         check(TOKrparen);
5739                     }
5740                     handler = parseStatement(0);
5741                     c = new Catch(catchloc, t, id, handler);
5742                     if (!catches)
5743                         catches = new Catches();
5744                     catches.push(c);
5745                 }
5746 
5747                 if (token.value == TOKfinally)
5748                 {
5749                     nextToken();
5750                     finalbody = parseStatement(0);
5751                 }
5752 
5753                 s = _body;
5754                 if (!catches && !finalbody)
5755                     error("catch or finally expected following try");
5756                 else
5757                 {
5758                     if (catches)
5759                         s = new TryCatchStatement(loc, _body, catches);
5760                     if (finalbody)
5761                         s = new TryFinallyStatement(loc, s, finalbody);
5762                 }
5763                 break;
5764             }
5765         case TOKthrow:
5766             {
5767                 Expression exp;
5768                 nextToken();
5769                 exp = parseExpression();
5770                 check(TOKsemicolon, "throw statement");
5771                 s = new ThrowStatement(loc, exp);
5772                 break;
5773             }
5774 
5775         case TOKasm:
5776             {
5777                 // Parse the asm block into a sequence of AsmStatements,
5778                 // each AsmStatement is one instruction.
5779                 // Separate out labels.
5780                 // Defer parsing of AsmStatements until semantic processing.
5781 
5782                 Loc labelloc;
5783 
5784                 nextToken();
5785                 StorageClass stc = parsePostfix(STCundefined, null);
5786                 if (stc & (STCconst | STCimmutable | STCshared | STCwild))
5787                     error("const/immutable/shared/inout attributes are not allowed on asm blocks");
5788 
5789                 check(TOKlcurly);
5790                 Token* toklist = null;
5791                 Token** ptoklist = &toklist;
5792                 Identifier label = null;
5793                 auto statements = new Statements();
5794                 size_t nestlevel = 0;
5795                 while (1)
5796                 {
5797                     switch (token.value)
5798                     {
5799                     case TOKidentifier:
5800                         if (!toklist)
5801                         {
5802                             // Look ahead to see if it is a label
5803                             Token* t = peek(&token);
5804                             if (t.value == TOKcolon)
5805                             {
5806                                 // It's a label
5807                                 label = token.ident;
5808                                 labelloc = token.loc;
5809                                 nextToken();
5810                                 nextToken();
5811                                 continue;
5812                             }
5813                         }
5814                         goto Ldefault;
5815 
5816                     case TOKlcurly:
5817                         ++nestlevel;
5818                         goto Ldefault;
5819 
5820                     case TOKrcurly:
5821                         if (nestlevel > 0)
5822                         {
5823                             --nestlevel;
5824                             goto Ldefault;
5825                         }
5826                         if (toklist || label)
5827                         {
5828                             error("asm statements must end in ';'");
5829                         }
5830                         break;
5831 
5832                     case TOKsemicolon:
5833                         if (nestlevel != 0)
5834                             error("mismatched number of curly brackets");
5835 
5836                         s = null;
5837                         if (toklist || label)
5838                         {
5839                             // Create AsmStatement from list of tokens we've saved
5840                             s = new AsmStatement(token.loc, toklist);
5841                             toklist = null;
5842                             ptoklist = &toklist;
5843                             if (label)
5844                             {
5845                                 s = new LabelStatement(labelloc, label, s);
5846                                 label = null;
5847                             }
5848                             statements.push(s);
5849                         }
5850                         nextToken();
5851                         continue;
5852 
5853                     case TOKeof:
5854                         /* { */
5855                         error("matching '}' expected, not end of file");
5856                         goto Lerror;
5857 
5858                     default:
5859                     Ldefault:
5860                         *ptoklist = Token.alloc();
5861                         memcpy(*ptoklist, &token, Token.sizeof);
5862                         ptoklist = &(*ptoklist).next;
5863                         *ptoklist = null;
5864                         nextToken();
5865                         continue;
5866                     }
5867                     break;
5868                 }
5869                 s = new CompoundAsmStatement(loc, statements, stc);
5870                 nextToken();
5871                 break;
5872             }
5873         case TOKimport:
5874             {
5875                 Dsymbols* imports = parseImport();
5876                 s = new ImportStatement(loc, imports);
5877                 if (flags & PSscope)
5878                     s = new ScopeStatement(loc, s, token.loc);
5879                 break;
5880             }
5881         case TOKtemplate:
5882             {
5883                 Dsymbol d = parseTemplateDeclaration();
5884                 s = new ExpStatement(loc, d);
5885                 break;
5886             }
5887         default:
5888             error("found '%s' instead of statement", token.toChars());
5889             goto Lerror;
5890 
5891         Lerror:
5892             while (token.value != TOKrcurly && token.value != TOKsemicolon && token.value != TOKeof)
5893                 nextToken();
5894             if (token.value == TOKsemicolon)
5895                 nextToken();
5896             s = null;
5897             break;
5898         }
5899         if (pEndloc)
5900             *pEndloc = token.loc;
5901         return s;
5902     }
5903 
5904     /*****************************************
5905      * Parse initializer for variable declaration.
5906      */
5907     Initializer parseInitializer()
5908     {
5909         StructInitializer _is;
5910         ArrayInitializer ia;
5911         ExpInitializer ie;
5912         Expression e;
5913         Identifier id;
5914         Initializer value;
5915         int comma;
5916         const loc = token.loc;
5917         Token* t;
5918         int braces;
5919         int brackets;
5920 
5921         switch (token.value)
5922         {
5923         case TOKlcurly:
5924             /* Scan ahead to see if it is a struct initializer or
5925              * a function literal.
5926              * If it contains a ';', it is a function literal.
5927              * Treat { } as a struct initializer.
5928              */
5929             braces = 1;
5930             for (t = peek(&token); 1; t = peek(t))
5931             {
5932                 switch (t.value)
5933                 {
5934                 case TOKsemicolon:
5935                 case TOKreturn:
5936                     goto Lexpression;
5937 
5938                 case TOKlcurly:
5939                     braces++;
5940                     continue;
5941 
5942                 case TOKrcurly:
5943                     if (--braces == 0)
5944                         break;
5945                     continue;
5946 
5947                 case TOKeof:
5948                     break;
5949 
5950                 default:
5951                     continue;
5952                 }
5953                 break;
5954             }
5955 
5956             _is = new StructInitializer(loc);
5957             nextToken();
5958             comma = 2;
5959             while (1)
5960             {
5961                 switch (token.value)
5962                 {
5963                 case TOKidentifier:
5964                     if (comma == 1)
5965                         error("comma expected separating field initializers");
5966                     t = peek(&token);
5967                     if (t.value == TOKcolon)
5968                     {
5969                         id = token.ident;
5970                         nextToken();
5971                         nextToken(); // skip over ':'
5972                     }
5973                     else
5974                     {
5975                         id = null;
5976                     }
5977                     value = parseInitializer();
5978                     _is.addInit(id, value);
5979                     comma = 1;
5980                     continue;
5981 
5982                 case TOKcomma:
5983                     if (comma == 2)
5984                         error("expression expected, not ','");
5985                     nextToken();
5986                     comma = 2;
5987                     continue;
5988 
5989                 case TOKrcurly: // allow trailing comma's
5990                     nextToken();
5991                     break;
5992 
5993                 case TOKeof:
5994                     error("found EOF instead of initializer");
5995                     break;
5996 
5997                 default:
5998                     if (comma == 1)
5999                         error("comma expected separating field initializers");
6000                     value = parseInitializer();
6001                     _is.addInit(null, value);
6002                     comma = 1;
6003                     continue;
6004                     //error("found '%s' instead of field initializer", token.toChars());
6005                     //break;
6006                 }
6007                 break;
6008             }
6009             return _is;
6010 
6011         case TOKlbracket:
6012             /* Scan ahead to see if it is an array initializer or
6013              * an expression.
6014              * If it ends with a ';' ',' or '}', it is an array initializer.
6015              */
6016             brackets = 1;
6017             for (t = peek(&token); 1; t = peek(t))
6018             {
6019                 switch (t.value)
6020                 {
6021                 case TOKlbracket:
6022                     brackets++;
6023                     continue;
6024 
6025                 case TOKrbracket:
6026                     if (--brackets == 0)
6027                     {
6028                         t = peek(t);
6029                         if (t.value != TOKsemicolon && t.value != TOKcomma && t.value != TOKrbracket && t.value != TOKrcurly)
6030                             goto Lexpression;
6031                         break;
6032                     }
6033                     continue;
6034 
6035                 case TOKeof:
6036                     break;
6037 
6038                 default:
6039                     continue;
6040                 }
6041                 break;
6042             }
6043 
6044             ia = new ArrayInitializer(loc);
6045             nextToken();
6046             comma = 2;
6047             while (1)
6048             {
6049                 switch (token.value)
6050                 {
6051                 default:
6052                     if (comma == 1)
6053                     {
6054                         error("comma expected separating array initializers, not %s", token.toChars());
6055                         nextToken();
6056                         break;
6057                     }
6058                     e = parseAssignExp();
6059                     if (!e)
6060                         break;
6061                     if (token.value == TOKcolon)
6062                     {
6063                         nextToken();
6064                         value = parseInitializer();
6065                     }
6066                     else
6067                     {
6068                         value = new ExpInitializer(e.loc, e);
6069                         e = null;
6070                     }
6071                     ia.addInit(e, value);
6072                     comma = 1;
6073                     continue;
6074 
6075                 case TOKlcurly:
6076                 case TOKlbracket:
6077                     if (comma == 1)
6078                         error("comma expected separating array initializers, not %s", token.toChars());
6079                     value = parseInitializer();
6080                     if (token.value == TOKcolon)
6081                     {
6082                         nextToken();
6083                         e = value.toExpression();
6084                         value = parseInitializer();
6085                     }
6086                     else
6087                         e = null;
6088                     ia.addInit(e, value);
6089                     comma = 1;
6090                     continue;
6091 
6092                 case TOKcomma:
6093                     if (comma == 2)
6094                         error("expression expected, not ','");
6095                     nextToken();
6096                     comma = 2;
6097                     continue;
6098 
6099                 case TOKrbracket: // allow trailing comma's
6100                     nextToken();
6101                     break;
6102 
6103                 case TOKeof:
6104                     error("found '%s' instead of array initializer", token.toChars());
6105                     break;
6106                 }
6107                 break;
6108             }
6109             return ia;
6110 
6111         case TOKvoid:
6112             t = peek(&token);
6113             if (t.value == TOKsemicolon || t.value == TOKcomma)
6114             {
6115                 nextToken();
6116                 return new VoidInitializer(loc);
6117             }
6118             goto Lexpression;
6119 
6120         default:
6121         Lexpression:
6122             e = parseAssignExp();
6123             ie = new ExpInitializer(loc, e);
6124             return ie;
6125         }
6126     }
6127 
6128     /*****************************************
6129      * Parses default argument initializer expression that is an assign expression,
6130      * with special handling for __FILE__, __FILE_DIR__, __LINE__, __MODULE__, __FUNCTION__, and __PRETTY_FUNCTION__.
6131      */
6132     Expression parseDefaultInitExp()
6133     {
6134         if (token.value == TOKfile || token.value == TOKfilefullpath || token.value == TOKline || token.value == TOKmodulestring || token.value == TOKfuncstring || token.value == TOKprettyfunc)
6135         {
6136             Token* t = peek(&token);
6137             if (t.value == TOKcomma || t.value == TOKrparen)
6138             {
6139                 Expression e = null;
6140                 if (token.value == TOKfile)
6141                     e = new FileInitExp(token.loc, TOKfile);
6142                 else if (token.value == TOKfilefullpath)
6143                     e = new FileInitExp(token.loc, TOKfilefullpath);
6144                 else if (token.value == TOKline)
6145                     e = new LineInitExp(token.loc);
6146                 else if (token.value == TOKmodulestring)
6147                     e = new ModuleInitExp(token.loc);
6148                 else if (token.value == TOKfuncstring)
6149                     e = new FuncInitExp(token.loc);
6150                 else if (token.value == TOKprettyfunc)
6151                     e = new PrettyFuncInitExp(token.loc);
6152                 else
6153                     assert(0);
6154                 nextToken();
6155                 return e;
6156             }
6157         }
6158         Expression e = parseAssignExp();
6159         return e;
6160     }
6161 
6162     void check(Loc loc, TOK value)
6163     {
6164         if (token.value != value)
6165             error(loc, "found '%s' when expecting '%s'", token.toChars(), Token.toChars(value));
6166         nextToken();
6167     }
6168 
6169     void check(TOK value)
6170     {
6171         check(token.loc, value);
6172     }
6173 
6174     void check(TOK value, const(char)* string)
6175     {
6176         if (token.value != value)
6177             error("found '%s' when expecting '%s' following %s", token.toChars(), Token.toChars(value), string);
6178         nextToken();
6179     }
6180 
6181     void checkParens(TOK value, Expression e)
6182     {
6183         if (precedence[e.op] == PREC.rel && !e.parens)
6184             error(e.loc, "%s must be parenthesized when next to operator %s", e.toChars(), Token.toChars(value));
6185     }
6186 
6187     enum NeedDeclaratorId
6188     {
6189         no,             // Declarator part must have no identifier
6190         opt,            // Declarator part identifier is optional
6191         must,           // Declarator part must have identifier
6192         mustIfDstyle,   // Declarator part must have identifier, but don't recognize old C-style syntax
6193     }
6194 
6195     /************************************
6196      * Determine if the scanner is sitting on the start of a declaration.
6197      * Params:
6198      *      needId
6199      * Output:
6200      *      if *pt is not NULL, it is set to the ending token, which would be endtok
6201      */
6202     bool isDeclaration(Token* t, NeedDeclaratorId needId, TOK endtok, Token** pt)
6203     {
6204         //printf("isDeclaration(needId = %d)\n", needId);
6205         int haveId = 0;
6206         int haveTpl = 0;
6207 
6208         while (1)
6209         {
6210             if ((t.value == TOKconst || t.value == TOKimmutable || t.value == TOKwild || t.value == TOKshared) && peek(t).value != TOKlparen)
6211             {
6212                 /* const type
6213                  * immutable type
6214                  * shared type
6215                  * wild type
6216                  */
6217                 t = peek(t);
6218                 continue;
6219             }
6220             break;
6221         }
6222 
6223         if (!isBasicType(&t))
6224         {
6225             goto Lisnot;
6226         }
6227         if (!isDeclarator(&t, &haveId, &haveTpl, endtok, needId != NeedDeclaratorId.mustIfDstyle))
6228             goto Lisnot;
6229         if ((needId == NeedDeclaratorId.no && !haveId) ||
6230             (needId == NeedDeclaratorId.opt) ||
6231             (needId == NeedDeclaratorId.must && haveId) ||
6232             (needId == NeedDeclaratorId.mustIfDstyle && haveId))
6233         {
6234             if (pt)
6235                 *pt = t;
6236             goto Lis;
6237         }
6238         else
6239             goto Lisnot;
6240 
6241     Lis:
6242         //printf("\tis declaration, t = %s\n", t->toChars());
6243         return true;
6244 
6245     Lisnot:
6246         //printf("\tis not declaration\n");
6247         return false;
6248     }
6249 
6250     bool isBasicType(Token** pt)
6251     {
6252         // This code parallels parseBasicType()
6253         Token* t = *pt;
6254         switch (t.value)
6255         {
6256         case TOKwchar:
6257         case TOKdchar:
6258         case TOKbool:
6259         case TOKchar:
6260         case TOKint8:
6261         case TOKuns8:
6262         case TOKint16:
6263         case TOKuns16:
6264         case TOKint32:
6265         case TOKuns32:
6266         case TOKint64:
6267         case TOKuns64:
6268         case TOKint128:
6269         case TOKuns128:
6270         case TOKfloat32:
6271         case TOKfloat64:
6272         case TOKfloat80:
6273         case TOKimaginary32:
6274         case TOKimaginary64:
6275         case TOKimaginary80:
6276         case TOKcomplex32:
6277         case TOKcomplex64:
6278         case TOKcomplex80:
6279         case TOKvoid:
6280             t = peek(t);
6281             break;
6282 
6283         case TOKidentifier:
6284         L5:
6285             t = peek(t);
6286             if (t.value == TOKnot)
6287             {
6288                 goto L4;
6289             }
6290             goto L3;
6291             while (1)
6292             {
6293             L2:
6294                 t = peek(t);
6295             L3:
6296                 if (t.value == TOKdot)
6297                 {
6298                 Ldot:
6299                     t = peek(t);
6300                     if (t.value != TOKidentifier)
6301                         goto Lfalse;
6302                     t = peek(t);
6303                     if (t.value != TOKnot)
6304                         goto L3;
6305                 L4:
6306                     /* Seen a !
6307                      * Look for:
6308                      * !( args ), !identifier, etc.
6309                      */
6310                     t = peek(t);
6311                     switch (t.value)
6312                     {
6313                     case TOKidentifier:
6314                         goto L5;
6315 
6316                     case TOKlparen:
6317                         if (!skipParens(t, &t))
6318                             goto Lfalse;
6319                         goto L3;
6320 
6321                     case TOKwchar:
6322                     case TOKdchar:
6323                     case TOKbool:
6324                     case TOKchar:
6325                     case TOKint8:
6326                     case TOKuns8:
6327                     case TOKint16:
6328                     case TOKuns16:
6329                     case TOKint32:
6330                     case TOKuns32:
6331                     case TOKint64:
6332                     case TOKuns64:
6333                     case TOKint128:
6334                     case TOKuns128:
6335                     case TOKfloat32:
6336                     case TOKfloat64:
6337                     case TOKfloat80:
6338                     case TOKimaginary32:
6339                     case TOKimaginary64:
6340                     case TOKimaginary80:
6341                     case TOKcomplex32:
6342                     case TOKcomplex64:
6343                     case TOKcomplex80:
6344                     case TOKvoid:
6345                     case TOKint32v:
6346                     case TOKuns32v:
6347                     case TOKint64v:
6348                     case TOKuns64v:
6349                     case TOKint128v:
6350                     case TOKuns128v:
6351                     case TOKfloat32v:
6352                     case TOKfloat64v:
6353                     case TOKfloat80v:
6354                     case TOKimaginary32v:
6355                     case TOKimaginary64v:
6356                     case TOKimaginary80v:
6357                     case TOKnull:
6358                     case TOKtrue:
6359                     case TOKfalse:
6360                     case TOKcharv:
6361                     case TOKwcharv:
6362                     case TOKdcharv:
6363                     case TOKstring:
6364                     case TOKxstring:
6365                     case TOKfile:
6366                     case TOKfilefullpath:
6367                     case TOKline:
6368                     case TOKmodulestring:
6369                     case TOKfuncstring:
6370                     case TOKprettyfunc:
6371                         goto L2;
6372 
6373                     default:
6374                         goto Lfalse;
6375                     }
6376                 }
6377                 else
6378                     break;
6379             }
6380             break;
6381 
6382         case TOKdot:
6383             goto Ldot;
6384 
6385         case TOKtypeof:
6386         case TOKvector:
6387             /* typeof(exp).identifier...
6388              */
6389             t = peek(t);
6390             if (!skipParens(t, &t))
6391                 goto Lfalse;
6392             goto L3;
6393 
6394         case TOKconst:
6395         case TOKimmutable:
6396         case TOKshared:
6397         case TOKwild:
6398             // const(type)  or  immutable(type)  or  shared(type)  or  wild(type)
6399             t = peek(t);
6400             if (t.value != TOKlparen)
6401                 goto Lfalse;
6402             t = peek(t);
6403             if (!isDeclaration(t, NeedDeclaratorId.no, TOKrparen, &t))
6404             {
6405                 goto Lfalse;
6406             }
6407             t = peek(t);
6408             break;
6409 
6410         default:
6411             goto Lfalse;
6412         }
6413         *pt = t;
6414         //printf("is\n");
6415         return true;
6416 
6417     Lfalse:
6418         //printf("is not\n");
6419         return false;
6420     }
6421 
6422     bool isDeclarator(Token** pt, int* haveId, int* haveTpl, TOK endtok, bool allowAltSyntax = true)
6423     {
6424         // This code parallels parseDeclarator()
6425         Token* t = *pt;
6426         int parens;
6427 
6428         //printf("Parser::isDeclarator() %s\n", t->toChars());
6429         if (t.value == TOKassign)
6430             return false;
6431 
6432         while (1)
6433         {
6434             parens = false;
6435             switch (t.value)
6436             {
6437             case TOKmul:
6438             //case TOKand:
6439                 t = peek(t);
6440                 continue;
6441 
6442             case TOKlbracket:
6443                 t = peek(t);
6444                 if (t.value == TOKrbracket)
6445                 {
6446                     t = peek(t);
6447                 }
6448                 else if (isDeclaration(t, NeedDeclaratorId.no, TOKrbracket, &t))
6449                 {
6450                     // It's an associative array declaration
6451                     t = peek(t);
6452 
6453                     // ...[type].ident
6454                     if (t.value == TOKdot && peek(t).value == TOKidentifier)
6455                     {
6456                         t = peek(t);
6457                         t = peek(t);
6458                     }
6459                 }
6460                 else
6461                 {
6462                     // [ expression ]
6463                     // [ expression .. expression ]
6464                     if (!isExpression(&t))
6465                         return false;
6466                     if (t.value == TOKslice)
6467                     {
6468                         t = peek(t);
6469                         if (!isExpression(&t))
6470                             return false;
6471                         if (t.value != TOKrbracket)
6472                             return false;
6473                         t = peek(t);
6474                     }
6475                     else
6476                     {
6477                         if (t.value != TOKrbracket)
6478                             return false;
6479                         t = peek(t);
6480                         // ...[index].ident
6481                         if (t.value == TOKdot && peek(t).value == TOKidentifier)
6482                         {
6483                             t = peek(t);
6484                             t = peek(t);
6485                         }
6486                     }
6487                 }
6488                 continue;
6489 
6490             case TOKidentifier:
6491                 if (*haveId)
6492                     return false;
6493                 *haveId = true;
6494                 t = peek(t);
6495                 break;
6496 
6497             case TOKlparen:
6498                 if (!allowAltSyntax)
6499                     return false;   // Do not recognize C-style declarations.
6500 
6501                 t = peek(t);
6502                 if (t.value == TOKrparen)
6503                     return false; // () is not a declarator
6504 
6505                 /* Regard ( identifier ) as not a declarator
6506                  * BUG: what about ( *identifier ) in
6507                  *      f(*p)(x);
6508                  * where f is a class instance with overloaded () ?
6509                  * Should we just disallow C-style function pointer declarations?
6510                  */
6511                 if (t.value == TOKidentifier)
6512                 {
6513                     Token* t2 = peek(t);
6514                     if (t2.value == TOKrparen)
6515                         return false;
6516                 }
6517 
6518                 if (!isDeclarator(&t, haveId, null, TOKrparen))
6519                     return false;
6520                 t = peek(t);
6521                 parens = true;
6522                 break;
6523 
6524             case TOKdelegate:
6525             case TOKfunction:
6526                 t = peek(t);
6527                 if (!isParameters(&t))
6528                     return false;
6529                 skipAttributes(t, &t);
6530                 continue;
6531 
6532             default:
6533                 break;
6534             }
6535             break;
6536         }
6537 
6538         while (1)
6539         {
6540             switch (t.value)
6541             {
6542                 static if (CARRAYDECL)
6543                 {
6544                 case TOKlbracket:
6545                     parens = false;
6546                     t = peek(t);
6547                     if (t.value == TOKrbracket)
6548                     {
6549                         t = peek(t);
6550                     }
6551                     else if (isDeclaration(t, NeedDeclaratorId.no, TOKrbracket, &t))
6552                     {
6553                         // It's an associative array declaration
6554                         t = peek(t);
6555                     }
6556                     else
6557                     {
6558                         // [ expression ]
6559                         if (!isExpression(&t))
6560                             return false;
6561                         if (t.value != TOKrbracket)
6562                             return false;
6563                         t = peek(t);
6564                     }
6565                     continue;
6566                 }
6567 
6568             case TOKlparen:
6569                 parens = false;
6570                 if (Token* tk = peekPastParen(t))
6571                 {
6572                     if (tk.value == TOKlparen)
6573                     {
6574                         if (!haveTpl)
6575                             return false;
6576                         *haveTpl = 1;
6577                         t = tk;
6578                     }
6579                     else if (tk.value == TOKassign)
6580                     {
6581                         if (!haveTpl)
6582                             return false;
6583                         *haveTpl = 1;
6584                         *pt = tk;
6585                         return true;
6586                     }
6587                 }
6588                 if (!isParameters(&t))
6589                     return false;
6590                 while (1)
6591                 {
6592                     switch (t.value)
6593                     {
6594                     case TOKconst:
6595                     case TOKimmutable:
6596                     case TOKshared:
6597                     case TOKwild:
6598                     case TOKpure:
6599                     case TOKnothrow:
6600                     case TOKreturn:
6601                     case TOKscope:
6602                         t = peek(t);
6603                         continue;
6604 
6605                     case TOKat:
6606                         t = peek(t); // skip '@'
6607                         t = peek(t); // skip identifier
6608                         continue;
6609 
6610                     default:
6611                         break;
6612                     }
6613                     break;
6614                 }
6615                 continue;
6616 
6617             // Valid tokens that follow a declaration
6618             case TOKrparen:
6619             case TOKrbracket:
6620             case TOKassign:
6621             case TOKcomma:
6622             case TOKdotdotdot:
6623             case TOKsemicolon:
6624             case TOKlcurly:
6625             case TOKin:
6626             case TOKout:
6627             case TOKbody:
6628                 // The !parens is to disallow unnecessary parentheses
6629                 if (!parens && (endtok == TOKreserved || endtok == t.value))
6630                 {
6631                     *pt = t;
6632                     return true;
6633                 }
6634                 return false;
6635 
6636             case TOKif:
6637                 return haveTpl ? true : false;
6638 
6639             default:
6640                 return false;
6641             }
6642         }
6643     }
6644 
6645     bool isParameters(Token** pt)
6646     {
6647         // This code parallels parseParameters()
6648         Token* t = *pt;
6649 
6650         //printf("isParameters()\n");
6651         if (t.value != TOKlparen)
6652             return false;
6653 
6654         t = peek(t);
6655         for (; 1; t = peek(t))
6656         {
6657         L1:
6658             switch (t.value)
6659             {
6660             case TOKrparen:
6661                 break;
6662 
6663             case TOKdotdotdot:
6664                 t = peek(t);
6665                 break;
6666 
6667             case TOKin:
6668             case TOKout:
6669             case TOKref:
6670             case TOKlazy:
6671             case TOKscope:
6672             case TOKfinal:
6673             case TOKauto:
6674                 continue;
6675 
6676             case TOKconst:
6677             case TOKimmutable:
6678             case TOKshared:
6679             case TOKwild:
6680                 t = peek(t);
6681                 if (t.value == TOKlparen)
6682                 {
6683                     t = peek(t);
6684                     if (!isDeclaration(t, NeedDeclaratorId.no, TOKrparen, &t))
6685                         return false;
6686                     t = peek(t); // skip past closing ')'
6687                     goto L2;
6688                 }
6689                 goto L1;
6690 
6691                 version (none)
6692                 {
6693                 case TOKstatic:
6694                     continue;
6695                 case TOKauto:
6696                 case TOKalias:
6697                     t = peek(t);
6698                     if (t.value == TOKidentifier)
6699                         t = peek(t);
6700                     if (t.value == TOKassign)
6701                     {
6702                         t = peek(t);
6703                         if (!isExpression(&t))
6704                             return false;
6705                     }
6706                     goto L3;
6707                 }
6708 
6709             default:
6710                 {
6711                     if (!isBasicType(&t))
6712                         return false;
6713                 L2:
6714                     int tmp = false;
6715                     if (t.value != TOKdotdotdot && !isDeclarator(&t, &tmp, null, TOKreserved))
6716                         return false;
6717                     if (t.value == TOKassign)
6718                     {
6719                         t = peek(t);
6720                         if (!isExpression(&t))
6721                             return false;
6722                     }
6723                     if (t.value == TOKdotdotdot)
6724                     {
6725                         t = peek(t);
6726                         break;
6727                     }
6728                 }
6729                 if (t.value == TOKcomma)
6730                 {
6731                     continue;
6732                 }
6733                 break;
6734             }
6735             break;
6736         }
6737         if (t.value != TOKrparen)
6738             return false;
6739         t = peek(t);
6740         *pt = t;
6741         return true;
6742     }
6743 
6744     bool isExpression(Token** pt)
6745     {
6746         // This is supposed to determine if something is an expression.
6747         // What it actually does is scan until a closing right bracket
6748         // is found.
6749 
6750         Token* t = *pt;
6751         int brnest = 0;
6752         int panest = 0;
6753         int curlynest = 0;
6754 
6755         for (;; t = peek(t))
6756         {
6757             switch (t.value)
6758             {
6759             case TOKlbracket:
6760                 brnest++;
6761                 continue;
6762 
6763             case TOKrbracket:
6764                 if (--brnest >= 0)
6765                     continue;
6766                 break;
6767 
6768             case TOKlparen:
6769                 panest++;
6770                 continue;
6771 
6772             case TOKcomma:
6773                 if (brnest || panest)
6774                     continue;
6775                 break;
6776 
6777             case TOKrparen:
6778                 if (--panest >= 0)
6779                     continue;
6780                 break;
6781 
6782             case TOKlcurly:
6783                 curlynest++;
6784                 continue;
6785 
6786             case TOKrcurly:
6787                 if (--curlynest >= 0)
6788                     continue;
6789                 return false;
6790 
6791             case TOKslice:
6792                 if (brnest)
6793                     continue;
6794                 break;
6795 
6796             case TOKsemicolon:
6797                 if (curlynest)
6798                     continue;
6799                 return false;
6800 
6801             case TOKeof:
6802                 return false;
6803 
6804             default:
6805                 continue;
6806             }
6807             break;
6808         }
6809 
6810         *pt = t;
6811         return true;
6812     }
6813 
6814     /*******************************************
6815      * Skip parens, brackets.
6816      * Input:
6817      *      t is on opening $(LPAREN)
6818      * Output:
6819      *      *pt is set to closing token, which is '$(RPAREN)' on success
6820      * Returns:
6821      *      true    successful
6822      *      false   some parsing error
6823      */
6824     bool skipParens(Token* t, Token** pt)
6825     {
6826         if (t.value != TOKlparen)
6827             return false;
6828 
6829         int parens = 0;
6830 
6831         while (1)
6832         {
6833             switch (t.value)
6834             {
6835             case TOKlparen:
6836                 parens++;
6837                 break;
6838 
6839             case TOKrparen:
6840                 parens--;
6841                 if (parens < 0)
6842                     goto Lfalse;
6843                 if (parens == 0)
6844                     goto Ldone;
6845                 break;
6846 
6847             case TOKeof:
6848                 goto Lfalse;
6849 
6850             default:
6851                 break;
6852             }
6853             t = peek(t);
6854         }
6855     Ldone:
6856         if (pt)
6857             *pt = peek(t); // skip found rparen
6858         return true;
6859 
6860     Lfalse:
6861         return false;
6862     }
6863 
6864     bool skipParensIf(Token* t, Token** pt)
6865     {
6866         if (t.value != TOKlparen)
6867         {
6868             if (pt)
6869                 *pt = t;
6870             return true;
6871         }
6872         return skipParens(t, pt);
6873     }
6874 
6875     /*******************************************
6876      * Skip attributes.
6877      * Input:
6878      *      t is on a candidate attribute
6879      * Output:
6880      *      *pt is set to first non-attribute token on success
6881      * Returns:
6882      *      true    successful
6883      *      false   some parsing error
6884      */
6885     bool skipAttributes(Token* t, Token** pt)
6886     {
6887         while (1)
6888         {
6889             switch (t.value)
6890             {
6891             case TOKconst:
6892             case TOKimmutable:
6893             case TOKshared:
6894             case TOKwild:
6895             case TOKfinal:
6896             case TOKauto:
6897             case TOKscope:
6898             case TOKoverride:
6899             case TOKabstract:
6900             case TOKsynchronized:
6901                 break;
6902 
6903             case TOKdeprecated:
6904                 if (peek(t).value == TOKlparen)
6905                 {
6906                     t = peek(t);
6907                     if (!skipParens(t, &t))
6908                         goto Lerror;
6909                     // t is on the next of closing parenthesis
6910                     continue;
6911                 }
6912                 break;
6913 
6914             case TOKnothrow:
6915             case TOKpure:
6916             case TOKref:
6917             case TOKgshared:
6918             case TOKreturn:
6919             //case TOKmanifest:
6920                 break;
6921 
6922             case TOKat:
6923                 t = peek(t);
6924                 if (t.value == TOKidentifier)
6925                 {
6926                     /* @identifier
6927                      * @identifier!arg
6928                      * @identifier!(arglist)
6929                      * any of the above followed by (arglist)
6930                      * @predefined_attribute
6931                      */
6932                     if (t.ident == Id.property || t.ident == Id.nogc || t.ident == Id.safe || t.ident == Id.trusted || t.ident == Id.system || t.ident == Id.disable)
6933                         break;
6934                     t = peek(t);
6935                     if (t.value == TOKnot)
6936                     {
6937                         t = peek(t);
6938                         if (t.value == TOKlparen)
6939                         {
6940                             // @identifier!(arglist)
6941                             if (!skipParens(t, &t))
6942                                 goto Lerror;
6943                             // t is on the next of closing parenthesis
6944                         }
6945                         else
6946                         {
6947                             // @identifier!arg
6948                             // Do low rent skipTemplateArgument
6949                             if (t.value == TOKvector)
6950                             {
6951                                 // identifier!__vector(type)
6952                                 t = peek(t);
6953                                 if (!skipParens(t, &t))
6954                                     goto Lerror;
6955                             }
6956                             else
6957                                 t = peek(t);
6958                         }
6959                     }
6960                     if (t.value == TOKlparen)
6961                     {
6962                         if (!skipParens(t, &t))
6963                             goto Lerror;
6964                         // t is on the next of closing parenthesis
6965                         continue;
6966                     }
6967                     continue;
6968                 }
6969                 if (t.value == TOKlparen)
6970                 {
6971                     // @( ArgumentList )
6972                     if (!skipParens(t, &t))
6973                         goto Lerror;
6974                     // t is on the next of closing parenthesis
6975                     continue;
6976                 }
6977                 goto Lerror;
6978 
6979             default:
6980                 goto Ldone;
6981             }
6982             t = peek(t);
6983         }
6984     Ldone:
6985         if (pt)
6986             *pt = t;
6987         return true;
6988 
6989     Lerror:
6990         return false;
6991     }
6992 
6993     Expression parseExpression()
6994     {
6995         auto loc = token.loc;
6996 
6997         //printf("Parser::parseExpression() loc = %d\n", loc.linnum);
6998         auto e = parseAssignExp();
6999         while (token.value == TOKcomma)
7000         {
7001             nextToken();
7002             auto e2 = parseAssignExp();
7003             e = new CommaExp(loc, e, e2, false);
7004             loc = token.loc;
7005         }
7006         return e;
7007     }
7008 
7009     /********************************* Expression Parser ***************************/
7010 
7011     Expression parsePrimaryExp()
7012     {
7013         Expression e;
7014         Type t;
7015         Identifier id;
7016         const loc = token.loc;
7017 
7018         //printf("parsePrimaryExp(): loc = %d\n", loc.linnum);
7019         switch (token.value)
7020         {
7021         case TOKidentifier:
7022             {
7023                 Token* t1 = peek(&token);
7024                 Token* t2 = peek(t1);
7025                 if (t1.value == TOKmin && t2.value == TOKgt)
7026                 {
7027                     // skip ident->
7028                     nextToken();
7029                     nextToken();
7030                     nextToken();
7031                     error("use '.' for member lookup, not '->'");
7032                     goto Lerr;
7033                 }
7034 
7035                 if (peekNext() == TOKgoesto)
7036                     goto case_delegate;
7037 
7038                 id = token.ident;
7039                 nextToken();
7040                 TOK save;
7041                 if (token.value == TOKnot && (save = peekNext()) != TOKis && save != TOKin)
7042                 {
7043                     // identifier!(template-argument-list)
7044                     auto tempinst = new TemplateInstance(loc, id, parseTemplateArguments());
7045                     e = new ScopeExp(loc, tempinst);
7046                 }
7047                 else
7048                     e = new IdentifierExp(loc, id);
7049                 break;
7050             }
7051         case TOKdollar:
7052             if (!inBrackets)
7053                 error("'$' is valid only inside [] of index or slice");
7054             e = new DollarExp(loc);
7055             nextToken();
7056             break;
7057 
7058         case TOKdot:
7059             // Signal global scope '.' operator with "" identifier
7060             e = new IdentifierExp(loc, Id.empty);
7061             break;
7062 
7063         case TOKthis:
7064             e = new ThisExp(loc);
7065             nextToken();
7066             break;
7067 
7068         case TOKsuper:
7069             e = new SuperExp(loc);
7070             nextToken();
7071             break;
7072 
7073         case TOKint32v:
7074             e = new IntegerExp(loc, cast(d_int32)token.int64value, Type.tint32);
7075             nextToken();
7076             break;
7077 
7078         case TOKuns32v:
7079             e = new IntegerExp(loc, cast(d_uns32)token.uns64value, Type.tuns32);
7080             nextToken();
7081             break;
7082 
7083         case TOKint64v:
7084             e = new IntegerExp(loc, token.int64value, Type.tint64);
7085             nextToken();
7086             break;
7087 
7088         case TOKuns64v:
7089             e = new IntegerExp(loc, token.uns64value, Type.tuns64);
7090             nextToken();
7091             break;
7092 
7093         case TOKfloat32v:
7094             e = new RealExp(loc, token.floatvalue, Type.tfloat32);
7095             nextToken();
7096             break;
7097 
7098         case TOKfloat64v:
7099             e = new RealExp(loc, token.floatvalue, Type.tfloat64);
7100             nextToken();
7101             break;
7102 
7103         case TOKfloat80v:
7104             e = new RealExp(loc, token.floatvalue, Type.tfloat80);
7105             nextToken();
7106             break;
7107 
7108         case TOKimaginary32v:
7109             e = new RealExp(loc, token.floatvalue, Type.timaginary32);
7110             nextToken();
7111             break;
7112 
7113         case TOKimaginary64v:
7114             e = new RealExp(loc, token.floatvalue, Type.timaginary64);
7115             nextToken();
7116             break;
7117 
7118         case TOKimaginary80v:
7119             e = new RealExp(loc, token.floatvalue, Type.timaginary80);
7120             nextToken();
7121             break;
7122 
7123         case TOKnull:
7124             e = new NullExp(loc);
7125             nextToken();
7126             break;
7127 
7128         case TOKfile:
7129             {
7130                 const(char)* s = loc.filename ? loc.filename : mod.ident.toChars();
7131                 e = new StringExp(loc, cast(char*)s);
7132                 nextToken();
7133                 break;
7134             }
7135         case TOKfilefullpath:
7136             {
7137                 const(char)* srcfile = mod.srcfile.name.toChars();
7138                 const(char)* s;
7139                 if(loc.filename && !FileName.equals(loc.filename, srcfile)) {
7140                     s = loc.filename;
7141                 } else {
7142                     s = FileName.combine(mod.srcfilePath, srcfile);
7143                 }
7144                 e = new StringExp(loc, cast(char*)s);
7145                 nextToken();
7146                 break;
7147             }
7148         case TOKline:
7149             e = new IntegerExp(loc, loc.linnum, Type.tint32);
7150             nextToken();
7151             break;
7152 
7153         case TOKmodulestring:
7154             {
7155                 const(char)* s = md ? md.toChars() : mod.toChars();
7156                 e = new StringExp(loc, cast(char*)s);
7157                 nextToken();
7158                 break;
7159             }
7160         case TOKfuncstring:
7161             e = new FuncInitExp(loc);
7162             nextToken();
7163             break;
7164 
7165         case TOKprettyfunc:
7166             e = new PrettyFuncInitExp(loc);
7167             nextToken();
7168             break;
7169 
7170         case TOKtrue:
7171             e = new IntegerExp(loc, 1, Type.tbool);
7172             nextToken();
7173             break;
7174 
7175         case TOKfalse:
7176             e = new IntegerExp(loc, 0, Type.tbool);
7177             nextToken();
7178             break;
7179 
7180         case TOKcharv:
7181             e = new IntegerExp(loc, cast(d_uns8)token.uns64value, Type.tchar);
7182             nextToken();
7183             break;
7184 
7185         case TOKwcharv:
7186             e = new IntegerExp(loc, cast(d_uns16)token.uns64value, Type.twchar);
7187             nextToken();
7188             break;
7189 
7190         case TOKdcharv:
7191             e = new IntegerExp(loc, cast(d_uns32)token.uns64value, Type.tdchar);
7192             nextToken();
7193             break;
7194 
7195         case TOKstring:
7196         case TOKxstring:
7197             {
7198                 // cat adjacent strings
7199                 auto s = token.ustring;
7200                 auto len = token.len;
7201                 auto postfix = token.postfix;
7202                 while (1)
7203                 {
7204                     nextToken();
7205                     if (token.value == TOKstring || token.value == TOKxstring)
7206                     {
7207                         if (token.postfix)
7208                         {
7209                             if (token.postfix != postfix)
7210                                 error("mismatched string literal postfixes '%c' and '%c'", postfix, token.postfix);
7211                             postfix = token.postfix;
7212                         }
7213 
7214                         const len1 = len;
7215                         const len2 = token.len;
7216                         len = len1 + len2;
7217                         auto s2 = cast(char*)mem.xmalloc(len * char.sizeof);
7218                         memcpy(s2, s, len1 * char.sizeof);
7219                         memcpy(s2 + len1, token.ustring, len2 * char.sizeof);
7220                         s = s2;
7221                     }
7222                     else
7223                         break;
7224                 }
7225                 e = new StringExp(loc, cast(char*)s, len, postfix);
7226                 break;
7227             }
7228         case TOKvoid:
7229             t = Type.tvoid;
7230             goto LabelX;
7231 
7232         case TOKint8:
7233             t = Type.tint8;
7234             goto LabelX;
7235 
7236         case TOKuns8:
7237             t = Type.tuns8;
7238             goto LabelX;
7239 
7240         case TOKint16:
7241             t = Type.tint16;
7242             goto LabelX;
7243 
7244         case TOKuns16:
7245             t = Type.tuns16;
7246             goto LabelX;
7247 
7248         case TOKint32:
7249             t = Type.tint32;
7250             goto LabelX;
7251 
7252         case TOKuns32:
7253             t = Type.tuns32;
7254             goto LabelX;
7255 
7256         case TOKint64:
7257             t = Type.tint64;
7258             goto LabelX;
7259 
7260         case TOKuns64:
7261             t = Type.tuns64;
7262             goto LabelX;
7263 
7264         case TOKint128:
7265             t = Type.tint128;
7266             goto LabelX;
7267 
7268         case TOKuns128:
7269             t = Type.tuns128;
7270             goto LabelX;
7271 
7272         case TOKfloat32:
7273             t = Type.tfloat32;
7274             goto LabelX;
7275 
7276         case TOKfloat64:
7277             t = Type.tfloat64;
7278             goto LabelX;
7279 
7280         case TOKfloat80:
7281             t = Type.tfloat80;
7282             goto LabelX;
7283 
7284         case TOKimaginary32:
7285             t = Type.timaginary32;
7286             goto LabelX;
7287 
7288         case TOKimaginary64:
7289             t = Type.timaginary64;
7290             goto LabelX;
7291 
7292         case TOKimaginary80:
7293             t = Type.timaginary80;
7294             goto LabelX;
7295 
7296         case TOKcomplex32:
7297             t = Type.tcomplex32;
7298             goto LabelX;
7299 
7300         case TOKcomplex64:
7301             t = Type.tcomplex64;
7302             goto LabelX;
7303 
7304         case TOKcomplex80:
7305             t = Type.tcomplex80;
7306             goto LabelX;
7307 
7308         case TOKbool:
7309             t = Type.tbool;
7310             goto LabelX;
7311 
7312         case TOKchar:
7313             t = Type.tchar;
7314             goto LabelX;
7315 
7316         case TOKwchar:
7317             t = Type.twchar;
7318             goto LabelX;
7319 
7320         case TOKdchar:
7321             t = Type.tdchar;
7322             goto LabelX;
7323         LabelX:
7324             nextToken();
7325             if (token.value == TOKlparen)
7326             {
7327                 e = new TypeExp(loc, t);
7328                 e = new CallExp(loc, e, parseArguments());
7329                 break;
7330             }
7331             check(TOKdot, t.toChars());
7332             if (token.value != TOKidentifier)
7333             {
7334                 error("found '%s' when expecting identifier following '%s.'", token.toChars(), t.toChars());
7335                 goto Lerr;
7336             }
7337             e = typeDotIdExp(loc, t, token.ident);
7338             nextToken();
7339             break;
7340 
7341         case TOKtypeof:
7342             {
7343                 t = parseTypeof();
7344                 e = new TypeExp(loc, t);
7345                 break;
7346             }
7347         case TOKvector:
7348             {
7349                 t = parseVector();
7350                 e = new TypeExp(loc, t);
7351                 break;
7352             }
7353         case TOKtypeid:
7354             {
7355                 nextToken();
7356                 check(TOKlparen, "typeid");
7357                 RootObject o;
7358                 if (isDeclaration(&token, NeedDeclaratorId.no, TOKreserved, null))
7359                 {
7360                     // argument is a type
7361                     o = parseType();
7362                 }
7363                 else
7364                 {
7365                     // argument is an expression
7366                     o = parseAssignExp();
7367                 }
7368                 check(TOKrparen);
7369                 e = new TypeidExp(loc, o);
7370                 break;
7371             }
7372         case TOKtraits:
7373             {
7374                 /* __traits(identifier, args...)
7375                  */
7376                 Identifier ident;
7377                 Objects* args = null;
7378 
7379                 nextToken();
7380                 check(TOKlparen);
7381                 if (token.value != TOKidentifier)
7382                 {
7383                     error("__traits(identifier, args...) expected");
7384                     goto Lerr;
7385                 }
7386                 ident = token.ident;
7387                 nextToken();
7388                 if (token.value == TOKcomma)
7389                     args = parseTemplateArgumentList(); // __traits(identifier, args...)
7390                 else
7391                     check(TOKrparen); // __traits(identifier)
7392 
7393                 e = new TraitsExp(loc, ident, args);
7394                 break;
7395             }
7396         case TOKis:
7397             {
7398                 Type targ;
7399                 Identifier ident = null;
7400                 Type tspec = null;
7401                 TOK tok = TOKreserved;
7402                 TOK tok2 = TOKreserved;
7403                 TemplateParameters* tpl = null;
7404 
7405                 nextToken();
7406                 if (token.value == TOKlparen)
7407                 {
7408                     nextToken();
7409                     targ = parseType(&ident);
7410                     if (token.value == TOKcolon || token.value == TOKequal)
7411                     {
7412                         tok = token.value;
7413                         nextToken();
7414                         if (tok == TOKequal && (token.value == TOKstruct || token.value == TOKunion || token.value == TOKclass || token.value == TOKsuper || token.value == TOKenum || token.value == TOKinterface || token.value == TOKargTypes || token.value == TOKparameters || token.value == TOKconst && peek(&token).value == TOKrparen || token.value == TOKimmutable && peek(&token).value == TOKrparen || token.value == TOKshared && peek(&token).value == TOKrparen || token.value == TOKwild && peek(&token).value == TOKrparen || token.value == TOKfunction || token.value == TOKdelegate || token.value == TOKreturn))
7415                         {
7416                             tok2 = token.value;
7417                             nextToken();
7418                         }
7419                         else
7420                         {
7421                             tspec = parseType();
7422                         }
7423                     }
7424                     if (tspec)
7425                     {
7426                         if (token.value == TOKcomma)
7427                             tpl = parseTemplateParameterList(1);
7428                         else
7429                         {
7430                             tpl = new TemplateParameters();
7431                             check(TOKrparen);
7432                         }
7433                     }
7434                     else
7435                         check(TOKrparen);
7436                 }
7437                 else
7438                 {
7439                     error("(type identifier : specialization) expected following is");
7440                     goto Lerr;
7441                 }
7442                 e = new IsExp(loc, targ, ident, tok, tspec, tok2, tpl);
7443                 break;
7444             }
7445         case TOKassert:
7446             {
7447                 Expression msg = null;
7448 
7449                 nextToken();
7450                 check(TOKlparen, "assert");
7451                 e = parseAssignExp();
7452                 if (token.value == TOKcomma)
7453                 {
7454                     nextToken();
7455                     if (token.value != TOKrparen)
7456                     {
7457                         msg = parseAssignExp();
7458                         if (token.value == TOKcomma)
7459                             nextToken();
7460                     }
7461                 }
7462                 check(TOKrparen);
7463                 e = new AssertExp(loc, e, msg);
7464                 break;
7465             }
7466         case TOKmixin:
7467             {
7468                 nextToken();
7469                 check(TOKlparen, "mixin");
7470                 e = parseAssignExp();
7471                 check(TOKrparen);
7472                 e = new CompileExp(loc, e);
7473                 break;
7474             }
7475         case TOKimport:
7476             {
7477                 nextToken();
7478                 check(TOKlparen, "import");
7479                 e = parseAssignExp();
7480                 check(TOKrparen);
7481                 e = new ImportExp(loc, e);
7482                 break;
7483             }
7484         case TOKnew:
7485             e = parseNewExp(null);
7486             break;
7487 
7488         case TOKlparen:
7489             {
7490                 Token* tk = peekPastParen(&token);
7491                 if (skipAttributes(tk, &tk) && (tk.value == TOKgoesto || tk.value == TOKlcurly))
7492                 {
7493                     // (arguments) => expression
7494                     // (arguments) { statements... }
7495                     goto case_delegate;
7496                 }
7497 
7498                 // ( expression )
7499                 nextToken();
7500                 e = parseExpression();
7501                 e.parens = 1;
7502                 check(loc, TOKrparen);
7503                 break;
7504             }
7505         case TOKlbracket:
7506             {
7507                 /* Parse array literals and associative array literals:
7508                  *  [ value, value, value ... ]
7509                  *  [ key:value, key:value, key:value ... ]
7510                  */
7511                 auto values = new Expressions();
7512                 Expressions* keys = null;
7513 
7514                 nextToken();
7515                 while (token.value != TOKrbracket && token.value != TOKeof)
7516                 {
7517                     e = parseAssignExp();
7518                     if (token.value == TOKcolon && (keys || values.dim == 0))
7519                     {
7520                         nextToken();
7521                         if (!keys)
7522                             keys = new Expressions();
7523                         keys.push(e);
7524                         e = parseAssignExp();
7525                     }
7526                     else if (keys)
7527                     {
7528                         error("'key:value' expected for associative array literal");
7529                         keys = null;
7530                     }
7531                     values.push(e);
7532                     if (token.value == TOKrbracket)
7533                         break;
7534                     check(TOKcomma);
7535                 }
7536                 check(loc, TOKrbracket);
7537 
7538                 if (keys)
7539                     e = new AssocArrayLiteralExp(loc, keys, values);
7540                 else
7541                     e = new ArrayLiteralExp(loc, values);
7542                 break;
7543             }
7544         case TOKlcurly:
7545         case TOKfunction:
7546         case TOKdelegate:
7547         case_delegate:
7548             {
7549                 Dsymbol s = parseFunctionLiteral();
7550                 e = new FuncExp(loc, s);
7551                 break;
7552             }
7553         default:
7554             error("expression expected, not '%s'", token.toChars());
7555         Lerr:
7556             // Anything for e, as long as it's not NULL
7557             e = new IntegerExp(loc, 0, Type.tint32);
7558             nextToken();
7559             break;
7560         }
7561         return e;
7562     }
7563 
7564     Expression parseUnaryExp()
7565     {
7566         Expression e;
7567         const loc = token.loc;
7568 
7569         switch (token.value)
7570         {
7571         case TOKand:
7572             nextToken();
7573             e = parseUnaryExp();
7574             e = new AddrExp(loc, e);
7575             break;
7576 
7577         case TOKplusplus:
7578             nextToken();
7579             e = parseUnaryExp();
7580             //e = new AddAssignExp(loc, e, new IntegerExp(loc, 1, Type::tint32));
7581             e = new PreExp(TOKpreplusplus, loc, e);
7582             break;
7583 
7584         case TOKminusminus:
7585             nextToken();
7586             e = parseUnaryExp();
7587             //e = new MinAssignExp(loc, e, new IntegerExp(loc, 1, Type::tint32));
7588             e = new PreExp(TOKpreminusminus, loc, e);
7589             break;
7590 
7591         case TOKmul:
7592             nextToken();
7593             e = parseUnaryExp();
7594             e = new PtrExp(loc, e);
7595             break;
7596 
7597         case TOKmin:
7598             nextToken();
7599             e = parseUnaryExp();
7600             e = new NegExp(loc, e);
7601             break;
7602 
7603         case TOKadd:
7604             nextToken();
7605             e = parseUnaryExp();
7606             e = new UAddExp(loc, e);
7607             break;
7608 
7609         case TOKnot:
7610             nextToken();
7611             e = parseUnaryExp();
7612             e = new NotExp(loc, e);
7613             break;
7614 
7615         case TOKtilde:
7616             nextToken();
7617             e = parseUnaryExp();
7618             e = new ComExp(loc, e);
7619             break;
7620 
7621         case TOKdelete:
7622             nextToken();
7623             e = parseUnaryExp();
7624             e = new DeleteExp(loc, e);
7625             break;
7626 
7627         case TOKcast: // cast(type) expression
7628             {
7629                 nextToken();
7630                 check(TOKlparen);
7631                 /* Look for cast(), cast(const), cast(immutable),
7632                  * cast(shared), cast(shared const), cast(wild), cast(shared wild)
7633                  */
7634                 ubyte m = 0;
7635                 while (1)
7636                 {
7637                     switch (token.value)
7638                     {
7639                     case TOKconst:
7640                         if (peekNext() == TOKlparen)
7641                             break; // const as type constructor
7642                         m |= MODconst; // const as storage class
7643                         nextToken();
7644                         continue;
7645 
7646                     case TOKimmutable:
7647                         if (peekNext() == TOKlparen)
7648                             break;
7649                         m |= MODimmutable;
7650                         nextToken();
7651                         continue;
7652 
7653                     case TOKshared:
7654                         if (peekNext() == TOKlparen)
7655                             break;
7656                         m |= MODshared;
7657                         nextToken();
7658                         continue;
7659 
7660                     case TOKwild:
7661                         if (peekNext() == TOKlparen)
7662                             break;
7663                         m |= MODwild;
7664                         nextToken();
7665                         continue;
7666 
7667                     default:
7668                         break;
7669                     }
7670                     break;
7671                 }
7672                 if (token.value == TOKrparen)
7673                 {
7674                     nextToken();
7675                     e = parseUnaryExp();
7676                     e = new CastExp(loc, e, m);
7677                 }
7678                 else
7679                 {
7680                     Type t = parseType(); // cast( type )
7681                     t = t.addMod(m); // cast( const type )
7682                     check(TOKrparen);
7683                     e = parseUnaryExp();
7684                     e = new CastExp(loc, e, t);
7685                 }
7686                 break;
7687             }
7688         case TOKwild:
7689         case TOKshared:
7690         case TOKconst:
7691         case TOKimmutable: // immutable(type)(arguments) / immutable(type).init
7692             {
7693                 StorageClass stc = parseTypeCtor();
7694 
7695                 Type t = parseBasicType();
7696                 t = t.addSTC(stc);
7697 
7698                 if (stc == 0 && token.value == TOKdot)
7699                 {
7700                     nextToken();
7701                     if (token.value != TOKidentifier)
7702                     {
7703                         error("identifier expected following (type).");
7704                         return null;
7705                     }
7706                     e = typeDotIdExp(loc, t, token.ident);
7707                     nextToken();
7708                     e = parsePostExp(e);
7709                 }
7710                 else
7711                 {
7712                     e = new TypeExp(loc, t);
7713                     if (token.value != TOKlparen)
7714                     {
7715                         error("(arguments) expected following %s", t.toChars());
7716                         return e;
7717                     }
7718                     e = new CallExp(loc, e, parseArguments());
7719                 }
7720                 break;
7721             }
7722         case TOKlparen:
7723             {
7724                 auto tk = peek(&token);
7725                 static if (CCASTSYNTAX)
7726                 {
7727                     // If cast
7728                     if (isDeclaration(tk, NeedDeclaratorId.no, TOKrparen, &tk))
7729                     {
7730                         tk = peek(tk); // skip over right parenthesis
7731                         switch (tk.value)
7732                         {
7733                         case TOKnot:
7734                             tk = peek(tk);
7735                             if (tk.value == TOKis || tk.value == TOKin) // !is or !in
7736                                 break;
7737                             goto case;
7738 
7739                         case TOKdot:
7740                         case TOKplusplus:
7741                         case TOKminusminus:
7742                         case TOKdelete:
7743                         case TOKnew:
7744                         case TOKlparen:
7745                         case TOKidentifier:
7746                         case TOKthis:
7747                         case TOKsuper:
7748                         case TOKint32v:
7749                         case TOKuns32v:
7750                         case TOKint64v:
7751                         case TOKuns64v:
7752                         case TOKint128v:
7753                         case TOKuns128v:
7754                         case TOKfloat32v:
7755                         case TOKfloat64v:
7756                         case TOKfloat80v:
7757                         case TOKimaginary32v:
7758                         case TOKimaginary64v:
7759                         case TOKimaginary80v:
7760                         case TOKnull:
7761                         case TOKtrue:
7762                         case TOKfalse:
7763                         case TOKcharv:
7764                         case TOKwcharv:
7765                         case TOKdcharv:
7766                         case TOKstring:
7767                             version (none)
7768                             {
7769                             case TOKtilde:
7770                             case TOKand:
7771                             case TOKmul:
7772                             case TOKmin:
7773                             case TOKadd:
7774                             }
7775                         case TOKfunction:
7776                         case TOKdelegate:
7777                         case TOKtypeof:
7778                         case TOKvector:
7779                         case TOKfile:
7780                         case TOKfilefullpath:
7781                         case TOKline:
7782                         case TOKmodulestring:
7783                         case TOKfuncstring:
7784                         case TOKprettyfunc:
7785                         case TOKwchar:
7786                         case TOKdchar:
7787                         case TOKbool:
7788                         case TOKchar:
7789                         case TOKint8:
7790                         case TOKuns8:
7791                         case TOKint16:
7792                         case TOKuns16:
7793                         case TOKint32:
7794                         case TOKuns32:
7795                         case TOKint64:
7796                         case TOKuns64:
7797                         case TOKint128:
7798                         case TOKuns128:
7799                         case TOKfloat32:
7800                         case TOKfloat64:
7801                         case TOKfloat80:
7802                         case TOKimaginary32:
7803                         case TOKimaginary64:
7804                         case TOKimaginary80:
7805                         case TOKcomplex32:
7806                         case TOKcomplex64:
7807                         case TOKcomplex80:
7808                         case TOKvoid:
7809                             {
7810                                 // (type) una_exp
7811                                 nextToken();
7812                                 auto t = parseType();
7813                                 check(TOKrparen);
7814 
7815                                 // if .identifier
7816                                 // or .identifier!( ... )
7817                                 if (token.value == TOKdot)
7818                                 {
7819                                     if (peekNext() != TOKidentifier && peekNext() != TOKnew)
7820                                     {
7821                                         error("identifier or new keyword expected following (...).");
7822                                         return null;
7823                                     }
7824                                     e = new TypeExp(loc, t);
7825                                     e = parsePostExp(e);
7826                                 }
7827                                 else
7828                                 {
7829                                     e = parseUnaryExp();
7830                                     e = new CastExp(loc, e, t);
7831                                     error("C style cast illegal, use %s", e.toChars());
7832                                 }
7833                                 return e;
7834                             }
7835                         default:
7836                             break;
7837                         }
7838                     }
7839                 }
7840                 e = parsePrimaryExp();
7841                 e = parsePostExp(e);
7842                 break;
7843             }
7844         default:
7845             e = parsePrimaryExp();
7846             e = parsePostExp(e);
7847             break;
7848         }
7849         assert(e);
7850 
7851         // ^^ is right associative and has higher precedence than the unary operators
7852         while (token.value == TOKpow)
7853         {
7854             nextToken();
7855             Expression e2 = parseUnaryExp();
7856             e = new PowExp(loc, e, e2);
7857         }
7858 
7859         return e;
7860     }
7861 
7862     Expression parsePostExp(Expression e)
7863     {
7864         while (1)
7865         {
7866             const loc = token.loc;
7867             switch (token.value)
7868             {
7869             case TOKdot:
7870                 nextToken();
7871                 if (token.value == TOKidentifier)
7872                 {
7873                     Identifier id = token.ident;
7874 
7875                     nextToken();
7876                     if (token.value == TOKnot && peekNext() != TOKis && peekNext() != TOKin)
7877                     {
7878                         Objects* tiargs = parseTemplateArguments();
7879                         e = new DotTemplateInstanceExp(loc, e, id, tiargs);
7880                     }
7881                     else
7882                         e = new DotIdExp(loc, e, id);
7883                     continue;
7884                 }
7885                 else if (token.value == TOKnew)
7886                 {
7887                     e = parseNewExp(e);
7888                     continue;
7889                 }
7890                 else
7891                     error("identifier expected following '.', not '%s'", token.toChars());
7892                 break;
7893 
7894             case TOKplusplus:
7895                 e = new PostExp(TOKplusplus, loc, e);
7896                 break;
7897 
7898             case TOKminusminus:
7899                 e = new PostExp(TOKminusminus, loc, e);
7900                 break;
7901 
7902             case TOKlparen:
7903                 e = new CallExp(loc, e, parseArguments());
7904                 continue;
7905 
7906             case TOKlbracket:
7907                 {
7908                     // array dereferences:
7909                     //      array[index]
7910                     //      array[]
7911                     //      array[lwr .. upr]
7912                     Expression index;
7913                     Expression upr;
7914                     auto arguments = new Expressions();
7915 
7916                     inBrackets++;
7917                     nextToken();
7918                     while (token.value != TOKrbracket && token.value != TOKeof)
7919                     {
7920                         index = parseAssignExp();
7921                         if (token.value == TOKslice)
7922                         {
7923                             // array[..., lwr..upr, ...]
7924                             nextToken();
7925                             upr = parseAssignExp();
7926                             arguments.push(new IntervalExp(loc, index, upr));
7927                         }
7928                         else
7929                             arguments.push(index);
7930                         if (token.value == TOKrbracket)
7931                             break;
7932                         check(TOKcomma);
7933                     }
7934                     check(TOKrbracket);
7935                     inBrackets--;
7936                     e = new ArrayExp(loc, e, arguments);
7937                     continue;
7938                 }
7939             default:
7940                 return e;
7941             }
7942             nextToken();
7943         }
7944     }
7945 
7946     Expression parseMulExp()
7947     {
7948         const loc = token.loc;
7949         auto e = parseUnaryExp();
7950 
7951         while (1)
7952         {
7953             switch (token.value)
7954             {
7955             case TOKmul:
7956                 nextToken();
7957                 auto e2 = parseUnaryExp();
7958                 e = new MulExp(loc, e, e2);
7959                 continue;
7960 
7961             case TOKdiv:
7962                 nextToken();
7963                 auto e2 = parseUnaryExp();
7964                 e = new DivExp(loc, e, e2);
7965                 continue;
7966 
7967             case TOKmod:
7968                 nextToken();
7969                 auto e2 = parseUnaryExp();
7970                 e = new ModExp(loc, e, e2);
7971                 continue;
7972 
7973             default:
7974                 break;
7975             }
7976             break;
7977         }
7978         return e;
7979     }
7980 
7981     Expression parseAddExp()
7982     {
7983         const loc = token.loc;
7984         auto e = parseMulExp();
7985 
7986         while (1)
7987         {
7988             switch (token.value)
7989             {
7990             case TOKadd:
7991                 nextToken();
7992                 auto e2 = parseMulExp();
7993                 e = new AddExp(loc, e, e2);
7994                 continue;
7995 
7996             case TOKmin:
7997                 nextToken();
7998                 auto e2 = parseMulExp();
7999                 e = new MinExp(loc, e, e2);
8000                 continue;
8001 
8002             case TOKtilde:
8003                 nextToken();
8004                 auto e2 = parseMulExp();
8005                 e = new CatExp(loc, e, e2);
8006                 continue;
8007 
8008             default:
8009                 break;
8010             }
8011             break;
8012         }
8013         return e;
8014     }
8015 
8016     Expression parseShiftExp()
8017     {
8018         const loc = token.loc;
8019         auto e = parseAddExp();
8020 
8021         while (1)
8022         {
8023             switch (token.value)
8024             {
8025             case TOKshl:
8026                 nextToken();
8027                 auto e2 = parseAddExp();
8028                 e = new ShlExp(loc, e, e2);
8029                 continue;
8030 
8031             case TOKshr:
8032                 nextToken();
8033                 auto e2 = parseAddExp();
8034                 e = new ShrExp(loc, e, e2);
8035                 continue;
8036 
8037             case TOKushr:
8038                 nextToken();
8039                 auto e2 = parseAddExp();
8040                 e = new UshrExp(loc, e, e2);
8041                 continue;
8042 
8043             default:
8044                 break;
8045             }
8046             break;
8047         }
8048         return e;
8049     }
8050 
8051     Expression parseCmpExp()
8052     {
8053         const loc = token.loc;
8054 
8055         auto e = parseShiftExp();
8056         TOK op = token.value;
8057 
8058         switch (op)
8059         {
8060         case TOKequal:
8061         case TOKnotequal:
8062             nextToken();
8063             auto e2 = parseShiftExp();
8064             e = new EqualExp(op, loc, e, e2);
8065             break;
8066 
8067         case TOKis:
8068             op = TOKidentity;
8069             goto L1;
8070 
8071         case TOKnot:
8072         {
8073             // Attempt to identify '!is'
8074             auto t = peek(&token);
8075             if (t.value == TOKin)
8076             {
8077                 nextToken();
8078                 nextToken();
8079                 auto e2 = parseShiftExp();
8080                 e = new InExp(loc, e, e2);
8081                 e = new NotExp(loc, e);
8082                 break;
8083             }
8084             if (t.value != TOKis)
8085                 break;
8086             nextToken();
8087             op = TOKnotidentity;
8088             goto L1;
8089         }
8090         L1:
8091             nextToken();
8092             auto e2 = parseShiftExp();
8093             e = new IdentityExp(op, loc, e, e2);
8094             break;
8095 
8096         case TOKlt:
8097         case TOKle:
8098         case TOKgt:
8099         case TOKge:
8100         case TOKunord:
8101         case TOKlg:
8102         case TOKleg:
8103         case TOKule:
8104         case TOKul:
8105         case TOKuge:
8106         case TOKug:
8107         case TOKue:
8108             nextToken();
8109             auto e2 = parseShiftExp();
8110             e = new CmpExp(op, loc, e, e2);
8111             break;
8112 
8113         case TOKin:
8114             nextToken();
8115             auto e2 = parseShiftExp();
8116             e = new InExp(loc, e, e2);
8117             break;
8118 
8119         default:
8120             break;
8121         }
8122         return e;
8123     }
8124 
8125     Expression parseAndExp()
8126     {
8127         Loc loc = token.loc;
8128         auto e = parseCmpExp();
8129         while (token.value == TOKand)
8130         {
8131             checkParens(TOKand, e);
8132             nextToken();
8133             auto e2 = parseCmpExp();
8134             checkParens(TOKand, e2);
8135             e = new AndExp(loc, e, e2);
8136             loc = token.loc;
8137         }
8138         return e;
8139     }
8140 
8141     Expression parseXorExp()
8142     {
8143         const loc = token.loc;
8144 
8145         auto e = parseAndExp();
8146         while (token.value == TOKxor)
8147         {
8148             checkParens(TOKxor, e);
8149             nextToken();
8150             auto e2 = parseAndExp();
8151             checkParens(TOKxor, e2);
8152             e = new XorExp(loc, e, e2);
8153         }
8154         return e;
8155     }
8156 
8157     Expression parseOrExp()
8158     {
8159         const loc = token.loc;
8160 
8161         auto e = parseXorExp();
8162         while (token.value == TOKor)
8163         {
8164             checkParens(TOKor, e);
8165             nextToken();
8166             auto e2 = parseXorExp();
8167             checkParens(TOKor, e2);
8168             e = new OrExp(loc, e, e2);
8169         }
8170         return e;
8171     }
8172 
8173     Expression parseAndAndExp()
8174     {
8175         const loc = token.loc;
8176 
8177         auto e = parseOrExp();
8178         while (token.value == TOKandand)
8179         {
8180             nextToken();
8181             auto e2 = parseOrExp();
8182             e = new AndAndExp(loc, e, e2);
8183         }
8184         return e;
8185     }
8186 
8187     Expression parseOrOrExp()
8188     {
8189         const loc = token.loc;
8190 
8191         auto e = parseAndAndExp();
8192         while (token.value == TOKoror)
8193         {
8194             nextToken();
8195             auto e2 = parseAndAndExp();
8196             e = new OrOrExp(loc, e, e2);
8197         }
8198         return e;
8199     }
8200 
8201     Expression parseCondExp()
8202     {
8203         const loc = token.loc;
8204 
8205         auto e = parseOrOrExp();
8206         if (token.value == TOKquestion)
8207         {
8208             nextToken();
8209             auto e1 = parseExpression();
8210             check(TOKcolon);
8211             auto e2 = parseCondExp();
8212             e = new CondExp(loc, e, e1, e2);
8213         }
8214         return e;
8215     }
8216 
8217     Expression parseAssignExp()
8218     {
8219         auto e = parseCondExp();
8220         while (1)
8221         {
8222             const loc = token.loc;
8223             switch (token.value)
8224             {
8225             case TOKassign:
8226                 nextToken();
8227                 auto e2 = parseAssignExp();
8228                 e = new AssignExp(loc, e, e2);
8229                 continue;
8230 
8231             case TOKaddass:
8232                 nextToken();
8233                 auto e2 = parseAssignExp();
8234                 e = new AddAssignExp(loc, e, e2);
8235                 continue;
8236 
8237             case TOKminass:
8238                 nextToken();
8239                 auto e2 = parseAssignExp();
8240                 e = new MinAssignExp(loc, e, e2);
8241                 continue;
8242 
8243             case TOKmulass:
8244                 nextToken();
8245                 auto e2 = parseAssignExp();
8246                 e = new MulAssignExp(loc, e, e2);
8247                 continue;
8248 
8249             case TOKdivass:
8250                 nextToken();
8251                 auto e2 = parseAssignExp();
8252                 e = new DivAssignExp(loc, e, e2);
8253                 continue;
8254 
8255             case TOKmodass:
8256                 nextToken();
8257                 auto e2 = parseAssignExp();
8258                 e = new ModAssignExp(loc, e, e2);
8259                 continue;
8260 
8261             case TOKpowass:
8262                 nextToken();
8263                 auto e2 = parseAssignExp();
8264                 e = new PowAssignExp(loc, e, e2);
8265                 continue;
8266 
8267             case TOKandass:
8268                 nextToken();
8269                 auto e2 = parseAssignExp();
8270                 e = new AndAssignExp(loc, e, e2);
8271                 continue;
8272 
8273             case TOKorass:
8274                 nextToken();
8275                 auto e2 = parseAssignExp();
8276                 e = new OrAssignExp(loc, e, e2);
8277                 continue;
8278 
8279             case TOKxorass:
8280                 nextToken();
8281                 auto e2 = parseAssignExp();
8282                 e = new XorAssignExp(loc, e, e2);
8283                 continue;
8284 
8285             case TOKshlass:
8286                 nextToken();
8287                 auto e2 = parseAssignExp();
8288                 e = new ShlAssignExp(loc, e, e2);
8289                 continue;
8290 
8291             case TOKshrass:
8292                 nextToken();
8293                 auto e2 = parseAssignExp();
8294                 e = new ShrAssignExp(loc, e, e2);
8295                 continue;
8296 
8297             case TOKushrass:
8298                 nextToken();
8299                 auto e2 = parseAssignExp();
8300                 e = new UshrAssignExp(loc, e, e2);
8301                 continue;
8302 
8303             case TOKcatass:
8304                 nextToken();
8305                 auto e2 = parseAssignExp();
8306                 e = new CatAssignExp(loc, e, e2);
8307                 continue;
8308 
8309             default:
8310                 break;
8311             }
8312             break;
8313         }
8314         return e;
8315     }
8316 
8317     /*************************
8318      * Collect argument list.
8319      * Assume current token is ',', '$(LPAREN)' or '['.
8320      */
8321     Expressions* parseArguments()
8322     {
8323         // function call
8324         Expressions* arguments;
8325         TOK endtok;
8326 
8327         arguments = new Expressions();
8328         if (token.value == TOKlbracket)
8329             endtok = TOKrbracket;
8330         else
8331             endtok = TOKrparen;
8332 
8333         {
8334             nextToken();
8335             while (token.value != endtok && token.value != TOKeof)
8336             {
8337                 auto arg = parseAssignExp();
8338                 arguments.push(arg);
8339                 if (token.value == endtok)
8340                     break;
8341                 check(TOKcomma);
8342             }
8343             check(endtok);
8344         }
8345         return arguments;
8346     }
8347 
8348     /*******************************************
8349      */
8350     Expression parseNewExp(Expression thisexp)
8351     {
8352         const loc = token.loc;
8353 
8354         nextToken();
8355         Expressions* newargs = null;
8356         Expressions* arguments = null;
8357         if (token.value == TOKlparen)
8358         {
8359             newargs = parseArguments();
8360         }
8361 
8362         // An anonymous nested class starts with "class"
8363         if (token.value == TOKclass)
8364         {
8365             nextToken();
8366             if (token.value == TOKlparen)
8367                 arguments = parseArguments();
8368 
8369             BaseClasses* baseclasses = null;
8370             if (token.value != TOKlcurly)
8371                 baseclasses = parseBaseClasses();
8372 
8373             Identifier id = null;
8374             Dsymbols* members = null;
8375 
8376             if (token.value != TOKlcurly)
8377             {
8378                 error("{ members } expected for anonymous class");
8379             }
8380             else
8381             {
8382                 nextToken();
8383                 members = parseDeclDefs(0);
8384                 if (token.value != TOKrcurly)
8385                     error("class member expected");
8386                 nextToken();
8387             }
8388 
8389             auto cd = new ClassDeclaration(loc, id, baseclasses, members, false);
8390             auto e = new NewAnonClassExp(loc, thisexp, newargs, cd, arguments);
8391             return e;
8392         }
8393 
8394         const stc = parseTypeCtor();
8395         auto t = parseBasicType(true);
8396         t = parseBasicType2(t);
8397         t = t.addSTC(stc);
8398         if (t.ty == Taarray)
8399         {
8400             TypeAArray taa = cast(TypeAArray)t;
8401             Type index = taa.index;
8402             auto edim = index.toExpression();
8403             if (!edim)
8404             {
8405                 error("need size of rightmost array, not type %s", index.toChars());
8406                 return new NullExp(loc);
8407             }
8408             t = new TypeSArray(taa.next, edim);
8409         }
8410         else if (t.ty == Tsarray)
8411         {
8412         }
8413         else if (token.value == TOKlparen)
8414         {
8415             arguments = parseArguments();
8416         }
8417 
8418         auto e = new NewExp(loc, thisexp, newargs, t, arguments);
8419         return e;
8420     }
8421 
8422     /**********************************************
8423      */
8424     void addComment(Dsymbol s, const(char)* blockComment)
8425     {
8426         s.addComment(combineComments(blockComment, token.lineComment));
8427         token.lineComment = null;
8428     }
8429 }
8430 
8431 enum PREC : int
8432 {
8433     zero,
8434     expr,
8435     assign,
8436     cond,
8437     oror,
8438     andand,
8439     or,
8440     xor,
8441     and,
8442     equal,
8443     rel,
8444     shift,
8445     add,
8446     mul,
8447     pow,
8448     unary,
8449     primary,
8450 }