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