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