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