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