root/trunk/src/parse.c

Revision 886, 180.9 kB (checked in by walter, 1 year ago)

bugzilla 2581 DDoc doesn't work for functions with auto return type.

  • Property svn:eol-style set to native
Line 
1 // Compiler implementation of the D programming language
2 // Copyright (c) 1999-2010 by Digital Mars
3 // All Rights Reserved
4 // written by Walter Bright
5 // http://www.digitalmars.com
6 // License for redistribution is by either the Artistic License
7 // in artistic.txt, or the GNU General Public License in gnu.txt.
8 // See the included readme.txt for details.
9
10 // This is the D parser
11
12 #include <stdio.h>
13 #include <assert.h>
14
15 #include "rmem.h"
16 #include "lexer.h"
17 #include "parse.h"
18 #include "init.h"
19 #include "attrib.h"
20 #include "cond.h"
21 #include "mtype.h"
22 #include "template.h"
23 #include "staticassert.h"
24 #include "expression.h"
25 #include "statement.h"
26 #include "module.h"
27 #include "dsymbol.h"
28 #include "import.h"
29 #include "declaration.h"
30 #include "aggregate.h"
31 #include "enum.h"
32 #include "id.h"
33 #include "version.h"
34 #include "aliasthis.h"
35
36 // How multiple declarations are parsed.
37 // If 1, treat as C.
38 // If 0, treat:
39 //      int *p, i;
40 // as:
41 //      int* p;
42 //      int* i;
43 #define CDECLSYNTAX     0
44
45 // Support C cast syntax:
46 //      (type)(expression)
47 #define CCASTSYNTAX     1
48
49 // Support postfix C array declarations, such as
50 //      int a[3][4];
51 #define CARRAYDECL      1
52
53 // Support D1 inout
54 #define D1INOUT         0
55
56 Parser::Parser(Module *module, unsigned char *base, unsigned length, int doDocComment)
57     : Lexer(module, base, 0, length, doDocComment, 0)
58 {
59     //printf("Parser::Parser()\n");
60     md = NULL;
61     linkage = LINKd;
62     endloc = 0;
63     inBrackets = 0;
64     //nextToken();              // start up the scanner
65 }
66
67 Dsymbols *Parser::parseModule()
68 {
69     Dsymbols *decldefs;
70
71     // ModuleDeclation leads off
72     if (token.value == TOKmodule)
73     {
74         unsigned char *comment = token.blockComment;
75         bool safe = FALSE;
76
77         nextToken();
78 #if 0 && DMDV2
79         if (token.value == TOKlparen)
80         {
81             nextToken();
82             if (token.value != TOKidentifier)
83             {   error("module (system) identifier expected");
84                 goto Lerr;
85             }
86             Identifier *id = token.ident;
87
88             if (id == Id::system)
89                 safe = TRUE;
90             else
91                 error("(safe) expected, not %s", id->toChars());
92             nextToken();
93             check(TOKrparen);
94         }
95 #endif
96
97         if (token.value != TOKidentifier)
98         {   error("Identifier expected following module");
99             goto Lerr;
100         }
101         else
102         {
103             Array *a = NULL;
104             Identifier *id;
105
106             id = token.ident;
107             while (nextToken() == TOKdot)
108             {
109                 if (!a)
110                     a = new Array();
111                 a->push(id);
112                 nextToken();
113                 if (token.value != TOKidentifier)
114                 {   error("Identifier expected following package");
115                     goto Lerr;
116                 }
117                 id = token.ident;
118             }
119
120             md = new ModuleDeclaration(a, id, safe);
121
122             if (token.value != TOKsemicolon)
123                 error("';' expected following module declaration instead of %s", token.toChars());
124             nextToken();
125             addComment(mod, comment);
126         }
127     }
128
129     decldefs = parseDeclDefs(0);
130     if (token.value != TOKeof)
131     {   error("unrecognized declaration");
132         goto Lerr;
133     }
134     return decldefs;
135
136 Lerr:
137     while (token.value != TOKsemicolon && token.value != TOKeof)
138         nextToken();
139     nextToken();
140     return new Dsymbols();
141 }
142
143 Dsymbols *Parser::parseDeclDefs(int once)
144 {   Dsymbol *s;
145     Dsymbols *decldefs;
146     Dsymbols *a;
147     Dsymbols *aelse;
148     enum PROT prot;
149     StorageClass stc;
150     StorageClass storageClass;
151     Condition *condition;
152     unsigned char *comment;
153
154     //printf("Parser::parseDeclDefs()\n");
155     decldefs = new Dsymbols();
156     do
157     {
158         comment = token.blockComment;
159         storageClass = STCundefined;
160         switch (token.value)
161         {
162             case TOKenum:
163             {   /* Determine if this is a manifest constant declaration,
164                  * or a conventional enum.
165                  */
166                 Token *t = peek(&token);
167                 if (t->value == TOKlcurly || t->value == TOKcolon)
168                     s = parseEnum();
169                 else if (t->value != TOKidentifier)
170                     goto Ldeclaration;
171                 else
172                 {
173                     t = peek(t);
174                     if (t->value == TOKlcurly || t->value == TOKcolon ||
175                         t->value == TOKsemicolon)
176                         s = parseEnum();
177                     else
178                         goto Ldeclaration;
179                 }
180                 break;
181             }
182
183             case TOKstruct:
184             case TOKunion:
185             case TOKclass:
186             case TOKinterface:
187                 s = parseAggregate();
188                 break;
189
190             case TOKimport:
191                 s = parseImport(decldefs, 0);
192                 break;
193
194             case TOKtemplate:
195                 s = (Dsymbol *)parseTemplateDeclaration(0);
196                 break;
197
198             case TOKmixin:
199             {   Loc loc = this->loc;
200                 switch (peekNext())
201                 {
202                     case TOKlparen:
203                     {   // mixin(string)
204                         nextToken();
205                         check(TOKlparen, "mixin");
206                         Expression *e = parseAssignExp();
207                         check(TOKrparen);
208                         check(TOKsemicolon);
209                         s = new CompileDeclaration(loc, e);
210                         break;
211                     }
212                     case TOKtemplate:
213                         // mixin template
214                         nextToken();
215                         s = (Dsymbol *)parseTemplateDeclaration(1);
216                         break;
217
218                     default:
219                         s = parseMixin();
220                         break;
221                 }
222                 break;
223             }
224
225             case BASIC_TYPES:
226             case TOKalias:
227             case TOKtypedef:
228             case TOKidentifier:
229             case TOKtypeof:
230             case TOKdot:
231             Ldeclaration:
232                 a = parseDeclarations(STCundefined, NULL);
233                 decldefs->append(a);
234                 continue;
235
236             case TOKthis:
237                 s = parseCtor();
238                 break;
239
240 #if 0 // dead end, use this(this){} instead
241             case TOKassign:
242                 s = parsePostBlit();
243                 break;
244 #endif
245             case TOKtilde:
246                 s = parseDtor();
247                 break;
248
249             case TOKinvariant:
250             {   Token *t;
251                 t = peek(&token);
252                 if (t->value == TOKlparen)
253                 {
254                     if (peek(t)->value == TOKrparen)
255                         // invariant() forms start of class invariant
256                         s = parseInvariant();
257                     else
258                         // invariant(type)
259                         goto Ldeclaration;
260                 }
261                 else
262                 {
263                     stc = STCimmutable;
264                     goto Lstc;
265                 }
266                 break;
267             }
268
269             case TOKunittest:
270                 s = parseUnitTest();
271                 break;
272
273             case TOKnew:
274                 s = parseNew();
275                 break;
276
277             case TOKdelete:
278                 s = parseDelete();
279                 break;
280
281             case TOKeof:
282             case TOKrcurly:
283                 return decldefs;
284
285             case TOKstatic:
286                 nextToken();
287                 if (token.value == TOKthis)
288                     s = parseStaticCtor();
289                 else if (token.value == TOKtilde)
290                     s = parseStaticDtor();
291                 else if (token.value == TOKassert)
292                     s = parseStaticAssert();
293                 else if (token.value == TOKif)
294                 {   condition = parseStaticIfCondition();
295                     a = parseBlock();
296                     aelse = NULL;
297                     if (token.value == TOKelse)
298                     {   nextToken();
299                         aelse = parseBlock();
300                     }
301                     s = new StaticIfDeclaration(condition, a, aelse);
302                     break;
303                 }
304                 else if (token.value == TOKimport)
305                 {
306                     s = parseImport(decldefs, 1);
307                 }
308                 else
309                 {   stc = STCstatic;
310                     goto Lstc2;
311                 }
312                 break;
313
314             case TOKconst:
315                 if (peekNext() == TOKlparen)
316                     goto Ldeclaration;
317                 stc = STCconst;
318                 goto Lstc;
319
320             case TOKimmutable:
321                 if (peekNext() == TOKlparen)
322                     goto Ldeclaration;
323                 stc = STCimmutable;
324                 goto Lstc;
325
326             case TOKshared:
327             {   TOK next = peekNext();
328                 if (next == TOKlparen)
329                     goto Ldeclaration;
330                 if (next == TOKstatic)
331                 {   TOK next2 = peekNext2();
332                     if (next2 == TOKthis)
333                     {   s = parseSharedStaticCtor();
334                         break;
335                     }
336                     if (next2 == TOKtilde)
337                     {   s = parseSharedStaticDtor();
338                         break;
339                     }
340                 }
341                 stc = STCshared;
342                 goto Lstc;
343             }
344
345             case TOKwild:
346                 if (peekNext() == TOKlparen)
347                     goto Ldeclaration;
348                 stc = STCwild;
349                 goto Lstc;
350
351             case TOKfinal:        stc = STCfinal;        goto Lstc;
352             case TOKauto:         stc = STCauto;         goto Lstc;
353             case TOKscope:        stc = STCscope;        goto Lstc;
354             case TOKoverride:     stc = STCoverride;     goto Lstc;
355             case TOKabstract:     stc = STCabstract;     goto Lstc;
356             case TOKsynchronized: stc = STCsynchronized; goto Lstc;
357             case TOKdeprecated:   stc = STCdeprecated;   goto Lstc;
358 #if DMDV2
359             case TOKnothrow:      stc = STCnothrow;      goto Lstc;
360             case TOKpure:         stc = STCpure;         goto Lstc;
361             case TOKref:          stc = STCref;          goto Lstc;
362             case TOKtls:          stc = STCtls;          goto Lstc;
363             case TOKgshared:      stc = STCgshared;      goto Lstc;
364             //case TOKmanifest:   stc = STCmanifest;     goto Lstc;
365             case TOKat:           stc = parseAttribute(); goto Lstc;
366 #endif
367
368             Lstc:
369                 if (storageClass & stc)
370                     error("redundant storage class %s", Token::toChars(token.value));
371                 composeStorageClass(storageClass | stc);
372                 nextToken();
373             Lstc2:
374                 storageClass |= stc;
375                 switch (token.value)
376                 {
377                     case TOKconst:
378                     case TOKinvariant:
379                     case TOKimmutable:
380                     case TOKshared:
381                     case TOKwild:
382                         // If followed by a (, it is not a storage class
383                         if (peek(&token)->value == TOKlparen)
384                             break;
385                         if (token.value == TOKconst)
386                             stc = STCconst;
387                         else if (token.value == TOKshared)
388                             stc = STCshared;
389                         else if (token.value == TOKwild)
390                             stc = STCwild;
391                         else
392                             stc = STCimmutable;
393                         goto Lstc;
394                     case TOKfinal:        stc = STCfinal;        goto Lstc;
395                     case TOKauto:         stc = STCauto;         goto Lstc;
396                     case TOKscope:        stc = STCscope;        goto Lstc;
397                     case TOKoverride:     stc = STCoverride;     goto Lstc;
398                     case TOKabstract:     stc = STCabstract;     goto Lstc;
399                     case TOKsynchronized: stc = STCsynchronized; goto Lstc;
400                     case TOKdeprecated:   stc = STCdeprecated;   goto Lstc;
401                     case TOKnothrow:      stc = STCnothrow;      goto Lstc;
402                     case TOKpure:         stc = STCpure;         goto Lstc;
403                     case TOKref:          stc = STCref;          goto Lstc;
404                     case TOKtls:          stc = STCtls;          goto Lstc;
405                     case TOKgshared:      stc = STCgshared;      goto Lstc;
406                     //case TOKmanifest:   stc = STCmanifest;     goto Lstc;
407                     case TOKat:           stc = parseAttribute(); goto Lstc;
408                     default:
409                         break;
410                 }
411
412                 /* Look for auto initializers:
413                  *      storage_class identifier = initializer;
414                  */
415                 if (token.value == TOKidentifier &&
416                     peek(&token)->value == TOKassign)
417                 {
418                     a = parseAutoDeclarations(storageClass, comment);
419                     decldefs->append(a);
420                     continue;
421                 }
422
423                 /* Look for return type inference for template functions.
424                  */
425                 Token *tk;
426                 if (token.value == TOKidentifier &&
427                     (tk = peek(&token))->value == TOKlparen &&
428                     skipParens(tk, &tk) &&
429                     (peek(tk)->value == TOKlparen ||
430                      peek(tk)->value == TOKlcurly)
431                    )
432                 {
433                     a = parseDeclarations(storageClass, comment);
434                     decldefs->append(a);
435                     continue;
436                 }
437                 a = parseBlock();
438                 s = new StorageClassDeclaration(storageClass, a);
439                 break;
440
441             case TOKextern:
442                 if (peek(&token)->value != TOKlparen)
443                 {   stc = STCextern;
444                     goto Lstc;
445                 }
446             {
447                 enum LINK linksave = linkage;
448                 linkage = parseLinkage();
449                 a = parseBlock();
450                 s = new LinkDeclaration(linkage, a);
451                 linkage = linksave;
452                 break;
453             }
454             case TOKprivate:    prot = PROTprivate;     goto Lprot;
455             case TOKpackage:    prot = PROTpackage;     goto Lprot;
456             case TOKprotected:  prot = PROTprotected;   goto Lprot;
457             case TOKpublic:     prot = PROTpublic;      goto Lprot;
458             case TOKexport:     prot = PROTexport;      goto Lprot;
459
460             Lprot:
461                 nextToken();
462                 switch (token.value)
463                 {
464                     case TOKprivate:
465                     case TOKpackage:
466                     case TOKprotected:
467                     case TOKpublic:
468                     case TOKexport:
469                         error("redundant protection attribute");
470                         break;
471                 }
472                 a = parseBlock();
473                 s = new ProtDeclaration(prot, a);
474                 break;
475
476             case TOKalign:
477             {   unsigned n;
478
479                 s = NULL;
480                 nextToken();
481                 if (token.value == TOKlparen)
482                 {
483                     nextToken();
484                     if (token.value == TOKint32v)
485                         n = (unsigned)token.uns64value;
486                     else
487                     {   error("integer expected, not %s", token.toChars());
488                         n = 1;
489                     }
490                     nextToken();
491                     check(TOKrparen);
492                 }
493                 else
494                     n = global.structalign;             // default
495
496                 a = parseBlock();
497                 s = new AlignDeclaration(n, a);
498                 break;
499             }
500
501             case TOKpragma:
502             {   Identifier *ident;
503                 Expressions *args = NULL;
504
505                 nextToken();
506                 check(TOKlparen);
507                 if (token.value != TOKidentifier)
508                 {   error("pragma(identifier expected");
509                     goto Lerror;
510                 }
511                 ident = token.ident;
512                 nextToken();
513                 if (token.value == TOKcomma && peekNext() != TOKrparen)
514                     args = parseArguments();    // pragma(identifier, args...)
515                 else
516                     check(TOKrparen);           // pragma(identifier)
517
518                 if (token.value == TOKsemicolon)
519                     a = NULL;
520                 else
521                     a = parseBlock();
522                 s = new PragmaDeclaration(loc, ident, args, a);
523                 break;
524             }
525
526             case TOKdebug:
527                 nextToken();
528                 if (token.value == TOKassign)
529                 {
530                     nextToken();
531                     if (token.value == TOKidentifier)
532                         s = new DebugSymbol(loc, token.ident);
533                     else if (token.value == TOKint32v)
534                         s = new DebugSymbol(loc, (unsigned)token.uns64value);
535                     else
536                     {   error("identifier or integer expected, not %s", token.toChars());
537                         s = NULL;
538                     }
539                     nextToken();
540                     if (token.value != TOKsemicolon)
541                         error("semicolon expected");
542                     nextToken();
543                     break;
544                 }
545
546                 condition = parseDebugCondition();
547                 goto Lcondition;
548
549             case TOKversion:
550                 nextToken();
551                 if (token.value == TOKassign)
552                 {
553                     nextToken();
554                     if (token.value == TOKidentifier)
555                         s = new VersionSymbol(loc, token.ident);
556                     else if (token.value == TOKint32v)
557                         s = new VersionSymbol(loc, (unsigned)token.uns64value);
558                     else
559                     {   error("identifier or integer expected, not %s", token.toChars());
560                         s = NULL;
561                     }
562                     nextToken();
563                     if (token.value != TOKsemicolon)
564                         error("semicolon expected");
565                     nextToken();
566                     break;
567                 }
568                 condition = parseVersionCondition();
569                 goto Lcondition;
570
571             Lcondition:
572                 a = parseBlock();
573                 aelse = NULL;
574                 if (token.value == TOKelse)
575                 {   nextToken();
576                     aelse = parseBlock();
577                 }
578                 s = new ConditionalDeclaration(condition, a, aelse);
579                 break;
580
581             case TOKsemicolon:          // empty declaration
582                 //error("empty declaration");
583                 nextToken();
584                 continue;
585
586             default:
587                 error("Declaration expected, not '%s'",token.toChars());
588             Lerror:
589                 while (token.value != TOKsemicolon && token.value != TOKeof)
590                     nextToken();
591                 nextToken();
592                 s = NULL;
593                 continue;
594         }
595         if (s)
596         {   decldefs->push(s);
597             addComment(s, comment);
598         }
599     } while (!once);
600     return decldefs;
601 }
602
603 /*********************************************
604  * Give error on conflicting storage classes.
605  */
606
607 #if DMDV2
608 void Parser::composeStorageClass(StorageClass stc)
609 {
610     StorageClass u = stc;
611     u &= STCconst | STCimmutable | STCmanifest;
612     if (u & (u - 1))
613         error("conflicting storage class %s", Token::toChars(token.value));
614     u = stc;
615     u &= STCgshared | STCshared | STCtls;
616     if (u & (u - 1))
617         error("conflicting storage class %s", Token::toChars(token.value));
618     u = stc;
619     u &= STCsafe | STCsystem | STCtrusted;
620     if (u & (u - 1))
621         error("conflicting attribute @%s", token.toChars());
622 }
623 #endif
624
625 /***********************************************
626  * Parse storage class, lexer is on '@'
627  */
628
629 #if DMDV2
630 StorageClass Parser::parseAttribute()
631 {
632     nextToken();
633     StorageClass stc = 0;
634     if (token.value != TOKidentifier)
635     {
636         error("identifier expected after @, not %s", token.toChars());
637     }
638     else if (token.ident == Id::property)
639         stc = STCproperty;
640     else if (token.ident == Id::safe)
641         stc = STCsafe;
642     else if (token.ident == Id::trusted)
643         stc = STCtrusted;
644     else if (token.ident == Id::system)
645         stc = STCsystem;
646     else if (token.ident == Id::disable)
647         stc = STCdisable;
648     else
649         error("valid attribute identifiers are @property, @safe, @trusted, @system, @disable not @%s", token.toChars());
650     return stc;
651 }
652 #endif
653
654 /***********************************************
655  * Parse const/immutable/shared/inout/nothrow/pure postfix
656  */
657
658 StorageClass Parser::parsePostfix()
659 {
660     StorageClass stc = 0;
661
662     while (1)
663     {
664         switch (token.value)
665         {
666             case TOKconst:              stc |= STCconst;                break;
667             case TOKinvariant:
668                 if (!global.params.useDeprecated)
669                     error("use of 'invariant' rather than 'immutable' is deprecated");
670             case TOKimmutable:          stc |= STCimmutable;            break;
671             case TOKshared:             stc |= STCshared;               break;
672             case TOKwild:               stc |= STCwild;                 break;
673             case TOKnothrow:            stc |= STCnothrow;              break;
674             case TOKpure:               stc |= STCpure;                 break;
675             case TOKat:                 stc |= parseAttribute();        break;
676
677             default:
678                 composeStorageClass(stc);
679                 return stc;
680         }
681         nextToken();
682     }
683 }
684
685 /********************************************
686  * Parse declarations after an align, protection, or extern decl.
687  */
688
689 Dsymbols *Parser::parseBlock()
690 {
691     Dsymbols *a = NULL;
692     Dsymbol *s;
693
694     //printf("parseBlock()\n");
695     switch (token.value)
696     {
697         case TOKsemicolon:
698             error("declaration expected following attribute, not ';'");
699             nextToken();
700             break;
701
702         case TOKeof:
703             error("declaration expected following attribute, not EOF");
704             break;
705
706         case TOKlcurly:
707             nextToken();
708             a = parseDeclDefs(0);
709             if (token.value != TOKrcurly)
710             {   /* { */
711                 error("matching '}' expected, not %s", token.toChars());
712             }
713             else
714                 nextToken();
715             break;
716
717         case TOKcolon:
718             nextToken();
719 #if 0
720             a = NULL;
721 #else
722             a = parseDeclDefs(0);       // grab declarations up to closing curly bracket
723 #endif
724             break;
725
726         default:
727             a = parseDeclDefs(1);
728             break;
729     }
730     return a;
731 }
732
733 /**********************************
734  * Parse a static assertion.
735  */
736
737 StaticAssert *Parser::parseStaticAssert()
738 {
739     Loc loc = this->loc;
740     Expression *exp;
741     Expression *msg = NULL;
742
743     //printf("parseStaticAssert()\n");
744     nextToken();
745     check(TOKlparen);
746     exp = parseAssignExp();
747     if (token.value == TOKcomma)
748     {   nextToken();
749         msg = parseAssignExp();
750     }
751     check(TOKrparen);
752     check(TOKsemicolon);
753     return new StaticAssert(loc, exp, msg);
754 }
755
756 /***********************************
757  * Parse typeof(expression).
758  * Current token is on the 'typeof'.
759  */
760
761 #if DMDV2
762 TypeQualified *Parser::parseTypeof()
763 {   TypeQualified *t;
764     Loc loc = this->loc;
765
766     nextToken();
767     check(TOKlparen);
768     if (token.value == TOKreturn)       // typeof(return)
769     {
770         nextToken();
771         t = new TypeReturn(loc);
772     }
773     else
774     {   Expression *exp = parseExpression();    // typeof(expression)
775         t = new TypeTypeof(loc, exp);
776     }
777     check(TOKrparen);
778     return t;
779 }
780 #endif
781
782 /***********************************
783  * Parse extern (linkage)
784  * The parser is on the 'extern' token.
785  */
786
787 enum LINK Parser::parseLinkage()
788 {
789     enum LINK link = LINKdefault;
790     nextToken();
791     assert(token.value == TOKlparen);
792     nextToken();
793     if (token.value == TOKidentifier)
794     {   Identifier *id = token.ident;
795
796         nextToken();
797         if (id == Id::Windows)
798             link = LINKwindows;
799         else if (id == Id::Pascal)
800             link = LINKpascal;
801         else if (id == Id::D)
802             link = LINKd;
803         else if (id == Id::C)
804         {
805             link = LINKc;
806             if (token.value == TOKplusplus)
807             {   link = LINKcpp;
808                 nextToken();
809             }
810         }
811         else if (id == Id::System)
812         {
813 #if _WIN32
814             link = LINKwindows;
815 #else
816             link = LINKc;
817 #endif
818         }
819         else
820         {
821             error("valid linkage identifiers are D, C, C++, Pascal, Windows, System");
822             link = LINKd;
823         }
824     }
825     else
826     {
827         link = LINKd;           // default
828     }
829     check(TOKrparen);
830     return link;
831 }
832
833 /**************************************
834  * Parse a debug conditional
835  */
836
837 Condition *Parser::parseDebugCondition()
838 {
839     Condition *c;
840
841     if (token.value == TOKlparen)
842     {
843         nextToken();
844         unsigned level = 1;
845         Identifier *id = NULL;
846
847         if (token.value == TOKidentifier)
848             id = token.ident;
849         else if (token.value == TOKint32v)
850             level = (unsigned)token.uns64value;
851         else
852             error("identifier or integer expected, not %s", token.toChars());
853         nextToken();
854         check(TOKrparen);
855         c = new DebugCondition(mod, level, id);
856     }
857     else
858         c = new DebugCondition(mod, 1, NULL);
859     return c;
860
861 }
862
863 /**************************************
864  * Parse a version conditional
865  */
866
867 Condition *Parser::parseVersionCondition()
868 {
869     Condition *c;
870     unsigned level = 1;
871     Identifier *id = NULL;
872
873     if (token.value == TOKlparen)
874     {
875         nextToken();
876         if (token.value == TOKidentifier)
877             id = token.ident;
878         else if (token.value == TOKint32v)
879             level = (unsigned)token.uns64value;
880 #if DMDV2
881         /* Allow:
882          *    version (unittest)
883          * even though unittest is a keyword
884          */
885         else if (token.value == TOKunittest)
886             id = Lexer::idPool(Token::toChars(TOKunittest));
887 #endif
888         else
889             error("identifier or integer expected, not %s", token.toChars());
890         nextToken();
891         check(TOKrparen);
892
893     }
894     else
895        error("(condition) expected following version");
896     c = new VersionCondition(mod, level, id);
897     return c;
898
899 }
900
901 /***********************************************
902  *      static if (expression)
903  *          body
904  *      else
905  *          body
906  */
907
908 Condition *Parser::parseStaticIfCondition()
909 {   Expression *exp;
910     Condition *condition;
911     Array *aif;
912     Array *aelse;
913     Loc loc = this->loc;
914
915     nextToken();
916     if (token.value == TOKlparen)
917     {
918         nextToken();
919         exp = parseAssignExp();
920         check(TOKrparen);
921     }
922     else
923     {   error("(expression) expected following static if");
924         exp = NULL;
925     }
926     condition = new StaticIfCondition(loc, exp);
927     return condition;
928 }
929
930
931 /*****************************************
932  * Parse a constructor definition:
933  *      this(parameters) { body }
934  * or postblit:
935  *      this(this) { body }
936  * or constructor template:
937  *      this(templateparameters)(parameters) { body }
938  * Current token is 'this'.
939  */
940
941 Dsymbol *Parser::parseCtor()
942 {
943     Loc loc = this->loc;
944
945     nextToken();
946     if (token.value == TOKlparen && peek(&token)->value == TOKthis)
947     {   // this(this) { ... }
948         nextToken();
949         nextToken();
950         check(TOKrparen);
951         PostBlitDeclaration *f = new PostBlitDeclaration(loc, 0);
952         parseContracts(f);
953         return f;
954     }
955
956     /* Look ahead to see if:
957      *   this(...)(...)
958      * which is a constructor template
959      */
960     TemplateParameters *tpl = NULL;
961     if (token.value == TOKlparen && peekPastParen(&token)->value == TOKlparen)
962     {   tpl = parseTemplateParameterList();
963
964         int varargs;
965         Parameters *parameters = parseParameters(&varargs);
966         StorageClass stc = parsePostfix();
967
968         Expression *constraint = tpl ? parseConstraint() : NULL;
969
970         CtorDeclaration *f = new CtorDeclaration(loc, 0, parameters, varargs, stc);
971         parseContracts(f);
972
973         // Wrap a template around it
974         Dsymbols *decldefs = new Dsymbols();
975         decldefs->push(f);
976         TemplateDeclaration *tempdecl =
977             new TemplateDeclaration(loc, f->ident, tpl, constraint, decldefs, 0);
978         return tempdecl;
979     }
980
981     /* Just a regular constructor
982      */
983     int varargs;
984     Parameters *parameters = parseParameters(&varargs);
985     StorageClass stc = parsePostfix();
986     CtorDeclaration *f = new CtorDeclaration(loc, 0, parameters, varargs, stc);
987     parseContracts(f);
988     return f;
989 }
990
991 /*****************************************
992  * Parse a postblit definition:
993  *      =this() { body }
994  * Current token is '='.
995  */
996
997 PostBlitDeclaration *Parser::parsePostBlit()
998 {
999     Loc loc = this->loc;
1000
1001     nextToken();
1002     check(TOKthis);
1003     check(TOKlparen);
1004     check(TOKrparen);
1005
1006     PostBlitDeclaration *f = new PostBlitDeclaration(loc, 0);
1007     parseContracts(f);
1008     return f;
1009 }
1010
1011 /*****************************************
1012  * Parse a destructor definition:
1013  *      ~this() { body }
1014  * Current token is '~'.
1015  */
1016
1017 DtorDeclaration *Parser::parseDtor()
1018 {
1019     DtorDeclaration *f;
1020     Loc loc = this->loc;
1021
1022     nextToken();
1023     check(TOKthis);
1024     check(TOKlparen);
1025     check(TOKrparen);
1026
1027     f = new DtorDeclaration(loc, 0);
1028     parseContracts(f);
1029     return f;
1030 }
1031
1032 /*****************************************
1033  * Parse a static constructor definition:
1034  *      static this() { body }
1035  * Current token is 'this'.
1036  */
1037
1038 StaticCtorDeclaration *Parser::parseStaticCtor()
1039 {
1040     Loc loc = this->loc;
1041
1042     nextToken();
1043     check(TOKlparen);
1044     check(TOKrparen);
1045
1046     StaticCtorDeclaration *f = new StaticCtorDeclaration(loc, 0);
1047     parseContracts(f);
1048     return f;
1049 }
1050
1051 /*****************************************
1052  * Parse a shared static constructor definition:
1053  *      shared static this() { body }
1054  * Current token is 'shared'.
1055  */
1056
1057 SharedStaticCtorDeclaration *Parser::parseSharedStaticCtor()
1058 {
1059     Loc loc = this->loc;
1060
1061     nextToken();
1062     nextToken();
1063     nextToken();
1064     check(TOKlparen);
1065     check(TOKrparen);
1066
1067     SharedStaticCtorDeclaration *f = new SharedStaticCtorDeclaration(loc, 0);
1068     parseContracts(f);
1069     return f;
1070 }
1071
1072 /*****************************************
1073  * Parse a static destructor definition:
1074  *      static ~this() { body }
1075  * Current token is '~'.
1076  */
1077
1078 StaticDtorDeclaration *Parser::parseStaticDtor()
1079 {
1080     Loc loc = this->loc;
1081
1082     nextToken();
1083     check(TOKthis);
1084     check(TOKlparen);
1085     check(TOKrparen);
1086
1087     StaticDtorDeclaration *f = new StaticDtorDeclaration(loc, 0);
1088     parseContracts(f);
1089     return f;
1090 }
1091
1092 /*****************************************
1093  * Parse a shared static destructor definition:
1094  *      shared static ~this() { body }
1095  * Current token is 'shared'.
1096  */
1097
1098 SharedStaticDtorDeclaration *Parser::parseSharedStaticDtor()
1099 {
1100     Loc loc = this->loc;
1101
1102     nextToken();
1103     nextToken();
1104     nextToken();
1105     check(TOKthis);
1106     check(TOKlparen);
1107     check(TOKrparen);
1108
1109     SharedStaticDtorDeclaration *f = new SharedStaticDtorDeclaration(loc, 0);
1110     parseContracts(f);
1111     return f;
1112 }
1113
1114 /*****************************************
1115  * Parse an invariant definition:
1116  *      invariant() { body }
1117  * Current token is 'invariant'.
1118  */
1119
1120 InvariantDeclaration *Parser::parseInvariant()
1121 {
1122     InvariantDeclaration *f;
1123     Loc loc = this->loc;
1124
1125     nextToken();
1126     if (token.value == TOKlparen)       // optional ()
1127     {
1128         nextToken();
1129         check(TOKrparen);
1130     }
1131
1132     f = new InvariantDeclaration(loc, 0);
1133     f->fbody = parseStatement(PScurly);
1134     return f;
1135 }
1136
1137 /*****************************************
1138  * Parse a unittest definition:
1139  *      unittest { body }
1140  * Current token is 'unittest'.
1141  */
1142
1143 UnitTestDeclaration *Parser::parseUnitTest()
1144 {
1145     UnitTestDeclaration *f;
1146     Statement *body;
1147     Loc loc = this->loc;
1148
1149     nextToken();
1150
1151     body = parseStatement(PScurly);
1152
1153     f = new UnitTestDeclaration(loc, this->loc);
1154     f->fbody = body;
1155     return f;
1156 }
1157
1158 /*****************************************
1159  * Parse a new definition:
1160  *      new(arguments) { body }
1161  * Current token is 'new'.
1162  */
1163
1164 NewDeclaration *Parser::parseNew()
1165 {
1166     NewDeclaration *f;
1167     Parameters *arguments;
1168     int varargs;
1169     Loc loc = this->loc;
1170
1171     nextToken();
1172     arguments = parseParameters(&varargs);
1173     f = new NewDeclaration(loc, 0, arguments, varargs);
1174     parseContracts(f);
1175     return f;
1176 }
1177
1178 /*****************************************
1179  * Parse a delete definition:
1180  *      delete(arguments) { body }
1181  * Current token is 'delete'.
1182  */
1183
1184 DeleteDeclaration *Parser::parseDelete()
1185 {
1186     DeleteDeclaration *f;
1187     Parameters *arguments;
1188     int varargs;
1189     Loc loc = this->loc;
1190
1191     nextToken();
1192     arguments = parseParameters(&varargs);
1193     if (varargs)
1194         error("... not allowed in delete function parameter list");
1195     f = new DeleteDeclaration(loc, 0, arguments);
1196     parseContracts(f);
1197     return f;
1198 }
1199
1200 /**********************************************
1201  * Parse parameter list.
1202  */
1203
1204 Parameters *Parser::parseParameters(int *pvarargs)
1205 {
1206     Parameters *arguments = new Parameters();
1207     int varargs = 0;
1208     int hasdefault = 0;
1209
1210     check(TOKlparen);
1211     while (1)
1212     {   Type *tb;
1213         Identifier *ai = NULL;
1214         Type *at;
1215         Parameter *a;
1216         StorageClass storageClass = 0;
1217         StorageClass stc;
1218         Expression *ae;
1219
1220         for (;1; nextToken())
1221         {
1222             switch (token.value)
1223             {
1224                 case TOKrparen:
1225                     break;
1226
1227                 case TOKdotdotdot:
1228                     varargs = 1;
1229                     nextToken();
1230                     break;
1231
1232                 case TOKconst:
1233                     if (peek(&token)->value == TOKlparen)
1234                         goto Ldefault;
1235                     stc = STCconst;
1236                     goto L2;
1237
1238                 case TOKinvariant:
1239                 case TOKimmutable:
1240                     if (peek(&token)->value == TOKlparen)
1241                         goto Ldefault;
1242                     stc = STCimmutable;
1243                     goto L2;
1244
1245                 case TOKshared:
1246                     if (peek(&token)->value == TOKlparen)
1247                         goto Ldefault;
1248                     stc = STCshared;
1249                     goto L2;
1250
1251                 case TOKwild:
1252                     if (peek(&token)->value == TOKlparen)
1253                         goto Ldefault;
1254                     stc = STCwild;
1255                     goto L2;
1256
1257                 case TOKin:        stc = STCin;         goto L2;
1258                 case TOKout:       stc = STCout;        goto L2;
1259 #if D1INOUT
1260                 case TOKinout:
1261 #endif
1262                 case TOKref:       stc = STCref;        goto L2;
1263                 case TOKlazy:      stc = STClazy;       goto L2;
1264                 case TOKscope:     stc = STCscope;      goto L2;
1265                 case TOKfinal:     stc = STCfinal;      goto L2;
1266                 case TOKauto:      stc = STCauto;       goto L2;
1267                 L2:
1268                     if (storageClass & stc ||
1269                         (storageClass & STCin && stc & (STCconst | STCscope)) ||
1270                         (stc & STCin && storageClass & (STCconst | STCscope))
1271                        )
1272                         error("redundant storage class %s", Token::toChars(token.value));
1273                     storageClass |= stc;
1274                     composeStorageClass(storageClass);
1275                     continue;
1276
1277 #if 0
1278                 case TOKstatic:    stc = STCstatic;             goto L2;
1279                 case TOKauto:   storageClass = STCauto;         goto L4;
1280                 case TOKalias:  storageClass = STCalias;        goto L4;
1281                 L4:
1282                     nextToken();
1283                     if (token.value == TOKidentifier)
1284                     {   ai = token.ident;
1285                         nextToken();
1286                     }
1287                     else
1288                         ai = NULL;
1289                     at = NULL;          // no type
1290                     ae = NULL;          // no default argument
1291                     if (token.value == TOKassign)       // = defaultArg
1292                     {   nextToken();
1293                         ae = parseDefaultInitExp();
1294                         hasdefault = 1;
1295                     }
1296                     else
1297                     {   if (hasdefault)
1298                             error("default argument expected for alias %s",
1299                                     ai ? ai->toChars() : "");
1300                     }
1301                     goto L3;
1302 #endif
1303
1304                 default:
1305                 Ldefault:
1306                     stc = storageClass & (STCin | STCout | STCref | STClazy);
1307                     if (stc & (stc - 1))        // if stc is not a power of 2
1308                         error("incompatible parameter storage classes");
1309                     if ((storageClass & (STCconst | STCout)) == (STCconst | STCout))
1310                         error("out cannot be const");
1311                     if ((storageClass & (STCimmutable | STCout)) == (STCimmutable | STCout))
1312                         error("out cannot be immutable");
1313                     if ((storageClass & STCscope) &&
1314                         (storageClass & (STCref | STCout)))
1315                         error("scope cannot be ref or out");
1316                     at = parseType(&ai);
1317                     ae = NULL;
1318                     if (token.value == TOKassign)       // = defaultArg
1319                     {   nextToken();
1320                         ae = parseDefaultInitExp();
1321                         hasdefault = 1;
1322                     }
1323                     else
1324                     {   if (hasdefault)
1325                             error("default argument expected for %s",
1326                                     ai ? ai->toChars() : at->toChars());
1327                     }
1328                     if (token.value == TOKdotdotdot)
1329                     {   /* This is:
1330                          *      at ai ...
1331                          */
1332
1333                         if (storageClass & (STCout | STCref))
1334                             error("variadic argument cannot be out or ref");
1335                         varargs = 2;
1336                         a = new Parameter(storageClass, at, ai, ae);
1337                         arguments->push(a);
1338                         nextToken();
1339                         break;
1340                     }
1341                 L3:
1342                     a = new Parameter(storageClass, at, ai, ae);
1343                     arguments->push(a);
1344                     if (token.value == TOKcomma)
1345                     {   nextToken();
1346                         goto L1;
1347                     }
1348                     break;
1349             }
1350             break;
1351         }
1352         break;
1353
1354     L1: ;
1355     }
1356     check(TOKrparen);
1357     *pvarargs = varargs;
1358     return arguments;
1359 }
1360
1361
1362 /*************************************
1363  */
1364
1365 EnumDeclaration *Parser::parseEnum()
1366 {   EnumDeclaration *e;
1367     Identifier *id;
1368     Type *memtype;
1369     Loc loc = this->loc;
1370
1371     //printf("Parser::parseEnum()\n");
1372     nextToken();
1373     if (token.value == TOKidentifier)
1374     {   id = token.ident;
1375         nextToken();
1376     }
1377     else
1378         id = NULL;
1379
1380     if (token.value == TOKcolon)
1381     {
1382         nextToken();
1383         memtype = parseBasicType();
1384         memtype = parseDeclarator(memtype, NULL, NULL);
1385     }
1386     else
1387         memtype = NULL;
1388
1389     e = new EnumDeclaration(loc, id, memtype);
1390     if (token.value == TOKsemicolon && id)
1391         nextToken();
1392     else if (token.value == TOKlcurly)
1393     {
1394         //printf("enum definition\n");
1395         e->members = new Dsymbols();
1396         nextToken();
1397         unsigned char *comment = token.blockComment;
1398         while (token.value != TOKrcurly)
1399         {
1400             /* Can take the following forms:
1401              *  1. ident
1402              *  2. ident = value
1403              *  3. type ident = value
1404              */
1405
1406             loc = this->loc;
1407
1408             Type *type = NULL;
1409             Identifier *ident;
1410             Token *tp = peek(&token);
1411             if (token.value == TOKidentifier &&
1412                 (tp->value == TOKassign || tp->value == TOKcomma || tp->value == TOKrcurly))
1413             {
1414                 ident = token.ident;
1415                 type = NULL;
1416                 nextToken();
1417             }
1418             else
1419             {
1420                 type = parseType(&ident, NULL);
1421                 if (id || memtype)
1422                     error("type only allowed if anonymous enum and no enum type");
1423             }
1424
1425             Expression *value;
1426             if (token.value == TOKassign)
1427             {
1428                 nextToken();
1429                 value = parseAssignExp();
1430             }
1431             else
1432             {   value = NULL;
1433                 if (type)
1434                     error("if type, there must be an initializer");
1435             }
1436
1437             EnumMember *em = new EnumMember(loc, ident, value, type);
1438             e->members->push(em);
1439
1440             if (token.value == TOKrcurly)
1441                 ;
1442             else
1443             {   addComment(em, comment);
1444                 comment = NULL;
1445                 check(TOKcomma);
1446             }
1447             addComment(em, comment);
1448             comment = token.blockComment;
1449         }
1450         nextToken();
1451     }
1452     else
1453         error("enum declaration is invalid");
1454
1455     //printf("-parseEnum() %s\n", e->toChars());
1456     return e;
1457 }
1458
1459 /********************************
1460  * Parse struct, union, interface, class.
1461  */
1462
1463 Dsymbol *Parser::parseAggregate()
1464 {   AggregateDeclaration *a = NULL;
1465     int anon = 0;
1466     enum TOK tok;
1467     Identifier *id;
1468     TemplateParameters *tpl = NULL;
1469     Expression *constraint = NULL;
1470
1471     //printf("Parser::parseAggregate()\n");
1472     tok = token.value;
1473     nextToken();
1474     if (token.value != TOKidentifier)
1475     {   id = NULL;
1476     }
1477     else
1478     {   id = token.ident;
1479         nextToken();
1480
1481         if (token.value == TOKlparen)
1482         {   // Class template declaration.
1483
1484             // Gather template parameter list
1485             tpl = parseTemplateParameterList();
1486             constraint = parseConstraint();
1487         }
1488     }
1489
1490     Loc loc = this->loc;
1491     switch (tok)
1492     {   case TOKclass:
1493         case TOKinterface:
1494         {
1495             if (!id)
1496                 error("anonymous classes not allowed");
1497
1498             // Collect base class(es)
1499             BaseClasses *baseclasses = NULL;
1500             if (token.value == TOKcolon)
1501             {
1502                 nextToken();
1503                 baseclasses = parseBaseClasses();
1504
1505                 if (token.value != TOKlcurly)
1506                     error("members expected");
1507             }
1508
1509             if (tok == TOKclass)
1510                 a = new ClassDeclaration(loc, id, baseclasses);
1511             else
1512                 a = new InterfaceDeclaration(loc, id, baseclasses);
1513             break;
1514         }
1515
1516         case TOKstruct:
1517             if (id)
1518                 a = new StructDeclaration(loc, id);
1519             else
1520                 anon = 1;
1521             break;
1522
1523         case TOKunion:
1524             if (id)
1525                 a = new UnionDeclaration(loc, id);
1526             else
1527                 anon = 2;
1528             break;
1529
1530         default:
1531             assert(0);
1532             break;
1533     }
1534     if (a && token.value == TOKsemicolon)
1535     {   nextToken();
1536     }
1537     else if (token.value == TOKlcurly)
1538     {
1539         //printf("aggregate definition\n");
1540         nextToken();
1541         Dsymbols *decl = parseDeclDefs(0);
1542         if (token.value != TOKrcurly)
1543             error("} expected following member declarations in aggregate");
1544         nextToken();
1545         if (anon)
1546         {
1547             /* Anonymous structs/unions are more like attributes.
1548              */
1549             return new AnonDeclaration(loc, anon - 1, decl);
1550         }
1551         else
1552             a->members = decl;
1553     }
1554     else
1555     {
1556         error("{ } expected following aggregate declaration");
1557         a = new StructDeclaration(loc, NULL);
1558     }
1559
1560     if (tpl)
1561     {   // Wrap a template around the aggregate declaration
1562
1563         Dsymbols *decldefs = new Dsymbols();
1564         decldefs->push(a);
1565         TemplateDeclaration *tempdecl =
1566                 new TemplateDeclaration(loc, id, tpl, constraint, decldefs, 0);
1567         return tempdecl;
1568     }
1569
1570     return a;
1571 }
1572
1573 /*******************************************
1574  */
1575
1576 BaseClasses *Parser::parseBaseClasses()
1577 {
1578     BaseClasses *baseclasses = new BaseClasses();
1579
1580     for (; 1; nextToken())
1581     {
1582         enum PROT protection = PROTpublic;
1583         switch (token.value)
1584         {
1585             case TOKprivate:
1586                 protection = PROTprivate;
1587                 nextToken();
1588                 break;
1589             case TOKpackage:
1590                 protection = PROTpackage;
1591                 nextToken();
1592                 break;
1593             case TOKprotected:
1594                 protection = PROTprotected;
1595                 nextToken();
1596                 break;
1597             case TOKpublic:
1598                 protection = PROTpublic;
1599                 nextToken();
1600                 break;
1601         }
1602         if (token.value == TOKidentifier)
1603         {
1604             BaseClass *b = new BaseClass(parseBasicType(), protection);
1605             baseclasses->push(b);
1606             if (token.value != TOKcomma)
1607                 break;
1608         }
1609         else
1610         {
1611             error("base classes expected instead of %s", token.toChars());
1612             return NULL;
1613         }
1614     }
1615     return baseclasses;
1616 }
1617
1618 /**************************************
1619  * Parse constraint.
1620  * Constraint is of the form:
1621  *      if ( ConstraintExpression )
1622  */
1623
1624 #if DMDV2
1625 Expression *Parser::parseConstraint()
1626 {   Expression *e = NULL;
1627
1628     if (token.value == TOKif)
1629     {
1630         nextToken();    // skip over 'if'
1631         check(TOKlparen);
1632         e = parseExpression();
1633         check(TOKrparen);
1634     }
1635     return e;
1636 }
1637 #endif
1638
1639 /**************************************
1640  * Parse a TemplateDeclaration.
1641  */
1642
1643 TemplateDeclaration *Parser::parseTemplateDeclaration(int ismixin)
1644 {
1645     TemplateDeclaration *tempdecl;
1646     Identifier *id;
1647     TemplateParameters *tpl;
1648     Dsymbols *decldefs;
1649     Expression *constraint = NULL;
1650     Loc loc = this->loc;
1651
1652     nextToken();
1653     if (token.value != TOKidentifier)
1654     {   error("TemplateIdentifier expected following template");
1655         goto Lerr;
1656     }
1657     id = token.ident;
1658     nextToken();
1659     tpl = parseTemplateParameterList();
1660     if (!tpl)
1661         goto Lerr;
1662
1663     constraint = parseConstraint();
1664
1665     if (token.value != TOKlcurly)
1666     {   error("members of template declaration expected");
1667         goto Lerr;
1668     }
1669     else
1670     {
1671         nextToken();
1672         decldefs = parseDeclDefs(0);
1673         if (token.value != TOKrcurly)
1674         {   error("template member expected");
1675             goto Lerr;
1676         }
1677         nextToken();
1678     }
1679
1680     tempdecl = new TemplateDeclaration(loc, id, tpl, constraint, decldefs, ismixin);
1681     return tempdecl;
1682
1683 Lerr:
1684     return NULL;
1685 }
1686
1687 /******************************************
1688  * Parse template parameter list.
1689  * Input:
1690  *      flag    0: parsing "( list )"
1691  *              1: parsing non-empty "list )"
1692  */
1693
1694 TemplateParameters *Parser::parseTemplateParameterList(int flag)
1695 {
1696     TemplateParameters *tpl = new TemplateParameters();
1697
1698     if (!flag && token.value != TOKlparen)
1699     {   error("parenthesized TemplateParameterList expected following TemplateIdentifier");
1700         goto Lerr;
1701     }
1702     nextToken();
1703
1704     // Get array of TemplateParameters
1705     if (flag || token.value != TOKrparen)
1706     {   int isvariadic = 0;
1707
1708         while (token.value != TOKrparen)
1709         {   TemplateParameter *tp;
1710             Identifier *tp_ident = NULL;
1711             Type *tp_spectype = NULL;
1712             Type *tp_valtype = NULL;
1713             Type *tp_defaulttype = NULL;
1714             Expression *tp_specvalue = NULL;
1715             Expression *tp_defaultvalue = NULL;
1716             Token *t;
1717
1718             // Get TemplateParameter
1719
1720             // First, look ahead to see if it is a TypeParameter or a ValueParameter
1721             t = peek(&token);
1722             if (token.value == TOKalias)
1723             {   // AliasParameter
1724                 nextToken();
1725                 Type *spectype = NULL;
1726                 if (isDeclaration(&token, 2, TOKreserved, NULL))
1727                 {
1728                     spectype = parseType(&tp_ident);
1729                 }
1730                 else
1731                 {
1732                     if (token.value != TOKidentifier)
1733                     {   error("identifier expected for template alias parameter");
1734                         goto Lerr;
1735                     }
1736                     tp_ident = token.ident;
1737                     nextToken();
1738                 }
1739                 Object *spec = NULL;
1740                 if (token.value == TOKcolon)    // : Type
1741                 {
1742                     nextToken();
1743                     if (isDeclaration(&token, 0, TOKreserved, NULL))
1744                         spec = parseType();
1745                     else
1746                         spec = parseCondExp();
1747                 }
1748                 Object *def = NULL;
1749                 if (token.value == TOKassign)   // = Type
1750                 {
1751                     nextToken();
1752                     if (isDeclaration(&token, 0, TOKreserved, NULL))
1753                         def = parseType();
1754                     else
1755                         def = parseCondExp();
1756                 }
1757                 tp = new TemplateAliasParameter(loc, tp_ident, spectype, spec, def);
1758             }
1759             else if (t->value == TOKcolon || t->value == TOKassign ||
1760                      t->value == TOKcomma || t->value == TOKrparen)
1761             {   // TypeParameter
1762                 if (token.value != TOKidentifier)
1763                 {   error("identifier expected for template type parameter");
1764                     goto Lerr;
1765                 }
1766                 tp_ident = token.ident;
1767                 nextToken();
1768                 if (token.value == TOKcolon)    // : Type
1769                 {
1770                     nextToken();
1771                     tp_spectype = parseType();
1772                 }
1773                 if (token.value == TOKassign)   // = Type
1774                 {
1775                     nextToken();
1776                     tp_defaulttype = parseType();
1777                 }
1778                 tp = new TemplateTypeParameter(loc, tp_ident, tp_spectype, tp_defaulttype);
1779             }
1780             else if (token.value == TOKidentifier && t->value == TOKdotdotdot)
1781             {   // ident...
1782                 if (isvariadic)
1783                     error("variadic template parameter must be last");
1784                 isvariadic = 1;
1785                 tp_ident = token.ident;
1786                 nextToken();
1787                 nextToken();
1788                 tp = new TemplateTupleParameter(loc, tp_ident);
1789             }
1790 #if DMDV2
1791             else if (token.value == TOKthis)
1792             {   // ThisParameter
1793                 nextToken();
1794                 if (token.value != TOKidentifier)
1795                 {   error("identifier expected for template this parameter");
1796                     goto Lerr;
1797                 }
1798                 tp_ident = token.ident;
1799                 nextToken();
1800                 if (token.value == TOKcolon)    // : Type
1801                 {
1802                     nextToken();
1803                     tp_spectype = parseType();
1804                 }
1805                 if (token.value == TOKassign)   // = Type
1806                 {
1807                     nextToken();
1808                     tp_defaulttype = parseType();
1809                 }
1810                 tp = new TemplateThisParameter(loc, tp_ident, tp_spectype, tp_defaulttype);
1811             }
1812 #endif
1813             else
1814             {   // ValueParameter
1815                 tp_valtype = parseType(&tp_ident);
1816                 if (!tp_ident)
1817                 {
1818                     error("identifier expected for template value parameter");
1819                     tp_ident = new Identifier("error", TOKidentifier);
1820                 }
1821                 if (token.value == TOKcolon)    // : CondExpression
1822                 {
1823                     nextToken();
1824                     tp_specvalue = parseCondExp();
1825                 }
1826                 if (token.value == TOKassign)   // = CondExpression
1827                 {
1828                     nextToken();
1829                     tp_defaultvalue = parseDefaultInitExp();
1830                 }
1831                 tp = new TemplateValueParameter(loc, tp_ident, tp_valtype, tp_specvalue, tp_defaultvalue);
1832             }
1833             tpl->push(tp);
1834             if (token.value != TOKcomma)
1835                 break;
1836             nextToken();
1837         }
1838     }
1839     check(TOKrparen);
1840 Lerr:
1841     return tpl;
1842 }
1843
1844 /******************************************
1845  * Parse template mixin.
1846  *      mixin Foo;
1847  *      mixin Foo!(args);
1848  *      mixin a.b.c!(args).Foo!(args);
1849  *      mixin Foo!(args) identifier;
1850  *      mixin typeof(expr).identifier!(args);
1851  */
1852
1853 Dsymbol *Parser::parseMixin()
1854 {
1855     TemplateMixin *tm;
1856     Identifier *id;
1857     Type *tqual;
1858     Objects *tiargs;
1859     Array *idents;
1860
1861     //printf("parseMixin()\n");
1862     nextToken();
1863     tqual = NULL;
1864     if (token.value == TOKdot)
1865     {
1866         id = Id::empty;
1867     }
1868     else
1869     {
1870         if (token.value == TOKtypeof)
1871         {
1872             tqual = parseTypeof();
1873             check(TOKdot);
1874         }
1875         if (token.value != TOKidentifier)
1876         {
1877             error("identifier expected, not %s", token.toChars());
1878             id = Id::empty;
1879         }
1880         else
1881             id = token.ident;
1882         nextToken();
1883     }
1884
1885     idents = new Array();
1886     while (1)
1887     {
1888         tiargs = NULL;
1889         if (token.value == TOKnot)
1890         {
1891             nextToken();
1892             if (token.value == TOKlparen)
1893                 tiargs = parseTemplateArgumentList();
1894             else
1895                 tiargs = parseTemplateArgument();
1896         }
1897
1898         if (token.value != TOKdot)
1899             break;
1900
1901         if (tiargs)
1902         {   TemplateInstance *tempinst = new TemplateInstance(loc, id);
1903             tempinst->tiargs = tiargs;
1904             id = (Identifier *)tempinst;
1905             tiargs = NULL;
1906         }
1907         idents->push(id);
1908
1909         nextToken();
1910         if (token.value != TOKidentifier)
1911         {   error("identifier expected following '.' instead of '%s'", token.toChars());
1912             break;
1913         }
1914         id = token.ident;
1915         nextToken();
1916     }
1917     idents->push(id);
1918
1919     if (token.value == TOKidentifier)
1920     {
1921         id = token.ident;
1922         nextToken();
1923     }
1924     else
1925         id = NULL;
1926
1927     tm = new TemplateMixin(loc, id, tqual, idents, tiargs);
1928     if (token.value != TOKsemicolon)
1929         error("';' expected after mixin");
1930     nextToken();
1931
1932     return tm;
1933 }
1934
1935 /******************************************
1936  * Parse template argument list.
1937  * Input:
1938  *      current token is opening '('
1939  * Output:
1940  *      current token is one after closing ')'
1941  */
1942
1943 Objects *Parser::parseTemplateArgumentList()
1944 {
1945     //printf("Parser::parseTemplateArgumentList()\n");
1946     if (token.value != TOKlparen && token.value != TOKlcurly)
1947     {   error("!(TemplateArgumentList) expected following TemplateIdentifier");
1948         return new Objects();
1949     }
1950     return parseTemplateArgumentList2();
1951 }
1952
1953 Objects *Parser::parseTemplateArgumentList2()
1954 {
1955     //printf("Parser::parseTemplateArgumentList2()\n");
1956     Objects *tiargs = new Objects();
1957     enum TOK endtok = TOKrparen;
1958     nextToken();
1959
1960     // Get TemplateArgumentList
1961     while (token.value != endtok)
1962     {
1963             // See if it is an Expression or a Type
1964             if (isDeclaration(&token, 0, TOKreserved, NULL))
1965             {   // Template argument is a type
1966                 Type *ta = parseType();
1967                 tiargs->push(ta);
1968             }
1969             else
1970             {   // Template argument is an expression
1971                 Expression *ea = parseAssignExp();
1972
1973                 if (ea->op == TOKfunction)
1974                 {   FuncLiteralDeclaration *fd = ((FuncExp *)ea)->fd;
1975                     if (fd->type->ty == Tfunction)
1976                     {
1977                         TypeFunction *tf = (TypeFunction *)fd->type;
1978                         /* If there are parameters that consist of only an identifier,
1979                          * rather than assuming the identifier is a type, as we would
1980                          * for regular function declarations, assume the identifier
1981                          * is the parameter name, and we're building a template with
1982                          * a deduced type.
1983                          */
1984                         TemplateParameters *tpl = NULL;
1985                         for (int i = 0; i < tf->parameters->dim; i++)
1986                         {   Parameter *param = (Parameter *)tf->parameters->data[i];
1987                             if (param->ident == NULL &&
1988                                 param->type &&
1989                                 param->type->ty == Tident &&
1990                                 ((TypeIdentifier *)param->type)->idents.dim == 0
1991                                )
1992                             {
1993                                 /* Switch parameter type to parameter identifier,
1994                                  * parameterize with template type parameter _T
1995                                  */
1996                                 TypeIdentifier *pt = (TypeIdentifier *)param->type;
1997                                 param->ident = pt->ident;
1998                                 Identifier *id = Lexer::uniqueId("__T");
1999                                 param->type = new TypeIdentifier(pt->loc, id);
2000                                 TemplateParameter *tp = new TemplateTypeParameter(fd->loc, id, NULL, NULL);
2001                                 if (!tpl)
2002                                     tpl = new TemplateParameters();
2003                                 tpl->push(tp);
2004                             }
2005                         }
2006
2007                         if (tpl)
2008                         {   // Wrap a template around function fd
2009                             Dsymbols *decldefs = new Dsymbols();
2010                             decldefs->push(fd);
2011                             TemplateDeclaration *tempdecl =
2012                                 new TemplateDeclaration(fd->loc, fd->ident, tpl, NULL, decldefs, 0);
2013                             tempdecl->literal = 1;      // it's a template 'literal'
2014                             tiargs->push(tempdecl);
2015                             goto L1;
2016                         }
2017                     }
2018                 }
2019
2020                 tiargs->push(ea);
2021             }
2022          L1:
2023             if (token.value != TOKcomma)
2024                 break;
2025             nextToken();
2026     }
2027     check(endtok, "template argument list");
2028     return tiargs;
2029 }
2030
2031 /*****************************
2032  * Parse single template argument, to support the syntax:
2033  *      foo!arg
2034  * Input:
2035  *      current token is the arg
2036  */
2037
2038 Objects *Parser::parseTemplateArgument()
2039 {
2040     //printf("parseTemplateArgument()\n");
2041     Objects *tiargs = new Objects();
2042     Type *ta;
2043     switch (token.value)
2044     {
2045         case TOKidentifier:
2046             ta = new TypeIdentifier(loc, token.ident);
2047             goto LabelX;
2048
2049         case BASIC_TYPES_X(ta):
2050             tiargs->push(ta);
2051             nextToken();
2052             break;
2053
2054         case TOKint32v:
2055         case TOKuns32v:
2056         case TOKint64v:
2057         case TOKuns64v:
2058         case TOKfloat32v:
2059         case TOKfloat64v:
2060         case TOKfloat80v:
2061         case TOKimaginary32v:
2062         case TOKimaginary64v:
2063         case TOKimaginary80v:
2064         case TOKnull:
2065         case TOKtrue:
2066         case TOKfalse:
2067         case TOKcharv:
2068         case TOKwcharv:
2069         case TOKdcharv:
2070         case TOKstring:
2071         case TOKfile:
2072         case TOKline:
2073         {   // Template argument is an expression
2074             Expression *ea = parsePrimaryExp();
2075             tiargs->push(ea);
2076             break;
2077         }
2078
2079         default:
2080             error("template argument expected following !");
2081             break;
2082     }
2083     if (token.value == TOKnot)
2084         error("multiple ! arguments are not allowed");
2085     return tiargs;
2086 }
2087
2088 Import *Parser::parseImport(Dsymbols *decldefs, int isstatic)
2089 {   Import *s;
2090     Identifier *id;
2091     Identifier *aliasid = NULL;
2092     Array *a;
2093     Loc loc;
2094
2095     //printf("Parser::parseImport()\n");
2096     do
2097     {
2098      L1:
2099         nextToken();
2100         if (token.value != TOKidentifier)
2101         {   error("Identifier expected following import");
2102             break;
2103         }
2104
2105         loc = this->loc;
2106         a = NULL;
2107         id = token.ident;
2108         nextToken();
2109         if (!aliasid && token.value == TOKassign)
2110         {
2111             aliasid = id;
2112             goto L1;
2113         }
2114         while (token.value == TOKdot)
2115         {
2116             if (!a)
2117                 a = new Array();
2118             a->push(id);
2119             nextToken();
2120             if (token.value != TOKidentifier)
2121             {   error("identifier expected following package");
2122                 break;
2123             }
2124             id = token.ident;
2125             nextToken();
2126         }
2127
2128         s = new Import(loc, a, id, aliasid, isstatic);
2129         decldefs->push(s);
2130
2131         /* Look for
2132          *      : alias=name, alias=name;
2133          * syntax.
2134          */
2135         if (token.value == TOKcolon)
2136         {
2137             do
2138             {   Identifier *name;
2139
2140                 nextToken();
2141                 if (token.value != TOKidentifier)
2142                 {   error("Identifier expected following :");
2143                     break;
2144                 }
2145                 Identifier *alias = token.ident;
2146                 nextToken();
2147                 if (token.value == TOKassign)
2148                 {
2149                     nextToken();
2150                     if (token.value != TOKidentifier)
2151                     {   error("Identifier expected following %s=", alias->toChars());
2152                         break;
2153                     }
2154                     name = token.ident;
2155                     nextToken();
2156                 }
2157                 else
2158                 {   name = alias;
2159                     alias = NULL;
2160                 }
2161                 s->addAlias(name, alias);
2162             } while (token.value == TOKcomma);
2163             break;      // no comma-separated imports of this form
2164         }
2165
2166         aliasid = NULL;
2167     } while (token.value == TOKcomma);
2168
2169     if (token.value == TOKsemicolon)
2170         nextToken();
2171     else
2172     {
2173         error("';' expected");
2174         nextToken();
2175     }
2176
2177     return NULL;
2178 }
2179
2180 #if DMDV2
2181 Type *Parser::parseType(Identifier **pident, TemplateParameters **tpl)
2182 {   Type *t;
2183
2184     /* Take care of the storage class prefixes that
2185      * serve as type attributes:
2186      *  const shared, shared const, const, invariant, shared
2187      */
2188     if (token.value == TOKconst && peekNext() == TOKshared && peekNext2() != TOKlparen ||
2189         token.value == TOKshared && peekNext() == TOKconst && peekNext2() != TOKlparen)
2190     {
2191         nextToken();
2192         nextToken();
2193         /* shared const type
2194          */
2195         t = parseType(pident, tpl);
2196         t = t->makeSharedConst();
2197         return t;
2198     }
2199     else if (token.value == TOKwild && peekNext() == TOKshared && peekNext2() != TOKlparen ||
2200         token.value == TOKshared && peekNext() == TOKwild && peekNext2() != TOKlparen)
2201     {
2202         nextToken();
2203         nextToken();
2204         /* shared wild type
2205          */
2206         t = parseType(pident, tpl);
2207         t = t->makeSharedWild();
2208         return t;
2209     }
2210     else if (token.value == TOKconst && peekNext() != TOKlparen)
2211     {
2212         nextToken();
2213         /* const type
2214          */
2215         t = parseType(pident, tpl);
2216         t = t->makeConst();
2217         return t;
2218     }
2219     else if ((token.value == TOKinvariant || token.value == TOKimmutable) &&
2220              peekNext() != TOKlparen)
2221     {
2222         nextToken();
2223         /* invariant type
2224          */
2225         t = parseType(pident, tpl);
2226         t = t->makeInvariant();
2227         return t;
2228     }
2229     else if (token.value == TOKshared && peekNext() != TOKlparen)
2230     {
2231         nextToken();
2232         /* shared type
2233          */
2234         t = parseType(pident, tpl);
2235         t = t->makeShared();
2236         return t;
2237     }
2238     else if (token.value == TOKwild && peekNext() != TOKlparen)
2239     {
2240         nextToken();
2241         /* wild type
2242          */
2243         t = parseType(pident, tpl);
2244         t = t->makeWild();
2245         return t;
2246     }
2247     else
2248         t = parseBasicType();
2249     t = parseDeclarator(t, pident, tpl);
2250     return t;
2251 }
2252 #endif
2253
2254 Type *Parser::parseBasicType()
2255 {   Type *t;
2256     Identifier *id;
2257     TypeQualified *tid;
2258
2259     //printf("parseBasicType()\n");
2260     switch (token.value)
2261     {
2262         case BASIC_TYPES_X(t):
2263             nextToken();
2264             break;
2265
2266         case TOKidentifier:
2267             id = token.ident;
2268             nextToken();
2269             if (token.value == TOKnot)
2270             {   // ident!(template_arguments)
2271                 TemplateInstance *tempinst = new TemplateInstance(loc, id);
2272                 nextToken();
2273                 if (token.value == TOKlparen)
2274                     // ident!(template_arguments)
2275                     tempinst->tiargs = parseTemplateArgumentList();
2276                 else
2277                     // ident!template_argument
2278                     tempinst->tiargs = parseTemplateArgument();
2279                 tid = new TypeInstance(loc, tempinst);
2280                 goto Lident2;
2281             }
2282         Lident:
2283             tid = new TypeIdentifier(loc, id);
2284         Lident2:
2285             while (token.value == TOKdot)
2286             {   nextToken();
2287                 if (token.value != TOKidentifier)
2288                 {   error("identifier expected following '.' instead of '%s'", token.toChars());
2289                     break;
2290                 }
2291                 id = token.ident;
2292                 nextToken();
2293                 if (token.value == TOKnot)
2294                 {
2295                     TemplateInstance *tempinst = new TemplateInstance(loc, id);
2296                     nextToken();
2297                     if (token.value == TOKlparen)
2298                         // ident!(template_arguments)
2299                         tempinst->tiargs = parseTemplateArgumentList();
2300                     else
2301                         // ident!template_argument
2302                         tempinst->tiargs = parseTemplateArgument();
2303                     tid->addIdent((Identifier *)tempinst);
2304                 }
2305                 else
2306                     tid->addIdent(id);
2307             }
2308             t = tid;
2309             break;
2310
2311         case TOKdot:
2312             // Leading . as in .foo
2313             id = Id::empty;
2314             goto Lident;
2315
2316         case TOKtypeof:
2317             // typeof(expression)
2318             tid = parseTypeof();
2319             goto Lident2;
2320
2321         case TOKconst:
2322             // const(type)
2323             nextToken();
2324             check(TOKlparen);
2325             t = parseType();
2326             check(TOKrparen);
2327             if (t->isShared())
2328                 t = t->makeSharedConst();
2329             else
2330                 t = t->makeConst();
2331             break;
2332
2333         case TOKinvariant:
2334             if (!global.params.useDeprecated)
2335                 error("use of 'invariant' rather than 'immutable' is deprecated");
2336         case TOKimmutable:
2337             // invariant(type)
2338             nextToken();
2339             check(TOKlparen);
2340             t = parseType();
2341             check(TOKrparen);
2342             t = t->makeInvariant();
2343             break;
2344
2345         case TOKshared:
2346             // shared(type)
2347             nextToken();
2348             check(TOKlparen);
2349             t = parseType();
2350             check(TOKrparen);
2351             if (t->isConst())
2352                 t = t->makeSharedConst();
2353             else if (t->isWild())
2354                 t = t->makeSharedWild();
2355             else
2356                 t = t->makeShared();
2357             break;
2358
2359         case TOKwild:
2360             // wild(type)
2361             nextToken();
2362             check(TOKlparen);
2363             t = parseType();
2364             check(TOKrparen);
2365             if (t->isShared())
2366                 t = t->makeSharedWild();
2367             else
2368                 t = t->makeWild();
2369             break;
2370
2371         default:
2372             error("basic type expected, not %s", token.toChars());
2373             t = Type::tint32;
2374             break;
2375     }
2376     return t;
2377 }
2378
2379 /******************************************
2380  * Parse things that follow the initial type t.
2381  *      t *
2382  *      t []
2383  *      t [type]
2384  *      t [expression]
2385  *      t [expression .. expression]
2386  *      t function
2387  *      t delegate
2388  */
2389
2390 Type *Parser::parseBasicType2(Type *t)
2391 {
2392     //printf("parseBasicType2()\n");
2393     while (1)
2394     {
2395         switch (token.value)
2396         {
2397             case TOKmul:
2398                 t = new TypePointer(t);
2399                 nextToken();
2400                 continue;
2401
2402             case TOKlbracket:
2403                 // Handle []. Make sure things like
2404                 //     int[3][1] a;
2405                 // is (array[1] of array[3] of int)
2406                 nextToken();
2407                 if (token.value == TOKrbracket)
2408                 {
2409                     t = new TypeDArray(t);                      // []
2410                     nextToken();
2411                 }
2412                 else if (isDeclaration(&token, 0, TOKrbracket, NULL))
2413                 {   // It's an associative array declaration
2414
2415                     //printf("it's an associative array\n");
2416                     Type *index = parseType();          // [ type ]
2417                     t = new TypeAArray(t, index);
2418                     check(TOKrbracket);
2419                 }
2420                 else
2421                 {
2422                     //printf("it's type[expression]\n");
2423                     inBrackets++;
2424                     Expression *e = parseAssignExp();           // [ expression ]
2425                     if (token.value == TOKslice)
2426                     {
2427                         nextToken();
2428                         Expression *e2 = parseAssignExp();      // [ exp .. exp ]
2429                         t = new TypeSlice(t, e, e2);
2430                     }
2431                     else
2432                         t = new TypeSArray(t,e);
2433                     inBrackets--;
2434                     check(TOKrbracket);
2435                 }
2436                 continue;
2437
2438             case TOKdelegate:
2439             case TOKfunction:
2440             {   // Handle delegate declaration:
2441                 //      t delegate(parameter list) nothrow pure
2442                 //      t function(parameter list) nothrow pure
2443                 Parameters *arguments;
2444                 int varargs;
2445                 enum TOK save = token.value;
2446
2447                 nextToken();
2448                 arguments = parseParameters(&varargs);
2449
2450                 StorageClass stc = parsePostfix();
2451                 if (stc & (STCconst | STCimmutable | STCshared | STCwild))
2452                     error("const/immutable/shared/inout attributes are only valid for non-static member functions");
2453
2454                 TypeFunction *tf = new TypeFunction(arguments, t, varargs, linkage, stc);
2455
2456                 if (save == TOKdelegate)
2457                     t = new TypeDelegate(tf);
2458                 else
2459                     t = new TypePointer(tf);    // pointer to function
2460                 continue;
2461             }
2462
2463             default:
2464                 return t;
2465         }
2466         assert(0);
2467     }
2468     assert(0);
2469     return NULL;
2470 }
2471
2472 Type *Parser::parseDeclarator(Type *t, Identifier **pident, TemplateParameters **tpl)
2473 {   Type *ts;
2474
2475     //printf("parseDeclarator(tpl = %p)\n", tpl);
2476     t = parseBasicType2(t);
2477
2478     switch (token.value)
2479     {
2480
2481         case TOKidentifier:
2482             if (pident)
2483                 *pident = token.ident;
2484             else
2485                 error("unexpected identifer '%s' in declarator", token.ident->toChars());
2486             ts = t;
2487             nextToken();
2488             break;
2489
2490         case TOKlparen:
2491             if (peekNext() == TOKmul ||                 // like: T (*fp)();
2492                 peekNext() == TOKlparen                 // like: T ((*fp))();
2493                 /* || peekNext() == TOKlbracket*/)      // like: T ([] a)
2494             {
2495                 /* Parse things with parentheses around the identifier, like:
2496                  *  int (*ident[3])[]
2497                  * although the D style would be:
2498                  *  int[]*[3] ident
2499                  */
2500                 if (!global.params.useDeprecated)
2501                 {
2502                     error("C-style function pointer and pointer to array syntax is deprecated. Use 'function' to declare function pointers");
2503                 }
2504                 nextToken();
2505                 ts = parseDeclarator(t, pident);
2506                 check(TOKrparen);
2507                 break;
2508             }
2509             ts = t;
2510         {
2511             Token *peekt = &token;
2512             /* Completely disallow C-style things like:
2513              *   T (a);
2514              * Improve error messages for the common bug of a missing return type
2515              * by looking to see if (a) looks like a parameter list.
2516              */
2517             if (isParameters(&peekt)) {
2518                 error("function declaration without return type. "
2519                 "(Note that constructors are always named 'this')");
2520             }
2521             else
2522                 error("unexpected ( in declarator");
2523         }
2524             break;
2525
2526         default:
2527             ts = t;
2528             break;
2529     }
2530
2531     // parse DeclaratorSuffixes
2532     while (1)
2533     {
2534         switch (token.value)
2535         {
2536 #if CARRAYDECL
2537             /* Support C style array syntax:
2538              *   int ident[]
2539              * as opposed to D-style:
2540              *   int[] ident
2541              */
2542             case TOKlbracket:
2543             {   // This is the old C-style post [] syntax.
2544                 TypeNext *ta;
2545                 nextToken();
2546                 if (token.value == TOKrbracket)
2547                 {   // It's a dynamic array
2548                     ta = new TypeDArray(t);             // []
2549                     nextToken();
2550                 }
2551                 else if (isDeclaration(&token, 0, TOKrbracket, NULL))
2552                 {   // It's an associative array
2553
2554                     //printf("it's an associative array\n");
2555                     Type *index = parseType();          // [ type ]
2556                     check(TOKrbracket);
2557                     ta = new TypeAArray(t, index);
2558                 }
2559                 else
2560                 {
2561                     //printf("It's a static array\n");
2562                     Expression *e = parseAssignExp();   // [ expression ]
2563                     ta = new TypeSArray(t, e);
2564                     check(TOKrbracket);
2565                 }
2566
2567                 /* Insert ta into
2568                  *   ts -> ... -> t
2569                  * so that
2570                  *   ts -> ... -> ta -> t
2571                  */
2572                 Type **pt;
2573                 for (pt = &ts; *pt != t; pt = &((TypeNext*)*pt)->next)
2574                     ;
2575                 *pt = ta;
2576                 continue;
2577             }
2578 #endif
2579             case TOKlparen:
2580             {
2581                 if (tpl)
2582                 {
2583                     /* Look ahead to see if this is (...)(...),
2584                      * i.e. a function template declaration
2585                      */
2586                     if (peekPastParen(&token)->value == TOKlparen)
2587                     {
2588                         //printf("function template declaration\n");
2589
2590                         // Gather template parameter list
2591                         *tpl = parseTemplateParameterList();
2592                     }
2593                 }
2594
2595                 int varargs;
2596                 Parameters *arguments = parseParameters(&varargs);
2597
2598                 /* Parse const/immutable/shared/inout/nothrow/pure postfix
2599                  */
2600                 StorageClass stc = parsePostfix();
2601                 Type *tf = new TypeFunction(arguments, t, varargs, linkage, stc);
2602
2603                 if (stc & STCconst)
2604                 {   if (tf->isShared())
2605                         tf = tf->makeSharedConst();
2606                     else
2607                         tf = tf->makeConst();
2608                 }
2609                 if (stc & STCimmutable)
2610                     tf = tf->makeInvariant();
2611                 if (stc & STCshared)
2612                 {   if (tf->isConst())
2613                         tf = tf->makeSharedConst();
2614                     else
2615                         tf = tf->makeShared();
2616                 }
2617                 if (stc & STCwild)
2618                 {   if (tf->isShared())
2619                         tf = tf->makeSharedWild();
2620                     else
2621                         tf = tf->makeWild();
2622                 }
2623
2624                 /* Insert tf into
2625                  *   ts -> ... -> t
2626                  * so that
2627                  *   ts -> ... -> tf -> t
2628                  */
2629                 Type **pt;
2630                 for (pt = &ts; *pt != t; pt = &((TypeNext*)*pt)->next)
2631                     ;
2632                 *pt = tf;
2633                 break;
2634             }
2635         }
2636         break;
2637     }
2638
2639     return ts;
2640 }
2641
2642 /**********************************
2643  * Parse Declarations.
2644  * These can be:
2645  *      1. declarations at global/class level
2646  *      2. declarations at statement level
2647  * Return array of Declaration *'s.
2648  */
2649
2650 Dsymbols *Parser::parseDeclarations(StorageClass storage_class, unsigned char *comment)
2651 {
2652     StorageClass stc;
2653     Type *ts;
2654     Type *t;
2655     Type *tfirst;
2656     Identifier *ident;
2657     Dsymbols *a;
2658     enum TOK tok = TOKreserved;
2659     enum LINK link = linkage;
2660
2661     //printf("parseDeclarations() %s\n", token.toChars());
2662     if (!comment)
2663         comment = token.blockComment;
2664
2665     if (storage_class)
2666     {   ts = NULL;              // infer type
2667         goto L2;
2668     }
2669
2670     switch (token.value)
2671     {
2672         case TOKalias:
2673             /* Look for:
2674              *   alias identifier this;
2675              */
2676             tok = token.value;
2677             nextToken();
2678             if (token.value == TOKidentifier && peek(&token)->value == TOKthis)
2679             {
2680                 AliasThis *s = new AliasThis(this->loc, token.ident);
2681                 nextToken();
2682                 check(TOKthis);
2683                 check(TOKsemicolon);
2684                 a = new Dsymbols();
2685                 a->push(s);
2686                 addComment(s, comment);
2687                 return a;
2688             }
2689             break;
2690         case TOKtypedef:
2691             tok = token.value;
2692             nextToken();
2693             break;
2694     }
2695
2696     storage_class = STCundefined;
2697     while (1)
2698     {
2699         switch (token.value)
2700         {
2701             case TOKconst:
2702                 if (peek(&token)->value == TOKlparen)
2703                     break;              // const as type constructor
2704                 stc = STCconst;         // const as storage class
2705                 goto L1;
2706
2707             case TOKinvariant:
2708             case TOKimmutable:
2709                 if (peek(&token)->value == TOKlparen)
2710                     break;
2711                 stc = STCimmutable;
2712                 goto L1;
2713
2714             case TOKshared:
2715                 if (peek(&token)->value == TOKlparen)
2716                     break;
2717                 stc = STCshared;
2718                 goto L1;
2719
2720             case TOKwild:
2721                 if (peek(&token)->value == TOKlparen)
2722                     break;
2723                 stc = STCwild;
2724                 goto L1;
2725
2726             case TOKstatic:     stc = STCstatic;         goto L1;
2727             case TOKfinal:      stc = STCfinal;          goto L1;
2728             case TOKauto:       stc = STCauto;           goto L1;
2729             case TOKscope:      stc = STCscope;          goto L1;
2730             case TOKoverride:   stc = STCoverride;       goto L1;
2731             case TOKabstract:   stc = STCabstract;       goto L1;
2732             case TOKsynchronized: stc = STCsynchronized; goto L1;
2733             case TOKdeprecated: stc = STCdeprecated;     goto L1;
2734 #if DMDV2
2735             case TOKnothrow:    stc = STCnothrow;        goto L1;
2736             case TOKpure:       stc = STCpure;           goto L1;
2737             case TOKref:        stc = STCref;            goto L1;
2738             case TOKtls:        stc = STCtls;            goto L1;
2739             case TOKgshared:    stc = STCgshared;        goto L1;
2740             case TOKenum:       stc = STCmanifest;       goto L1;
2741             case TOKat:         stc = parseAttribute();  goto L1;
2742 #endif
2743             L1:
2744                 if (storage_class & stc)
2745                     error("redundant storage class '%s'", token.toChars());
2746                 storage_class = storage_class | stc;
2747                 composeStorageClass(storage_class);
2748                 nextToken();
2749                 continue;
2750
2751             case TOKextern:
2752                 if (peek(&token)->value != TOKlparen)
2753                 {   stc = STCextern;
2754                     goto L1;
2755                 }
2756
2757                 link = parseLinkage();
2758                 continue;
2759
2760             default:
2761                 break;
2762         }
2763         break;
2764     }
2765
2766     /* Look for auto initializers:
2767      *  storage_class identifier = initializer;
2768      */
2769     if (storage_class &&
2770         token.value == TOKidentifier &&
2771         peek(&token)->value == TOKassign)
2772     {
2773         return parseAutoDeclarations(storage_class, comment);
2774     }
2775
2776     if (token.value == TOKclass)
2777     {
2778         AggregateDeclaration *s = (AggregateDeclaration *)parseAggregate();
2779         s->storage_class |= storage_class;
2780         Dsymbols *a = new Dsymbols();
2781         a->push(s);
2782         addComment(s, comment);
2783         return a;
2784     }
2785
2786     /* Look for return type inference for template functions.
2787      */
2788     {
2789     Token *tk;
2790     if (storage_class &&
2791         token.value == TOKidentifier &&
2792         (tk = peek(&token))->value == TOKlparen &&
2793         skipParens(tk, &tk) &&
2794         peek(tk)->value == TOKlparen)
2795     {
2796         ts = NULL;
2797     }
2798     else
2799     {
2800         ts = parseBasicType();
2801         ts = parseBasicType2(ts);
2802     }
2803     }
2804
2805 L2:
2806     tfirst = NULL;
2807     a = new Dsymbols();
2808
2809     while (1)
2810     {
2811         Loc loc = this->loc;
2812         TemplateParameters *tpl = NULL;
2813
2814         ident = NULL;
2815         t = parseDeclarator(ts, &ident, &tpl);
2816         assert(t);
2817         if (!tfirst)
2818             tfirst = t;
2819         else if (t != tfirst)
2820             error("multiple declarations must have the same type, not %s and %s",
2821                 tfirst->toChars(), t->toChars());
2822         if (!ident)
2823             error("no identifier for declarator %s", t->toChars());
2824
2825         if (tok == TOKtypedef || tok == TOKalias)
2826         {   Declaration *v;
2827             Initializer *init = NULL;
2828
2829             if (token.value == TOKassign)
2830             {
2831                 nextToken();
2832                 init = parseInitializer();
2833             }
2834             if (tok == TOKtypedef)
2835                 v = new TypedefDeclaration(loc, ident, t, init);
2836             else
2837             {   if (init)
2838                     error("alias cannot have initializer");
2839                 v = new AliasDeclaration(loc, ident, t);
2840             }
2841             v->storage_class = storage_class;
2842             if (link == linkage)
2843                 a->push(v);
2844             else
2845             {
2846                 Dsymbols *ax = new Dsymbols();
2847                 ax->push(v);
2848                 Dsymbol *s = new LinkDeclaration(link, ax);
2849                 a->push(s);
2850             }
2851             switch (token.value)
2852             {   case TOKsemicolon:
2853                     nextToken();
2854                     addComment(v, comment);
2855                     break;
2856
2857                 case TOKcomma:
2858                     nextToken();
2859                     addComment(v, comment);
2860                     continue;
2861
2862                 default:
2863                     error("semicolon expected to close %s declaration", Token::toChars(tok));
2864                     break;
2865             }
2866         }
2867         else if (t->ty == Tfunction)
2868         {
2869             TypeFunction *tf = (TypeFunction *)t;
2870             Expression *constraint = NULL;
2871 #if 0
2872             if (Parameter::isTPL(tf->parameters))
2873             {
2874                 if (!tpl)
2875                     tpl = new TemplateParameters();
2876             }
2877 #endif
2878             FuncDeclaration *f =
2879                 new FuncDeclaration(loc, 0, ident, storage_class, t);
2880             addComment(f, comment);
2881             if (tpl)
2882                 constraint = parseConstraint();
2883             parseContracts(f);
2884             addComment(f, NULL);
2885             Dsymbol *s;
2886             if (link == linkage)
2887             {
2888                 s = f;
2889             }
2890             else
2891             {
2892                 Dsymbols *ax = new Dsymbols();
2893                 ax->push(f);
2894                 s = new LinkDeclaration(link, ax);
2895             }
2896             /* A template parameter list means it's a function template
2897              */
2898             if (tpl)
2899             {
2900                 // Wrap a template around the function declaration
2901                 Dsymbols *decldefs = new Dsymbols();
2902                 decldefs->push(s);
2903                 TemplateDeclaration *tempdecl =
2904                     new TemplateDeclaration(loc, s->ident, tpl, constraint, decldefs, 0);
2905                 s = tempdecl;
2906             }
2907             addComment(s, comment);
2908             a->push(s);
2909         }
2910         else
2911         {
2912             Initializer *init = NULL;
2913             if (token.value == TOKassign)
2914             {
2915                 nextToken();
2916                 init = parseInitializer();
2917             }
2918
2919             VarDeclaration *v = new VarDeclaration(loc, t, ident, init);
2920             v->storage_class = storage_class;
2921             if (link == linkage)
2922                 a->push(v);
2923             else
2924             {
2925                 Dsymbols *ax = new Dsymbols();
2926                 ax->push(v);
2927                 Dsymbol *s = new LinkDeclaration(link, ax);
2928                 a->push(s);
2929             }
2930             switch (token.value)
2931             {   case TOKsemicolon:
2932                     nextToken();
2933                     addComment(v, comment);
2934                     break;
2935
2936                 case TOKcomma:
2937                     nextToken();
2938                     addComment(v, comment);
2939                     continue;
2940
2941                 default:
2942                     error("semicolon expected, not '%s'", token.toChars());
2943                     break;
2944             }
2945         }
2946         break;
2947     }
2948     return a;
2949 }
2950
2951 /*****************************************
2952  * Parse auto declarations of the form:
2953  *   storageClass ident = init, ident = init, ... ;
2954  * and return the array of them.
2955  * Starts with token on the first ident.
2956  * Ends with scanner past closing ';'
2957  */
2958
2959 #if DMDV2
2960 Dsymbols *Parser::parseAutoDeclarations(StorageClass storageClass, unsigned char *comment)
2961 {
2962     Dsymbols *a = new Dsymbols;
2963
2964     while (1)
2965     {
2966         Identifier *ident = token.ident;
2967         nextToken();            // skip over ident
2968         assert(token.value == TOKassign);
2969         nextToken();            // skip over '='
2970         Initializer *init = parseInitializer();
2971         VarDeclaration *v = new VarDeclaration(loc, NULL, ident, init);
2972         v->storage_class = storageClass;
2973         a->push(v);
2974         if (token.value == TOKsemicolon)
2975         {
2976             nextToken();
2977             addComment(v, comment);
2978         }
2979         else if (token.value == TOKcomma)
2980         {
2981             nextToken();
2982             if (token.value == TOKidentifier &&
2983                 peek(&token)->value == TOKassign)
2984             {
2985                 addComment(v, comment);
2986                 continue;
2987             }
2988             else
2989                 error("Identifier expected following comma");
2990         }
2991         else
2992             error("semicolon expected following auto declaration, not '%s'", token.toChars());
2993         break;
2994     }
2995     return a;
2996 }
2997 #endif
2998
2999 /*****************************************
3000  * Parse contracts following function declaration.
3001  */
3002
3003 void Parser::parseContracts(FuncDeclaration *f)
3004 {
3005     enum LINK linksave = linkage;
3006
3007     // The following is irrelevant, as it is overridden by sc->linkage in
3008     // TypeFunction::semantic
3009     linkage = LINKd;            // nested functions have D linkage
3010 L1:
3011     switch (token.value)
3012     {
3013         case TOKlcurly:
3014             if (f->frequire || f->fensure)
3015                 error("missing body { ... } after in or out");
3016             f->fbody = parseStatement(PSsemi);
3017             f->endloc = endloc;
3018             break;
3019
3020         case TOKbody:
3021             nextToken();
3022             f->fbody = parseStatement(PScurly);
3023             f->endloc = endloc;
3024             break;
3025
3026         case TOKsemicolon:
3027             if (f->frequire || f->fensure)
3028                 error("missing body { ... } after in or out");
3029             nextToken();
3030             break;
3031
3032 #if 0   // Do we want this for function declarations, so we can do:
3033     // int x, y, foo(), z;
3034         case TOKcomma:
3035             nextToken();
3036             continue;
3037 #endif
3038
3039 #if 0 // Dumped feature
3040         case TOKthrow:
3041             if (!f->fthrows)
3042                 f->fthrows = new Array();
3043             nextToken();
3044             check(TOKlparen);
3045             while (1)
3046             {
3047                 Type *tb = parseBasicType();
3048                 f->fthrows->push(tb);
3049                 if (token.value == TOKcomma)
3050                 {   nextToken();
3051                     continue;
3052                 }
3053                 break;
3054             }
3055             check(TOKrparen);
3056             goto L1;
3057 #endif
3058
3059         case TOKin:
3060             nextToken();
3061             if (f->frequire)
3062                 error("redundant 'in' statement");
3063             f->frequire = parseStatement(PScurly | PSscope);
3064             goto L1;
3065
3066         case TOKout:
3067             // parse: out (identifier) { statement }
3068             nextToken();
3069             if (token.value != TOKlcurly)
3070             {
3071                 check(TOKlparen);
3072                 if (token.value != TOKidentifier)
3073                     error("(identifier) following 'out' expected, not %s", token.toChars());
3074                 f->outId = token.ident;
3075                 nextToken();
3076                 check(TOKrparen);
3077             }
3078             if (f->fensure)
3079                 error("redundant 'out' statement");
3080             f->fensure = parseStatement(PScurly | PSscope);
3081             goto L1;
3082
3083         default:
3084             if (!f->frequire && !f->fensure)            // allow these even with no body
3085                 error("semicolon expected following function declaration");
3086             break;
3087     }
3088     linkage = linksave;
3089 }
3090
3091 /*****************************************
3092  * Parse initializer for variable declaration.
3093  */
3094
3095 Initializer *Parser::parseInitializer()
3096 {
3097     StructInitializer *is;
3098     ArrayInitializer *ia;
3099     ExpInitializer *ie;
3100     Expression *e;
3101     Identifier *id;
3102     Initializer *value;
3103     int comma;
3104     Loc loc = this->loc;
3105     Token *t;
3106     int braces;
3107     int brackets;
3108
3109     switch (token.value)
3110     {
3111         case TOKlcurly:
3112             /* Scan ahead to see if it is a struct initializer or
3113              * a function literal.
3114              * If it contains a ';', it is a function literal.
3115              * Treat { } as a struct initializer.
3116              */
3117             braces = 1;
3118             for (t = peek(&token); 1; t = peek(t))
3119             {
3120                 switch (t->value)
3121                 {
3122                     case TOKsemicolon:
3123                     case TOKreturn:
3124                         goto Lexpression;
3125
3126                     case TOKlcurly:
3127                         braces++;
3128                         continue;
3129
3130                     case TOKrcurly:
3131                         if (--braces == 0)
3132                             break;
3133                         continue;
3134
3135                     case TOKeof:
3136                         break;
3137
3138                     default:
3139                         continue;
3140                 }
3141                 break;
3142             }
3143
3144             is = new StructInitializer(loc);
3145             nextToken();
3146             comma = 0;
3147             while (1)
3148             {
3149                 switch (token.value)
3150                 {
3151                     case TOKidentifier:
3152                         if (comma == 1)
3153                             error("comma expected separating field initializers");
3154                         t = peek(&token);
3155                         if (t->value == TOKcolon)
3156                         {
3157                             id = token.ident;
3158                             nextToken();
3159                             nextToken();        // skip over ':'
3160                         }
3161                         else
3162                         {   id = NULL;
3163                         }
3164                         value = parseInitializer();
3165                         is->addInit(id, value);
3166                         comma = 1;
3167                         continue;
3168
3169                     case TOKcomma:
3170                         nextToken();
3171                         comma = 2;
3172                         continue;
3173
3174                     case TOKrcurly:             // allow trailing comma's
3175                         nextToken();
3176                         break;
3177
3178                     case TOKeof:
3179                         error("found EOF instead of initializer");
3180                         break;
3181
3182                     default:
3183                         value = parseInitializer();
3184                         is->addInit(NULL, value);
3185                         comma = 1;
3186                         continue;
3187                         //error("found '%s' instead of field initializer", token.toChars());
3188                         //break;
3189                 }
3190                 break;
3191             }
3192             return is;
3193
3194         case TOKlbracket:
3195             /* Scan ahead to see if it is an array initializer or
3196              * an expression.
3197              * If it ends with a ';' ',' or '}', it is an array initializer.
3198              */
3199             brackets = 1;
3200             for (t = peek(&token); 1; t = peek(t))
3201             {
3202                 switch (t->value)
3203                 {
3204                     case TOKlbracket:
3205                         brackets++;
3206                         continue;
3207
3208                     case TOKrbracket:
3209                         if (--brackets == 0)
3210                         {   t = peek(t);
3211                             if (t->value != TOKsemicolon &&
3212                                 t->value != TOKcomma &&
3213                                 t->value != TOKrbracket &&
3214                                 t->value != TOKrcurly)
3215                                 goto Lexpression;
3216                             break;
3217                         }
3218                         continue;
3219
3220                     case TOKeof:
3221                         break;
3222
3223                     default:
3224                         continue;
3225                 }
3226                 break;
3227             }
3228
3229             ia = new ArrayInitializer(loc);
3230             nextToken();
3231             comma = 0;
3232             while (1)
3233             {
3234                 switch (token.value)
3235                 {
3236                     default:
3237                         if (comma == 1)
3238                         {   error("comma expected separating array initializers, not %s", token.toChars());
3239                             nextToken();
3240                             break;
3241                         }
3242                         e = parseAssignExp();
3243                         if (!e)
3244                             break;
3245                         if (token.value == TOKcolon)
3246                         {
3247                             nextToken();
3248                             value = parseInitializer();
3249                         }
3250                         else
3251                         {   value = new ExpInitializer(e->loc, e);
3252                             e = NULL;
3253                         }
3254                         ia->addInit(e, value);
3255                         comma = 1;
3256                         continue;
3257
3258                     case TOKlcurly:
3259                     case TOKlbracket:
3260                         if (comma == 1)
3261                             error("comma expected separating array initializers, not %s", token.toChars());
3262                         value = parseInitializer();
3263                         ia->addInit(NULL, value);
3264                         comma = 1;
3265                         continue;
3266
3267                     case TOKcomma:
3268                         nextToken();
3269                         comma = 2;
3270                         continue;
3271
3272                     case TOKrbracket:           // allow trailing comma's
3273                         nextToken();
3274                         break;
3275
3276                     case TOKeof:
3277                         error("found '%s' instead of array initializer", token.toChars());
3278                         break;
3279                 }
3280                 break;
3281             }
3282             return ia;
3283
3284         case TOKvoid:
3285             t = peek(&token);
3286             if (t->value == TOKsemicolon || t->value == TOKcomma)
3287             {
3288                 nextToken();
3289                 return new VoidInitializer(loc);
3290             }
3291             goto Lexpression;
3292
3293         default:
3294         Lexpression:
3295             e = parseAssignExp();
3296             ie = new ExpInitializer(loc, e);
3297             return ie;
3298     }
3299 }
3300
3301 /*****************************************
3302  * Parses default argument initializer expression that is an assign expression,
3303  * with special handling for __FILE__ and __LINE__.
3304  */
3305
3306 #if DMDV2
3307 Expression *Parser::parseDefaultInitExp()
3308 {
3309     if (token.value == TOKfile ||
3310         token.value == TOKline)
3311     {
3312         Token *t = peek(&token);
3313         if (t->value == TOKcomma || t->value == TOKrparen)
3314         {   Expression *e;
3315
3316             if (token.value == TOKfile)
3317                 e = new FileInitExp(loc);
3318             else
3319                 e = new LineInitExp(loc);
3320             nextToken();
3321             return e;
3322         }
3323     }
3324
3325     Expression *e = parseAssignExp();
3326     return e;
3327 }
3328 #endif
3329
3330 /*****************************************
3331  * Input:
3332  *      flags   PSxxxx
3333  */
3334
3335 Statement *Parser::parseStatement(int flags)
3336 {   Statement *s;
3337     Token *t;
3338     Condition *condition;
3339     Statement *ifbody;
3340     Statement *elsebody;
3341     bool isfinal;
3342     Loc loc = this->loc;
3343
3344     //printf("parseStatement()\n");
3345
3346     if (flags & PScurly && token.value != TOKlcurly)
3347         error("statement expected to be { }, not %s", token.toChars());
3348
3349     switch (token.value)
3350     {
3351         case TOKidentifier:
3352             /* A leading identifier can be a declaration, label, or expression.
3353              * The easiest case to check first is label:
3354              */
3355             t = peek(&token);
3356             if (t->value == TOKcolon)
3357             {   // It's a label
3358
3359                 Identifier *ident = token.ident;
3360                 nextToken();
3361                 nextToken();
3362                 s = parseStatement(PSsemi);
3363                 s = new LabelStatement(loc, ident, s);
3364                 break;
3365             }
3366             // fallthrough to TOKdot
3367         case TOKdot:
3368         case TOKtypeof:
3369             if (isDeclaration(&token, 2, TOKreserved, NULL))
3370                 goto Ldeclaration;
3371             else
3372                 goto Lexp;
3373             break;
3374
3375         case TOKassert:
3376         case TOKthis:
3377         case TOKsuper:
3378         case TOKint32v:
3379         case TOKuns32v:
3380         case TOKint64v:
3381         case TOKuns64v:
3382         case TOKfloat32v:
3383         case TOKfloat64v:
3384         case TOKfloat80v:
3385         case TOKimaginary32v:
3386         case TOKimaginary64v:
3387         case TOKimaginary80v:
3388         case TOKcharv:
3389         case TOKwcharv:
3390         case TOKdcharv:
3391         case TOKnull:
3392         case TOKtrue:
3393         case TOKfalse:
3394         case TOKstring:
3395         case TOKlparen:
3396         case TOKcast:
3397         case TOKmul:
3398         case TOKmin:
3399         case TOKadd:
3400         case TOKtilde:
3401         case TOKnot:
3402         case TOKplusplus:
3403         case TOKminusminus:
3404         case TOKnew:
3405         case TOKdelete:
3406         case TOKdelegate:
3407         case TOKfunction:
3408         case TOKtypeid:
3409         case TOKis:
3410         case TOKlbracket:
3411 #if DMDV2
3412         case TOKtraits:
3413         case TOKfile:
3414         case TOKline:
3415 #endif
3416         Lexp:
3417         {
3418             Expression *exp = parseExpression();
3419             check(TOKsemicolon, "statement");
3420             s = new ExpStatement(loc, exp);
3421             break;
3422         }
3423
3424         case TOKstatic:
3425         {   // Look ahead to see if it's static assert() or static if()
3426             Token *t;
3427
3428             t = peek(&token);
3429             if (t->value == TOKassert)
3430             {
3431                 nextToken();
3432                 s = new StaticAssertStatement(parseStaticAssert());
3433                 break;
3434             }
3435             if (t->value == TOKif)
3436             {
3437                 nextToken();
3438                 condition = parseStaticIfCondition();
3439                 goto Lcondition;
3440             }
3441             if (t->value == TOKstruct || t->value == TOKunion || t->value == TOKclass)
3442             {
3443                 nextToken();
3444                 Dsymbols *a = parseBlock();
3445                 Dsymbol *d = new StorageClassDeclaration(STCstatic, a);
3446                 s = new DeclarationStatement(loc, d);
3447                 if (flags & PSscope)
3448                     s = new ScopeStatement(loc, s);
3449                 break;
3450             }
3451             goto Ldeclaration;
3452         }
3453
3454         case TOKfinal:
3455             if (peekNext() == TOKswitch)
3456             {
3457                 nextToken();
3458                 isfinal = TRUE;
3459                 goto Lswitch;
3460             }
3461             goto Ldeclaration;
3462
3463         case BASIC_TYPES:
3464         case TOKtypedef:
3465         case TOKalias:
3466         case TOKconst:
3467         case TOKauto:
3468         case TOKextern:
3469         case TOKinvariant:
3470 #if DMDV2
3471         case TOKimmutable:
3472         case TOKshared:
3473         case TOKwild:
3474         case TOKnothrow:
3475         case TOKpure:
3476         case TOKtls:
3477         case TOKgshared:
3478         case TOKat:
3479 #endif
3480 //      case TOKtypeof:
3481         Ldeclaration:
3482         {   Array *a;
3483
3484             a = parseDeclarations(STCundefined, NULL);
3485             if (a->dim > 1)
3486             {
3487                 Statements *as = new Statements();
3488                 as->reserve(a->dim);
3489                 for (int i = 0; i < a->dim; i++)
3490                 {
3491                     Dsymbol *d = (Dsymbol *)a->data[i];
3492                     s = new DeclarationStatement(loc, d);
3493                     as->push(s);
3494                 }
3495                 s = new CompoundDeclarationStatement(loc, as);
3496             }
3497             else if (a->dim == 1)
3498             {
3499                 Dsymbol *d = (Dsymbol *)a->data[0];
3500                 s = new DeclarationStatement(loc, d);
3501             }
3502             else
3503                 assert(0);
3504             if (flags & PSscope)
3505                 s = new ScopeStatement(loc, s);
3506             break;
3507         }
3508
3509         case TOKstruct:
3510         case TOKunion:
3511         case TOKclass:
3512         case TOKinterface:
3513         {   Dsymbol *d;
3514
3515             d = parseAggregate();
3516             s = new DeclarationStatement(loc, d);
3517             break;
3518         }
3519
3520         case TOKenum:
3521         {   /* Determine if this is a manifest constant declaration,
3522              * or a conventional enum.
3523              */
3524             Dsymbol *d;
3525             Token *t = peek(&token);
3526             if (t->value == TOKlcurly || t->value == TOKcolon)
3527                 d = parseEnum();
3528             else if (t->value != TOKidentifier)
3529                 goto Ldeclaration;
3530             else
3531             {
3532                 t = peek(t);
3533                 if (t->value == TOKlcurly || t->value == TOKcolon ||
3534                     t->value == TOKsemicolon)
3535                     d = parseEnum();
3536                 else
3537                     goto Ldeclaration;
3538             }
3539             s = new DeclarationStatement(loc, d);
3540             break;
3541         }
3542
3543         case TOKmixin:
3544         {   t = peek(&token);
3545             if (t->value == TOKlparen)
3546             {   // mixin(string)
3547                 nextToken();
3548                 check(TOKlparen, "mixin");
3549                 Expression *e = parseAssignExp();
3550                 check(TOKrparen);
3551                 check(TOKsemicolon);
3552                 s = new CompileStatement(loc, e);
3553                 break;
3554             }
3555             Dsymbol *d = parseMixin();
3556             s = new DeclarationStatement(loc, d);
3557             break;
3558         }
3559
3560         case TOKlcurly:
3561         {
3562             nextToken();
3563             //if (token.value == TOKsemicolon)
3564                 //error("use '{ }' for an empty statement, not a ';'");
3565             Statements *statements = new Statements();
3566             while (token.value != TOKrcurly && token.value != TOKeof)
3567             {
3568                 statements->push(parseStatement(PSsemi | PScurlyscope));
3569             }
3570             endloc = this->loc;
3571             s = new CompoundStatement(loc, statements);
3572             if (flags & (PSscope | PScurlyscope))
3573                 s = new ScopeStatement(loc, s);
3574             check(TOKrcurly, "compound statement");
3575             break;
3576         }
3577
3578         case TOKwhile:
3579         {   Expression *condition;
3580             Statement *body;
3581
3582             nextToken();
3583             check(TOKlparen);
3584             condition = parseExpression();
3585             check(TOKrparen);
3586             body = parseStatement(PSscope);
3587             s = new WhileStatement(loc, condition, body);
3588             break;
3589         }
3590
3591         case TOKsemicolon:
3592             if (!(flags & PSsemi))
3593                 error("use '{ }' for an empty statement, not a ';'");
3594             nextToken();
3595             s = new ExpStatement(loc, NULL);
3596             break;
3597
3598         case TOKdo:
3599         {   Statement *body;
3600             Expression *condition;
3601
3602             nextToken();
3603             body = parseStatement(PSscope);
3604             check(TOKwhile);
3605             check(TOKlparen);
3606             condition = parseExpression();
3607             check(TOKrparen);
3608             s = new DoStatement(loc, body, condition);
3609             break;
3610         }
3611
3612         case TOKfor:
3613         {
3614             Statement *init;
3615             Expression *condition;
3616             Expression *increment;
3617             Statement *body;
3618
3619             nextToken();
3620             check(TOKlparen);
3621             if (token.value == TOKsemicolon)
3622             {   init = NULL;
3623                 nextToken();
3624             }
3625             else
3626             {   init = parseStatement(0);
3627             }
3628             if (token.value == TOKsemicolon)
3629             {
3630                 condition = NULL;
3631                 nextToken();
3632             }
3633             else
3634             {
3635                 condition = parseExpression();
3636                 check(TOKsemicolon, "for condition");
3637             }
3638             if (token.value == TOKrparen)
3639             {   increment = NULL;
3640                 nextToken();
3641             }
3642             else
3643             {   increment = parseExpression();
3644                 check(TOKrparen);
3645             }
3646             body = parseStatement(PSscope);
3647             s = new ForStatement(loc, init, condition, increment, body);
3648             if (init)
3649                 s = new ScopeStatement(loc, s);
3650             break;
3651         }
3652
3653         case TOKforeach:
3654         case TOKforeach_reverse:
3655         {
3656             enum TOK op = token.value;
3657
3658             nextToken();
3659             check(TOKlparen);
3660
3661             Parameters *arguments = new Parameters();
3662
3663             while (1)
3664             {
3665                 Identifier *ai = NULL;
3666                 Type *at;
3667
3668                 StorageClass storageClass = 0;
3669                 if (token.value == TOKref
3670 #if D1INOUT
3671                         || token.value == TOKinout
3672 #endif
3673                    )
3674                 {   storageClass = STCref;
3675                     nextToken();
3676                 }
3677                 if (token.value == TOKidentifier)
3678                 {
3679                     Token *t = peek(&token);
3680                     if (t->value == TOKcomma || t->value == TOKsemicolon)
3681                     {   ai = token.ident;
3682                         at = NULL;              // infer argument type
3683                         nextToken();
3684                         goto Larg;
3685                     }
3686                 }
3687                 at = parseType(&ai);
3688                 if (!ai)
3689                     error("no identifier for declarator %s", at->toChars());
3690               Larg:
3691                 Parameter *a = new Parameter(storageClass, at, ai, NULL);
3692                 arguments->push(a);
3693                 if (token.value == TOKcomma)
3694                 {   nextToken();
3695                     continue;
3696                 }
3697                 break;
3698             }
3699             check(TOKsemicolon);
3700
3701             Expression *aggr = parseExpression();
3702             if (token.value == TOKslice && arguments->dim == 1)
3703             {
3704                 Parameter *a = (Parameter *)arguments->data[0];
3705                 delete arguments;
3706                 nextToken();
3707                 Expression *upr = parseExpression();
3708                 check(TOKrparen);
3709                 Statement *body = parseStatement(0);
3710                 s = new ForeachRangeStatement(loc, op, a, aggr, upr, body);
3711             }
3712             else
3713             {
3714                 check(TOKrparen);
3715                 Statement *body = parseStatement(0);
3716                 s = new ForeachStatement(loc, op, arguments, aggr, body);
3717             }
3718             break;
3719         }
3720
3721         case TOKif:
3722         {   Parameter *arg = NULL;
3723             Expression *condition;
3724             Statement *ifbody;
3725             Statement *elsebody;
3726
3727             nextToken();
3728             check(TOKlparen);
3729
3730             if (token.value == TOKauto)
3731             {
3732                 nextToken();
3733                 if (token.value == TOKidentifier)
3734                 {
3735                     Token *t = peek(&token);
3736                     if (t->value == TOKassign)
3737                     {
3738                         arg = new Parameter(0, NULL, token.ident, NULL);
3739                         nextToken();
3740                         nextToken();
3741                     }
3742                     else
3743                     {   error("= expected following auto identifier");
3744                         goto Lerror;
3745                     }
3746                 }
3747                 else
3748                 {   error("identifier expected following auto");
3749                     goto Lerror;
3750                 }
3751             }
3752             else if (isDeclaration(&token, 2, TOKassign, NULL))
3753             {
3754                 Type *at;
3755                 Identifier *ai;
3756
3757                 at = parseType(&ai);
3758                 check(TOKassign);
3759                 arg = new Parameter(0, at, ai, NULL);
3760             }
3761
3762             // Check for " ident;"
3763             else if (token.value == TOKidentifier)
3764             {
3765                 Token *t = peek(&token);
3766                 if (t->value == TOKcomma || t->value == TOKsemicolon)
3767                 {
3768                     arg = new Parameter(0, NULL, token.ident, NULL);
3769                     nextToken();
3770                     nextToken();
3771                     if (1 || !global.params.useDeprecated)
3772                         error("if (v; e) is deprecated, use if (auto v = e)");
3773                 }
3774             }
3775
3776             condition = parseExpression();
3777             check(TOKrparen);
3778             ifbody = parseStatement(PSscope);
3779             if (token.value == TOKelse)
3780             {
3781                 nextToken();
3782                 elsebody = parseStatement(PSscope);
3783             }
3784             else
3785                 elsebody = NULL;
3786             if (condition && ifbody)
3787                 s = new IfStatement(loc, arg, condition, ifbody, elsebody);
3788             else
3789                 s = NULL;               // don't propagate parsing errors
3790             break;
3791         }
3792
3793         case TOKscope:
3794             if (peek(&token)->value != TOKlparen)
3795                 goto Ldeclaration;              // scope used as storage class
3796             nextToken();
3797             check(TOKlparen);
3798             if (token.value != TOKidentifier)
3799             {   error("scope identifier expected");
3800                 goto Lerror;
3801             }
3802             else
3803             {   TOK t = TOKon_scope_exit;
3804                 Identifier *id = token.ident;
3805
3806                 if (id == Id::exit)
3807                     t = TOKon_scope_exit;
3808                 else if (id == Id::failure)
3809                     t = TOKon_scope_failure;
3810                 else if (id == Id::success)
3811                     t = TOKon_scope_success;
3812                 else
3813                     error("valid scope identifiers are exit, failure, or success, not %s", id->toChars());
3814                 nextToken();
3815                 check(TOKrparen);
3816                 Statement *st = parseStatement(PScurlyscope);
3817                 s = new OnScopeStatement(loc, t, st);
3818                 break;
3819             }
3820
3821         case TOKdebug:
3822             nextToken();
3823             condition = parseDebugCondition();
3824             goto Lcondition;
3825
3826         case TOKversion:
3827             nextToken();
3828             condition = parseVersionCondition();
3829             goto Lcondition;
3830
3831         Lcondition:
3832             ifbody = parseStatement(0 /*PSsemi*/);
3833             elsebody = NULL;
3834             if (token.value == TOKelse)
3835             {
3836                 nextToken();
3837                 elsebody = parseStatement(0 /*PSsemi*/);
3838             }
3839             s = new ConditionalStatement(loc, condition, ifbody, elsebody);
3840             break;
3841
3842         case TOKpragma:
3843         {   Identifier *ident;
3844             Expressions *args = NULL;
3845             Statement *body;
3846
3847             nextToken();
3848             check(TOKlparen);
3849             if (token.value != TOKidentifier)
3850             {   error("pragma(identifier expected");
3851                 goto Lerror;
3852             }
3853             ident = token.ident;
3854             nextToken();
3855             if (token.value == TOKcomma && peekNext() != TOKrparen)
3856                 args = parseArguments();        // pragma(identifier, args...);
3857             else
3858                 check(TOKrparen);               // pragma(identifier);
3859             if (token.value == TOKsemicolon)
3860             {   nextToken();
3861                 body = NULL;
3862             }
3863             else
3864                 body = parseStatement(PSsemi);
3865             s = new PragmaStatement(loc, ident, args, body);
3866             break;
3867         }
3868
3869         case TOKswitch:
3870             isfinal = FALSE;
3871             goto Lswitch;
3872
3873         Lswitch:
3874         {
3875             nextToken();
3876             check(TOKlparen);
3877             Expression *condition = parseExpression();
3878             check(TOKrparen);
3879             Statement *body = parseStatement(PSscope);
3880             s = new SwitchStatement(loc, condition, body, isfinal);
3881             break;
3882         }
3883
3884         case TOKcase:
3885         {   Expression *exp;
3886             Statements *statements;
3887             Array cases;        // array of Expression's
3888             Expression *last = NULL;
3889
3890             while (1)
3891             {
3892                 nextToken();
3893                 exp = parseAssignExp();
3894                 cases.push(exp);
3895                 if (token.value != TOKcomma)
3896                     break;
3897             }
3898             check(TOKcolon);
3899
3900 #if DMDV2
3901             /* case exp: .. case last:
3902              */
3903             if (token.value == TOKslice)
3904             {
3905                 if (cases.dim > 1)
3906                     error("only one case allowed for start of case range");
3907                 nextToken();
3908                 check(TOKcase);
3909                 last = parseAssignExp();
3910                 check(TOKcolon);
3911             }
3912 #endif
3913
3914             statements = new Statements();
3915             while (token.value != TOKcase &&
3916                    token.value != TOKdefault &&
3917                    token.value != TOKeof &&
3918                    token.value != TOKrcurly)
3919             {
3920                 statements->push(parseStatement(PSsemi | PScurlyscope));
3921             }
3922             s = new CompoundStatement(loc, statements);
3923             s = new ScopeStatement(loc, s);
3924
3925 #if DMDV2
3926             if (last)
3927             {
3928                 s = new CaseRangeStatement(loc, exp, last, s);
3929             }
3930             else
3931 #endif
3932             {
3933                 // Keep cases in order by building the case statements backwards
3934                 for (int i = cases.dim; i; i--)
3935                 {
3936                     exp = (Expression *)cases.data[i - 1];
3937                     s = new CaseStatement(loc, exp, s);
3938                 }
3939             }
3940             break;
3941         }
3942
3943         case TOKdefault:
3944         {
3945             Statements *statements;
3946
3947             nextToken();
3948             check(TOKcolon);
3949
3950             statements = new Statements();
3951             while (token.value != TOKcase &&
3952                    token.value != TOKdefault &&
3953                    token.value != TOKeof &&
3954                    token.value != TOKrcurly)
3955             {
3956                 statements->push(parseStatement(PSsemi | PScurlyscope));
3957             }
3958             s = new CompoundStatement(loc, statements);
3959             s = new ScopeStatement(loc, s);
3960             s = new DefaultStatement(loc, s);
3961             break;
3962         }
3963
3964         case TOKreturn:
3965         {   Expression *exp;
3966
3967             nextToken();
3968             if (token.value == TOKsemicolon)
3969                 exp = NULL;
3970             else
3971                 exp = parseExpression();
3972             check(TOKsemicolon, "return statement");
3973             s = new ReturnStatement(loc, exp);
3974             break;
3975         }
3976
3977         case TOKbreak:
3978         {   Identifier *ident;
3979
3980             nextToken();
3981             if (token.value == TOKidentifier)
3982             {   ident = token.ident;
3983                 nextToken();
3984             }
3985             else
3986                 ident = NULL;
3987             check(TOKsemicolon, "break statement");
3988             s = new BreakStatement(loc, ident);
3989             break;
3990         }
3991
3992         case TOKcontinue:
3993         {   Identifier *ident;
3994
3995             nextToken();
3996             if (token.value == TOKidentifier)
3997             {   ident = token.ident;
3998                 nextToken();
3999             }
4000             else
4001                 ident = NULL;
4002             check(TOKsemicolon, "continue statement");
4003             s = new ContinueStatement(loc, ident);
4004             break;
4005         }
4006
4007         case TOKgoto:
4008         {   Identifier *ident;
4009
4010             nextToken();
4011             if (token.value == TOKdefault)
4012             {
4013                 nextToken();
4014                 s = new GotoDefaultStatement(loc);
4015             }
4016             else if (token.value == TOKcase)
4017             {
4018                 Expression *exp = NULL;
4019
4020                 nextToken();
4021                 if (token.value != TOKsemicolon)
4022                     exp = parseExpression();
4023                 s = new GotoCaseStatement(loc, exp);
4024             }
4025             else
4026             {
4027                 if (token.value != TOKidentifier)
4028                 {   error("Identifier expected following goto");
4029                     ident = NULL;
4030                 }
4031                 else
4032                 {   ident = token.ident;
4033                     nextToken();
4034                 }
4035                 s = new GotoStatement(loc, ident);
4036             }
4037             check(TOKsemicolon, "goto statement");
4038             break;
4039         }
4040
4041         case TOKsynchronized:
4042         {   Expression *exp;
4043             Statement *body;
4044
4045             nextToken();
4046             if (token.value == TOKlparen)
4047             {
4048                 nextToken();
4049                 exp = parseExpression();
4050                 check(TOKrparen);
4051             }
4052             else
4053                 exp = NULL;
4054             body = parseStatement(PSscope);
4055             s = new SynchronizedStatement(loc, exp, body);
4056             break;
4057         }
4058
4059         case TOKwith:
4060         {   Expression *exp;
4061             Statement *body;
4062
4063             nextToken();
4064             check(TOKlparen);
4065             exp = parseExpression();
4066             check(TOKrparen);
4067             body = parseStatement(PSscope);
4068             s = new WithStatement(loc, exp, body);
4069             break;
4070         }
4071
4072         case TOKtry:
4073         {   Statement *body;
4074             Array *catches = NULL;
4075             Statement *finalbody = NULL;
4076
4077             nextToken();
4078             body = parseStatement(PSscope);
4079             while (token.value == TOKcatch)
4080             {
4081                 Statement *handler;
4082                 Catch *c;
4083                 Type *t;
4084                 Identifier *id;
4085                 Loc loc = this->loc;
4086
4087                 nextToken();
4088                 if (token.value == TOKlcurly)
4089                 {
4090                     t = NULL;
4091                     id = NULL;
4092                 }
4093                 else
4094                 {
4095                     check(TOKlparen);
4096                     id = NULL;
4097                     t = parseType(&id);
4098                     check(TOKrparen);
4099                 }
4100                 handler = parseStatement(0);
4101                 c = new Catch(loc, t, id, handler);
4102                 if (!catches)
4103                     catches = new Array();
4104                 catches->push(c);
4105             }
4106
4107             if (token.value == TOKfinally)
4108             {   nextToken();
4109                 finalbody = parseStatement(0);
4110             }
4111
4112             s = body;
4113             if (!catches && !finalbody)
4114                 error("catch or finally expected following try");
4115             else
4116             {   if (catches)
4117                     s = new TryCatchStatement(loc, body, catches);
4118                 if (finalbody)
4119                     s = new TryFinallyStatement(loc, s, finalbody);
4120             }
4121             break;
4122         }
4123
4124         case TOKthrow:
4125         {   Expression *exp;
4126
4127             nextToken();
4128             exp = parseExpression();
4129             check(TOKsemicolon, "throw statement");
4130             s = new ThrowStatement(loc, exp);
4131             break;
4132         }
4133
4134         case TOKvolatile:
4135             nextToken();
4136             s = parseStatement(PSsemi | PScurlyscope);
4137 #if DMDV2
4138             if (!global.params.useDeprecated)
4139                 error("volatile statements deprecated; used synchronized statements instead");
4140 #endif
4141             s = new VolatileStatement(loc, s);
4142             break;
4143
4144         case TOKasm:
4145         {   Statements *statements;
4146             Identifier *label;
4147             Loc labelloc;
4148             Token *toklist;
4149             Token **ptoklist;
4150
4151             // Parse the asm block into a sequence of AsmStatements,
4152             // each AsmStatement is one instruction.
4153             // Separate out labels.
4154             // Defer parsing of AsmStatements until semantic processing.
4155
4156             nextToken();
4157             check(TOKlcurly);
4158             toklist = NULL;
4159             ptoklist = &toklist;
4160             label = NULL;
4161             statements = new Statements();
4162             while (1)
4163             {
4164                 switch (token.value)
4165                 {
4166                     case TOKidentifier:
4167                         if (!toklist)
4168                         {
4169                             // Look ahead to see if it is a label
4170                             t = peek(&token);
4171                             if (t->value == TOKcolon)
4172                             {   // It's a label
4173                                 label = token.ident;
4174                                 labelloc = this->loc;
4175                                 nextToken();
4176                                 nextToken();
4177                                 continue;
4178                             }
4179                         }
4180                         goto Ldefault;
4181
4182                     case TOKrcurly:
4183                         if (toklist || label)
4184                         {
4185                             error("asm statements must end in ';'");
4186                         }
4187                         break;
4188
4189                     case TOKsemicolon:
4190                         s = NULL;
4191                         if (toklist || label)
4192                         {   // Create AsmStatement from list of tokens we've saved
4193                             s = new AsmStatement(this->loc, toklist);
4194                             toklist = NULL;
4195                             ptoklist = &toklist;
4196                             if (label)
4197                             {   s = new LabelStatement(labelloc, label, s);
4198                                 label = NULL;
4199                             }
4200                             statements->push(s);
4201                         }
4202                         nextToken();
4203                         continue;
4204
4205                     case TOKeof:
4206                         /* { */
4207                         error("matching '}' expected, not end of file");
4208                         break;
4209
4210                     default:
4211                     Ldefault:
4212                         *ptoklist = new Token();
4213                         memcpy(*ptoklist, &token, sizeof(Token));
4214                         ptoklist = &(*ptoklist)->next;
4215                         *ptoklist = NULL;
4216
4217                         nextToken();
4218                         continue;
4219                 }
4220                 break;
4221             }
4222             s = new CompoundStatement(loc, statements);
4223             nextToken();
4224             break;
4225         }
4226
4227         default:
4228             error("found '%s' instead of statement", token.toChars());
4229             goto Lerror;
4230
4231         Lerror:
4232             while (token.value != TOKrcurly &&
4233                    token.value != TOKsemicolon &&
4234                    token.value != TOKeof)
4235                 nextToken();
4236             if (token.value == TOKsemicolon)
4237                 nextToken();
4238             s = NULL;
4239             break;
4240     }
4241
4242     return s;
4243 }
4244
4245 void Parser::check(enum TOK value)
4246 {
4247     check(loc, value);
4248 }
4249
4250 void Parser::check(Loc loc, enum TOK value)
4251 {
4252     if (token.value != value)
4253         error(loc, "found '%s' when expecting '%s'", token.toChars(), Token::toChars(value));
4254     nextToken();
4255 }
4256
4257 void Parser::check(enum TOK value, const char *string)
4258 {
4259     if (token.value != value)
4260         error("found '%s' when expecting '%s' following %s",
4261             token.toChars(), Token::toChars(value), string);
4262     nextToken();
4263 }
4264
4265 void Parser::checkParens(enum TOK value, Expression *e)
4266 {
4267     if (precedence[e->op] == PREC_rel && !e->parens)
4268         error(loc, "%s must be parenthesized when next to operator %s", e->toChars(), Token::toChars(value));
4269 }
4270
4271 /************************************
4272  * Determine if the scanner is sitting on the start of a declaration.
4273  * Input:
4274  *      needId  0       no identifier
4275  *              1       identifier optional
4276  *              2       must have identifier
4277  * Output:
4278  *      if *pt is not NULL, it is set to the ending token, which would be endtok
4279  */
4280
4281 int Parser::isDeclaration(Token *t, int needId, enum TOK endtok, Token **pt)
4282 {
4283     //printf("isDeclaration(needId = %d)\n", needId);
4284     int haveId = 0;
4285
4286 #if DMDV2
4287     if ((t->value == TOKconst ||
4288          t->value == TOKinvariant ||
4289          t->value == TOKimmutable ||
4290          t->value == TOKwild ||
4291          t->value == TOKshared) &&
4292         peek(t)->value != TOKlparen)
4293     {   /* const type
4294          * immutable type
4295          * shared type
4296          * wild type
4297          */
4298         t = peek(t);
4299     }
4300 #endif
4301
4302     if (!isBasicType(&t))
4303     {
4304         goto Lisnot;
4305     }
4306     if (!isDeclarator(&t, &haveId, endtok))
4307         goto Lisnot;
4308     if ( needId == 1 ||
4309         (needId == 0 && !haveId) ||
4310         (needId == 2 &&  haveId))
4311     {   if (pt)
4312             *pt = t;
4313         goto Lis;
4314     }
4315     else
4316         goto Lisnot;
4317
4318 Lis:
4319     //printf("\tis declaration, t = %s\n", t->toChars());
4320     return TRUE;
4321
4322 Lisnot:
4323     //printf("\tis not declaration\n");
4324     return FALSE;
4325 }
4326
4327 int Parser::isBasicType(Token **pt)
4328 {
4329     // This code parallels parseBasicType()
4330     Token *t = *pt;
4331     Token *t2;
4332     int parens;
4333     int haveId = 0;
4334
4335     switch (t->value)
4336     {
4337         case BASIC_TYPES:
4338             t = peek(t);
4339             break;
4340
4341         case TOKidentifier:
4342         L5:
4343             t = peek(t);
4344             if (t->value == TOKnot)
4345             {
4346                 goto L4;
4347             }
4348             goto L3;
4349             while (1)
4350             {
4351         L2:
4352                 t = peek(t);
4353         L3:
4354                 if (t->value == TOKdot)
4355                 {
4356         Ldot:
4357                     t = peek(t);
4358                     if (t->value != TOKidentifier)
4359                         goto Lfalse;
4360                     t = peek(t);
4361                     if (t->value != TOKnot)
4362                         goto L3;
4363         L4:
4364                     /* Seen a !
4365                      * Look for:
4366                      * !( args ), !identifier, etc.
4367                      */
4368                     t = peek(t);
4369                     switch (t->value)
4370                     {   case TOKidentifier:
4371                             goto L5;
4372                         case TOKlparen:
4373                             if (!skipParens(t, &t))
4374                                 goto Lfalse;
4375                             break;
4376                         case BASIC_TYPES:
4377                         case TOKint32v:
4378                         case TOKuns32v:
4379                         case TOKint64v:
4380                         case TOKuns64v:
4381                         case TOKfloat32v:
4382                         case TOKfloat64v:
4383                         case TOKfloat80v:
4384                         case TOKimaginary32v:
4385                         case TOKimaginary64v:
4386                         case TOKimaginary80v:
4387                         case TOKnull:
4388                         case TOKtrue:
4389                         case TOKfalse:
4390                         case TOKcharv:
4391                         case TOKwcharv:
4392                         case TOKdcharv:
4393                         case TOKstring:
4394                         case TOKfile:
4395                         case TOKline:
4396                             goto L2;
4397                         default:
4398                             goto Lfalse;
4399                     }
4400                 }
4401                 else
4402                     break;
4403             }
4404             break;
4405
4406         case TOKdot:
4407             goto Ldot;
4408
4409         case TOKtypeof:
4410             /* typeof(exp).identifier...
4411              */
4412             t = peek(t);
4413             if (t->value != TOKlparen)
4414                 goto Lfalse;
4415             if (!skipParens(t, &t))
4416                 goto Lfalse;
4417             goto L2;
4418
4419         case TOKconst:
4420         case TOKinvariant:
4421         case TOKimmutable:
4422         case TOKshared:
4423         case TOKwild:
4424             // const(type)  or  immutable(type)  or  shared(type)  or  wild(type)
4425             t = peek(t);
4426             if (t->value != TOKlparen)
4427                 goto Lfalse;
4428             t = peek(t);
4429             if (!isDeclaration(t, 0, TOKrparen, &t))
4430             {
4431                 goto Lfalse;
4432             }
4433             t = peek(t);
4434             break;
4435
4436         default:
4437             goto Lfalse;
4438     }
4439     *pt = t;
4440     //printf("is\n");
4441     return TRUE;
4442
4443 Lfalse:
4444     //printf("is not\n");
4445     return FALSE;
4446 }
4447
4448 int Parser::isDeclarator(Token **pt, int *haveId, enum TOK endtok)
4449 {   // This code parallels parseDeclarator()
4450     Token *t = *pt;
4451     int parens;
4452
4453     //printf("Parser::isDeclarator()\n");
4454     //t->print();
4455     if (t->value == TOKassign)
4456         return FALSE;
4457
4458     while (1)
4459     {
4460         parens = FALSE;
4461         switch (t->value)
4462         {
4463             case TOKmul:
4464             //case TOKand:
4465                 t = peek(t);
4466                 continue;
4467
4468             case TOKlbracket:
4469                 t = peek(t);
4470                 if (t->value == TOKrbracket)
4471                 {
4472                     t = peek(t);
4473                 }
4474                 else if (isDeclaration(t, 0, TOKrbracket, &t))
4475                 {   // It's an associative array declaration
4476                     t = peek(t);
4477                 }
4478                 else
4479                 {
4480                     // [ expression ]
4481                     // [ expression .. expression ]
4482                     if (!isExpression(&t))
4483                         return FALSE;
4484                     if (t->value == TOKslice)
4485                     {   t = peek(t);
4486                         if (!isExpression(&t))
4487                             return FALSE;
4488                     }
4489                     if (t->value != TOKrbracket)
4490                         return FALSE;
4491                     t = peek(t);
4492                 }
4493                 continue;
4494
4495             case TOKidentifier:
4496                 if (*haveId)
4497                     return FALSE;
4498                 *haveId = TRUE;
4499                 t = peek(t);
4500                 break;
4501
4502             case TOKlparen:
4503                 t = peek(t);
4504
4505                 if (t->value == TOKrparen)
4506                     return FALSE;               // () is not a declarator
4507
4508                 /* Regard ( identifier ) as not a declarator
4509                  * BUG: what about ( *identifier ) in
4510                  *      f(*p)(x);
4511                  * where f is a class instance with overloaded () ?
4512                  * Should we just disallow C-style function pointer declarations?
4513                  */
4514                 if (t->value == TOKidentifier)
4515                 {   Token *t2 = peek(t);
4516                     if (t2->value == TOKrparen)
4517                         return FALSE;
4518                 }
4519
4520
4521                 if (!isDeclarator(&t, haveId, TOKrparen))
4522                     return FALSE;
4523                 t = peek(t);
4524                 parens = TRUE;
4525                 break;
4526
4527             case TOKdelegate:
4528             case TOKfunction:
4529                 t = peek(t);
4530                 if (!isParameters(&t))
4531                     return FALSE;
4532                 continue;
4533         }
4534         break;
4535     }
4536
4537     while (1)
4538     {
4539         switch (t->value)
4540         {
4541 #if CARRAYDECL
4542             case TOKlbracket:
4543                 parens = FALSE;
4544                 t = peek(t);
4545                 if (t->value == TOKrbracket)
4546                 {
4547                     t = peek(t);
4548                 }
4549                 else if (isDeclaration(t, 0, TOKrbracket, &t))
4550                 {   // It's an associative array declaration
4551                     t = peek(t);
4552                 }
4553                 else
4554                 {
4555                     // [ expression ]
4556                     if (!isExpression(&t))
4557                         return FALSE;
4558                     if (t->value != TOKrbracket)
4559                         return FALSE;
4560                     t = peek(t);
4561                 }
4562                 continue;
4563 #endif
4564
4565             case TOKlparen:
4566                 parens = FALSE;
4567                 if (!isParameters(&t))
4568                     return FALSE;
4569 #if DMDV2
4570                 while (1)
4571                 {
4572                     switch (t->value)
4573                     {
4574                         case TOKconst:
4575                         case TOKinvariant:
4576                         case TOKimmutable:
4577                         case TOKshared:
4578                         case TOKwild:
4579                         case TOKpure:
4580                         case TOKnothrow:
4581                             t = peek(t);
4582                             continue;
4583                         case TOKat:
4584                             t = peek(t);        // skip '@'
4585                             t = peek(t);        // skip identifier
4586                             continue;
4587                         default:
4588                             break;
4589                     }
4590                     break;
4591                 }
4592 #endif
4593                 continue;
4594
4595             // Valid tokens that follow a declaration
4596             case TOKrparen:
4597             case TOKrbracket:
4598             case TOKassign:
4599             case TOKcomma:
4600             case TOKsemicolon:
4601             case TOKlcurly:
4602             case TOKin:
4603                 // The !parens is to disallow unnecessary parentheses
4604                 if (!parens && (endtok == TOKreserved || endtok == t->value))
4605                 {   *pt = t;
4606                     return TRUE;
4607                 }
4608                 return FALSE;
4609
4610             default:
4611                 return FALSE;
4612         }
4613     }
4614 }
4615
4616
4617 int Parser::isParameters(Token **pt)
4618 {   // This code parallels parseParameters()
4619     Token *t = *pt;
4620
4621     //printf("isParameters()\n");
4622     if (t->value != TOKlparen)
4623         return FALSE;
4624
4625     t = peek(t);
4626     for (;1; t = peek(t))
4627     {
4628      L1:
4629         switch (t->value)
4630         {
4631             case TOKrparen:
4632                 break;
4633
4634             case TOKdotdotdot:
4635                 t = peek(t);
4636                 break;
4637
4638 #if D1INOUT
4639             case TOKinout:
4640 #endif
4641             case TOKin:
4642             case TOKout:
4643             case TOKref:
4644             case TOKlazy:
4645             case TOKfinal:
4646             case TOKauto:
4647                 continue;
4648
4649             case TOKconst:
4650             case TOKinvariant:
4651             case TOKimmutable:
4652             case TOKshared:
4653             case TOKwild:
4654                 t = peek(t);
4655                 if (t->value == TOKlparen)
4656                 {
4657                     t = peek(t);
4658                     if (!isDeclaration(t, 0, TOKrparen, &t))
4659                         return FALSE;
4660                     t = peek(t);        // skip past closing ')'
4661                     goto L2;
4662                 }
4663                 goto L1;
4664
4665 #if 0
4666             case TOKstatic:
4667                 continue;
4668             case TOKauto:
4669             case TOKalias:
4670                 t = peek(t);
4671                 if (t->value == TOKidentifier)
4672                     t = peek(t);
4673                 if (t->value == TOKassign)
4674                 {   t = peek(t);
4675                     if (!isExpression(&t))
4676                         return FALSE;
4677                 }
4678                 goto L3;
4679 #endif
4680
4681             default:
4682             {   if (!isBasicType(&t))
4683                     return FALSE;
4684             L2:
4685                 int tmp = FALSE;
4686                 if (t->value != TOKdotdotdot &&
4687                     !isDeclarator(&t, &tmp, TOKreserved))
4688                     return FALSE;
4689                 if (t->value == TOKassign)
4690                 {   t = peek(t);
4691                     if (!isExpression(&t))
4692                         return FALSE;
4693                 }
4694                 if (t->value == TOKdotdotdot)
4695                 {
4696                     t = peek(t);
4697                     break;
4698                 }
4699             }
4700             L3:
4701                 if (t->value == TOKcomma)
4702                 {
4703                     continue;
4704                 }
4705                 break;
4706         }
4707         break;
4708     }
4709     if (t->value != TOKrparen)
4710         return FALSE;
4711     t = peek(t);
4712     *pt = t;
4713     return TRUE;
4714 }
4715
4716 int Parser::isExpression(Token **pt)
4717 {
4718     // This is supposed to determine if something is an expression.
4719     // What it actually does is scan until a closing right bracket
4720     // is found.
4721
4722     Token *t = *pt;
4723     int brnest = 0;
4724     int panest = 0;
4725     int curlynest = 0;
4726
4727     for (;; t = peek(t))
4728     {
4729         switch (t->value)
4730         {
4731             case TOKlbracket:
4732                 brnest++;
4733                 continue;
4734
4735             case TOKrbracket:
4736                 if (--brnest >= 0)
4737                     continue;
4738                 break;
4739
4740             case TOKlparen:
4741                 panest++;
4742                 continue;
4743
4744             case TOKcomma:
4745                 if (brnest || panest)
4746                     continue;
4747                 break;
4748
4749             case TOKrparen:
4750                 if (--panest >= 0)
4751                     continue;
4752                 break;
4753
4754             case TOKlcurly:
4755                 curlynest++;
4756                 continue;
4757
4758             case TOKrcurly:
4759                 if (--curlynest >= 0)
4760                     continue;
4761                 return FALSE;
4762
4763             case TOKslice:
4764                 if (brnest)
4765                     continue;
4766                 break;
4767
4768             case TOKsemicolon:
4769                 if (curlynest)
4770                     continue;
4771                 return FALSE;
4772
4773             case TOKeof:
4774                 return FALSE;
4775
4776             default:
4777                 continue;
4778         }
4779         break;
4780     }
4781
4782     *pt = t;
4783     return TRUE;
4784 }
4785
4786 /**********************************************
4787  * Skip over
4788  *      instance foo.bar(parameters...)
4789  * Output:
4790  *      if (pt), *pt is set to the token following the closing )
4791  * Returns:
4792  *      1       it's valid instance syntax
4793  *      0       invalid instance syntax
4794  */
4795
4796 int Parser::isTemplateInstance(Token *t, Token **pt)
4797 {
4798     t = peek(t);
4799     if (t->value != TOKdot)
4800     {
4801         if (t->value != TOKidentifier)
4802             goto Lfalse;
4803         t = peek(t);
4804     }
4805     while (t->value == TOKdot)
4806     {
4807         t = peek(t);
4808         if (t->value != TOKidentifier)
4809             goto Lfalse;
4810         t = peek(t);
4811     }
4812     if (t->value != TOKlparen)
4813         goto Lfalse;
4814
4815     // Skip over the template arguments
4816     while (1)
4817     {
4818         while (1)
4819         {
4820             t = peek(t);
4821             switch (t->value)
4822             {
4823                 case TOKlparen:
4824                     if (!skipParens(t, &t))
4825                         goto Lfalse;
4826                     continue;
4827                 case TOKrparen:
4828                     break;
4829                 case TOKcomma:
4830                     break;
4831                 case TOKeof:
4832                 case TOKsemicolon:
4833                     goto Lfalse;
4834                 default:
4835                     continue;
4836             }
4837             break;
4838         }
4839
4840         if (t->value != TOKcomma)
4841             break;
4842     }
4843     if (t->value != TOKrparen)
4844         goto Lfalse;
4845     t = peek(t);
4846     if (pt)
4847         *pt = t;
4848     return 1;
4849
4850 Lfalse:
4851     return 0;
4852 }
4853
4854 /*******************************************
4855  * Skip parens, brackets.
4856  * Input:
4857  *      t is on opening (
4858  * Output:
4859  *      *pt is set to closing token, which is ')' on success
4860  * Returns:
4861  *      !=0     successful
4862  *      0       some parsing error
4863  */
4864
4865 int Parser::skipParens(Token *t, Token **pt)
4866 {
4867     int parens = 0;
4868
4869     while (1)
4870     {
4871         switch (t->value)
4872         {
4873             case TOKlparen:
4874                 parens++;
4875                 break;
4876
4877             case TOKrparen:
4878                 parens--;
4879                 if (parens < 0)
4880                     goto Lfalse;
4881                 if (parens == 0)
4882                     goto Ldone;
4883                 break;
4884
4885             case TOKeof:
4886             case TOKsemicolon:
4887                 goto Lfalse;
4888
4889              default:
4890                 break;
4891         }
4892         t = peek(t);
4893     }
4894
4895   Ldone:
4896     if (*pt)
4897         *pt = t;
4898     return 1;
4899
4900   Lfalse:
4901     return 0;
4902 }
4903
4904 /********************************* Expression Parser ***************************/
4905
4906 Expression *Parser::parsePrimaryExp()
4907 {   Expression *e;
4908     Type *t;
4909     Identifier *id;
4910     enum TOK save;
4911     Loc loc = this->loc;
4912
4913     //printf("parsePrimaryExp(): loc = %d\n", loc.linnum);
4914     switch (token.value)
4915     {
4916         case TOKidentifier:
4917             id = token.ident;
4918             nextToken();
4919             if (token.value == TOKnot && (save = peekNext()) != TOKis && save != TOKin)
4920             {   // identifier!(template-argument-list)
4921                 TemplateInstance *tempinst;
4922
4923                 tempinst = new TemplateInstance(loc, id);
4924                 nextToken();
4925                 if (token.value == TOKlparen)
4926                     // ident!(template_arguments)
4927                     tempinst->tiargs = parseTemplateArgumentList();
4928                 else
4929                     // ident!template_argument
4930                     tempinst->tiargs = parseTemplateArgument();
4931                 e = new ScopeExp(loc, tempinst);
4932             }
4933             else
4934                 e = new IdentifierExp(loc, id);
4935             break;
4936
4937         case TOKdollar:
4938             if (!inBrackets)
4939                 error("'$' is valid only inside [] of index or slice");
4940             e = new DollarExp(loc);
4941             nextToken();
4942             break;
4943
4944         case TOKdot:
4945             // Signal global scope '.' operator with "" identifier
4946             e = new IdentifierExp(loc, Id::empty);
4947             break;
4948
4949         case TOKthis:
4950             e = new ThisExp(loc);
4951             nextToken();
4952             break;
4953
4954         case TOKsuper:
4955             e = new SuperExp(loc);
4956             nextToken();
4957             break;
4958
4959         case TOKint32v:
4960             e = new IntegerExp(loc, token.int32value, Type::tint32);
4961             nextToken();
4962             break;
4963
4964         case TOKuns32v:
4965             e = new IntegerExp(loc, token.uns32value, Type::tuns32);
4966             nextToken();
4967             break;
4968
4969         case TOKint64v:
4970             e = new IntegerExp(loc, token.int64value, Type::tint64);
4971             nextToken();
4972             break;
4973
4974         case TOKuns64v:
4975             e = new IntegerExp(loc, token.uns64value, Type::tuns64);
4976             nextToken();
4977             break;
4978
4979         case TOKfloat32v:
4980             e = new RealExp(loc, token.float80value, Type::tfloat32);
4981             nextToken();
4982             break;
4983
4984         case TOKfloat64v:
4985             e = new RealExp(loc, token.float80value, Type::tfloat64);
4986             nextToken();
4987             break;
4988
4989         case TOKfloat80v:
4990             e = new RealExp(loc, token.float80value, Type::tfloat80);
4991             nextToken();
4992             break;
4993
4994         case TOKimaginary32v:
4995             e = new RealExp(loc, token.float80value, Type::timaginary32);
4996             nextToken();
4997             break;
4998
4999         case TOKimaginary64v:
5000             e = new RealExp(loc, token.float80value, Type::timaginary64);
5001             nextToken();
5002             break;
5003
5004         case TOKimaginary80v:
5005             e = new RealExp(loc, token.float80value, Type::timaginary80);
5006             nextToken();
5007             break;
5008
5009         case TOKnull:
5010             e = new NullExp(loc);
5011             nextToken();
5012             break;
5013
5014 #if DMDV2
5015         case TOKfile:
5016         {   const char *s = loc.filename ? loc.filename : mod->ident->toChars();
5017             e = new StringExp(loc, (char *)s, strlen(s), 0);
5018             nextToken();
5019             break;
5020         }
5021
5022         case TOKline:
5023             e = new IntegerExp(loc, loc.linnum, Type::tint32);
5024             nextToken();
5025             break;
5026 #endif
5027
5028         case TOKtrue:
5029             e = new IntegerExp(loc, 1, Type::tbool);
5030             nextToken();
5031             break;
5032
5033         case TOKfalse:
5034             e = new IntegerExp(loc, 0, Type::tbool);
5035             nextToken();
5036             break;
5037
5038         case TOKcharv:
5039             e = new IntegerExp(loc, token.uns32value, Type::tchar);
5040             nextToken();
5041             break;
5042
5043         case TOKwcharv:
5044             e = new IntegerExp(loc, token.uns32value, Type::twchar);
5045             nextToken();
5046             break;
5047
5048         case TOKdcharv:
5049             e = new IntegerExp(loc, token.uns32value, Type::tdchar);
5050             nextToken();
5051             break;
5052
5053         case TOKstring:
5054         {   unsigned char *s;
5055             unsigned len;
5056             unsigned char postfix;
5057
5058             // cat adjacent strings
5059             s = token.ustring;
5060             len = token.len;
5061             postfix = token.postfix;
5062             while (1)
5063             {
5064                 nextToken();
5065                 if (token.value == TOKstring)
5066                 {   unsigned len1;
5067                     unsigned len2;
5068                     unsigned char *s2;
5069
5070                     if (token.postfix)
5071                     {   if (token.postfix != postfix)
5072                             error("mismatched string literal postfixes '%c' and '%c'", postfix, token.postfix);
5073                         postfix = token.postfix;
5074                     }
5075
5076                     len1 = len;
5077                     len2 = token.len;
5078                     len = len1 + len2;
5079                     s2 = (unsigned char *)mem.malloc((len + 1) * sizeof(unsigned char));
5080                     memcpy(s2, s, len1 * sizeof(unsigned char));
5081                     memcpy(s2 + len1, token.ustring, (len2 + 1) * sizeof(unsigned char));
5082                     s = s2;
5083                 }
5084                 else
5085                     break;
5086             }
5087             e = new StringExp(loc, s, len, postfix);
5088             break;
5089         }
5090
5091         case BASIC_TYPES_X(t):
5092             nextToken();
5093         L1:
5094             check(TOKdot, t->toChars());
5095             if (token.value != TOKidentifier)
5096             {   error("found '%s' when expecting identifier following '%s.'", token.toChars(), t->toChars());
5097                 goto Lerr;
5098             }
5099             e = typeDotIdExp(loc, t, token.ident);
5100             nextToken();
5101             break;
5102
5103         case TOKtypeof:
5104         {
5105             t = parseTypeof();
5106             e = new TypeExp(loc, t);
5107             break;
5108         }
5109
5110         case TOKtypeid:
5111         {
5112             nextToken();
5113             check(TOKlparen, "typeid");
5114             Object *o;
5115             if (isDeclaration(&token, 0, TOKreserved, NULL))
5116             {   // argument is a type
5117                 o = parseType();
5118             }
5119             else
5120             {   // argument is an expression
5121                 o = parseAssignExp();
5122             }
5123             check(TOKrparen);
5124             e = new TypeidExp(loc, o);
5125             break;
5126         }
5127
5128 #if DMDV2
5129         case TOKtraits:
5130         {   /* __traits(identifier, args...)
5131              */
5132             Identifier *ident;
5133             Objects *args = NULL;
5134
5135             nextToken();
5136             check(TOKlparen);
5137             if (token.value != TOKidentifier)
5138             {   error("__traits(identifier, args...) expected");
5139                 goto Lerr;
5140             }
5141             ident = token.ident;
5142             nextToken();
5143             if (token.value == TOKcomma)
5144                 args = parseTemplateArgumentList2();    // __traits(identifier, args...)
5145             else
5146                 check(TOKrparen);               // __traits(identifier)
5147
5148             e = new TraitsExp(loc, ident, args);
5149             break;
5150         }
5151 #endif
5152
5153         case TOKis:
5154         {   Type *targ;
5155             Identifier *ident = NULL;
5156             Type *tspec = NULL;
5157             enum TOK tok = TOKreserved;
5158             enum TOK tok2 = TOKreserved;
5159             TemplateParameters *tpl = NULL;
5160             Loc loc = this->loc;
5161
5162             nextToken();
5163             if (token.value == TOKlparen)
5164             {
5165                 nextToken();
5166                 targ = parseType(&ident);
5167                 if (token.value == TOKcolon || token.value == TOKequal)
5168                 {
5169                     tok = token.value;
5170                     nextToken();
5171                     if (tok == TOKequal &&
5172                         (token.value == TOKtypedef ||
5173                          token.value == TOKstruct ||
5174                          token.value == TOKunion ||
5175                          token.value == TOKclass ||
5176                          token.value == TOKsuper ||
5177                          token.value == TOKenum ||
5178                          token.value == TOKinterface ||
5179                          token.value == TOKargTypes ||
5180 #if DMDV2
5181                          token.value == TOKconst && peek(&token)->value == TOKrparen ||
5182                          token.value == TOKinvariant && peek(&token)->value == TOKrparen ||
5183                          token.value == TOKimmutable && peek(&token)->value == TOKrparen ||
5184                          token.value == TOKshared && peek(&token)->value == TOKrparen ||
5185                          token.value == TOKwild && peek(&token)->value == TOKrparen ||
5186 #endif
5187                          token.value == TOKfunction ||
5188                          token.value == TOKdelegate ||
5189                          token.value == TOKreturn))
5190                     {
5191                         tok2 = token.value;
5192                         nextToken();
5193                     }
5194                     else
5195                     {
5196                         tspec = parseType();
5197                     }
5198                 }
5199                 if (ident && tspec)
5200                 {
5201                     if (token.value == TOKcomma)
5202                         tpl = parseTemplateParameterList(1);
5203                     else
5204                     {   tpl = new TemplateParameters();
5205                         check(TOKrparen);
5206                     }
5207                     TemplateParameter *tp = new TemplateTypeParameter(loc, ident, NULL, NULL);
5208                     tpl->insert(0, tp);
5209                 }
5210                 else
5211                     check(TOKrparen);
5212             }
5213             else
5214             {   error("(type identifier : specialization) expected following is");
5215                 goto Lerr;
5216             }
5217             e = new IsExp(loc, targ, ident, tok, tspec, tok2, tpl);
5218             break;
5219         }
5220
5221         case TOKassert:
5222         {   Expression *msg = NULL;
5223
5224             nextToken();
5225             check(TOKlparen, "assert");
5226             e = parseAssignExp();
5227             if (token.value == TOKcomma)
5228             {   nextToken();
5229                 msg = parseAssignExp();
5230             }
5231             check(TOKrparen);
5232             e = new AssertExp(loc, e, msg);
5233             break;
5234         }
5235
5236         case TOKmixin:
5237         {
5238             nextToken();
5239             check(TOKlparen, "mixin");
5240             e = parseAssignExp();
5241             check(TOKrparen);
5242             e = new CompileExp(loc, e);
5243             break;
5244         }
5245
5246         case TOKimport:
5247         {
5248             nextToken();
5249             check(TOKlparen, "import");
5250             e = parseAssignExp();
5251             check(TOKrparen);
5252             e = new FileExp(loc, e);
5253             break;
5254         }
5255
5256         case TOKlparen:
5257             if (peekPastParen(&token)->value == TOKlcurly)
5258             {   // (arguments) { statements... }
5259                 save = TOKdelegate;
5260                 goto case_delegate;
5261             }
5262             // ( expression )
5263             nextToken();
5264             e = parseExpression();
5265             e->parens = 1;
5266             check(loc, TOKrparen);
5267             break;
5268
5269         case TOKlbracket:
5270         {   /* Parse array literals and associative array literals:
5271              *  [ value, value, value ... ]
5272              *  [ key:value, key:value, key:value ... ]
5273              */
5274             Expressions *values = new Expressions();
5275             Expressions *keys = NULL;
5276
5277             nextToken();
5278             while (token.value != TOKrbracket && token.value != TOKeof)
5279             {
5280                     Expression *e = parseAssignExp();
5281                     if (token.value == TOKcolon && (keys || values->dim == 0))
5282                     {   nextToken();
5283                         if (!keys)
5284                             keys = new Expressions();
5285                         keys->push(e);
5286                         e = parseAssignExp();
5287                     }
5288                     else if (keys)
5289                     {   error("'key:value' expected for associative array literal");
5290                         delete keys;
5291                         keys = NULL;
5292                     }
5293                     values->push(e);
5294                     if (token.value == TOKrbracket)
5295                         break;
5296                     check(TOKcomma);
5297             }
5298             check(loc, TOKrbracket);
5299
5300             if (keys)
5301                 e = new AssocArrayLiteralExp(loc, keys, values);
5302             else
5303                 e = new ArrayLiteralExp(loc, values);
5304             break;
5305         }
5306
5307         case TOKlcurly:
5308             // { statements... }
5309             save = TOKdelegate;
5310             goto case_delegate;
5311
5312         case TOKfunction:
5313         case TOKdelegate:
5314             save = token.value;
5315             nextToken();
5316         case_delegate:
5317         {
5318             /* function type(parameters) { body } pure nothrow
5319              * delegate type(parameters) { body } pure nothrow
5320              * (parameters) { body }
5321              * { body }
5322              */
5323             Parameters *arguments;
5324             int varargs;
5325             FuncLiteralDeclaration *fd;
5326             Type *t;
5327             StorageClass stc = 0;
5328
5329             if (token.value == TOKlcurly)
5330             {
5331                 t = NULL;
5332                 varargs = 0;
5333                 arguments = new Parameters();
5334             }
5335             else
5336             {
5337                 if (token.value == TOKlparen)
5338                     t = NULL;
5339                 else
5340                 {
5341                     t = parseBasicType();
5342                     t = parseBasicType2(t);     // function return type
5343                 }
5344                 arguments = parseParameters(&varargs);
5345                 stc = parsePostfix();
5346                 if (stc & (STCconst | STCimmutable | STCshared | STCwild))
5347                     error("const/immutable/shared/inout attributes are only valid for non-static member functions");
5348             }
5349
5350             TypeFunction *tf = new TypeFunction(arguments, t, varargs, linkage, stc);
5351
5352             fd = new FuncLiteralDeclaration(loc, 0, tf, save, NULL);
5353             parseContracts(fd);
5354             e = new FuncExp(loc, fd);
5355             break;
5356         }
5357
5358         default:
5359             error("expression expected, not '%s'", token.toChars());
5360         Lerr:
5361             // Anything for e, as long as it's not NULL
5362             e = new IntegerExp(loc, 0, Type::tint32);
5363             nextToken();
5364             break;
5365     }
5366     return e;
5367 }
5368
5369 Expression *Parser::parsePostExp(Expression *e)
5370 {
5371     Loc loc;
5372
5373     while (1)
5374     {
5375         loc = this->loc;
5376         switch (token.value)
5377         {
5378             case TOKdot:
5379                 nextToken();
5380                 if (token.value == TOKidentifier)
5381                 {   Identifier *id = token.ident;
5382
5383                     nextToken();
5384                     if (token.value == TOKnot && peekNext() != TOKis)
5385                     {   // identifier!(template-argument-list)
5386                         TemplateInstance *tempinst = new TemplateInstance(loc, id);
5387                         Objects *tiargs;
5388                         nextToken();
5389                         if (token.value == TOKlparen)
5390                             // ident!(template_arguments)
5391                             tiargs = parseTemplateArgumentList();
5392                         else
5393                             // ident!template_argument
5394                             tiargs = parseTemplateArgument();
5395                         e = new DotTemplateInstanceExp(loc, e, id, tiargs);
5396                     }
5397                     else
5398                         e = new DotIdExp(loc, e, id);
5399                     continue;
5400                 }
5401                 else if (token.value == TOKnew)
5402                 {
5403                     e = parseNewExp(e);
5404                     continue;
5405                 }
5406                 else
5407                     error("identifier expected following '.', not '%s'", token.toChars());
5408                 break;
5409
5410             case TOKplusplus:
5411                 e = new PostExp(TOKplusplus, loc, e);
5412                 break;
5413
5414             case TOKminusminus:
5415                 e = new PostExp(TOKminusminus, loc, e);
5416                 break;
5417
5418             case TOKlparen:
5419                 e = new CallExp(loc, e, parseArguments());
5420                 continue;
5421
5422             case TOKlbracket:
5423             {   // array dereferences:
5424                 //      array[index]
5425                 //      array[]
5426                 //      array[lwr .. upr]
5427                 Expression *index;
5428                 Expression *upr;
5429
5430                 inBrackets++;
5431                 nextToken();
5432                 if (token.value == TOKrbracket)
5433                 {   // array[]
5434                     e = new SliceExp(loc, e, NULL, NULL);
5435                     nextToken();
5436                 }
5437                 else
5438                 {
5439                     index = parseAssignExp();
5440                     if (token.value == TOKslice)
5441                     {   // array[lwr .. upr]
5442                         nextToken();
5443                         upr = parseAssignExp();
5444                         e = new SliceExp(loc, e, index, upr);
5445                     }
5446                     else
5447                     {   // array[index, i2, i3, i4, ...]
5448                         Expressions *arguments = new Expressions();
5449                         arguments->push(index);
5450                         if (token.value == TOKcomma)
5451                         {
5452                             nextToken();
5453                             while (token.value != TOKrbracket && token.value != TOKeof)
5454                             {
5455                                 Expression *arg = parseAssignExp();
5456                                 arguments->push(arg);
5457                                 if (token.value == TOKrbracket)
5458                                     break;
5459                                 check(TOKcomma);
5460                             }
5461                         }
5462                         e = new ArrayExp(loc, e, arguments);
5463                     }
5464                     check(TOKrbracket);
5465                     inBrackets--;
5466                 }
5467                 continue;
5468             }
5469
5470             default:
5471                 return e;
5472         }
5473         nextToken();
5474     }
5475 }
5476
5477 Expression *Parser::parseUnaryExp()
5478 {   Expression *e;
5479     Loc loc = this->loc;
5480
5481     switch (token.value)
5482     {
5483         case TOKand:
5484             nextToken();
5485             e = parseUnaryExp();
5486             e = new AddrExp(loc, e);
5487             break;
5488
5489         case TOKplusplus:
5490             nextToken();
5491             e = parseUnaryExp();
5492             //e = new AddAssignExp(loc, e, new IntegerExp(loc, 1, Type::tint32));
5493             e = new PreExp(TOKpreplusplus, loc, e);
5494             break;
5495
5496         case TOKminusminus:
5497             nextToken();
5498             e = parseUnaryExp();
5499             //e = new MinAssignExp(loc, e, new IntegerExp(loc, 1, Type::tint32));
5500             e = new PreExp(TOKpreminusminus, loc, e);
5501             break;
5502
5503         case TOKmul:
5504             nextToken();
5505             e = parseUnaryExp();
5506             e = new PtrExp(loc, e);
5507             break;
5508
5509         case TOKmin:
5510             nextToken();
5511             e = parseUnaryExp();
5512             e = new NegExp(loc, e);
5513             break;
5514
5515         case TOKadd:
5516             nextToken();
5517             e = parseUnaryExp();
5518             e = new UAddExp(loc, e);
5519             break;
5520
5521         case TOKnot:
5522             nextToken();
5523             e = parseUnaryExp();
5524             e = new NotExp(loc, e);
5525             break;
5526
5527         case TOKtilde:
5528             nextToken();
5529             e = parseUnaryExp();
5530             e = new ComExp(loc, e);
5531             break;
5532
5533         case TOKdelete:
5534             nextToken();
5535             e = parseUnaryExp();
5536             e = new DeleteExp(loc, e);
5537             break;
5538
5539         case TOKnew:
5540             e = parseNewExp(NULL);
5541             break;
5542
5543         case TOKcast:                           // cast(type) expression
5544         {
5545             nextToken();
5546             check(TOKlparen);
5547             /* Look for cast(), cast(const), cast(immutable),
5548              * cast(shared), cast(shared const), cast(wild), cast(shared wild)
5549              */
5550             unsigned m;
5551             if (token.value == TOKrparen)
5552             {
5553                 m = 0;
5554                 goto Lmod1;
5555             }
5556             else if (token.value == TOKconst && peekNext() == TOKrparen)
5557             {
5558                 m = MODconst;
5559                 goto Lmod2;
5560             }
5561             else if ((token.value == TOKimmutable || token.value == TOKinvariant) && peekNext() == TOKrparen)
5562             {
5563                 m = MODimmutable;
5564                 goto Lmod2;
5565             }
5566             else if (token.value == TOKshared && peekNext() == TOKrparen)
5567             {
5568                 m = MODshared;
5569                 goto Lmod2;
5570             }
5571             else if (token.value == TOKwild && peekNext() == TOKrparen)
5572             {
5573                 m = MODwild;
5574                 goto Lmod2;
5575             }
5576             else if (token.value == TOKwild && peekNext() == TOKshared && peekNext2() == TOKrparen ||
5577                      token.value == TOKshared && peekNext() == TOKwild && peekNext2() == TOKrparen)
5578             {
5579                 m = MODshared | MODwild;
5580                 goto Lmod3;
5581             }
5582             else if (token.value == TOKconst && peekNext() == TOKshared && peekNext2() == TOKrparen ||
5583                      token.value == TOKshared && peekNext() == TOKconst && peekNext2() == TOKrparen)
5584             {
5585                 m = MODshared | MODconst;
5586               Lmod3:
5587                 nextToken();
5588               Lmod2:
5589                 nextToken();
5590               Lmod1:
5591                 nextToken();
5592                 e = parseUnaryExp();
5593                 e = new CastExp(loc, e, m);
5594             }
5595             else
5596             {
5597                 Type *t = parseType();          // ( type )
5598                 check(TOKrparen);
5599                 e = parseUnaryExp();
5600                 e = new CastExp(loc, e, t);
5601             }
5602             break;
5603         }
5604
5605         case TOKwild:
5606         case TOKshared:
5607         case TOKconst:
5608         case TOKinvariant:
5609         case TOKimmutable:      // immutable(type)(arguments)
5610         {
5611             Type *t = parseBasicType();
5612             if (token.value != TOKlparen)
5613                 error("(arguments) expected following type");
5614             e = new TypeExp(loc, t);
5615             e = new CallExp(loc, e, parseArguments());
5616             break;
5617         }
5618
5619
5620         case TOKlparen:
5621         {   Token *tk;
5622
5623             tk = peek(&token);
5624 #if CCASTSYNTAX
5625             // If cast
5626             if (isDeclaration(tk, 0, TOKrparen, &tk))
5627             {
5628                 tk = peek(tk);          // skip over right parenthesis
5629                 switch (tk->value)
5630                 {
5631                     case TOKnot:
5632                         tk = peek(tk);
5633                         if (tk->value == TOKis || tk->value == TOKin)   // !is or !in
5634                             break;
5635                     case TOKdot:
5636                     case TOKplusplus:
5637                     case TOKminusminus:
5638                     case TOKdelete:
5639                     case TOKnew:
5640                     case TOKlparen:
5641                     case TOKidentifier:
5642                     case TOKthis:
5643                     case TOKsuper:
5644                     case TOKint32v:
5645                     case TOKuns32v:
5646                     case TOKint64v:
5647                     case TOKuns64v:
5648                     case TOKfloat32v:
5649                     case TOKfloat64v:
5650                     case TOKfloat80v:
5651                     case TOKimaginary32v:
5652                     case TOKimaginary64v:
5653                     case TOKimaginary80v:
5654                     case TOKnull:
5655                     case TOKtrue:
5656                     case TOKfalse:
5657                     case TOKcharv:
5658                     case TOKwcharv:
5659                     case TOKdcharv:
5660                     case TOKstring:
5661 #if 0
5662                     case TOKtilde:
5663                     case TOKand:
5664                     case TOKmul:
5665                     case TOKmin:
5666                     case TOKadd:
5667 #endif
5668                     case TOKfunction:
5669                     case TOKdelegate:
5670                     case TOKtypeof:
5671 #if DMDV2
5672                     case TOKfile:
5673                     case TOKline:
5674 #endif
5675                     case BASIC_TYPES:           // (type)int.size
5676                     {   // (type) una_exp
5677                         Type *t;
5678
5679                         nextToken();
5680                         t = parseType();
5681                         check(TOKrparen);
5682
5683                         // if .identifier
5684                         if (token.value == TOKdot)
5685                         {
5686                             nextToken();
5687                             if (token.value != TOKidentifier)
5688                             {   error("Identifier expected following (type).");
5689                                 return NULL;
5690                             }
5691                             e = typeDotIdExp(loc, t, token.ident);
5692                             nextToken();
5693                             e = parsePostExp(e);
5694                         }
5695                         else
5696                         {
5697                             e = parseUnaryExp();
5698                             e = new CastExp(loc, e, t);
5699                             error("C style cast illegal, use %s", e->toChars());
5700                         }
5701                         return e;
5702                     }
5703                 }
5704             }
5705 #endif
5706             e = parsePrimaryExp();
5707             e = parsePostExp(e);
5708             break;
5709         }
5710         default:
5711             e = parsePrimaryExp();
5712             e = parsePostExp(e);
5713             break;
5714     }
5715     assert(e);
5716
5717     // ^^ is right associative and has higher precedence than the unary operators
5718     while (token.value == TOKpow)
5719     {
5720         nextToken();
5721         Expression *e2 = parseUnaryExp();
5722         e = new PowExp(loc, e, e2);
5723     }
5724
5725     return e;
5726 }
5727
5728 Expression *Parser::parseMulExp()
5729 {   Expression *e;
5730     Expression *e2;
5731     Loc loc = this->loc;
5732
5733     e = parseUnaryExp();
5734     while (1)
5735     {
5736         switch (token.value)
5737         {
5738             case TOKmul: nextToken(); e2 = parseUnaryExp(); e = new MulExp(loc,e,e2); continue;
5739             case TOKdiv: nextToken(); e2 = parseUnaryExp(); e = new DivExp(loc,e,e2); continue;
5740             case TOKmod: nextToken(); e2 = parseUnaryExp(); e = new ModExp(loc,e,e2); continue;
5741
5742             default:
5743                 break;
5744         }
5745         break;
5746     }
5747     return e;
5748 }
5749
5750 Expression *Parser::parseAddExp()
5751 {   Expression *e;
5752     Expression *e2;
5753     Loc loc = this->loc;
5754
5755     e = parseMulExp();
5756     while (1)
5757     {
5758         switch (token.value)
5759         {
5760             case TOKadd:    nextToken(); e2 = parseMulExp(); e = new AddExp(loc,e,e2); continue;
5761             case TOKmin:    nextToken(); e2 = parseMulExp(); e = new MinExp(loc,e,e2); continue;
5762             case TOKtilde:  nextToken(); e2 = parseMulExp(); e = new CatExp(loc,e,e2); continue;
5763
5764             default:
5765                 break;
5766         }
5767         break;
5768     }
5769     return e;
5770 }
5771
5772 Expression *Parser::parseShiftExp()
5773 {   Expression *e;
5774     Expression *e2;
5775     Loc loc = this->loc;
5776
5777     e = parseAddExp();
5778     while (1)
5779     {
5780         switch (token.value)
5781         {
5782             case TOKshl:  nextToken(); e2 = parseAddExp(); e = new ShlExp(loc,e,e2);  continue;
5783             case TOKshr:  nextToken(); e2 = parseAddExp(); e = new ShrExp(loc,e,e2);  continue;
5784             case TOKushr: nextToken(); e2 = parseAddExp(); e = new UshrExp(loc,e,e2); continue;
5785
5786             default:
5787                 break;
5788         }
5789         break;
5790     }
5791     return e;
5792 }
5793
5794 #if DMDV1
5795 Expression *Parser::parseRelExp()
5796 {   Expression *e;
5797     Expression *e2;
5798     enum TOK op;
5799     Loc loc = this->loc;
5800
5801     e = parseShiftExp();
5802     while (1)
5803     {
5804         switch (token.value)
5805         {
5806             case TOKlt:
5807             case TOKle:
5808             case TOKgt:
5809             case TOKge:
5810             case TOKunord:
5811             case TOKlg:
5812             case TOKleg:
5813             case TOKule:
5814             case TOKul:
5815             case TOKuge:
5816             case TOKug:
5817             case TOKue:
5818                 op = token.value;
5819                 nextToken();
5820                 e2 = parseShiftExp();
5821                 e = new CmpExp(op, loc, e, e2);
5822                 continue;
5823
5824             case TOKnot:                // could be !in
5825                 if (peekNext() == TOKin)
5826                 {
5827                     nextToken();
5828                     nextToken();
5829                     e2 = parseShiftExp();
5830                     e = new InExp(loc, e, e2);
5831                     e = new NotExp(loc, e);
5832                     continue;
5833                 }
5834                 break;
5835
5836             case TOKin:
5837                 nextToken();
5838                 e2 = parseShiftExp();
5839                 e = new InExp(loc, e, e2);
5840                 continue;
5841
5842             default:
5843                 break;
5844         }
5845         break;
5846     }
5847     return e;
5848 }
5849 #endif
5850
5851 #if DMDV1
5852 Expression *Parser::parseEqualExp()
5853 {   Expression *e;
5854     Expression *e2;
5855     Token *t;
5856     Loc loc = this->loc;
5857
5858     e = parseRelExp();
5859     while (1)
5860     {   enum TOK value = token.value;
5861
5862         switch (value)
5863         {
5864             case TOKequal:
5865             case TOKnotequal:
5866                 nextToken();
5867                 e2 = parseRelExp();
5868                 e = new EqualExp(value, loc, e, e2);
5869                 continue;
5870
5871             case TOKidentity:
5872                 error("'===' is no longer legal, use 'is' instead");
5873                 goto L1;
5874
5875             case TOKnotidentity:
5876                 error("'!==' is no longer legal, use '!is' instead");
5877                 goto L1;
5878
5879             case TOKis:
5880                 value = TOKidentity;
5881                 goto L1;
5882
5883             case TOKnot:
5884                 // Attempt to identify '!is'
5885                 t = peek(&token);
5886                 if (t->value != TOKis)
5887                     break;
5888                 nextToken();
5889                 value = TOKnotidentity;
5890                 goto L1;
5891
5892             L1:
5893                 nextToken();
5894                 e2 = parseRelExp();
5895                 e = new IdentityExp(value, loc, e, e2);
5896                 continue;
5897
5898             default:
5899                 break;
5900         }
5901         break;
5902     }
5903     return e;
5904 }
5905 #endif
5906
5907 Expression *Parser::parseCmpExp()
5908 {   Expression *e;
5909     Expression *e2;
5910     Token *t;
5911     Loc loc = this->loc;
5912
5913     e = parseShiftExp();
5914     enum TOK op = token.value;
5915
5916     switch (op)
5917     {
5918         case TOKequal:
5919         case TOKnotequal:
5920             nextToken();
5921             e2 = parseShiftExp();
5922             e = new EqualExp(op, loc, e, e2);
5923             break;
5924
5925         case TOKis:
5926             op = TOKidentity;
5927             goto L1;
5928
5929         case TOKnot:
5930             // Attempt to identify '!is'
5931             t = peek(&token);
5932             if (t->value == TOKin)
5933             {
5934                 nextToken();
5935                 nextToken();
5936                 e2 = parseShiftExp();
5937                 e = new InExp(loc, e, e2);
5938                 e = new NotExp(loc, e);
5939                 break;
5940             }
5941             if (t->value != TOKis)
5942                 break;
5943             nextToken();
5944             op = TOKnotidentity;
5945             goto L1;
5946
5947         L1:
5948             nextToken();
5949             e2 = parseShiftExp();
5950             e = new IdentityExp(op, loc, e, e2);
5951             break;
5952
5953         case TOKlt:
5954         case TOKle:
5955         case TOKgt:
5956         case TOKge:
5957         case TOKunord:
5958         case TOKlg:
5959         case TOKleg:
5960         case TOKule:
5961         case TOKul:
5962         case TOKuge:
5963         case TOKug:
5964         case TOKue:
5965             nextToken();
5966             e2 = parseShiftExp();
5967             e = new CmpExp(op, loc, e, e2);
5968             break;
5969
5970         case TOKin:
5971             nextToken();
5972             e2 = parseShiftExp();
5973             e = new InExp(loc, e, e2);
5974             break;
5975
5976         default:
5977             break;
5978     }
5979     return e;
5980 }
5981
5982 Expression *Parser::parseAndExp()
5983 {
5984     Loc loc = this->loc;
5985
5986     Expression *e = parseCmpExp();
5987     while (token.value == TOKand)
5988     {
5989         checkParens(TOKand, e);
5990         nextToken();
5991         Expression *e2 = parseCmpExp();
5992         checkParens(TOKand, e2);
5993         e = new AndExp(loc,e,e2);
5994         loc = this->loc;
5995     }
5996     return e;
5997 }
5998
5999 Expression *Parser::parseXorExp()
6000 {
6001     Loc loc = this->loc;
6002
6003     Expression *e = parseAndExp();
6004     while (token.value == TOKxor)
6005     {
6006         checkParens(TOKxor, e);
6007         nextToken();
6008         Expression *e2 = parseAndExp();
6009         checkParens(TOKxor, e2);
6010         e = new XorExp(loc, e, e2);
6011     }
6012     return e;
6013 }
6014
6015 Expression *Parser::parseOrExp()
6016 {
6017     Loc loc = this->loc;
6018
6019     Expression *e = parseXorExp();
6020     while (token.value == TOKor)
6021     {
6022         checkParens(TOKor, e);
6023         nextToken();
6024         Expression *e2 = parseXorExp();
6025         checkParens(TOKor, e2);
6026         e = new OrExp(loc, e, e2);
6027     }
6028     return e;
6029 }
6030
6031 Expression *Parser::parseAndAndExp()
6032 {   Expression *e;
6033     Expression *e2;
6034     Loc loc = this->loc;
6035
6036     e = parseOrExp();
6037     while (token.value == TOKandand)
6038     {
6039         nextToken();
6040         e2 = parseOrExp();
6041         e = new AndAndExp(loc, e, e2);
6042     }
6043     return e;
6044 }
6045
6046 Expression *Parser::parseOrOrExp()
6047 {   Expression *e;
6048     Expression *e2;
6049     Loc loc = this->loc;
6050
6051     e = parseAndAndExp();
6052     while (token.value == TOKoror)
6053     {
6054         nextToken();
6055         e2 = parseAndAndExp();
6056         e = new OrOrExp(loc, e, e2);
6057     }
6058     return e;
6059 }
6060
6061 Expression *Parser::parseCondExp()
6062 {   Expression *e;
6063     Expression *e1;
6064     Expression *e2;
6065     Loc loc = this->loc;
6066
6067     e = parseOrOrExp();
6068     if (token.value == TOKquestion)
6069     {
6070         nextToken();
6071         e1 = parseExpression();
6072         check(TOKcolon);
6073         e2 = parseCondExp();
6074         e = new CondExp(loc, e, e1, e2);
6075     }
6076     return e;
6077 }
6078
6079 Expression *Parser::parseAssignExp()
6080 {   Expression *e;
6081     Expression *e2;
6082     Loc loc;
6083
6084     e = parseCondExp();
6085     while (1)
6086     {
6087         loc = this->loc;
6088         switch (token.value)
6089         {
6090 #define X(tok,ector) \
6091             case tok:  nextToken(); e2 = parseAssignExp(); e = new ector(loc,e,e2); continue;
6092
6093             X(TOKassign,    AssignExp);
6094             X(TOKaddass,    AddAssignExp);
6095             X(TOKminass,    MinAssignExp);
6096             X(TOKmulass,    MulAssignExp);
6097             X(TOKdivass,    DivAssignExp);
6098             X(TOKmodass,    ModAssignExp);
6099             X(TOKpowass,    PowAssignExp);
6100             X(TOKandass,    AndAssignExp);
6101             X(TOKorass,     OrAssignExp);
6102             X(TOKxorass,    XorAssignExp);
6103             X(TOKshlass,    ShlAssignExp);
6104             X(TOKshrass,    ShrAssignExp);
6105             X(TOKushrass,   UshrAssignExp);
6106             X(TOKcatass,    CatAssignExp);
6107
6108 #undef X
6109             default:
6110                 break;
6111         }
6112         break;
6113     }
6114     return e;
6115 }
6116
6117 Expression *Parser::parseExpression()
6118 {   Expression *e;
6119     Expression *e2;
6120     Loc loc = this->loc;
6121
6122     //printf("Parser::parseExpression() loc = %d\n", loc.linnum);
6123     e = parseAssignExp();
6124     while (token.value == TOKcomma)
6125     {
6126         nextToken();
6127         e2 = parseAssignExp();
6128         e = new CommaExp(loc, e, e2);
6129         loc = this->loc;
6130     }
6131     return e;
6132 }
6133
6134
6135 /*************************
6136  * Collect argument list.
6137  * Assume current token is ',', '(' or '['.
6138  */
6139
6140 Expressions *Parser::parseArguments()
6141 {   // function call
6142     Expressions *arguments;
6143     Expression *arg;
6144     enum TOK endtok;
6145
6146     arguments = new Expressions();
6147     if (token.value == TOKlbracket)
6148         endtok = TOKrbracket;
6149     else
6150         endtok = TOKrparen;
6151
6152     {
6153         nextToken();
6154         while (token.value != endtok)
6155         {
6156                 arg = parseAssignExp();
6157                 arguments->push(arg);
6158                 if (token.value == endtok)
6159                     break;
6160                 check(TOKcomma);
6161         }
6162         check(endtok);
6163     }
6164     return arguments;
6165 }
6166
6167 /*******************************************
6168  */
6169
6170 Expression *Parser::parseNewExp(Expression *thisexp)
6171 {   Type *t;
6172     Expressions *newargs;
6173     Expressions *arguments = NULL;
6174     Expression *e;
6175     Loc loc = this->loc;
6176
6177     nextToken();
6178     newargs = NULL;
6179     if (token.value == TOKlparen)
6180     {
6181         newargs = parseArguments();
6182     }
6183
6184     // An anonymous nested class starts with "class"
6185     if (token.value == TOKclass)
6186     {
6187         nextToken();
6188         if (token.value == TOKlparen)
6189             arguments = parseArguments();
6190
6191         BaseClasses *baseclasses = NULL;
6192         if (token.value != TOKlcurly)
6193             baseclasses = parseBaseClasses();
6194
6195         Identifier *id = NULL;
6196         ClassDeclaration *cd = new ClassDeclaration(loc, id, baseclasses);
6197
6198         if (token.value != TOKlcurly)
6199         {   error("{ members } expected for anonymous class");
6200             cd->members = NULL;
6201         }
6202         else
6203         {
6204             nextToken();
6205             Dsymbols *decl = parseDeclDefs(0);
6206             if (token.value != TOKrcurly)
6207                 error("class member expected");
6208             nextToken();
6209             cd->members = decl;
6210         }
6211
6212         e = new NewAnonClassExp(loc, thisexp, newargs, cd, arguments);
6213
6214         return e;
6215     }
6216
6217     t = parseBasicType();
6218     t = parseBasicType2(t);
6219     if (t->ty == Taarray)
6220     {   TypeAArray *taa = (TypeAArray *)t;
6221         Type *index = taa->index;
6222
6223         Expression *e = index->toExpression();
6224         if (e)
6225         {   arguments = new Expressions();
6226             arguments->push(e);
6227             t = new TypeDArray(taa->next);
6228         }
6229         else
6230         {
6231             error("need size of rightmost array, not type %s", index->toChars());
6232             return new NullExp(loc);
6233         }
6234     }
6235     else if (t->ty == Tsarray)
6236     {
6237         TypeSArray *tsa = (TypeSArray *)t;
6238         Expression *e = tsa->dim;
6239
6240         arguments = new Expressions();
6241         arguments->push(e);
6242         t = new TypeDArray(tsa->next);
6243     }
6244     else if (token.value == TOKlparen)
6245     {
6246         arguments = parseArguments();
6247     }
6248     e = new NewExp(loc, thisexp, newargs, t, arguments);
6249     return e;
6250 }
6251
6252 /**********************************************
6253  */
6254
6255 void Parser::addComment(Dsymbol *s, unsigned char *blockComment)
6256 {
6257     s->addComment(combineComments(blockComment, token.lineComment));
6258     token.lineComment = NULL;
6259 }
6260
6261
6262 /**********************************
6263  * Set operator precedence for each operator.
6264  */
6265
6266 enum PREC precedence[TOKMAX];
6267
6268 void initPrecedence()
6269 {
6270     for (int i = 0; i < TOKMAX; i++)
6271         precedence[i] = PREC_zero;
6272
6273     precedence[TOKtype] = PREC_expr;
6274     precedence[TOKerror] = PREC_expr;
6275
6276     precedence[TOKtypeof] = PREC_primary;
6277     precedence[TOKmixin] = PREC_primary;
6278
6279     precedence[TOKdotvar] = PREC_primary;
6280     precedence[TOKimport] = PREC_primary;
6281     precedence[TOKidentifier] = PREC_primary;
6282     precedence[TOKthis] = PREC_primary;
6283     precedence[TOKsuper] = PREC_primary;
6284     precedence[TOKint64] = PREC_primary;
6285     precedence[TOKfloat64] = PREC_primary;
6286     precedence[TOKcomplex80] = PREC_primary;
6287     precedence[TOKnull] = PREC_primary;
6288     precedence[TOKstring] = PREC_primary;
6289     precedence[TOKarrayliteral] = PREC_primary;
6290     precedence[TOKassocarrayliteral] = PREC_primary;
6291 #if DMDV2
6292     precedence[TOKfile] = PREC_primary;
6293     precedence[TOKline] = PREC_primary;
6294 #endif
6295     precedence[TOKtypeid] = PREC_primary;
6296     precedence[TOKis] = PREC_primary;
6297     precedence[TOKassert] = PREC_primary;
6298     precedence[TOKhalt] = PREC_primary;
6299     precedence[TOKtemplate] = PREC_primary;
6300     precedence[TOKdsymbol] = PREC_primary;
6301     precedence[TOKfunction] = PREC_primary;
6302     precedence[TOKvar] = PREC_primary;
6303     precedence[TOKsymoff] = PREC_primary;
6304     precedence[TOKstructliteral] = PREC_primary;
6305     precedence[TOKarraylength] = PREC_primary;
6306     precedence[TOKremove] = PREC_primary;
6307     precedence[TOKtuple] = PREC_primary;
6308 #if DMDV2
6309     precedence[TOKtraits] = PREC_primary;
6310     precedence[TOKdefault] = PREC_primary;
6311     precedence[TOKoverloadset] = PREC_primary;
6312 #endif
6313
6314     // post
6315     precedence[TOKdotti] = PREC_primary;
6316     precedence[TOKdot] = PREC_primary;
6317     precedence[TOKdottd] = PREC_primary;
6318     precedence[TOKdotexp] = PREC_primary;
6319     precedence[TOKdottype] = PREC_primary;
6320 //  precedence[TOKarrow] = PREC_primary;
6321     precedence[TOKplusplus] = PREC_primary;
6322     precedence[TOKminusminus] = PREC_primary;
6323 #if DMDV2
6324     precedence[TOKpreplusplus] = PREC_primary;
6325     precedence[TOKpreminusminus] = PREC_primary;
6326 #endif
6327     precedence[TOKcall] = PREC_primary;
6328     precedence[TOKslice] = PREC_primary;
6329     precedence[TOKarray] = PREC_primary;
6330     precedence[TOKindex] = PREC_primary;
6331
6332     precedence[TOKdelegate] = PREC_unary;
6333     precedence[TOKaddress] = PREC_unary;
6334     precedence[TOKstar] = PREC_unary;
6335     precedence[TOKneg] = PREC_unary;
6336     precedence[TOKuadd] = PREC_unary;
6337     precedence[TOKnot] = PREC_unary;
6338     precedence[TOKtobool] = PREC_add;
6339     precedence[TOKtilde] = PREC_unary;
6340     precedence[TOKdelete] = PREC_unary;
6341     precedence[TOKnew] = PREC_unary;
6342     precedence[TOKnewanonclass] = PREC_unary;
6343     precedence[TOKcast] = PREC_unary;
6344
6345 #if DMDV2
6346     precedence[TOKpow] = PREC_pow;
6347 #endif
6348
6349     precedence[TOKmul] = PREC_mul;
6350     precedence[TOKdiv] = PREC_mul;
6351     precedence[TOKmod] = PREC_mul;
6352
6353     precedence[TOKadd] = PREC_add;
6354     precedence[TOKmin] = PREC_add;
6355     precedence[TOKcat] = PREC_add;
6356
6357     precedence[TOKshl] = PREC_shift;
6358     precedence[TOKshr] = PREC_shift;
6359     precedence[TOKushr] = PREC_shift;
6360
6361     precedence[TOKlt] = PREC_rel;
6362     precedence[TOKle] = PREC_rel;
6363     precedence[TOKgt] = PREC_rel;
6364     precedence[TOKge] = PREC_rel;
6365     precedence[TOKunord] = PREC_rel;
6366     precedence[TOKlg] = PREC_rel;
6367     precedence[TOKleg] = PREC_rel;
6368     precedence[TOKule] = PREC_rel;
6369     precedence[TOKul] = PREC_rel;
6370     precedence[TOKuge] = PREC_rel;
6371     precedence[TOKug] = PREC_rel;
6372     precedence[TOKue] = PREC_rel;
6373     precedence[TOKin] = PREC_rel;
6374
6375 #if 0
6376     precedence[TOKequal] = PREC_equal;
6377     precedence[TOKnotequal] = PREC_equal;
6378     precedence[TOKidentity] = PREC_equal;
6379     precedence[TOKnotidentity] = PREC_equal;
6380 #else
6381     /* Note that we changed precedence, so that < and != have the same
6382      * precedence. This change is in the parser, too.
6383      */
6384     precedence[TOKequal] = PREC_rel;
6385     precedence[TOKnotequal] = PREC_rel;
6386     precedence[TOKidentity] = PREC_rel;
6387     precedence[TOKnotidentity] = PREC_rel;
6388 #endif
6389
6390     precedence[TOKand] = PREC_and;
6391
6392     precedence[TOKxor] = PREC_xor;
6393
6394     precedence[TOKor] = PREC_or;
6395
6396     precedence[TOKandand] = PREC_andand;
6397
6398     precedence[TOKoror] = PREC_oror;
6399
6400     precedence[TOKquestion] = PREC_cond;
6401
6402     precedence[TOKassign] = PREC_assign;
6403     precedence[TOKconstruct] = PREC_assign;
6404     precedence[TOKblit] = PREC_assign;
6405     precedence[TOKaddass] = PREC_assign;
6406     precedence[TOKminass] = PREC_assign;
6407     precedence[TOKcatass] = PREC_assign;
6408     precedence[TOKmulass] = PREC_assign;
6409     precedence[TOKdivass] = PREC_assign;
6410     precedence[TOKmodass] = PREC_assign;
6411 #if DMDV2
6412     precedence[TOKpowass] = PREC_assign;
6413 #endif
6414     precedence[TOKshlass] = PREC_assign;
6415     precedence[TOKshrass] = PREC_assign;
6416     precedence[TOKushrass] = PREC_assign;
6417     precedence[TOKandass] = PREC_assign;
6418     precedence[TOKorass] = PREC_assign;
6419     precedence[TOKxorass] = PREC_assign;
6420
6421     precedence[TOKcomma] = PREC_expr;
6422     precedence[TOKdeclaration] = PREC_expr;
6423 }
Note: See TracBrowser for help on using the browser.