2 /* Compiler implementation of the D programming language
3 * Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved
4 * written by Walter Bright
5 * http://www.digitalmars.com
6 * Distributed under the Boost Software License, Version 1.0.
7 * http://www.boost.org/LICENSE_1_0.txt
8 * https://github.com/D-Programming-Language/dmd/blob/master/src/parse.c
11 // This is the D parser
13 #include "root/dsystem.h" // strlen(),memcpy()
14 #include "root/rmem.h"
24 #include "staticassert.h"
25 #include "expression.h"
26 #include "statement.h"
30 #include "declaration.h"
31 #include "aggregate.h"
35 #include "aliasthis.h"
39 Expression *typeToExpression(Type *t);
41 // Support C cast syntax:
45 // Support postfix C array declarations, such as
49 Parser::Parser(Module *module, const utf8_t *base, size_t length, bool doDocComment)
50 : Lexer(module ? module->srcfile->toChars() : NULL, base, 0, length, doDocComment, false)
52 //printf("Parser::Parser()\n");
58 lookingForElse = Loc();
59 //nextToken(); // start up the scanner
62 /*********************
63 * Use this constructor for string mixins.
65 * loc location in source file of mixin
67 Parser::Parser(Loc loc, Module *module, const utf8_t *base, size_t length, bool doDocComment)
68 : Lexer(module ? module->srcfile->toChars() : NULL, base, 0, length, doDocComment, false)
70 //printf("Parser::Parser()\n");
76 /* Create a pseudo-filename for the mixin string, as it may not even exist
79 char *filename = (char *)mem.xmalloc(strlen(loc.filename) + 7 + sizeof(loc.linnum) * 3 + 1);
80 sprintf(filename, "%s-mixin-%d", loc.filename, (int)loc.linnum);
81 scanloc.filename = filename;
90 lookingForElse = Loc();
91 //nextToken(); // start up the scanner
94 Dsymbols *Parser::parseModule()
96 const utf8_t *comment = token.blockComment;
97 bool isdeprecated = false;
98 Expression *msg = NULL;
99 Expressions *udas = NULL;
103 if (skipAttributes(&token, &tk) && tk->value == TOKmodule)
105 while (token.value != TOKmodule)
111 // deprecated (...) module ...
114 error("there is only one deprecation attribute allowed for module declaration");
121 if (token.value == TOKlparen)
124 msg = parseAssignExp();
131 Expressions *exps = NULL;
132 StorageClass stc = parseAttribute(&exps);
134 if (stc == STCproperty || stc == STCnogc || stc == STCdisable ||
135 stc == STCsafe || stc == STCtrusted || stc == STCsystem)
137 error("@%s attribute for module declaration is not supported", token.toChars());
141 udas = UserAttributeDeclaration::concat(udas, exps);
149 error("'module' expected instead of %s", token.toChars());
159 Dsymbols *a = new Dsymbols();
160 UserAttributeDeclaration *udad = new UserAttributeDeclaration(udas, a);
161 mod->userAttribDecl = udad;
164 // ModuleDeclation leads off
165 if (token.value == TOKmodule)
170 if (token.value != TOKidentifier)
172 error("identifier expected following module");
177 Identifiers *a = NULL;
181 while (nextToken() == TOKdot)
184 a = new Identifiers();
187 if (token.value != TOKidentifier)
189 error("identifier expected following package");
195 md = new ModuleDeclaration(loc, a, id);
196 md->isdeprecated = isdeprecated;
199 if (token.value != TOKsemicolon)
200 error("';' expected following module declaration instead of %s", token.toChars());
202 addComment(mod, comment);
206 decldefs = parseDeclDefs(0);
207 if (token.value != TOKeof)
209 error(token.loc, "unrecognized declaration");
215 while (token.value != TOKsemicolon && token.value != TOKeof)
218 return new Dsymbols();
221 struct PrefixAttributes
223 StorageClass storageClass;
230 const utf8_t *comment;
233 : storageClass(STCundefined),
236 protection(PROTundefined),
245 Dsymbols *Parser::parseDeclDefs(int once, Dsymbol **pLastDecl, PrefixAttributes *pAttrs)
247 Dsymbol *lastDecl = NULL; // used to link unittest to its previous declaration
249 pLastDecl = &lastDecl;
251 LINK linksave = linkage; // save global state
253 //printf("Parser::parseDeclDefs()\n");
254 Dsymbols *decldefs = new Dsymbols();
261 PrefixAttributes attrs;
262 if (!once || !pAttrs)
265 pAttrs->comment = token.blockComment;
269 Condition *condition;
277 /* Determine if this is a manifest constant declaration,
278 * or a conventional enum.
280 Token *t = peek(&token);
281 if (t->value == TOKlcurly || t->value == TOKcolon)
283 else if (t->value != TOKidentifier)
288 if (t->value == TOKlcurly || t->value == TOKcolon ||
289 t->value == TOKsemicolon)
303 s = (Dsymbol *)parseTemplateDeclaration();
315 check(TOKlparen, "mixin");
316 Expression *e = parseAssignExp();
319 s = new CompileDeclaration(loc, e);
325 s = (Dsymbol *)parseTemplateDeclaration(true);
335 case TOKwchar: case TOKdchar:
336 case TOKbool: case TOKchar:
337 case TOKint8: case TOKuns8:
338 case TOKint16: case TOKuns16:
339 case TOKint32: case TOKuns32:
340 case TOKint64: case TOKuns64:
341 case TOKint128: case TOKuns128:
342 case TOKfloat32: case TOKfloat64: case TOKfloat80:
343 case TOKimaginary32: case TOKimaginary64: case TOKimaginary80:
344 case TOKcomplex32: case TOKcomplex64: case TOKcomplex80:
357 a = parseDeclarations(false, pAttrs, pAttrs->comment);
359 *pLastDecl = (*a)[a->dim-1];
363 if (peekNext() == TOKdot)
366 s = parseCtor(pAttrs);
370 s = parseDtor(pAttrs);
375 Token *t = peek(&token);
376 if ((t->value == TOKlparen && peek(t)->value == TOKrparen) ||
377 t->value == TOKlcurly)
381 s = parseInvariant(pAttrs);
385 error("invariant body expected, not '%s'", token.toChars());
392 if (global.params.useUnitTests || global.params.doDocComments || global.params.doHdrGeneration)
394 s = parseUnitTest(pAttrs);
396 (*pLastDecl)->ddocUnittest = (UnitTestDeclaration *)s;
400 // Skip over unittest block by counting { }
420 error(loc, "closing } of unittest not found before end of file");
428 // Workaround 14894. Add an empty unittest declaration to keep
429 // the number of symbols in this scope independent of -unittest.
430 s = new UnitTestDeclaration(loc, token.loc, STCundefined, NULL);
435 s = parseNew(pAttrs);
439 s = parseDelete(pAttrs);
444 error("declaration expected, not '%s'",token.toChars());
450 error("declaration expected, not '%s'", token.toChars());
455 TOK next = peekNext();
457 s = parseStaticCtor(pAttrs);
458 else if (next == TOKtilde)
459 s = parseStaticDtor(pAttrs);
460 else if (next == TOKassert)
461 s = parseStaticAssert();
462 else if (next == TOKif)
464 condition = parseStaticIfCondition();
466 if (token.value == TOKcolon)
467 athen = parseBlock(pLastDecl);
470 Loc lookingForElseSave = lookingForElse;
471 lookingForElse = token.loc;
472 athen = parseBlock(pLastDecl);
473 lookingForElse = lookingForElseSave;
475 Dsymbols *aelse = NULL;
476 if (token.value == TOKelse)
478 Loc elseloc = token.loc;
480 aelse = parseBlock(pLastDecl);
481 checkDanglingElse(elseloc);
483 s = new StaticIfDeclaration(condition, athen, aelse);
485 else if (next == TOKimport)
499 if (peekNext() == TOKlparen)
505 if (peekNext() == TOKlparen)
512 TOK next = peekNext();
513 if (next == TOKlparen)
515 if (next == TOKstatic)
517 TOK next2 = peekNext2();
518 if (next2 == TOKthis)
520 s = parseSharedStaticCtor(pAttrs);
523 if (next2 == TOKtilde)
525 s = parseSharedStaticDtor(pAttrs);
534 if (peekNext() == TOKlparen)
539 case TOKfinal: stc = STCfinal; goto Lstc;
540 case TOKauto: stc = STCauto; goto Lstc;
541 case TOKscope: stc = STCscope; goto Lstc;
542 case TOKoverride: stc = STCoverride; goto Lstc;
543 case TOKabstract: stc = STCabstract; goto Lstc;
544 case TOKsynchronized: stc = STCsynchronized; goto Lstc;
545 case TOKnothrow: stc = STCnothrow; goto Lstc;
546 case TOKpure: stc = STCpure; goto Lstc;
547 case TOKref: stc = STCref; goto Lstc;
548 case TOKgshared: stc = STCgshared; goto Lstc;
549 //case TOKmanifest: stc = STCmanifest; goto Lstc;
552 Expressions *exps = NULL;
553 stc = parseAttribute(&exps);
555 goto Lstc; // it's a predefined attribute
556 // no redundant/conflicting check for UDAs
557 pAttrs->udas = UserAttributeDeclaration::concat(pAttrs->udas, exps);
561 pAttrs->storageClass = appendStorageClass(pAttrs->storageClass, stc);
567 /* Look for auto initializers:
568 * storage_class identifier = initializer;
569 * storage_class identifier(...) = initializer;
571 if (token.value == TOKidentifier &&
572 skipParensIf(peek(&token), &tk) &&
573 tk->value == TOKassign)
575 a = parseAutoDeclarations(pAttrs->storageClass, pAttrs->comment);
576 pAttrs->storageClass = STCundefined;
578 *pLastDecl = (*a)[a->dim-1];
581 s = new UserAttributeDeclaration(pAttrs->udas, a);
587 /* Look for return type inference for template functions.
589 if (token.value == TOKidentifier && skipParens(peek(&token), &tk) && skipAttributes(tk, &tk) &&
590 (tk->value == TOKlparen || tk->value == TOKlcurly || tk->value == TOKin ||
591 tk->value == TOKout || tk->value == TOKdo ||
592 (tk->value == TOKidentifier && tk->ident == Id::_body))
595 a = parseDeclarations(true, pAttrs, pAttrs->comment);
597 *pLastDecl = (*a)[a->dim-1];
600 s = new UserAttributeDeclaration(pAttrs->udas, a);
606 a = parseBlock(pLastDecl, pAttrs);
607 if (pAttrs->storageClass != STCundefined)
609 s = new StorageClassDeclaration(pAttrs->storageClass, a);
610 pAttrs->storageClass = STCundefined;
619 s = new UserAttributeDeclaration(pAttrs->udas, a);
626 if (peek(&token)->value != TOKlparen)
633 Expression *e = parseAssignExp();
637 error("conflicting storage class 'deprecated(%s)' and 'deprecated(%s)'",
638 pAttrs->depmsg->toChars(), e->toChars());
641 a = parseBlock(pLastDecl, pAttrs);
644 s = new DeprecatedDeclaration(pAttrs->depmsg, a);
645 pAttrs->depmsg = NULL;
652 if (peekNext() == TOKrbracket)
653 error("empty attribute list is not allowed");
654 error("use @(attributes) instead of [attributes]");
655 Expressions *exps = parseArguments();
656 // no redundant/conflicting check for UDAs
658 pAttrs->udas = UserAttributeDeclaration::concat(pAttrs->udas, exps);
659 a = parseBlock(pLastDecl, pAttrs);
662 s = new UserAttributeDeclaration(pAttrs->udas, a);
670 if (peek(&token)->value != TOKlparen)
676 Loc linkLoc = token.loc;
677 Identifiers *idents = NULL;
678 CPPMANGLE cppmangle = CPPMANGLEdefault;
679 LINK link = parseLinkage(&idents, &cppmangle);
680 if (pAttrs->link != LINKdefault)
682 if (pAttrs->link != link)
684 error("conflicting linkage extern (%s) and extern (%s)",
685 linkageToChars(pAttrs->link), linkageToChars(link));
690 // extern(C++, foo) extern(C++, bar) void foo();
691 // to be equivalent with:
692 // extern(C++, foo.bar) void foo();
695 error("redundant linkage extern (%s)", linkageToChars(pAttrs->link));
698 this->linkage = link;
699 a = parseBlock(pLastDecl, pAttrs);
702 assert(link == LINKcpp);
704 for (size_t i = idents->dim; i;)
706 Identifier *id = (*idents)[--i];
712 s = new Nspace(linkLoc, id, a);
715 pAttrs->link = LINKdefault;
717 else if (pAttrs->link != LINKdefault)
719 s = new LinkDeclaration(pAttrs->link, a);
720 pAttrs->link = LINKdefault;
722 else if (cppmangle != CPPMANGLEdefault)
724 assert(link == LINKcpp);
725 s = new CPPMangleDeclaration(cppmangle, a);
730 case TOKprivate: prot = PROTprivate; goto Lprot;
731 case TOKpackage: prot = PROTpackage; goto Lprot;
732 case TOKprotected: prot = PROTprotected; goto Lprot;
733 case TOKpublic: prot = PROTpublic; goto Lprot;
734 case TOKexport: prot = PROTexport; goto Lprot;
737 if (pAttrs->protection.kind != PROTundefined)
739 if (pAttrs->protection.kind != prot)
740 error("conflicting protection attribute '%s' and '%s'",
741 protectionToChars(pAttrs->protection.kind), protectionToChars(prot));
743 error("redundant protection attribute '%s'", protectionToChars(prot));
745 pAttrs->protection.kind = prot;
749 // optional qualified package identifier to bind
751 Identifiers *pkg_prot_idents = NULL;
752 if (pAttrs->protection.kind == PROTpackage && token.value == TOKlparen)
754 pkg_prot_idents = parseQualifiedIdentifier("protection package");
760 while (token.value != TOKsemicolon && token.value != TOKeof)
767 Loc attrloc = token.loc;
768 a = parseBlock(pLastDecl, pAttrs);
769 if (pAttrs->protection.kind != PROTundefined)
771 if (pAttrs->protection.kind == PROTpackage && pkg_prot_idents)
772 s = new ProtDeclaration(attrloc, pkg_prot_idents, a);
774 s = new ProtDeclaration(attrloc, pAttrs->protection, a);
776 pAttrs->protection = Prot(PROTundefined);
783 const Loc attrLoc = token.loc;
787 Expression *e = NULL; // default
788 if (token.value == TOKlparen)
791 e = parseAssignExp();
795 if (pAttrs->setAlignment)
801 buf1.printf("(%s)", e->toChars());
802 s1 = buf1.peekString();
804 error("redundant alignment attribute align%s", s1);
807 pAttrs->setAlignment = true;
809 a = parseBlock(pLastDecl, pAttrs);
810 if (pAttrs->setAlignment)
812 s = new AlignDeclaration(attrLoc, pAttrs->ealign, a);
813 pAttrs->setAlignment = false;
814 pAttrs->ealign = NULL;
821 Expressions *args = NULL;
826 if (token.value != TOKidentifier)
828 error("pragma(identifier) expected");
831 Identifier *ident = token.ident;
833 if (token.value == TOKcomma && peekNext() != TOKrparen)
834 args = parseArguments(); // pragma(identifier, args...)
836 check(TOKrparen); // pragma(identifier)
839 if (token.value == TOKsemicolon)
841 /* Bugzilla 2354: Accept single semicolon as an empty
842 * DeclarationBlock following attribute.
844 * Attribute DeclarationBlock
851 a2 = parseBlock(pLastDecl);
852 s = new PragmaDeclaration(loc, ident, args, a2);
858 if (token.value == TOKassign)
861 if (token.value == TOKidentifier)
862 s = new DebugSymbol(token.loc, token.ident);
863 else if (token.value == TOKint32v || token.value == TOKint64v)
864 s = new DebugSymbol(token.loc, (unsigned)token.uns64value);
867 error("identifier or integer expected, not %s", token.toChars());
871 if (token.value != TOKsemicolon)
872 error("semicolon expected");
877 condition = parseDebugCondition();
882 if (token.value == TOKassign)
885 if (token.value == TOKidentifier)
886 s = new VersionSymbol(token.loc, token.ident);
887 else if (token.value == TOKint32v || token.value == TOKint64v)
888 s = new VersionSymbol(token.loc, (unsigned)token.uns64value);
891 error("identifier or integer expected, not %s", token.toChars());
895 if (token.value != TOKsemicolon)
896 error("semicolon expected");
900 condition = parseVersionCondition();
906 if (token.value == TOKcolon)
907 athen = parseBlock(pLastDecl);
910 Loc lookingForElseSave = lookingForElse;
911 lookingForElse = token.loc;
912 athen = parseBlock(pLastDecl);
913 lookingForElse = lookingForElseSave;
915 Dsymbols *aelse = NULL;
916 if (token.value == TOKelse)
918 Loc elseloc = token.loc;
920 aelse = parseBlock(pLastDecl);
921 checkDanglingElse(elseloc);
923 s = new ConditionalDeclaration(condition, athen, aelse);
927 case TOKsemicolon: // empty declaration
928 //error("empty declaration");
933 error("declaration expected, not '%s'",token.toChars());
935 while (token.value != TOKsemicolon && token.value != TOKeof)
944 if (!s->isAttribDeclaration())
947 addComment(s, pAttrs->comment);
949 else if (a && a->dim)
960 /*********************************************
961 * Give error on redundant/conflicting storage class.
963 * TODO: remove deprecation in 2.068 and keep only error
966 StorageClass Parser::appendStorageClass(StorageClass storageClass, StorageClass stc,
969 if ((storageClass & stc) ||
970 (storageClass & STCin && stc & (STCconst | STCscope)) ||
971 (stc & STCin && storageClass & (STCconst | STCscope)))
974 stcToBuffer(&buf, stc);
976 deprecation("redundant attribute '%s'", buf.peekString());
978 error("redundant attribute '%s'", buf.peekString());
979 return storageClass | stc;
984 if (stc & (STCconst | STCimmutable | STCmanifest))
986 StorageClass u = storageClass & (STCconst | STCimmutable | STCmanifest);
988 error("conflicting attribute '%s'", Token::toChars(token.value));
990 if (stc & (STCgshared | STCshared | STCtls))
992 StorageClass u = storageClass & (STCgshared | STCshared | STCtls);
994 error("conflicting attribute '%s'", Token::toChars(token.value));
996 if (stc & (STCsafe | STCsystem | STCtrusted))
998 StorageClass u = storageClass & (STCsafe | STCsystem | STCtrusted);
1000 error("conflicting attribute '@%s'", token.toChars());
1003 return storageClass;
1006 /***********************************************
1007 * Parse attribute, lexer is on '@'.
1009 * pudas array of UDAs to append to
1011 * storage class if a predefined attribute; also scanner remains on identifier.
1012 * 0 if not a predefined attribute
1013 * *pudas set if user defined attribute, scanner is past UDA
1014 * *pudas NULL if not a user defined attribute
1017 StorageClass Parser::parseAttribute(Expressions **pudas)
1020 Expressions *udas = NULL;
1021 StorageClass stc = 0;
1022 if (token.value == TOKidentifier)
1024 if (token.ident == Id::property)
1026 else if (token.ident == Id::nogc)
1028 else if (token.ident == Id::safe)
1030 else if (token.ident == Id::trusted)
1032 else if (token.ident == Id::system)
1034 else if (token.ident == Id::disable)
1036 else if (token.ident == Id::future)
1040 // Allow identifier, template instantiation, or function call
1041 Expression *exp = parsePrimaryExp();
1042 if (token.value == TOKlparen)
1044 Loc loc = token.loc;
1045 exp = new CallExp(loc, exp, parseArguments());
1048 udas = new Expressions();
1052 else if (token.value == TOKlparen)
1054 // @( ArgumentList )
1055 // Concatenate with existing
1056 if (peekNext() == TOKrparen)
1057 error("empty attribute list is not allowed");
1058 udas = parseArguments();
1062 error("@identifier or @(ArgumentList) expected, not @%s", token.toChars());
1070 *pudas = UserAttributeDeclaration::concat(*pudas, udas);
1073 error("valid attributes are @property, @safe, @trusted, @system, @disable");
1077 /***********************************************
1078 * Parse const/immutable/shared/inout/nothrow/pure postfix
1081 StorageClass Parser::parsePostfix(StorageClass storageClass, Expressions **pudas)
1086 switch (token.value)
1088 case TOKconst: stc = STCconst; break;
1089 case TOKimmutable: stc = STCimmutable; break;
1090 case TOKshared: stc = STCshared; break;
1091 case TOKwild: stc = STCwild; break;
1092 case TOKnothrow: stc = STCnothrow; break;
1093 case TOKpure: stc = STCpure; break;
1094 case TOKreturn: stc = STCreturn; break;
1095 case TOKscope: stc = STCscope; break;
1098 Expressions *udas = NULL;
1099 stc = parseAttribute(&udas);
1103 *pudas = UserAttributeDeclaration::concat(*pudas, udas);
1107 // void function() @uda fp;
1108 // () @uda { return 1; }
1109 error("user defined attributes cannot appear as postfixes");
1117 return storageClass;
1119 storageClass = appendStorageClass(storageClass, stc, true);
1124 StorageClass Parser::parseTypeCtor()
1126 StorageClass storageClass = STCundefined;
1130 if (peek(&token)->value == TOKlparen)
1131 return storageClass;
1134 switch (token.value)
1136 case TOKconst: stc = STCconst; break;
1137 case TOKimmutable: stc = STCimmutable; break;
1138 case TOKshared: stc = STCshared; break;
1139 case TOKwild: stc = STCwild; break;
1142 return storageClass;
1144 storageClass = appendStorageClass(storageClass, stc);
1149 /********************************************
1150 * Parse declarations after an align, protection, or extern decl.
1153 Dsymbols *Parser::parseBlock(Dsymbol **pLastDecl, PrefixAttributes *pAttrs)
1157 //printf("parseBlock()\n");
1158 switch (token.value)
1161 error("declaration expected following attribute, not ';'");
1166 error("declaration expected following attribute, not EOF");
1171 Loc lookingForElseSave = lookingForElse;
1172 lookingForElse = Loc();
1175 a = parseDeclDefs(0, pLastDecl);
1176 if (token.value != TOKrcurly)
1179 error("matching '}' expected, not %s", token.toChars());
1183 lookingForElse = lookingForElseSave;
1189 a = parseDeclDefs(0, pLastDecl); // grab declarations up to closing curly bracket
1193 a = parseDeclDefs(1, pLastDecl, pAttrs);
1199 /**********************************
1200 * Parse a static assertion.
1201 * Current token is 'static'.
1204 StaticAssert *Parser::parseStaticAssert()
1206 Loc loc = token.loc;
1208 Expression *msg = NULL;
1210 //printf("parseStaticAssert()\n");
1214 exp = parseAssignExp();
1215 if (token.value == TOKcomma)
1218 if (token.value != TOKrparen)
1220 msg = parseAssignExp();
1221 if (token.value == TOKcomma)
1226 check(TOKsemicolon);
1227 return new StaticAssert(loc, exp, msg);
1230 /***********************************
1231 * Parse typeof(expression).
1232 * Current token is on the 'typeof'.
1235 TypeQualified *Parser::parseTypeof()
1238 Loc loc = token.loc;
1242 if (token.value == TOKreturn) // typeof(return)
1245 t = new TypeReturn(loc);
1249 Expression *exp = parseExpression(); // typeof(expression)
1250 t = new TypeTypeof(loc, exp);
1256 /***********************************
1257 * Parse __vector(type).
1258 * Current token is on the '__vector'.
1261 Type *Parser::parseVector()
1265 Type *tb = parseType();
1267 return new TypeVector(tb);
1270 /***********************************
1273 * extern (C++, namespaces)
1274 * The parser is on the 'extern' token.
1277 LINK Parser::parseLinkage(Identifiers **pidents, CPPMANGLE *pcppmangle)
1279 Identifiers *idents = NULL;
1280 CPPMANGLE cppmangle = CPPMANGLEdefault;
1281 LINK link = LINKdefault;
1283 assert(token.value == TOKlparen);
1285 if (token.value == TOKidentifier)
1286 { Identifier *id = token.ident;
1289 if (id == Id::Windows)
1291 else if (id == Id::Pascal)
1293 else if (id == Id::D)
1295 else if (id == Id::C)
1298 if (token.value == TOKplusplus)
1302 if (token.value == TOKcomma) // , namespaces or class or struct
1305 if (token.value == TOKclass || token.value == TOKstruct)
1307 cppmangle = token.value == TOKclass ? CPPMANGLEclass : CPPMANGLEstruct;
1312 idents = new Identifiers();
1315 if (token.value == TOKidentifier)
1317 Identifier *idn = token.ident;
1320 if (token.value == TOKdot)
1328 error("identifier expected for C++ namespace");
1329 idents = NULL; // error occurred, invalidate list of elements.
1337 else if (id == Id::Objective) // Looking for tokens "Objective-C"
1339 if (token.value == TOKmin)
1342 if (token.ident == Id::C)
1348 goto LinvalidLinkage;
1351 goto LinvalidLinkage;
1353 else if (id == Id::System)
1360 error("valid linkage identifiers are D, C, C++, Objective-C, Pascal, Windows, System");
1366 link = LINKd; // default
1370 *pcppmangle = cppmangle;
1374 /***********************************
1375 * Parse ident1.ident2.ident3
1378 * entity = what qualified identifier is expected to resolve into.
1379 * Used only for better error message
1382 * array of identifiers with actual qualified one stored last
1384 Identifiers *Parser::parseQualifiedIdentifier(const char *entity)
1386 Identifiers *qualified = NULL;
1391 if (token.value != TOKidentifier)
1393 error("%s expected as dot-separated identifiers, got '%s'",
1394 entity, token.toChars());
1398 Identifier *id = token.ident;
1400 qualified = new Identifiers();
1401 qualified->push(id);
1404 } while (token.value == TOKdot);
1409 /**************************************
1410 * Parse a debug conditional
1413 Condition *Parser::parseDebugCondition()
1417 if (token.value == TOKlparen)
1421 Identifier *id = NULL;
1423 if (token.value == TOKidentifier)
1425 else if (token.value == TOKint32v || token.value == TOKint64v)
1426 level = (unsigned)token.uns64value;
1428 error("identifier or integer expected, not %s", token.toChars());
1431 c = new DebugCondition(mod, level, id);
1434 c = new DebugCondition(mod, 1, NULL);
1439 /**************************************
1440 * Parse a version conditional
1443 Condition *Parser::parseVersionCondition()
1447 Identifier *id = NULL;
1449 if (token.value == TOKlparen)
1453 * version (unittest)
1455 * even though they are keywords
1457 if (token.value == TOKidentifier)
1459 else if (token.value == TOKint32v || token.value == TOKint64v)
1460 level = (unsigned)token.uns64value;
1461 else if (token.value == TOKunittest)
1462 id = Identifier::idPool(Token::toChars(TOKunittest));
1463 else if (token.value == TOKassert)
1464 id = Identifier::idPool(Token::toChars(TOKassert));
1466 error("identifier or integer expected, not %s", token.toChars());
1472 error("(condition) expected following version");
1473 c = new VersionCondition(mod, level, id);
1478 /***********************************************
1479 * static if (expression)
1483 * Current token is 'static'.
1486 Condition *Parser::parseStaticIfCondition()
1489 Condition *condition;
1490 Loc loc = token.loc;
1494 if (token.value == TOKlparen)
1497 exp = parseAssignExp();
1502 error("(expression) expected following static if");
1505 condition = new StaticIfCondition(loc, exp);
1510 /*****************************************
1511 * Parse a constructor definition:
1512 * this(parameters) { body }
1514 * this(this) { body }
1515 * or constructor template:
1516 * this(templateparameters)(parameters) { body }
1517 * Current token is 'this'.
1520 Dsymbol *Parser::parseCtor(PrefixAttributes *pAttrs)
1522 Expressions *udas = NULL;
1523 Loc loc = token.loc;
1524 StorageClass stc = pAttrs ? pAttrs->storageClass : STCundefined;
1527 if (token.value == TOKlparen && peekNext() == TOKthis && peekNext2() == TOKrparen)
1529 // this(this) { ... }
1534 stc = parsePostfix(stc, &udas);
1535 if (stc & STCstatic)
1536 error(loc, "postblit cannot be static");
1538 PostBlitDeclaration *f = new PostBlitDeclaration(loc, Loc(), stc, Id::postblit);
1540 pAttrs->storageClass = STCundefined;
1541 Dsymbol *s = parseContracts(f);
1544 Dsymbols *a = new Dsymbols();
1546 s = new UserAttributeDeclaration(udas, a);
1551 /* Look ahead to see if:
1553 * which is a constructor template
1555 TemplateParameters *tpl = NULL;
1556 if (token.value == TOKlparen && peekPastParen(&token)->value == TOKlparen)
1558 tpl = parseTemplateParameterList();
1561 /* Just a regular constructor
1564 Parameters *parameters = parseParameters(&varargs);
1565 stc = parsePostfix(stc, &udas);
1566 if (varargs != 0 || Parameter::dim(parameters) != 0)
1568 if (stc & STCstatic)
1569 error(loc, "constructor cannot be static");
1571 else if (StorageClass ss = stc & (STCshared | STCstatic)) // this()
1573 if (ss == STCstatic)
1574 error(loc, "use 'static this()' to declare a static constructor");
1575 else if (ss == (STCshared | STCstatic))
1576 error(loc, "use 'shared static this()' to declare a shared static constructor");
1579 Expression *constraint = tpl ? parseConstraint() : NULL;
1581 Type *tf = new TypeFunction(parameters, NULL, varargs, linkage, stc); // RetrunType -> auto
1582 tf = tf->addSTC(stc);
1584 CtorDeclaration *f = new CtorDeclaration(loc, Loc(), stc, tf);
1586 pAttrs->storageClass = STCundefined;
1587 Dsymbol *s = parseContracts(f);
1590 Dsymbols *a = new Dsymbols();
1592 s = new UserAttributeDeclaration(udas, a);
1597 // Wrap a template around it
1598 Dsymbols *decldefs = new Dsymbols();
1600 s = new TemplateDeclaration(loc, f->ident, tpl, constraint, decldefs);
1606 /*****************************************
1607 * Parse a destructor definition:
1609 * Current token is '~'.
1612 Dsymbol *Parser::parseDtor(PrefixAttributes *pAttrs)
1614 Expressions *udas = NULL;
1615 Loc loc = token.loc;
1616 StorageClass stc = pAttrs ? pAttrs->storageClass : STCundefined;
1623 stc = parsePostfix(stc, &udas);
1624 if (StorageClass ss = stc & (STCshared | STCstatic))
1626 if (ss == STCstatic)
1627 error(loc, "use 'static ~this()' to declare a static destructor");
1628 else if (ss == (STCshared | STCstatic))
1629 error(loc, "use 'shared static ~this()' to declare a shared static destructor");
1632 DtorDeclaration *f = new DtorDeclaration(loc, Loc(), stc, Id::dtor);
1634 pAttrs->storageClass = STCundefined;
1635 Dsymbol *s = parseContracts(f);
1638 Dsymbols *a = new Dsymbols();
1640 s = new UserAttributeDeclaration(udas, a);
1645 /*****************************************
1646 * Parse a static constructor definition:
1647 * static this() { body }
1648 * Current token is 'static'.
1651 Dsymbol *Parser::parseStaticCtor(PrefixAttributes *pAttrs)
1653 //Expressions *udas = NULL;
1654 Loc loc = token.loc;
1655 StorageClass stc = pAttrs ? pAttrs->storageClass : STCundefined;
1662 stc = parsePostfix(stc & ~STC_TYPECTOR, NULL) | stc;
1663 if (stc & STCshared)
1664 error(loc, "use 'shared static this()' to declare a shared static constructor");
1665 else if (stc & STCstatic)
1666 appendStorageClass(stc, STCstatic); // complaint for the redundancy
1667 else if (StorageClass modStc = stc & STC_TYPECTOR)
1670 stcToBuffer(&buf, modStc);
1671 error(loc, "static constructor cannot be %s", buf.peekString());
1673 stc &= ~(STCstatic | STC_TYPECTOR);
1675 StaticCtorDeclaration *f = new StaticCtorDeclaration(loc, Loc(), stc);
1677 pAttrs->storageClass = STCundefined;
1678 Dsymbol *s = parseContracts(f);
1682 /*****************************************
1683 * Parse a static destructor definition:
1684 * static ~this() { body }
1685 * Current token is 'static'.
1688 Dsymbol *Parser::parseStaticDtor(PrefixAttributes *pAttrs)
1690 Expressions *udas = NULL;
1691 Loc loc = token.loc;
1692 StorageClass stc = pAttrs ? pAttrs->storageClass : STCundefined;
1700 stc = parsePostfix(stc & ~STC_TYPECTOR, &udas) | stc;
1701 if (stc & STCshared)
1702 error(loc, "use 'shared static ~this()' to declare a shared static destructor");
1703 else if (stc & STCstatic)
1704 appendStorageClass(stc, STCstatic); // complaint for the redundancy
1705 else if (StorageClass modStc = stc & STC_TYPECTOR)
1708 stcToBuffer(&buf, modStc);
1709 error(loc, "static destructor cannot be %s", buf.peekString());
1711 stc &= ~(STCstatic | STC_TYPECTOR);
1713 StaticDtorDeclaration *f = new StaticDtorDeclaration(loc, Loc(), stc);
1715 pAttrs->storageClass = STCundefined;
1716 Dsymbol *s = parseContracts(f);
1719 Dsymbols *a = new Dsymbols();
1721 s = new UserAttributeDeclaration(udas, a);
1726 /*****************************************
1727 * Parse a shared static constructor definition:
1728 * shared static this() { body }
1729 * Current token is 'shared'.
1732 Dsymbol *Parser::parseSharedStaticCtor(PrefixAttributes *pAttrs)
1734 //Expressions *udas = NULL;
1735 Loc loc = token.loc;
1736 StorageClass stc = pAttrs ? pAttrs->storageClass : STCundefined;
1744 stc = parsePostfix(stc & ~STC_TYPECTOR, NULL) | stc;
1745 if (StorageClass ss = stc & (STCshared | STCstatic))
1746 appendStorageClass(stc, ss); // complaint for the redundancy
1747 else if (StorageClass modStc = stc & STC_TYPECTOR)
1750 stcToBuffer(&buf, modStc);
1751 error(loc, "shared static constructor cannot be %s", buf.peekString());
1753 stc &= ~(STCstatic | STC_TYPECTOR);
1755 SharedStaticCtorDeclaration *f = new SharedStaticCtorDeclaration(loc, Loc(), stc);
1757 pAttrs->storageClass = STCundefined;
1758 Dsymbol *s = parseContracts(f);
1762 /*****************************************
1763 * Parse a shared static destructor definition:
1764 * shared static ~this() { body }
1765 * Current token is 'shared'.
1768 Dsymbol *Parser::parseSharedStaticDtor(PrefixAttributes *pAttrs)
1770 Expressions *udas = NULL;
1771 Loc loc = token.loc;
1772 StorageClass stc = pAttrs ? pAttrs->storageClass : STCundefined;
1781 stc = parsePostfix(stc & ~STC_TYPECTOR, &udas) | stc;
1782 if (StorageClass ss = stc & (STCshared | STCstatic))
1783 appendStorageClass(stc, ss); // complaint for the redundancy
1784 else if (StorageClass modStc = stc & STC_TYPECTOR)
1787 stcToBuffer(&buf, modStc);
1788 error(loc, "shared static destructor cannot be %s", buf.peekString());
1790 stc &= ~(STCstatic | STC_TYPECTOR);
1792 SharedStaticDtorDeclaration *f = new SharedStaticDtorDeclaration(loc, Loc(), stc);
1794 pAttrs->storageClass = STCundefined;
1795 Dsymbol *s = parseContracts(f);
1798 Dsymbols *a = new Dsymbols();
1800 s = new UserAttributeDeclaration(udas, a);
1805 /*****************************************
1806 * Parse an invariant definition:
1807 * invariant() { body }
1808 * Current token is 'invariant'.
1811 Dsymbol *Parser::parseInvariant(PrefixAttributes *pAttrs)
1813 Loc loc = token.loc;
1814 StorageClass stc = pAttrs ? pAttrs->storageClass : STCundefined;
1817 if (token.value == TOKlparen) // optional ()
1823 InvariantDeclaration *f = new InvariantDeclaration(loc, Loc(), stc);
1825 pAttrs->storageClass = STCundefined;
1826 f->fbody = parseStatement(PScurly);
1830 /*****************************************
1831 * Parse a unittest definition:
1833 * Current token is 'unittest'.
1836 Dsymbol *Parser::parseUnitTest(PrefixAttributes *pAttrs)
1838 Loc loc = token.loc;
1839 StorageClass stc = pAttrs ? pAttrs->storageClass : STCundefined;
1843 const utf8_t *begPtr = token.ptr + 1; // skip '{'
1844 const utf8_t *endPtr = NULL;
1845 Statement *sbody = parseStatement(PScurly, &endPtr);
1847 /** Extract unittest body as a string. Must be done eagerly since memory
1848 will be released by the lexer before doc gen. */
1849 char *docline = NULL;
1850 if (global.params.doDocComments && endPtr > begPtr)
1852 /* Remove trailing whitespaces */
1853 for (const utf8_t *p = endPtr - 1;
1854 begPtr <= p && (*p == ' ' || *p == '\r' || *p == '\n' || *p == '\t'); --p)
1859 size_t len = endPtr - begPtr;
1862 docline = (char *)mem.xmalloc(len + 2);
1863 memcpy(docline, begPtr, len);
1864 docline[len ] = '\n'; // Terminate all lines by LF
1865 docline[len+1] = '\0';
1869 UnitTestDeclaration *f = new UnitTestDeclaration(loc, token.loc, stc, docline);
1871 pAttrs->storageClass = STCundefined;
1876 /*****************************************
1877 * Parse a new definition:
1878 * new(parameters) { body }
1879 * Current token is 'new'.
1882 Dsymbol *Parser::parseNew(PrefixAttributes *pAttrs)
1884 Loc loc = token.loc;
1885 StorageClass stc = pAttrs ? pAttrs->storageClass : STCundefined;
1890 Parameters *parameters = parseParameters(&varargs);
1891 NewDeclaration *f = new NewDeclaration(loc, Loc(), stc, parameters, varargs);
1893 pAttrs->storageClass = STCundefined;
1894 Dsymbol *s = parseContracts(f);
1898 /*****************************************
1899 * Parse a delete definition:
1900 * delete(parameters) { body }
1901 * Current token is 'delete'.
1904 Dsymbol *Parser::parseDelete(PrefixAttributes *pAttrs)
1906 Loc loc = token.loc;
1907 StorageClass stc = pAttrs ? pAttrs->storageClass : STCundefined;
1912 Parameters *parameters = parseParameters(&varargs);
1914 error("... not allowed in delete function parameter list");
1915 DeleteDeclaration *f = new DeleteDeclaration(loc, Loc(), stc, parameters);
1917 pAttrs->storageClass = STCundefined;
1918 Dsymbol *s = parseContracts(f);
1922 /**********************************************
1923 * Parse parameter list.
1926 Parameters *Parser::parseParameters(int *pvarargs, TemplateParameters **tpl)
1928 Parameters *parameters = new Parameters();
1935 Identifier *ai = NULL;
1937 StorageClass storageClass = 0;
1941 for (;1; nextToken())
1943 switch (token.value)
1954 if (peek(&token)->value == TOKlparen)
1960 if (peek(&token)->value == TOKlparen)
1966 if (peek(&token)->value == TOKlparen)
1972 if (peek(&token)->value == TOKlparen)
1977 case TOKin: stc = STCin; goto L2;
1978 case TOKout: stc = STCout; goto L2;
1979 case TOKref: stc = STCref; goto L2;
1980 case TOKlazy: stc = STClazy; goto L2;
1981 case TOKscope: stc = STCscope; goto L2;
1982 case TOKfinal: stc = STCfinal; goto L2;
1983 case TOKauto: stc = STCauto; goto L2;
1984 case TOKreturn: stc = STCreturn; goto L2;
1986 storageClass = appendStorageClass(storageClass, stc);
1991 { stc = storageClass & (STCin | STCout | STCref | STClazy);
1992 // if stc is not a power of 2
1993 if (stc & (stc - 1) &&
1994 !(stc == (STCin | STCref)))
1995 error("incompatible parameter storage classes");
1996 //if ((storageClass & STCscope) && (storageClass & (STCref | STCout)))
1997 //error("scope cannot be ref or out");
2000 if (tpl && token.value == TOKidentifier &&
2001 (t = peek(&token), (t->value == TOKcomma ||
2002 t->value == TOKrparen ||
2003 t->value == TOKdotdotdot)))
2005 Identifier *id = Identifier::generateId("__T");
2006 Loc loc = token.loc;
2007 at = new TypeIdentifier(loc, id);
2009 *tpl = new TemplateParameters();
2010 TemplateParameter *tp = new TemplateTypeParameter(loc, id, NULL, NULL);
2017 at = parseType(&ai);
2019 if (token.value == TOKassign) // = defaultArg
2021 ae = parseDefaultInitExp();
2026 error("default argument expected for %s",
2027 ai ? ai->toChars() : at->toChars());
2029 if (token.value == TOKdotdotdot)
2034 if (storageClass & (STCout | STCref))
2035 error("variadic argument cannot be out or ref");
2037 parameters->push(new Parameter(storageClass, at, ai, ae));
2041 parameters->push(new Parameter(storageClass, at, ai, ae));
2042 if (token.value == TOKcomma)
2056 *pvarargs = varargs;
2061 /*************************************
2064 EnumDeclaration *Parser::parseEnum()
2069 Loc loc = token.loc;
2071 //printf("Parser::parseEnum()\n");
2073 if (token.value == TOKidentifier)
2081 if (token.value == TOKcolon)
2086 Loc typeLoc = token.loc;
2087 memtype = parseBasicType();
2088 memtype = parseDeclarator(memtype, &alt, NULL);
2089 checkCstyleTypeSyntax(typeLoc, memtype, alt, NULL);
2094 e = new EnumDeclaration(loc, id, memtype);
2095 if (token.value == TOKsemicolon && id)
2097 else if (token.value == TOKlcurly)
2099 //printf("enum definition\n");
2100 e->members = new Dsymbols();
2102 const utf8_t *comment = token.blockComment;
2103 while (token.value != TOKrcurly)
2105 /* Can take the following forms:
2108 * 3. type ident = value
2114 Identifier *ident = NULL;
2115 Token *tp = peek(&token);
2116 if (token.value == TOKidentifier &&
2117 (tp->value == TOKassign || tp->value == TOKcomma || tp->value == TOKrcurly))
2119 ident = token.ident;
2125 type = parseType(&ident, NULL);
2127 error("no identifier for declarator %s", type->toChars());
2129 error("type only allowed if anonymous enum and no enum type");
2133 if (token.value == TOKassign)
2136 value = parseAssignExp();
2142 error("if type, there must be an initializer");
2145 EnumMember *em = new EnumMember(loc, ident, value, type);
2146 e->members->push(em);
2148 if (token.value == TOKrcurly)
2152 addComment(em, comment);
2156 addComment(em, comment);
2157 comment = token.blockComment;
2159 if (token.value == TOKeof)
2161 error("premature end of file");
2168 error("enum declaration is invalid");
2170 //printf("-parseEnum() %s\n", e->toChars());
2174 /********************************
2175 * Parse struct, union, interface, class.
2178 Dsymbol *Parser::parseAggregate()
2180 AggregateDeclaration *a = NULL;
2183 TemplateParameters *tpl = NULL;
2184 Expression *constraint = NULL;
2185 Loc loc = token.loc;
2186 TOK tok = token.value;
2188 //printf("Parser::parseAggregate()\n");
2190 if (token.value != TOKidentifier)
2199 if (token.value == TOKlparen)
2201 // Class template declaration.
2202 // Gather template parameter list
2203 tpl = parseTemplateParameterList();
2204 constraint = parseConstraint();
2214 error(loc, "anonymous classes not allowed");
2216 // Collect base class(es)
2217 BaseClasses *baseclasses = NULL;
2218 if (token.value == TOKcolon)
2221 baseclasses = parseBaseClasses();
2225 Expression *tempCons = parseConstraint();
2229 error("members expected");
2231 constraint = tempCons;
2235 if (token.value != TOKlcurly)
2236 error("members expected");
2239 if (tok == TOKclass)
2241 bool inObject = md && !md->packages && md->id == Id::object;
2242 a = new ClassDeclaration(loc, id, baseclasses, NULL, inObject);
2245 a = new InterfaceDeclaration(loc, id, baseclasses);
2252 bool inObject = md && !md->packages && md->id == Id::object;
2253 a = new StructDeclaration(loc, id, inObject);
2261 a = new UnionDeclaration(loc, id);
2270 if (a && token.value == TOKsemicolon)
2274 else if (token.value == TOKlcurly)
2276 const Loc lookingForElseSave = lookingForElse;
2277 lookingForElse = Loc();
2278 //printf("aggregate definition\n");
2280 Dsymbols *decl = parseDeclDefs(0);
2281 lookingForElse = lookingForElseSave;
2282 if (token.value != TOKrcurly)
2283 error("} expected following members in %s declaration at %s",
2284 Token::toChars(tok), loc.toChars());
2288 /* Anonymous structs/unions are more like attributes.
2290 return new AnonDeclaration(loc, anon == 2, decl);
2297 error("{ } expected following %s declaration", Token::toChars(tok));
2298 a = new StructDeclaration(loc, NULL, false);
2303 // Wrap a template around the aggregate declaration
2304 Dsymbols *decldefs = new Dsymbols();
2306 TemplateDeclaration *tempdecl =
2307 new TemplateDeclaration(loc, id, tpl, constraint, decldefs);
2314 /*******************************************
2317 BaseClasses *Parser::parseBaseClasses()
2319 BaseClasses *baseclasses = new BaseClasses();
2321 for (; 1; nextToken())
2324 Prot protection = Prot(PROTpublic);
2325 switch (token.value)
2329 protection = Prot(PROTprivate);
2334 protection = Prot(PROTpackage);
2339 protection = Prot(PROTprotected);
2344 protection = Prot(PROTpublic);
2350 error("use of base class protection is no longer supported");
2351 BaseClass *b = new BaseClass(parseBasicType());
2352 baseclasses->push(b);
2353 if (token.value != TOKcomma)
2359 /**************************************
2361 * Constraint is of the form:
2362 * if ( ConstraintExpression )
2365 Expression *Parser::parseConstraint()
2366 { Expression *e = NULL;
2368 if (token.value == TOKif)
2370 nextToken(); // skip over 'if'
2372 e = parseExpression();
2378 /**************************************
2379 * Parse a TemplateDeclaration.
2382 TemplateDeclaration *Parser::parseTemplateDeclaration(bool ismixin)
2384 TemplateDeclaration *tempdecl;
2386 TemplateParameters *tpl;
2388 Expression *constraint = NULL;
2389 Loc loc = token.loc;
2392 if (token.value != TOKidentifier)
2394 error("identifier expected following template");
2399 tpl = parseTemplateParameterList();
2403 constraint = parseConstraint();
2405 if (token.value != TOKlcurly)
2407 error("members of template declaration expected");
2411 decldefs = parseBlock(NULL);
2413 tempdecl = new TemplateDeclaration(loc, id, tpl, constraint, decldefs, ismixin);
2420 /******************************************
2421 * Parse template parameter list.
2423 * flag 0: parsing "( list )"
2424 * 1: parsing non-empty "list )"
2427 TemplateParameters *Parser::parseTemplateParameterList(int flag)
2429 TemplateParameters *tpl = new TemplateParameters();
2431 if (!flag && token.value != TOKlparen)
2432 { error("parenthesized TemplateParameterList expected following TemplateIdentifier");
2437 // Get array of TemplateParameters
2438 if (flag || token.value != TOKrparen)
2441 while (token.value != TOKrparen)
2443 TemplateParameter *tp;
2445 Identifier *tp_ident = NULL;
2446 Type *tp_spectype = NULL;
2447 Type *tp_valtype = NULL;
2448 Type *tp_defaulttype = NULL;
2449 Expression *tp_specvalue = NULL;
2450 Expression *tp_defaultvalue = NULL;
2453 // Get TemplateParameter
2455 // First, look ahead to see if it is a TypeParameter or a ValueParameter
2457 if (token.value == TOKalias)
2460 loc = token.loc; // todo
2461 Type *spectype = NULL;
2462 if (isDeclaration(&token, 2, TOKreserved, NULL))
2464 spectype = parseType(&tp_ident);
2468 if (token.value != TOKidentifier)
2470 error("identifier expected for template alias parameter");
2473 tp_ident = token.ident;
2476 RootObject *spec = NULL;
2477 if (token.value == TOKcolon) // : Type
2480 if (isDeclaration(&token, 0, TOKreserved, NULL))
2483 spec = parseCondExp();
2485 RootObject *def = NULL;
2486 if (token.value == TOKassign) // = Type
2489 if (isDeclaration(&token, 0, TOKreserved, NULL))
2492 def = parseCondExp();
2494 tp = new TemplateAliasParameter(loc, tp_ident, spectype, spec, def);
2496 else if (t->value == TOKcolon || t->value == TOKassign ||
2497 t->value == TOKcomma || t->value == TOKrparen)
2500 if (token.value != TOKidentifier)
2502 error("identifier expected for template type parameter");
2506 tp_ident = token.ident;
2508 if (token.value == TOKcolon) // : Type
2511 tp_spectype = parseType();
2513 if (token.value == TOKassign) // = Type
2516 tp_defaulttype = parseType();
2518 tp = new TemplateTypeParameter(loc, tp_ident, tp_spectype, tp_defaulttype);
2520 else if (token.value == TOKidentifier && t->value == TOKdotdotdot)
2524 error("variadic template parameter must be last");
2527 tp_ident = token.ident;
2530 tp = new TemplateTupleParameter(loc, tp_ident);
2532 else if (token.value == TOKthis)
2536 if (token.value != TOKidentifier)
2538 error("identifier expected for template this parameter");
2542 tp_ident = token.ident;
2544 if (token.value == TOKcolon) // : Type
2547 tp_spectype = parseType();
2549 if (token.value == TOKassign) // = Type
2552 tp_defaulttype = parseType();
2554 tp = new TemplateThisParameter(loc, tp_ident, tp_spectype, tp_defaulttype);
2559 loc = token.loc; // todo
2560 tp_valtype = parseType(&tp_ident);
2563 error("identifier expected for template value parameter");
2564 tp_ident = Identifier::idPool("error");
2566 if (token.value == TOKcolon) // : CondExpression
2569 tp_specvalue = parseCondExp();
2571 if (token.value == TOKassign) // = CondExpression
2574 tp_defaultvalue = parseDefaultInitExp();
2576 tp = new TemplateValueParameter(loc, tp_ident, tp_valtype, tp_specvalue, tp_defaultvalue);
2579 if (token.value != TOKcomma)
2589 /******************************************
2590 * Parse template mixin.
2593 * mixin a.b.c!(args).Foo!(args);
2594 * mixin Foo!(args) identifier;
2595 * mixin typeof(expr).identifier!(args);
2598 Dsymbol *Parser::parseMixin()
2604 //printf("parseMixin()\n");
2605 Loc locMixin = token.loc;
2606 nextToken(); // skip 'mixin'
2608 Loc loc = token.loc;
2609 TypeQualified *tqual = NULL;
2610 if (token.value == TOKdot)
2616 if (token.value == TOKtypeof)
2618 tqual = parseTypeof();
2621 if (token.value != TOKidentifier)
2623 error("identifier expected, not %s", token.toChars());
2634 if (token.value == TOKnot)
2636 tiargs = parseTemplateArguments();
2639 if (tiargs && token.value == TOKdot)
2641 TemplateInstance *tempinst = new TemplateInstance(loc, id);
2642 tempinst->tiargs = tiargs;
2644 tqual = new TypeInstance(loc, tempinst);
2646 tqual->addInst(tempinst);
2652 tqual = new TypeIdentifier(loc, id);
2654 tqual->addIdent(id);
2657 if (token.value != TOKdot)
2661 if (token.value != TOKidentifier)
2663 error("identifier expected following '.' instead of '%s'", token.toChars());
2671 if (token.value == TOKidentifier)
2679 tm = new TemplateMixin(locMixin, id, tqual, tiargs);
2680 if (token.value != TOKsemicolon)
2681 error("';' expected after mixin");
2687 /******************************************
2688 * Parse template arguments.
2690 * current token is opening '!'
2692 * current token is one after closing ')'
2695 Objects *Parser::parseTemplateArguments()
2700 if (token.value == TOKlparen)
2702 // ident!(template_arguments)
2703 tiargs = parseTemplateArgumentList();
2707 // ident!template_argument
2708 tiargs = parseTemplateSingleArgument();
2710 if (token.value == TOKnot)
2712 TOK tok = peekNext();
2713 if (tok != TOKis && tok != TOKin)
2715 error("multiple ! arguments are not allowed");
2718 if (token.value == TOKlparen)
2719 parseTemplateArgumentList();
2721 parseTemplateSingleArgument();
2722 if (token.value == TOKnot && (tok = peekNext()) != TOKis && tok != TOKin)
2729 /******************************************
2730 * Parse template argument list.
2732 * current token is opening '(',
2733 * or ',' for __traits
2735 * current token is one after closing ')'
2738 Objects *Parser::parseTemplateArgumentList()
2740 //printf("Parser::parseTemplateArgumentList()\n");
2741 Objects *tiargs = new Objects();
2742 TOK endtok = TOKrparen;
2743 assert(token.value == TOKlparen || token.value == TOKcomma);
2746 // Get TemplateArgumentList
2747 while (token.value != endtok)
2749 // See if it is an Expression or a Type
2750 if (isDeclaration(&token, 0, TOKreserved, NULL))
2751 { // Template argument is a type
2752 Type *ta = parseType();
2756 { // Template argument is an expression
2757 Expression *ea = parseAssignExp();
2760 if (token.value != TOKcomma)
2764 check(endtok, "template argument list");
2768 /*****************************
2769 * Parse single template argument, to support the syntax:
2772 * current token is the arg
2775 Objects *Parser::parseTemplateSingleArgument()
2777 //printf("parseTemplateSingleArgument()\n");
2778 Objects *tiargs = new Objects();
2780 switch (token.value)
2783 ta = new TypeIdentifier(token.loc, token.ident);
2790 case TOKvoid: ta = Type::tvoid; goto LabelX;
2791 case TOKint8: ta = Type::tint8; goto LabelX;
2792 case TOKuns8: ta = Type::tuns8; goto LabelX;
2793 case TOKint16: ta = Type::tint16; goto LabelX;
2794 case TOKuns16: ta = Type::tuns16; goto LabelX;
2795 case TOKint32: ta = Type::tint32; goto LabelX;
2796 case TOKuns32: ta = Type::tuns32; goto LabelX;
2797 case TOKint64: ta = Type::tint64; goto LabelX;
2798 case TOKuns64: ta = Type::tuns64; goto LabelX;
2799 case TOKint128: ta = Type::tint128; goto LabelX;
2800 case TOKuns128: ta = Type::tuns128; goto LabelX;
2801 case TOKfloat32: ta = Type::tfloat32; goto LabelX;
2802 case TOKfloat64: ta = Type::tfloat64; goto LabelX;
2803 case TOKfloat80: ta = Type::tfloat80; goto LabelX;
2804 case TOKimaginary32: ta = Type::timaginary32; goto LabelX;
2805 case TOKimaginary64: ta = Type::timaginary64; goto LabelX;
2806 case TOKimaginary80: ta = Type::timaginary80; goto LabelX;
2807 case TOKcomplex32: ta = Type::tcomplex32; goto LabelX;
2808 case TOKcomplex64: ta = Type::tcomplex64; goto LabelX;
2809 case TOKcomplex80: ta = Type::tcomplex80; goto LabelX;
2810 case TOKbool: ta = Type::tbool; goto LabelX;
2811 case TOKchar: ta = Type::tchar; goto LabelX;
2812 case TOKwchar: ta = Type::twchar; goto LabelX;
2813 case TOKdchar: ta = Type::tdchar; goto LabelX;
2828 case TOKimaginary32v:
2829 case TOKimaginary64v:
2830 case TOKimaginary80v:
2840 case TOKfilefullpath:
2842 case TOKmodulestring:
2846 { // Template argument is an expression
2847 Expression *ea = parsePrimaryExp();
2853 error("template argument expected following !");
2859 Dsymbols *Parser::parseImport()
2861 Dsymbols *decldefs = new Dsymbols();
2862 Identifier *aliasid = NULL;
2864 int isstatic = token.value == TOKstatic;
2868 //printf("Parser::parseImport()\n");
2873 if (token.value != TOKidentifier)
2875 error("identifier expected following import");
2879 Loc loc = token.loc;
2880 Identifier *id = token.ident;
2881 Identifiers *a = NULL;
2883 if (!aliasid && token.value == TOKassign)
2888 while (token.value == TOKdot)
2891 a = new Identifiers();
2894 if (token.value != TOKidentifier)
2896 error("identifier expected following package");
2903 Import *s = new Import(loc, a, id, aliasid, isstatic);
2907 * : alias=name, alias=name;
2910 if (token.value == TOKcolon)
2915 if (token.value != TOKidentifier)
2917 error("identifier expected following :");
2920 Identifier *alias = token.ident;
2923 if (token.value == TOKassign)
2926 if (token.value != TOKidentifier)
2928 error("identifier expected following %s=", alias->toChars());
2939 s->addAlias(name, alias);
2940 } while (token.value == TOKcomma);
2941 break; // no comma-separated imports of this form
2945 } while (token.value == TOKcomma);
2947 if (token.value == TOKsemicolon)
2951 error("';' expected");
2958 Type *Parser::parseType(Identifier **pident, TemplateParameters **ptpl)
2960 /* Take care of the storage class prefixes that
2961 * serve as type attributes:
2969 * shared inout const type
2971 StorageClass stc = 0;
2974 switch (token.value)
2977 if (peekNext() == TOKlparen)
2978 break; // const as type constructor
2979 stc |= STCconst; // const as storage class
2984 if (peekNext() == TOKlparen)
2986 stc |= STCimmutable;
2991 if (peekNext() == TOKlparen)
2998 if (peekNext() == TOKlparen)
3010 Loc typeLoc = token.loc;
3013 t = parseBasicType();
3016 t = parseDeclarator(t, &alt, pident, ptpl);
3017 checkCstyleTypeSyntax(typeLoc, t, alt, pident ? *pident : NULL);
3023 Type *Parser::parseBasicType(bool dontLookDotIdents)
3029 //printf("parseBasicType()\n");
3030 switch (token.value)
3032 case TOKvoid: t = Type::tvoid; goto LabelX;
3033 case TOKint8: t = Type::tint8; goto LabelX;
3034 case TOKuns8: t = Type::tuns8; goto LabelX;
3035 case TOKint16: t = Type::tint16; goto LabelX;
3036 case TOKuns16: t = Type::tuns16; goto LabelX;
3037 case TOKint32: t = Type::tint32; goto LabelX;
3038 case TOKuns32: t = Type::tuns32; goto LabelX;
3039 case TOKint64: t = Type::tint64; goto LabelX;
3040 case TOKuns64: t = Type::tuns64; goto LabelX;
3041 case TOKint128: t = Type::tint128; goto LabelX;
3042 case TOKuns128: t = Type::tuns128; goto LabelX;
3043 case TOKfloat32: t = Type::tfloat32; goto LabelX;
3044 case TOKfloat64: t = Type::tfloat64; goto LabelX;
3045 case TOKfloat80: t = Type::tfloat80; goto LabelX;
3046 case TOKimaginary32: t = Type::timaginary32; goto LabelX;
3047 case TOKimaginary64: t = Type::timaginary64; goto LabelX;
3048 case TOKimaginary80: t = Type::timaginary80; goto LabelX;
3049 case TOKcomplex32: t = Type::tcomplex32; goto LabelX;
3050 case TOKcomplex64: t = Type::tcomplex64; goto LabelX;
3051 case TOKcomplex80: t = Type::tcomplex80; goto LabelX;
3052 case TOKbool: t = Type::tbool; goto LabelX;
3053 case TOKchar: t = Type::tchar; goto LabelX;
3054 case TOKwchar: t = Type::twchar; goto LabelX;
3055 case TOKdchar: t = Type::tdchar; goto LabelX;
3066 if (token.value == TOKnot)
3068 // ident!(template_arguments)
3069 TemplateInstance *tempinst = new TemplateInstance(loc, id);
3070 tempinst->tiargs = parseTemplateArguments();
3071 t = parseBasicTypeStartingAt(new TypeInstance(loc, tempinst), dontLookDotIdents);
3075 t = parseBasicTypeStartingAt(new TypeIdentifier(loc, id), dontLookDotIdents);
3080 // Leading . as in .foo
3081 t = parseBasicTypeStartingAt(new TypeIdentifier(token.loc, Id::empty), dontLookDotIdents);
3085 // typeof(expression)
3086 t = parseBasicTypeStartingAt(parseTypeof(), dontLookDotIdents);
3097 t = parseType()->addSTC(STCconst);
3105 t = parseType()->addSTC(STCimmutable);
3113 t = parseType()->addSTC(STCshared);
3121 t = parseType()->addSTC(STCwild);
3126 error("basic type expected, not %s", token.toChars());
3133 Type *Parser::parseBasicTypeStartingAt(TypeQualified *tid, bool dontLookDotIdents)
3135 Type *maybeArray = NULL;
3136 // See https://issues.dlang.org/show_bug.cgi?id=1215
3137 // A basic type can look like MyType (typical case), but also:
3138 // MyType.T -> A type
3139 // MyType[expr] -> Either a static array of MyType or a type (iif MyType is a Ttuple)
3140 // MyType[expr].T -> A type.
3141 // MyType[expr].T[expr] -> Either a static array of MyType[expr].T or a type
3142 // (iif MyType[expr].T is a Ttuple)
3145 switch (token.value)
3150 if (token.value != TOKidentifier)
3152 error("identifier expected following '.' instead of '%s'", token.toChars());
3157 // This is actually a TypeTuple index, not an {a/s}array.
3158 // We need to have a while loop to unwind all index taking:
3159 // T[e1][e2].U -> T, addIndex(e1), addIndex(e2)
3161 Type *t = maybeArray;
3164 if (t->ty == Tsarray)
3166 // The index expression is an Expression.
3167 TypeSArray *a = (TypeSArray *)t;
3168 dimStack.push(a->dim->syntaxCopy());
3169 t = a->next->syntaxCopy();
3171 else if (t->ty == Taarray)
3173 // The index expression is a Type. It will be interpreted as an expression at semantic time.
3174 TypeAArray *a = (TypeAArray *)t;
3175 dimStack.push(a->index->syntaxCopy());
3176 t = a->next->syntaxCopy();
3183 assert(dimStack.dim > 0);
3184 // We're good. Replay indices in the reverse order.
3185 tid = (TypeQualified *)t;
3186 while (dimStack.dim)
3188 tid->addIndex(dimStack.pop());
3192 Loc loc = token.loc;
3193 Identifier *id = token.ident;
3195 if (token.value == TOKnot)
3197 TemplateInstance *tempinst = new TemplateInstance(loc, id);
3198 tempinst->tiargs = parseTemplateArguments();
3199 tid->addInst(tempinst);
3207 if (dontLookDotIdents) // workaround for Bugzilla 14911
3211 Type *t = maybeArray ? maybeArray : (Type *)tid;
3212 if (token.value == TOKrbracket)
3214 // It's a dynamic array, and we're done:
3215 // T[].U does not make sense.
3216 t = new TypeDArray(t);
3220 else if (isDeclaration(&token, 0, TOKrbracket, NULL))
3222 // This can be one of two things:
3223 // 1 - an associative array declaration, T[type]
3224 // 2 - an associative array declaration, T[expr]
3225 // These can only be disambiguated later.
3226 Type *index = parseType(); // [ type ]
3227 maybeArray = new TypeAArray(t, index);
3232 // This can be one of three things:
3233 // 1 - an static array declaration, T[expr]
3234 // 2 - a slice, T[expr .. expr]
3235 // 3 - a template parameter pack index expression, T[expr].U
3236 // 1 and 3 can only be disambiguated later.
3237 //printf("it's type[expression]\n");
3239 Expression *e = parseAssignExp(); // [ expression ]
3240 if (token.value == TOKslice)
3242 // It's a slice, and we're done.
3244 Expression *e2 = parseAssignExp(); // [ exp .. exp ]
3245 t = new TypeSlice(t, e, e2);
3252 maybeArray = new TypeSArray(t, e);
3265 return maybeArray ? maybeArray : (Type *)tid;
3268 /******************************************
3269 * Parse things that follow the initial type t.
3274 * t [expression .. expression]
3279 Type *Parser::parseBasicType2(Type *t)
3281 //printf("parseBasicType2()\n");
3284 switch (token.value)
3287 t = new TypePointer(t);
3292 // Handle []. Make sure things like
3294 // is (array[1] of array[3] of int)
3296 if (token.value == TOKrbracket)
3298 t = new TypeDArray(t); // []
3301 else if (isDeclaration(&token, 0, TOKrbracket, NULL))
3303 // It's an associative array declaration
3304 //printf("it's an associative array\n");
3305 Type *index = parseType(); // [ type ]
3306 t = new TypeAArray(t, index);
3311 //printf("it's type[expression]\n");
3313 Expression *e = parseAssignExp(); // [ expression ]
3314 if (token.value == TOKslice)
3317 Expression *e2 = parseAssignExp(); // [ exp .. exp ]
3318 t = new TypeSlice(t, e, e2);
3322 t = new TypeSArray(t,e);
3332 // Handle delegate declaration:
3333 // t delegate(parameter list) nothrow pure
3334 // t function(parameter list) nothrow pure
3335 TOK save = token.value;
3339 Parameters *parameters = parseParameters(&varargs);
3341 StorageClass stc = parsePostfix(STCundefined, NULL);
3342 TypeFunction *tf = new TypeFunction(parameters, t, varargs, linkage, stc);
3343 if (stc & (STCconst | STCimmutable | STCshared | STCwild | STCreturn))
3345 if (save == TOKfunction)
3346 error("const/immutable/shared/inout/return attributes are only valid for non-static member functions");
3348 tf = (TypeFunction *)tf->addSTC(stc);
3351 if (save == TOKdelegate)
3352 t = new TypeDelegate(tf);
3354 t = new TypePointer(tf); // pointer to function
3367 Type *Parser::parseDeclarator(Type *t, int *palt, Identifier **pident,
3368 TemplateParameters **tpl, StorageClass storageClass, int *pdisable, Expressions **pudas)
3370 //printf("parseDeclarator(tpl = %p)\n", tpl);
3371 t = parseBasicType2(t);
3374 switch (token.value)
3378 *pident = token.ident;
3380 error("unexpected identifer '%s' in declarator", token.ident->toChars());
3388 // like: T ((*fp))();
3389 if (peekNext() == TOKmul ||
3390 peekNext() == TOKlparen)
3392 /* Parse things with parentheses around the identifier, like:
3394 * although the D style would be:
3399 ts = parseDeclarator(t, palt, pident);
3405 Token *peekt = &token;
3406 /* Completely disallow C-style things like:
3408 * Improve error messages for the common bug of a missing return type
3409 * by looking to see if (a) looks like a parameter list.
3411 if (isParameters(&peekt))
3413 error("function declaration without return type. (Note that constructors are always named 'this')");
3416 error("unexpected ( in declarator");
3425 // parse DeclaratorSuffixes
3428 switch (token.value)
3431 /* Support C style array syntax:
3433 * as opposed to D-style:
3438 // This is the old C-style post [] syntax.
3441 if (token.value == TOKrbracket)
3443 // It's a dynamic array
3444 ta = new TypeDArray(t); // []
3448 else if (isDeclaration(&token, 0, TOKrbracket, NULL))
3450 // It's an associative array
3451 //printf("it's an associative array\n");
3452 Type *index = parseType(); // [ type ]
3454 ta = new TypeAArray(t, index);
3459 //printf("It's a static array\n");
3460 Expression *e = parseAssignExp(); // [ expression ]
3461 ta = new TypeSArray(t, e);
3469 * ts -> ... -> ta -> t
3472 for (pt = &ts; *pt != t; pt = &((TypeNext *)*pt)->next)
3482 Token *tk = peekPastParen(&token);
3483 if (tk->value == TOKlparen)
3485 /* Look ahead to see if this is (...)(...),
3486 * i.e. a function template declaration
3488 //printf("function template declaration\n");
3490 // Gather template parameter list
3491 *tpl = parseTemplateParameterList();
3493 else if (tk->value == TOKassign)
3496 * i.e. a variable template declaration
3498 //printf("variable template declaration\n");
3499 *tpl = parseTemplateParameterList();
3505 Parameters *parameters = parseParameters(&varargs);
3507 /* Parse const/immutable/shared/inout/nothrow/pure/return postfix
3509 StorageClass stc = parsePostfix(storageClass, pudas);
3510 // merge prefix storage classes
3511 Type *tf = new TypeFunction(parameters, t, varargs, linkage, stc);
3512 tf = tf->addSTC(stc);
3514 *pdisable = stc & STCdisable ? 1 : 0;
3519 * ts -> ... -> tf -> t
3522 for (pt = &ts; *pt != t; pt = &((TypeNext *)*pt)->next)
3535 void Parser::parseStorageClasses(StorageClass &storage_class, LINK &link,
3536 bool &setAlignment, Expression *&ealign, Expressions *&udas)
3539 bool sawLinkage = false; // seen a linkage declaration
3543 switch (token.value)
3546 if (peek(&token)->value == TOKlparen)
3547 break; // const as type constructor
3548 stc = STCconst; // const as storage class
3552 if (peek(&token)->value == TOKlparen)
3558 if (peek(&token)->value == TOKlparen)
3564 if (peek(&token)->value == TOKlparen)
3569 case TOKstatic: stc = STCstatic; goto L1;
3570 case TOKfinal: stc = STCfinal; goto L1;
3571 case TOKauto: stc = STCauto; goto L1;
3572 case TOKscope: stc = STCscope; goto L1;
3573 case TOKoverride: stc = STCoverride; goto L1;
3574 case TOKabstract: stc = STCabstract; goto L1;
3575 case TOKsynchronized: stc = STCsynchronized; goto L1;
3576 case TOKdeprecated: stc = STCdeprecated; goto L1;
3577 case TOKnothrow: stc = STCnothrow; goto L1;
3578 case TOKpure: stc = STCpure; goto L1;
3579 case TOKref: stc = STCref; goto L1;
3580 case TOKgshared: stc = STCgshared; goto L1;
3581 case TOKenum: stc = STCmanifest; goto L1;
3584 stc = parseAttribute(&udas);
3590 storage_class = appendStorageClass(storage_class, stc);
3596 if (peek(&token)->value != TOKlparen)
3603 error("redundant linkage declaration");
3605 Identifiers *idents = NULL;
3606 CPPMANGLE cppmangle = CPPMANGLEdefault;
3607 link = parseLinkage(&idents, &cppmangle);
3610 error("C++ name spaces not allowed here");
3613 if (cppmangle != CPPMANGLEdefault)
3615 error("C++ mangle declaration not allowed here");
3623 setAlignment = true;
3624 if (token.value == TOKlparen)
3627 ealign = parseExpression();
3639 /**********************************
3640 * Parse Declarations.
3642 * 1. declarations at global/class level
3643 * 2. declarations at statement level
3644 * Return array of Declaration *'s.
3647 Dsymbols *Parser::parseDeclarations(bool autodecl, PrefixAttributes *pAttrs, const utf8_t *comment)
3649 StorageClass storage_class = STCundefined;
3654 TOK tok = TOKreserved;
3655 LINK link = linkage;
3656 bool setAlignment = false;
3657 Expression *ealign = NULL;
3658 Loc loc = token.loc;
3659 Expressions *udas = NULL;
3662 //printf("parseDeclarations() %s\n", token.toChars());
3664 comment = token.blockComment;
3668 ts = NULL; // infer type
3672 if (token.value == TOKalias)
3678 * alias identifier this;
3680 if (token.value == TOKidentifier && peekNext() == TOKthis)
3682 AliasThis *s = new AliasThis(loc, token.ident);
3685 check(TOKsemicolon);
3686 Dsymbols *a = new Dsymbols();
3688 addComment(s, comment);
3692 * alias identifier = type;
3693 * alias identifier(...) = type;
3695 if (token.value == TOKidentifier &&
3696 skipParensIf(peek(&token), &tk) &&
3697 tk->value == TOKassign)
3699 Dsymbols *a = new Dsymbols();
3702 ident = token.ident;
3704 TemplateParameters *tpl = NULL;
3705 if (token.value == TOKlparen)
3706 tpl = parseTemplateParameterList();
3710 if (token.value == TOKfunction ||
3711 token.value == TOKdelegate ||
3712 (token.value == TOKlparen &&
3713 skipAttributes(peekPastParen(&token), &tk) &&
3714 (tk->value == TOKgoesto || tk->value == TOKlcurly)) ||
3715 token.value == TOKlcurly ||
3716 (token.value == TOKidentifier && peekNext() == TOKgoesto))
3718 // function (parameters) { statements... }
3719 // delegate (parameters) { statements... }
3720 // (parameters) { statements... }
3721 // (parameters) => expression
3722 // { statements... }
3723 // identifier => expression
3725 Dsymbol *s = parseFunctionLiteral();
3726 v = new AliasDeclaration(loc, ident, s);
3730 // StorageClasses type
3732 storage_class = STCundefined;
3734 setAlignment = false;
3737 parseStorageClasses(storage_class, link, setAlignment, ealign, udas);
3740 error("user defined attributes not allowed for %s declarations", Token::toChars(tok));
3743 v = new AliasDeclaration(loc, ident, t);
3745 v->storage_class = storage_class;
3750 Dsymbols *a2 = new Dsymbols();
3752 TemplateDeclaration *tempdecl =
3753 new TemplateDeclaration(loc, ident, tpl, NULL, a2);
3758 Dsymbols *ax = new Dsymbols();
3760 s = new AlignDeclaration(v->loc, ealign, ax);
3762 if (link != linkage)
3764 Dsymbols *a2 = new Dsymbols();
3766 s = new LinkDeclaration(link, a2);
3770 switch (token.value)
3774 addComment(s, comment);
3778 addComment(s, comment);
3779 if (token.value != TOKidentifier)
3781 error("identifier expected following comma, not %s", token.toChars());
3784 if (peekNext() != TOKassign && peekNext() != TOKlparen)
3786 error("= expected following identifier");
3792 error("semicolon expected to close %s declaration", Token::toChars(tok));
3800 // alias StorageClasses type ident;
3803 parseStorageClasses(storage_class, link, setAlignment, ealign, udas);
3805 if (token.value == TOKstruct ||
3806 token.value == TOKunion ||
3807 token.value == TOKclass ||
3808 token.value == TOKinterface)
3810 Dsymbol *s = parseAggregate();
3811 Dsymbols *a = new Dsymbols();
3816 s = new StorageClassDeclaration(storage_class, a);
3822 s = new AlignDeclaration(s->loc, ealign, a);
3826 if (link != linkage)
3828 s = new LinkDeclaration(link, a);
3834 s = new UserAttributeDeclaration(udas, a);
3839 addComment(s, comment);
3843 /* Look for auto initializers:
3844 * storage_class identifier = initializer;
3845 * storage_class identifier(...) = initializer;
3847 if ((storage_class || udas) &&
3848 token.value == TOKidentifier &&
3849 skipParensIf(peek(&token), &tk) &&
3850 tk->value == TOKassign)
3852 Dsymbols *a = parseAutoDeclarations(storage_class, comment);
3855 Dsymbol *s = new UserAttributeDeclaration(udas, a);
3862 /* Look for return type inference for template functions.
3864 if ((storage_class || udas) && token.value == TOKidentifier && skipParens(peek(&token), &tk) &&
3865 skipAttributes(tk, &tk) &&
3866 (tk->value == TOKlparen || tk->value == TOKlcurly || tk->value == TOKin || tk->value == TOKout ||
3867 tk->value == TOKdo || (tk->value == TOKidentifier && tk->ident == Id::_body)))
3873 ts = parseBasicType();
3874 ts = parseBasicType2(ts);
3879 Dsymbols *a = new Dsymbols();
3883 storage_class |= pAttrs->storageClass;
3884 //pAttrs->storageClass = STCundefined;
3889 TemplateParameters *tpl = NULL;
3895 t = parseDeclarator(ts, &alt, &ident, &tpl, storage_class, &disable, &udas);
3899 else if (t != tfirst)
3900 error("multiple declarations must have the same type, not %s and %s",
3901 tfirst->toChars(), t->toChars());
3902 bool isThis = (t->ty == Tident && ((TypeIdentifier *)t)->ident == Id::This && token.value == TOKassign);
3904 checkCstyleTypeSyntax(loc, t, alt, ident);
3906 error("no identifier for declarator %s", t->toChars());
3908 if (tok == TOKalias)
3911 Initializer *init = NULL;
3913 /* Aliases can no longer have multiple declarators, storage classes,
3914 * linkages, or auto declarations.
3915 * These never made any sense, anyway.
3916 * The code below needs to be fixed to reject them.
3917 * The grammar has already been fixed to preclude them.
3921 error("user defined attributes not allowed for %s declarations", Token::toChars(tok));
3923 if (token.value == TOKassign)
3926 init = parseInitializer();
3931 error("cannot use syntax 'alias this = %s', use 'alias %s this' instead",
3932 init->toChars(), init->toChars());
3934 error("alias cannot have initializer");
3936 v = new AliasDeclaration(loc, ident, t);
3938 v->storage_class = storage_class;
3941 /* AliasDeclaration distinguish @safe, @system, @trusted atttributes
3942 * on prefix and postfix.
3943 * @safe alias void function() FP1;
3944 * alias @safe void function() FP2; // FP2 is not @safe
3945 * alias void function() @safe FP3;
3947 pAttrs->storageClass &= (STCsafe | STCsystem | STCtrusted);
3951 if (link != linkage)
3953 Dsymbols *ax = new Dsymbols();
3955 s = new LinkDeclaration(link, ax);
3958 switch (token.value)
3962 addComment(s, comment);
3967 addComment(s, comment);
3971 error("semicolon expected to close %s declaration", Token::toChars(tok));
3975 else if (t->ty == Tfunction)
3977 Expression *constraint = NULL;
3979 //printf("%s funcdecl t = %s, storage_class = x%lx\n", loc.toChars(), t->toChars(), storage_class);
3980 FuncDeclaration *f =
3981 new FuncDeclaration(loc, Loc(), ident, storage_class | (disable ? STCdisable : 0), t);
3983 pAttrs->storageClass = STCundefined;
3985 constraint = parseConstraint();
3986 Dsymbol *s = parseContracts(f);
3987 Identifier *tplIdent = s->ident;
3988 if (link != linkage)
3990 Dsymbols *ax = new Dsymbols();
3992 s = new LinkDeclaration(link, ax);
3996 Dsymbols *ax = new Dsymbols();
3998 s = new UserAttributeDeclaration(udas, ax);
4001 /* A template parameter list means it's a function template
4005 // Wrap a template around the function declaration
4006 Dsymbols *decldefs = new Dsymbols();
4008 TemplateDeclaration *tempdecl =
4009 new TemplateDeclaration(loc, tplIdent, tpl, constraint, decldefs);
4012 if (storage_class & STCstatic)
4014 assert(f->storage_class & STCstatic);
4015 f->storage_class &= ~STCstatic;
4017 Dsymbols *ax = new Dsymbols();
4019 s = new StorageClassDeclaration(STCstatic, ax);
4023 addComment(s, comment);
4027 Initializer *init = NULL;
4028 if (token.value == TOKassign)
4031 init = parseInitializer();
4034 VarDeclaration *v = new VarDeclaration(loc, t, ident, init);
4035 v->storage_class = storage_class;
4037 pAttrs->storageClass = STCundefined;
4043 Dsymbols *a2 = new Dsymbols();
4045 TemplateDeclaration *tempdecl =
4046 new TemplateDeclaration(loc, ident, tpl, NULL, a2, 0);
4049 if (link != linkage)
4051 Dsymbols *ax = new Dsymbols();
4053 s = new LinkDeclaration(link, ax);
4057 Dsymbols *ax = new Dsymbols();
4059 s = new UserAttributeDeclaration(udas, ax);
4062 switch (token.value)
4066 addComment(s, comment);
4071 addComment(s, comment);
4075 error("semicolon expected, not '%s'", token.toChars());
4084 Dsymbol *Parser::parseFunctionLiteral()
4086 Loc loc = token.loc;
4088 TemplateParameters *tpl = NULL;
4089 Parameters *parameters = NULL;
4092 StorageClass stc = 0;
4093 TOK save = TOKreserved;
4095 switch (token.value)
4101 if (token.value != TOKlparen && token.value != TOKlcurly)
4103 // function type (parameters) { statements... }
4104 // delegate type (parameters) { statements... }
4105 tret = parseBasicType();
4106 tret = parseBasicType2(tret); // function return type
4109 if (token.value == TOKlparen)
4111 // function (parameters) { statements... }
4112 // delegate (parameters) { statements... }
4116 // function { statements... }
4117 // delegate { statements... }
4124 // (parameters) => expression
4125 // (parameters) { statements... }
4126 parameters = parseParameters(&varargs, &tpl);
4127 stc = parsePostfix(STCundefined, NULL);
4128 if (StorageClass modStc = stc & STC_TYPECTOR)
4130 if (save == TOKfunction)
4133 stcToBuffer(&buf, modStc);
4134 error("function literal cannot be %s", buf.peekString());
4142 // { statements... }
4147 // identifier => expression
4148 parameters = new Parameters();
4149 Identifier *id = Identifier::generateId("__T");
4150 Type *t = new TypeIdentifier(loc, id);
4151 parameters->push(new Parameter(0, t, token.ident, NULL));
4153 tpl = new TemplateParameters();
4154 TemplateParameter *tp = new TemplateTypeParameter(loc, id, NULL, NULL);
4165 parameters = new Parameters();
4166 TypeFunction *tf = new TypeFunction(parameters, tret, varargs, linkage, stc);
4167 tf = (TypeFunction *)tf->addSTC(stc);
4168 FuncLiteralDeclaration *fd = new FuncLiteralDeclaration(loc, Loc(), tf, save, NULL);
4170 if (token.value == TOKgoesto)
4173 Loc returnloc = token.loc;
4174 Expression *ae = parseAssignExp();
4175 fd->fbody = new ReturnStatement(returnloc, ae);
4176 fd->endloc = token.loc;
4185 // Wrap a template around function fd
4186 Dsymbols *decldefs = new Dsymbols();
4188 return new TemplateDeclaration(fd->loc, fd->ident, tpl, NULL, decldefs, false, true);
4194 /*****************************************
4195 * Parse auto declarations of the form:
4196 * storageClass ident = init, ident = init, ... ;
4197 * and return the array of them.
4198 * Starts with token on the first ident.
4199 * Ends with scanner past closing ';'
4202 Dsymbols *Parser::parseAutoDeclarations(StorageClass storageClass, const utf8_t *comment)
4204 //printf("parseAutoDeclarations\n");
4206 Dsymbols *a = new Dsymbols;
4210 Loc loc = token.loc;
4211 Identifier *ident = token.ident;
4212 nextToken(); // skip over ident
4214 TemplateParameters *tpl = NULL;
4215 if (token.value == TOKlparen)
4216 tpl = parseTemplateParameterList();
4218 check(TOKassign); // skip over '='
4219 Initializer *init = parseInitializer();
4220 VarDeclaration *v = new VarDeclaration(loc, NULL, ident, init);
4221 v->storage_class = storageClass;
4226 Dsymbols *a2 = new Dsymbols();
4228 TemplateDeclaration *tempdecl =
4229 new TemplateDeclaration(loc, ident, tpl, NULL, a2, 0);
4233 switch (token.value)
4237 addComment(s, comment);
4242 if (!(token.value == TOKidentifier &&
4243 skipParensIf(peek(&token), &tk) &&
4244 tk->value == TOKassign))
4246 error("identifier expected following comma");
4249 addComment(s, comment);
4253 error("semicolon expected following auto declaration, not '%s'", token.toChars());
4261 /*****************************************
4262 * Parse contracts following function declaration.
4265 FuncDeclaration *Parser::parseContracts(FuncDeclaration *f)
4267 LINK linksave = linkage;
4269 bool literal = f->isFuncLiteralDeclaration() != NULL;
4271 // The following is irrelevant, as it is overridden by sc->linkage in
4272 // TypeFunction::semantic
4273 linkage = LINKd; // nested functions have D linkage
4275 switch (token.value)
4278 if (f->frequire || f->fensure)
4279 error("missing body { ... } after in or out");
4280 f->fbody = parseStatement(PSsemi);
4285 if (token.ident != Id::_body)
4291 f->fbody = parseStatement(PScurly);
4298 error("redundant 'in' statement");
4299 f->frequire = parseStatement(PScurly | PSscope);
4303 // parse: out (identifier) { statement }
4305 if (token.value != TOKlcurly)
4308 if (token.value != TOKidentifier)
4309 error("(identifier) following 'out' expected, not %s", token.toChars());
4310 f->outId = token.ident;
4315 error("redundant 'out' statement");
4316 f->fensure = parseStatement(PScurly | PSscope);
4322 // Bugzilla 15799: Semicolon becomes a part of function declaration
4323 // only when neither of contracts exists.
4324 if (!f->frequire && !f->fensure)
4334 const char *sbody = (f->frequire || f->fensure) ? "body " : "";
4335 error("missing %s{ ... } for function literal", sbody);
4337 else if (!f->frequire && !f->fensure) // allow these even with no body
4339 error("semicolon expected following function declaration");
4343 if (literal && !f->fbody)
4345 // Set empty function body for error recovery
4346 f->fbody = new CompoundStatement(Loc(), (Statement *)NULL);
4354 /*****************************************
4355 * Parse initializer for variable declaration.
4358 Initializer *Parser::parseInitializer()
4360 StructInitializer *is;
4361 ArrayInitializer *ia;
4367 Loc loc = token.loc;
4372 switch (token.value)
4375 /* Scan ahead to see if it is a struct initializer or
4376 * a function literal.
4377 * If it contains a ';', it is a function literal.
4378 * Treat { } as a struct initializer.
4381 for (t = peek(&token); 1; t = peek(t))
4407 is = new StructInitializer(loc);
4412 switch (token.value)
4416 error("comma expected separating field initializers");
4418 if (t->value == TOKcolon)
4422 nextToken(); // skip over ':'
4427 value = parseInitializer();
4428 is->addInit(id, value);
4434 error("expression expected, not ','");
4439 case TOKrcurly: // allow trailing comma's
4444 error("found EOF instead of initializer");
4449 error("comma expected separating field initializers");
4450 value = parseInitializer();
4451 is->addInit(NULL, value);
4454 //error("found '%s' instead of field initializer", token.toChars());
4462 /* Scan ahead to see if it is an array initializer or
4464 * If it ends with a ';' ',' or '}', it is an array initializer.
4467 for (t = peek(&token); 1; t = peek(t))
4476 if (--brackets == 0)
4478 if (t->value != TOKsemicolon &&
4479 t->value != TOKcomma &&
4480 t->value != TOKrbracket &&
4481 t->value != TOKrcurly)
4496 ia = new ArrayInitializer(loc);
4501 switch (token.value)
4505 { error("comma expected separating array initializers, not %s", token.toChars());
4509 e = parseAssignExp();
4512 if (token.value == TOKcolon)
4515 value = parseInitializer();
4518 { value = new ExpInitializer(e->loc, e);
4521 ia->addInit(e, value);
4528 error("comma expected separating array initializers, not %s", token.toChars());
4529 value = parseInitializer();
4530 if (token.value == TOKcolon)
4533 e = initializerToExpression(value);
4534 value = parseInitializer();
4538 ia->addInit(e, value);
4544 error("expression expected, not ','");
4549 case TOKrbracket: // allow trailing comma's
4554 error("found '%s' instead of array initializer", token.toChars());
4563 if (t->value == TOKsemicolon || t->value == TOKcomma)
4566 return new VoidInitializer(loc);
4572 e = parseAssignExp();
4573 ie = new ExpInitializer(loc, e);
4578 /*****************************************
4579 * Parses default argument initializer expression that is an assign expression,
4580 * with special handling for __FILE__, __FILE_FULL_PATH__, __LINE__, __MODULE__, __FUNCTION__, and __PRETTY_FUNCTION__.
4583 Expression *Parser::parseDefaultInitExp()
4585 if (token.value == TOKfile ||
4586 token.value == TOKfilefullpath ||
4587 token.value == TOKline ||
4588 token.value == TOKmodulestring ||
4589 token.value == TOKfuncstring ||
4590 token.value == TOKprettyfunc)
4592 Token *t = peek(&token);
4593 if (t->value == TOKcomma || t->value == TOKrparen)
4595 Expression *e = NULL;
4596 if (token.value == TOKfile)
4597 e = new FileInitExp(token.loc, TOKfile);
4598 else if (token.value == TOKfilefullpath)
4599 e = new FileInitExp(token.loc, TOKfilefullpath);
4600 else if (token.value == TOKline)
4601 e = new LineInitExp(token.loc);
4602 else if (token.value == TOKmodulestring)
4603 e = new ModuleInitExp(token.loc);
4604 else if (token.value == TOKfuncstring)
4605 e = new FuncInitExp(token.loc);
4606 else if (token.value == TOKprettyfunc)
4607 e = new PrettyFuncInitExp(token.loc);
4615 Expression *e = parseAssignExp();
4619 /*****************************************
4622 void Parser::checkDanglingElse(Loc elseloc)
4624 if (token.value != TOKelse &&
4625 token.value != TOKcatch &&
4626 token.value != TOKfinally &&
4627 lookingForElse.linnum != 0)
4629 warning(elseloc, "else is dangling, add { } after condition at %s", lookingForElse.toChars());
4633 void Parser::checkCstyleTypeSyntax(Loc loc, Type *t, int alt, Identifier *ident)
4638 const char *sp = !ident ? "" : " ";
4639 const char *s = !ident ? "" : ident->toChars();
4640 if (alt & 1) // contains C-style function pointer syntax
4641 error(loc, "instead of C-style syntax, use D-style '%s%s%s'", t->toChars(), sp, s);
4643 ::warning(loc, "instead of C-style syntax, use D-style syntax '%s%s%s'", t->toChars(), sp, s);
4647 /*****************************************
4651 * pEndloc if { ... statements ... }, store location of closing brace, otherwise loc of first token of next statement
4654 Statement *Parser::parseStatement(int flags, const utf8_t** endPtr, Loc *pEndloc)
4656 Statement *s = NULL;
4659 Statement *elsebody;
4661 Loc loc = token.loc;
4663 //printf("parseStatement()\n");
4665 if (flags & PScurly && token.value != TOKlcurly)
4666 error("statement expected to be { }, not %s", token.toChars());
4668 switch (token.value)
4671 { /* A leading identifier can be a declaration, label, or expression.
4672 * The easiest case to check first is label:
4674 Token *t = peek(&token);
4675 if (t->value == TOKcolon)
4677 Token *nt = peek(t);
4678 if (nt->value == TOKcolon)
4684 error("use `.` for member lookup, not `::`");
4688 Identifier *ident = token.ident;
4691 if (token.value == TOKrcurly)
4693 else if (token.value == TOKlcurly)
4694 s = parseStatement(PScurly | PSscope);
4696 s = parseStatement(PSsemi_ok);
4697 s = new LabelStatement(loc, ident, s);
4705 /* Bugzilla 15163: If tokens can be handled as
4706 * old C-style declaration or D expression, prefer the latter.
4708 if (isDeclaration(&token, 3, TOKreserved, NULL))
4726 case TOKimaginary32v:
4727 case TOKimaginary64v:
4728 case TOKimaginary80v:
4755 case TOKfilefullpath:
4757 case TOKmodulestring:
4762 Expression *exp = parseExpression();
4763 check(TOKsemicolon, "statement");
4764 s = new ExpStatement(loc, exp);
4769 { // Look ahead to see if it's static assert() or static if()
4771 Token *t = peek(&token);
4772 if (t->value == TOKassert)
4774 s = new StaticAssertStatement(parseStaticAssert());
4777 if (t->value == TOKif)
4779 cond = parseStaticIfCondition();
4782 if (t->value == TOKimport)
4784 Dsymbols *imports = parseImport();
4785 s = new ImportStatement(loc, imports);
4786 if (flags & PSscope)
4787 s = new ScopeStatement(loc, s, token.loc);
4794 if (peekNext() == TOKswitch)
4802 case TOKwchar: case TOKdchar:
4803 case TOKbool: case TOKchar:
4804 case TOKint8: case TOKuns8:
4805 case TOKint16: case TOKuns16:
4806 case TOKint32: case TOKuns32:
4807 case TOKint64: case TOKuns64:
4808 case TOKint128: case TOKuns128:
4809 case TOKfloat32: case TOKfloat64: case TOKfloat80:
4810 case TOKimaginary32: case TOKimaginary64: case TOKimaginary80:
4811 case TOKcomplex32: case TOKcomplex64: case TOKcomplex80:
4813 // bug 7773: int.max is always a part of expression
4814 if (peekNext() == TOKdot)
4816 if (peekNext() == TOKlparen)
4841 Dsymbols *a = parseDeclarations(false, NULL, NULL);
4844 Statements *as = new Statements();
4845 as->reserve(a->dim);
4846 for (size_t i = 0; i < a->dim; i++)
4848 Dsymbol *d = (*a)[i];
4849 s = new ExpStatement(loc, d);
4852 s = new CompoundDeclarationStatement(loc, as);
4854 else if (a->dim == 1)
4856 Dsymbol *d = (*a)[0];
4857 s = new ExpStatement(loc, d);
4860 s = new ExpStatement(loc, (Expression *)NULL);
4861 if (flags & PSscope)
4862 s = new ScopeStatement(loc, s, token.loc);
4867 { /* Determine if this is a manifest constant declaration,
4868 * or a conventional enum.
4871 Token *t = peek(&token);
4872 if (t->value == TOKlcurly || t->value == TOKcolon)
4874 else if (t->value != TOKidentifier)
4879 if (t->value == TOKlcurly || t->value == TOKcolon ||
4880 t->value == TOKsemicolon)
4885 s = new ExpStatement(loc, d);
4886 if (flags & PSscope)
4887 s = new ScopeStatement(loc, s, token.loc);
4892 { Token *t = peek(&token);
4893 if (t->value == TOKlparen)
4895 Expression *e = parseAssignExp();
4896 check(TOKsemicolon);
4897 if (e->op == TOKmixin)
4899 CompileExp *cpe = (CompileExp *)e;
4900 s = new CompileStatement(loc, cpe->e1);
4904 s = new ExpStatement(loc, e);
4908 Dsymbol *d = parseMixin();
4909 s = new ExpStatement(loc, d);
4910 if (flags & PSscope)
4911 s = new ScopeStatement(loc, s, token.loc);
4917 Loc lookingForElseSave = lookingForElse;
4918 lookingForElse = Loc();
4921 //if (token.value == TOKsemicolon)
4922 //error("use '{ }' for an empty statement, not a ';'");
4923 Statements *statements = new Statements();
4924 while (token.value != TOKrcurly && token.value != TOKeof)
4926 statements->push(parseStatement(PSsemi | PScurlyscope));
4928 if (endPtr) *endPtr = token.ptr;
4932 *pEndloc = token.loc;
4933 pEndloc = NULL; // don't set it again
4935 s = new CompoundStatement(loc, statements);
4936 if (flags & (PSscope | PScurlyscope))
4937 s = new ScopeStatement(loc, s, token.loc);
4938 check(TOKrcurly, "compound statement");
4939 lookingForElse = lookingForElseSave;
4947 Expression *condition = parseExpression();
4950 Statement *body = parseStatement(PSscope, NULL, &endloc);
4951 s = new WhileStatement(loc, condition, body, endloc);
4956 if (!(flags & PSsemi_ok))
4959 deprecation("use '{ }' for an empty statement, not a ';'");
4961 error("use '{ }' for an empty statement, not a ';'");
4964 s = new ExpStatement(loc, (Expression *)NULL);
4969 Expression *condition;
4972 Loc lookingForElseSave = lookingForElse;
4973 lookingForElse = Loc();
4974 body = parseStatement(PSscope);
4975 lookingForElse = lookingForElseSave;
4978 condition = parseExpression();
4980 if (token.value == TOKsemicolon)
4983 error("terminating ';' required after do-while statement");
4984 s = new DoStatement(loc, body, condition, token.loc);
4991 Expression *condition;
4992 Expression *increment;
4996 if (token.value == TOKsemicolon)
5002 Loc lookingForElseSave = lookingForElse;
5003 lookingForElse = Loc();
5004 init = parseStatement(0);
5005 lookingForElse = lookingForElseSave;
5007 if (token.value == TOKsemicolon)
5014 condition = parseExpression();
5015 check(TOKsemicolon, "for condition");
5017 if (token.value == TOKrparen)
5022 { increment = parseExpression();
5026 Statement *body = parseStatement(PSscope, NULL, &endloc);
5027 s = new ForStatement(loc, init, condition, increment, body, endloc);
5032 case TOKforeach_reverse:
5034 TOK op = token.value;
5039 Parameters *parameters = new Parameters();
5043 Identifier *ai = NULL;
5046 StorageClass storageClass = 0;
5047 StorageClass stc = 0;
5051 storageClass = appendStorageClass(storageClass, stc);
5054 switch (token.value)
5061 if (peekNext() != TOKlparen)
5068 if (peekNext() != TOKlparen)
5075 if (peekNext() != TOKlparen)
5082 if (peekNext() != TOKlparen)
5091 if (token.value == TOKidentifier)
5093 Token *t = peek(&token);
5094 if (t->value == TOKcomma || t->value == TOKsemicolon)
5096 at = NULL; // infer argument type
5101 at = parseType(&ai);
5103 error("no identifier for declarator %s", at->toChars());
5105 Parameter *p = new Parameter(storageClass, at, ai, NULL);
5106 parameters->push(p);
5107 if (token.value == TOKcomma)
5113 check(TOKsemicolon);
5115 Expression *aggr = parseExpression();
5116 if (token.value == TOKslice && parameters->dim == 1)
5118 Parameter *p = (*parameters)[0];
5121 Expression *upr = parseExpression();
5124 Statement *body = parseStatement(0, NULL, &endloc);
5125 s = new ForeachRangeStatement(loc, op, p, aggr, upr, body, endloc);
5131 Statement *body = parseStatement(0, NULL, &endloc);
5132 s = new ForeachStatement(loc, op, parameters, aggr, body, endloc);
5139 Parameter *param = NULL;
5140 Expression *condition;
5145 StorageClass storageClass = 0;
5146 StorageClass stc = 0;
5150 storageClass = appendStorageClass(storageClass, stc);
5153 switch (token.value)
5162 if (peekNext() != TOKlparen)
5169 if (peekNext() != TOKlparen)
5176 if (peekNext() != TOKlparen)
5183 if (peekNext() != TOKlparen)
5193 if (storageClass != 0 &&
5194 token.value == TOKidentifier &&
5195 peek(&token)->value == TOKassign)
5197 Identifier *ai = token.ident;
5198 Type *at = NULL; // infer parameter type
5201 param = new Parameter(storageClass, at, ai, NULL);
5203 else if (isDeclaration(&token, 2, TOKassign, NULL))
5206 Type *at = parseType(&ai);
5208 param = new Parameter(storageClass, at, ai, NULL);
5211 condition = parseExpression();
5214 Loc lookingForElseSave = lookingForElse;
5215 lookingForElse = loc;
5216 ifbody = parseStatement(PSscope);
5217 lookingForElse = lookingForElseSave;
5219 if (token.value == TOKelse)
5221 Loc elseloc = token.loc;
5223 elsebody = parseStatement(PSscope);
5224 checkDanglingElse(elseloc);
5228 if (condition && ifbody)
5229 s = new IfStatement(loc, param, condition, ifbody, elsebody, token.loc);
5231 s = NULL; // don't propagate parsing errors
5236 if (peek(&token)->value != TOKlparen)
5237 goto Ldeclaration; // scope used as storage class
5240 if (token.value != TOKidentifier)
5241 { error("scope identifier expected");
5245 { TOK t = TOKon_scope_exit;
5246 Identifier *id = token.ident;
5249 t = TOKon_scope_exit;
5250 else if (id == Id::failure)
5251 t = TOKon_scope_failure;
5252 else if (id == Id::success)
5253 t = TOKon_scope_success;
5255 error("valid scope identifiers are exit, failure, or success, not %s", id->toChars());
5258 Statement *st = parseStatement(PSscope);
5259 s = new OnScopeStatement(loc, t, st);
5265 if (token.value == TOKassign)
5267 error("debug conditions can only be declared at module scope");
5272 cond = parseDebugCondition();
5277 if (token.value == TOKassign)
5279 error("version conditions can only be declared at module scope");
5284 cond = parseVersionCondition();
5289 Loc lookingForElseSave = lookingForElse;
5290 lookingForElse = loc;
5291 ifbody = parseStatement(0);
5292 lookingForElse = lookingForElseSave;
5295 if (token.value == TOKelse)
5297 Loc elseloc = token.loc;
5299 elsebody = parseStatement(0);
5300 checkDanglingElse(elseloc);
5302 s = new ConditionalStatement(loc, cond, ifbody, elsebody);
5303 if (flags & PSscope)
5304 s = new ScopeStatement(loc, s, token.loc);
5308 { Identifier *ident;
5309 Expressions *args = NULL;
5314 if (token.value != TOKidentifier)
5315 { error("pragma(identifier expected");
5318 ident = token.ident;
5320 if (token.value == TOKcomma && peekNext() != TOKrparen)
5321 args = parseArguments(); // pragma(identifier, args...);
5323 check(TOKrparen); // pragma(identifier);
5324 if (token.value == TOKsemicolon)
5329 body = parseStatement(PSsemi);
5330 s = new PragmaStatement(loc, ident, args, body);
5342 Expression *condition = parseExpression();
5344 Statement *body = parseStatement(PSscope);
5345 s = new SwitchStatement(loc, condition, body, isfinal);
5351 Expressions cases; // array of Expression's
5352 Expression *last = NULL;
5357 exp = parseAssignExp();
5359 if (token.value != TOKcomma)
5364 /* case exp: .. case last:
5366 if (token.value == TOKslice)
5369 error("only one case allowed for start of case range");
5372 last = parseAssignExp();
5376 if (flags & PScurlyscope)
5378 Statements *statements = new Statements();
5379 while (token.value != TOKcase &&
5380 token.value != TOKdefault &&
5381 token.value != TOKeof &&
5382 token.value != TOKrcurly)
5384 statements->push(parseStatement(PSsemi | PScurlyscope));
5386 s = new CompoundStatement(loc, statements);
5389 s = parseStatement(PSsemi | PScurlyscope);
5390 s = new ScopeStatement(loc, s, token.loc);
5394 s = new CaseRangeStatement(loc, exp, last, s);
5398 // Keep cases in order by building the case statements backwards
5399 for (size_t i = cases.dim; i; i--)
5402 s = new CaseStatement(loc, exp, s);
5413 if (flags & PScurlyscope)
5415 Statements *statements = new Statements();
5416 while (token.value != TOKcase &&
5417 token.value != TOKdefault &&
5418 token.value != TOKeof &&
5419 token.value != TOKrcurly)
5421 statements->push(parseStatement(PSsemi | PScurlyscope));
5423 s = new CompoundStatement(loc, statements);
5426 s = parseStatement(PSsemi | PScurlyscope);
5427 s = new ScopeStatement(loc, s, token.loc);
5428 s = new DefaultStatement(loc, s);
5436 if (token.value == TOKsemicolon)
5439 exp = parseExpression();
5440 check(TOKsemicolon, "return statement");
5441 s = new ReturnStatement(loc, exp);
5446 { Identifier *ident;
5449 if (token.value == TOKidentifier)
5450 { ident = token.ident;
5455 check(TOKsemicolon, "break statement");
5456 s = new BreakStatement(loc, ident);
5461 { Identifier *ident;
5464 if (token.value == TOKidentifier)
5465 { ident = token.ident;
5470 check(TOKsemicolon, "continue statement");
5471 s = new ContinueStatement(loc, ident);
5476 { Identifier *ident;
5479 if (token.value == TOKdefault)
5482 s = new GotoDefaultStatement(loc);
5484 else if (token.value == TOKcase)
5486 Expression *exp = NULL;
5489 if (token.value != TOKsemicolon)
5490 exp = parseExpression();
5491 s = new GotoCaseStatement(loc, exp);
5495 if (token.value != TOKidentifier)
5497 error("identifier expected following goto");
5502 ident = token.ident;
5505 s = new GotoStatement(loc, ident);
5507 check(TOKsemicolon, "goto statement");
5511 case TOKsynchronized:
5515 Token *t = peek(&token);
5516 if (skipAttributes(t, &t) && t->value == TOKclass)
5520 if (token.value == TOKlparen)
5523 exp = parseExpression();
5528 body = parseStatement(PSscope);
5529 s = new SynchronizedStatement(loc, exp, body);
5539 exp = parseExpression();
5541 body = parseStatement(PSscope);
5542 s = new WithStatement(loc, exp, body, token.loc);
5548 Catches *catches = NULL;
5549 Statement *finalbody = NULL;
5552 Loc lookingForElseSave = lookingForElse;
5553 lookingForElse = Loc();
5554 body = parseStatement(PSscope);
5555 lookingForElse = lookingForElseSave;
5556 while (token.value == TOKcatch)
5562 Loc catchloc = token.loc;
5565 if (token.value == TOKlcurly || token.value != TOKlparen)
5577 handler = parseStatement(0);
5578 c = new Catch(catchloc, t, id, handler);
5580 catches = new Catches();
5584 if (token.value == TOKfinally)
5587 finalbody = parseStatement(PSscope);
5591 if (!catches && !finalbody)
5592 error("catch or finally expected following try");
5595 s = new TryCatchStatement(loc, body, catches);
5597 s = new TryFinallyStatement(loc, s, finalbody);
5606 exp = parseExpression();
5607 check(TOKsemicolon, "throw statement");
5608 s = new ThrowStatement(loc, exp);
5614 // Parse the asm block into a sequence of AsmStatements,
5615 // each AsmStatement is one instruction.
5616 // Separate out labels.
5617 // Defer parsing of AsmStatements until semantic processing.
5622 StorageClass stc = parsePostfix(STCundefined, NULL);
5623 if (stc & (STCconst | STCimmutable | STCshared | STCwild))
5624 error("const/immutable/shared/inout attributes are not allowed on asm blocks");
5627 Token *toklist = NULL;
5628 Token **ptoklist = &toklist;
5629 Identifier *label = NULL;
5630 Statements *statements = new Statements();
5631 size_t nestlevel = 0;
5634 switch (token.value)
5639 // Look ahead to see if it is a label
5640 Token *t = peek(&token);
5641 if (t->value == TOKcolon)
5643 label = token.ident;
5644 labelloc = token.loc;
5663 if (toklist || label)
5665 error("asm statements must end in ';'");
5671 error("mismatched number of curly brackets");
5674 if (toklist || label)
5676 // Create AsmStatement from list of tokens we've saved
5677 s = new AsmStatement(token.loc, toklist);
5679 ptoklist = &toklist;
5681 { s = new LabelStatement(labelloc, label, s);
5684 statements->push(s);
5691 error("matching '}' expected, not end of file");
5697 *ptoklist = Token::alloc();
5698 memcpy(*ptoklist, &token, sizeof(Token));
5699 ptoklist = &(*ptoklist)->next;
5707 s = new CompoundAsmStatement(loc, statements, stc);
5714 Dsymbols *imports = parseImport();
5715 s = new ImportStatement(loc, imports);
5716 if (flags & PSscope)
5717 s = new ScopeStatement(loc, s, token.loc);
5723 Dsymbol *d = parseTemplateDeclaration();
5724 s = new ExpStatement(loc, d);
5729 error("found '%s' instead of statement", token.toChars());
5733 while (token.value != TOKrcurly &&
5734 token.value != TOKsemicolon &&
5735 token.value != TOKeof)
5737 if (token.value == TOKsemicolon)
5743 *pEndloc = token.loc;
5747 void Parser::check(TOK value)
5749 check(token.loc, value);
5752 void Parser::check(Loc loc, TOK value)
5754 if (token.value != value)
5755 error(loc, "found '%s' when expecting '%s'", token.toChars(), Token::toChars(value));
5759 void Parser::check(TOK value, const char *string)
5761 if (token.value != value)
5762 error("found '%s' when expecting '%s' following %s",
5763 token.toChars(), Token::toChars(value), string);
5767 void Parser::checkParens(TOK value, Expression *e)
5769 if (precedence[e->op] == PREC_rel && !e->parens)
5770 error(e->loc, "%s must be parenthesized when next to operator %s", e->toChars(), Token::toChars(value));
5773 /************************************
5774 * Determine if the scanner is sitting on the start of a declaration.
5776 * needId 0 no identifier
5777 * 1 identifier optional
5778 * 2 must have identifier
5779 * 3 must have identifier, but don't recognize old C-style syntax.
5781 * if *pt is not NULL, it is set to the ending token, which would be endtok
5784 bool Parser::isDeclaration(Token *t, int needId, TOK endtok, Token **pt)
5786 //printf("isDeclaration(needId = %d)\n", needId);
5792 if ((t->value == TOKconst ||
5793 t->value == TOKimmutable ||
5794 t->value == TOKwild ||
5795 t->value == TOKshared) &&
5796 peek(t)->value != TOKlparen)
5809 if (!isBasicType(&t))
5813 if (!isDeclarator(&t, &haveId, &haveTpl, endtok, needId != 3))
5815 if (needId == 1 || (needId == 0 && !haveId) || ((needId == 2 || needId == 3) && haveId))
5825 //printf("\tis declaration, t = %s\n", t->toChars());
5829 //printf("\tis not declaration\n");
5833 bool Parser::isBasicType(Token **pt)
5835 // This code parallels parseBasicType()
5840 case TOKwchar: case TOKdchar:
5841 case TOKbool: case TOKchar:
5842 case TOKint8: case TOKuns8:
5843 case TOKint16: case TOKuns16:
5844 case TOKint32: case TOKuns32:
5845 case TOKint64: case TOKuns64:
5846 case TOKint128: case TOKuns128:
5847 case TOKfloat32: case TOKfloat64: case TOKfloat80:
5848 case TOKimaginary32: case TOKimaginary64: case TOKimaginary80:
5849 case TOKcomplex32: case TOKcomplex64: case TOKcomplex80:
5857 if (t->value == TOKnot)
5867 if (t->value == TOKdot)
5871 if (t->value != TOKidentifier)
5874 if (t->value != TOKnot)
5879 * !( args ), !identifier, etc.
5887 if (!skipParens(t, &t))
5890 case TOKwchar: case TOKdchar:
5891 case TOKbool: case TOKchar:
5892 case TOKint8: case TOKuns8:
5893 case TOKint16: case TOKuns16:
5894 case TOKint32: case TOKuns32:
5895 case TOKint64: case TOKuns64:
5896 case TOKint128: case TOKuns128:
5897 case TOKfloat32: case TOKfloat64: case TOKfloat80:
5898 case TOKimaginary32: case TOKimaginary64: case TOKimaginary80:
5899 case TOKcomplex32: case TOKcomplex64: case TOKcomplex80:
5910 case TOKimaginary32v:
5911 case TOKimaginary64v:
5912 case TOKimaginary80v:
5922 case TOKfilefullpath:
5924 case TOKmodulestring:
5942 /* typeof(exp).identifier...
5945 if (!skipParens(t, &t))
5953 // const(type) or immutable(type) or shared(type) or wild(type)
5955 if (t->value != TOKlparen)
5958 if (!isDeclaration(t, 0, TOKrparen, &t))
5973 //printf("is not\n");
5977 bool Parser::isDeclarator(Token **pt, int *haveId, int *haveTpl, TOK endtok, bool allowAltSyntax)
5978 { // This code parallels parseDeclarator()
5982 //printf("Parser::isDeclarator() %s\n", t->toChars());
5983 if (t->value == TOKassign)
5998 if (t->value == TOKrbracket)
6002 else if (isDeclaration(t, 0, TOKrbracket, &t))
6004 // It's an associative array declaration
6008 if (t->value == TOKdot && peek(t)->value == TOKidentifier)
6017 // [ expression .. expression ]
6018 if (!isExpression(&t))
6020 if (t->value == TOKslice)
6023 if (!isExpression(&t))
6025 if (t->value != TOKrbracket)
6031 if (t->value != TOKrbracket)
6036 if (t->value == TOKdot && peek(t)->value == TOKidentifier)
6053 if (!allowAltSyntax)
6054 return false; // Do not recognize C-style declarations.
6058 if (t->value == TOKrparen)
6059 return false; // () is not a declarator
6061 /* Regard ( identifier ) as not a declarator
6062 * BUG: what about ( *identifier ) in
6064 * where f is a class instance with overloaded () ?
6065 * Should we just disallow C-style function pointer declarations?
6067 if (t->value == TOKidentifier)
6068 { Token *t2 = peek(t);
6069 if (t2->value == TOKrparen)
6074 if (!isDeclarator(&t, haveId, NULL, TOKrparen))
6083 if (!isParameters(&t))
6085 skipAttributes(t, &t);
6100 if (t->value == TOKrbracket)
6104 else if (isDeclaration(t, 0, TOKrbracket, &t))
6105 { // It's an associative array declaration
6111 if (!isExpression(&t))
6113 if (t->value != TOKrbracket)
6122 if (Token *tk = peekPastParen(t))
6124 if (tk->value == TOKlparen)
6126 if (!haveTpl) return false;
6130 else if (tk->value == TOKassign)
6132 if (!haveTpl) return false;
6138 if (!isParameters(&t))
6155 t = peek(t); // skip '@'
6156 t = peek(t); // skip identifier
6166 if (t->ident != Id::_body)
6170 // Valid tokens that follow a declaration
6181 // The !parens is to disallow unnecessary parentheses
6182 if (!parens && (endtok == TOKreserved || endtok == t->value))
6189 return haveTpl ? true : false;
6200 bool Parser::isParameters(Token **pt)
6201 { // This code parallels parseParameters()
6204 //printf("isParameters()\n");
6205 if (t->value != TOKlparen)
6209 for (;1; t = peek(t))
6236 if (t->value == TOKlparen)
6239 if (!isDeclaration(t, 0, TOKrparen, &t))
6241 t = peek(t); // skip past closing ')'
6247 { if (!isBasicType(&t))
6251 if (t->value != TOKdotdotdot &&
6252 !isDeclarator(&t, &tmp, NULL, TOKreserved))
6254 if (t->value == TOKassign)
6256 if (!isExpression(&t))
6259 if (t->value == TOKdotdotdot)
6265 if (t->value == TOKcomma)
6273 if (t->value != TOKrparen)
6280 bool Parser::isExpression(Token **pt)
6282 // This is supposed to determine if something is an expression.
6283 // What it actually does is scan until a closing right bracket
6291 for (;; t = peek(t))
6309 if (brnest || panest)
6323 if (--curlynest >= 0)
6350 /*******************************************
6351 * Skip parens, brackets.
6355 * *pt is set to closing token, which is ')' on success
6358 * false some parsing error
6361 bool Parser::skipParens(Token *t, Token **pt)
6363 if (t->value != TOKlparen)
6395 *pt = peek(t); // skip found rparen
6402 bool Parser::skipParensIf(Token *t, Token **pt)
6404 if (t->value != TOKlparen)
6410 return skipParens(t, pt);
6413 /*******************************************
6416 * t is on a candidate attribute
6418 * *pt is set to first non-attribute token on success
6421 * false some parsing error
6424 bool Parser::skipAttributes(Token *t, Token **pt)
6439 case TOKsynchronized:
6442 if (peek(t)->value == TOKlparen)
6445 if (!skipParens(t, &t))
6447 // t is on the next of closing parenthesis
6460 if (t->value == TOKidentifier)
6464 * @identifier!(arglist)
6465 * any of the above followed by (arglist)
6466 * @predefined_attribute
6468 if (t->ident == Id::property ||
6469 t->ident == Id::nogc ||
6470 t->ident == Id::safe ||
6471 t->ident == Id::trusted ||
6472 t->ident == Id::system ||
6473 t->ident == Id::disable)
6476 if (t->value == TOKnot)
6479 if (t->value == TOKlparen)
6481 // @identifier!(arglist)
6482 if (!skipParens(t, &t))
6484 // t is on the next of closing parenthesis
6489 // Do low rent skipTemplateArgument
6490 if (t->value == TOKvector)
6492 // identifier!__vector(type)
6494 if (!skipParens(t, &t))
6501 if (t->value == TOKlparen)
6503 if (!skipParens(t, &t))
6505 // t is on the next of closing parenthesis
6510 if (t->value == TOKlparen)
6512 // @( ArgumentList )
6513 if (!skipParens(t, &t))
6515 // t is on the next of closing parenthesis
6534 /********************************* Expression Parser ***************************/
6536 Expression *Parser::parsePrimaryExp()
6541 Loc loc = token.loc;
6543 //printf("parsePrimaryExp(): loc = %d\n", loc.linnum);
6544 switch (token.value)
6548 Token *t1 = peek(&token);
6549 Token *t2 = peek(t1);
6550 if (t1->value == TOKmin && t2->value == TOKgt)
6556 error("use `.` for member lookup, not `->`");
6560 if (peekNext() == TOKgoesto)
6566 if (token.value == TOKnot && (save = peekNext()) != TOKis && save != TOKin)
6568 // identifier!(template-argument-list)
6569 TemplateInstance *tempinst;
6570 tempinst = new TemplateInstance(loc, id);
6571 tempinst->tiargs = parseTemplateArguments();
6572 e = new ScopeExp(loc, tempinst);
6575 e = new IdentifierExp(loc, id);
6581 error("'$' is valid only inside [] of index or slice");
6582 e = new DollarExp(loc);
6587 // Signal global scope '.' operator with "" identifier
6588 e = new IdentifierExp(loc, Id::empty);
6592 e = new ThisExp(loc);
6597 e = new SuperExp(loc);
6602 e = new IntegerExp(loc, (d_int32)token.int64value, Type::tint32);
6607 e = new IntegerExp(loc, (d_uns32)token.uns64value, Type::tuns32);
6612 e = new IntegerExp(loc, token.int64value, Type::tint64);
6617 e = new IntegerExp(loc, token.uns64value, Type::tuns64);
6622 e = new RealExp(loc, token.floatvalue, Type::tfloat32);
6627 e = new RealExp(loc, token.floatvalue, Type::tfloat64);
6632 e = new RealExp(loc, token.floatvalue, Type::tfloat80);
6636 case TOKimaginary32v:
6637 e = new RealExp(loc, token.floatvalue, Type::timaginary32);
6641 case TOKimaginary64v:
6642 e = new RealExp(loc, token.floatvalue, Type::timaginary64);
6646 case TOKimaginary80v:
6647 e = new RealExp(loc, token.floatvalue, Type::timaginary80);
6652 e = new NullExp(loc);
6658 const char *s = loc.filename ? loc.filename : mod->ident->toChars();
6659 e = new StringExp(loc, const_cast<char *>(s), strlen(s), 0);
6664 case TOKfilefullpath:
6666 const char *srcfile = mod->srcfile->name->toChars();
6668 if (loc.filename && !FileName::equals(loc.filename, srcfile))
6671 s = FileName::combine(mod->srcfilePath, srcfile);
6672 e = new StringExp(loc, const_cast<char *>(s), strlen(s), 0);
6678 e = new IntegerExp(loc, loc.linnum, Type::tint32);
6682 case TOKmodulestring:
6684 const char *s = md ? md->toChars() : mod->toChars();
6685 e = new StringExp(loc, const_cast<char *>(s), strlen(s), 0);
6691 e = new FuncInitExp(loc);
6696 e = new PrettyFuncInitExp(loc);
6701 e = new IntegerExp(loc, 1, Type::tbool);
6706 e = new IntegerExp(loc, 0, Type::tbool);
6711 e = new IntegerExp(loc, (d_uns8)token.uns64value, Type::tchar);
6716 e = new IntegerExp(loc, (d_uns16)token.uns64value, Type::twchar);
6721 e = new IntegerExp(loc, (d_uns32)token.uns64value, Type::tdchar);
6728 // cat adjacent strings
6729 utf8_t *s = token.ustring;
6730 size_t len = token.len;
6731 unsigned char postfix = token.postfix;
6734 const Token prev = token;
6736 if (token.value == TOKstring ||
6737 token.value == TOKxstring)
6740 { if (token.postfix != postfix)
6741 error("mismatched string literal postfixes '%c' and '%c'", postfix, token.postfix);
6742 postfix = token.postfix;
6745 deprecation("Implicit string concatenation is deprecated, use %s ~ %s instead",
6746 prev.toChars(), token.toChars());
6749 size_t len2 = token.len;
6751 utf8_t *s2 = (utf8_t *)mem.xmalloc((len + 1) * sizeof(utf8_t));
6752 memcpy(s2, s, len1 * sizeof(utf8_t));
6753 memcpy(s2 + len1, token.ustring, (len2 + 1) * sizeof(utf8_t));
6759 e = new StringExp(loc, s, len, postfix);
6763 case TOKvoid: t = Type::tvoid; goto LabelX;
6764 case TOKint8: t = Type::tint8; goto LabelX;
6765 case TOKuns8: t = Type::tuns8; goto LabelX;
6766 case TOKint16: t = Type::tint16; goto LabelX;
6767 case TOKuns16: t = Type::tuns16; goto LabelX;
6768 case TOKint32: t = Type::tint32; goto LabelX;
6769 case TOKuns32: t = Type::tuns32; goto LabelX;
6770 case TOKint64: t = Type::tint64; goto LabelX;
6771 case TOKuns64: t = Type::tuns64; goto LabelX;
6772 case TOKint128: t = Type::tint128; goto LabelX;
6773 case TOKuns128: t = Type::tuns128; goto LabelX;
6774 case TOKfloat32: t = Type::tfloat32; goto LabelX;
6775 case TOKfloat64: t = Type::tfloat64; goto LabelX;
6776 case TOKfloat80: t = Type::tfloat80; goto LabelX;
6777 case TOKimaginary32: t = Type::timaginary32; goto LabelX;
6778 case TOKimaginary64: t = Type::timaginary64; goto LabelX;
6779 case TOKimaginary80: t = Type::timaginary80; goto LabelX;
6780 case TOKcomplex32: t = Type::tcomplex32; goto LabelX;
6781 case TOKcomplex64: t = Type::tcomplex64; goto LabelX;
6782 case TOKcomplex80: t = Type::tcomplex80; goto LabelX;
6783 case TOKbool: t = Type::tbool; goto LabelX;
6784 case TOKchar: t = Type::tchar; goto LabelX;
6785 case TOKwchar: t = Type::twchar; goto LabelX;
6786 case TOKdchar: t = Type::tdchar; goto LabelX;
6789 if (token.value == TOKlparen)
6791 e = new TypeExp(loc, t);
6792 e = new CallExp(loc, e, parseArguments());
6795 check(TOKdot, t->toChars());
6796 if (token.value != TOKidentifier)
6797 { error("found '%s' when expecting identifier following '%s.'", token.toChars(), t->toChars());
6800 e = typeDotIdExp(loc, t, token.ident);
6807 e = new TypeExp(loc, t);
6814 e = new TypeExp(loc, t);
6821 check(TOKlparen, "typeid");
6823 if (isDeclaration(&token, 0, TOKreserved, NULL))
6824 { // argument is a type
6828 { // argument is an expression
6829 o = parseAssignExp();
6832 e = new TypeidExp(loc, o);
6837 { /* __traits(identifier, args...)
6840 Objects *args = NULL;
6844 if (token.value != TOKidentifier)
6845 { error("__traits(identifier, args...) expected");
6848 ident = token.ident;
6850 if (token.value == TOKcomma)
6851 args = parseTemplateArgumentList(); // __traits(identifier, args...)
6853 check(TOKrparen); // __traits(identifier)
6855 e = new TraitsExp(loc, ident, args);
6862 Identifier *ident = NULL;
6864 TOK tok = TOKreserved;
6865 TOK tok2 = TOKreserved;
6866 TemplateParameters *tpl = NULL;
6869 if (token.value == TOKlparen)
6872 targ = parseType(&ident);
6873 if (token.value == TOKcolon || token.value == TOKequal)
6877 if (tok == TOKequal &&
6878 (token.value == TOKstruct ||
6879 token.value == TOKunion ||
6880 token.value == TOKclass ||
6881 token.value == TOKsuper ||
6882 token.value == TOKenum ||
6883 token.value == TOKinterface ||
6884 token.value == TOKargTypes ||
6885 token.value == TOKparameters ||
6886 (token.value == TOKconst && peek(&token)->value == TOKrparen) ||
6887 (token.value == TOKimmutable && peek(&token)->value == TOKrparen) ||
6888 (token.value == TOKshared && peek(&token)->value == TOKrparen) ||
6889 (token.value == TOKwild && peek(&token)->value == TOKrparen) ||
6890 token.value == TOKfunction ||
6891 token.value == TOKdelegate ||
6892 token.value == TOKreturn ||
6893 (token.value == TOKvector && peek(&token)->value == TOKrparen)))
6900 tspec = parseType();
6905 if (token.value == TOKcomma)
6906 tpl = parseTemplateParameterList(1);
6909 tpl = new TemplateParameters();
6918 error("(type identifier : specialization) expected following is");
6921 e = new IsExp(loc, targ, ident, tok, tspec, tok2, tpl);
6926 { Expression *msg = NULL;
6929 check(TOKlparen, "assert");
6930 e = parseAssignExp();
6931 if (token.value == TOKcomma)
6934 if (token.value != TOKrparen)
6936 msg = parseAssignExp();
6937 if (token.value == TOKcomma)
6942 e = new AssertExp(loc, e, msg);
6949 check(TOKlparen, "mixin");
6950 e = parseAssignExp();
6952 e = new CompileExp(loc, e);
6959 check(TOKlparen, "import");
6960 e = parseAssignExp();
6962 e = new ImportExp(loc, e);
6967 e = parseNewExp(NULL);
6972 Token *tk = peekPastParen(&token);
6973 if (skipAttributes(tk, &tk) &&
6974 (tk->value == TOKgoesto || tk->value == TOKlcurly))
6976 // (arguments) => expression
6977 // (arguments) { statements... }
6983 e = parseExpression();
6985 check(loc, TOKrparen);
6990 { /* Parse array literals and associative array literals:
6991 * [ value, value, value ... ]
6992 * [ key:value, key:value, key:value ... ]
6994 Expressions *values = new Expressions();
6995 Expressions *keys = NULL;
6998 while (token.value != TOKrbracket && token.value != TOKeof)
7000 e = parseAssignExp();
7001 if (token.value == TOKcolon && (keys || values->dim == 0))
7004 keys = new Expressions();
7006 e = parseAssignExp();
7009 { error("'key:value' expected for associative array literal");
7014 if (token.value == TOKrbracket)
7018 check(loc, TOKrbracket);
7021 e = new AssocArrayLiteralExp(loc, keys, values);
7023 e = new ArrayLiteralExp(loc, NULL, values);
7032 Dsymbol *s = parseFunctionLiteral();
7033 e = new FuncExp(loc, s);
7038 error("expression expected, not '%s'", token.toChars());
7040 // Anything for e, as long as it's not NULL
7041 e = new IntegerExp(loc, 0, Type::tint32);
7048 Expression *Parser::parsePostExp(Expression *e)
7055 switch (token.value)
7059 if (token.value == TOKidentifier)
7060 { Identifier *id = token.ident;
7063 if (token.value == TOKnot && peekNext() != TOKis && peekNext() != TOKin)
7065 Objects *tiargs = parseTemplateArguments();
7066 e = new DotTemplateInstanceExp(loc, e, id, tiargs);
7069 e = new DotIdExp(loc, e, id);
7072 else if (token.value == TOKnew)
7078 error("identifier expected following '.', not '%s'", token.toChars());
7082 e = new PostExp(TOKplusplus, loc, e);
7086 e = new PostExp(TOKminusminus, loc, e);
7090 e = new CallExp(loc, e, parseArguments());
7094 { // array dereferences:
7097 // array[lwr .. upr]
7100 Expressions *arguments = new Expressions();
7104 while (token.value != TOKrbracket && token.value != TOKeof)
7106 index = parseAssignExp();
7107 if (token.value == TOKslice)
7109 // array[..., lwr..upr, ...]
7111 upr = parseAssignExp();
7112 arguments->push(new IntervalExp(loc, index, upr));
7115 arguments->push(index);
7116 if (token.value == TOKrbracket)
7122 e = new ArrayExp(loc, e, arguments);
7133 Expression *Parser::parseUnaryExp()
7136 Loc loc = token.loc;
7138 switch (token.value)
7142 e = parseUnaryExp();
7143 e = new AddrExp(loc, e);
7148 e = parseUnaryExp();
7149 //e = new AddAssignExp(loc, e, new IntegerExp(loc, 1, Type::tint32));
7150 e = new PreExp(TOKpreplusplus, loc, e);
7155 e = parseUnaryExp();
7156 //e = new MinAssignExp(loc, e, new IntegerExp(loc, 1, Type::tint32));
7157 e = new PreExp(TOKpreminusminus, loc, e);
7162 e = parseUnaryExp();
7163 e = new PtrExp(loc, e);
7168 e = parseUnaryExp();
7169 e = new NegExp(loc, e);
7174 e = parseUnaryExp();
7175 e = new UAddExp(loc, e);
7180 e = parseUnaryExp();
7181 e = new NotExp(loc, e);
7186 e = parseUnaryExp();
7187 e = new ComExp(loc, e);
7192 e = parseUnaryExp();
7193 e = new DeleteExp(loc, e, false);
7196 case TOKcast: // cast(type) expression
7200 /* Look for cast(), cast(const), cast(immutable),
7201 * cast(shared), cast(shared const), cast(wild), cast(shared wild)
7203 unsigned char m = 0;
7206 switch (token.value)
7209 if (peekNext() == TOKlparen)
7210 break; // const as type constructor
7211 m |= MODconst; // const as storage class
7216 if (peekNext() == TOKlparen)
7223 if (peekNext() == TOKlparen)
7230 if (peekNext() == TOKlparen)
7241 if (token.value == TOKrparen)
7244 e = parseUnaryExp();
7245 e = new CastExp(loc, e, m);
7249 Type *t = parseType(); // cast( type )
7250 t = t->addMod(m); // cast( const type )
7252 e = parseUnaryExp();
7253 e = new CastExp(loc, e, t);
7261 case TOKimmutable: // immutable(type)(arguments) / immutable(type).init
7263 StorageClass stc = parseTypeCtor();
7264 Type *t = parseBasicType();
7266 e = new TypeExp(loc, t);
7267 if (stc == 0 && token.value == TOKdot)
7270 if (token.value != TOKidentifier)
7272 error("identifier expected following (type).");
7275 e = typeDotIdExp(loc, t, token.ident);
7277 e = parsePostExp(e);
7280 else if (token.value != TOKlparen)
7282 error("(arguments) expected following %s", t->toChars());
7285 e = new CallExp(loc, e, parseArguments());
7296 if (isDeclaration(tk, 0, TOKrparen, &tk))
7298 tk = peek(tk); // skip over right parenthesis
7303 if (tk->value == TOKis || tk->value == TOKin) // !is or !in
7325 case TOKimaginary32v:
7326 case TOKimaginary64v:
7327 case TOKimaginary80v:
7340 case TOKfilefullpath:
7342 case TOKmodulestring:
7345 case TOKwchar: case TOKdchar:
7346 case TOKbool: case TOKchar:
7347 case TOKint8: case TOKuns8:
7348 case TOKint16: case TOKuns16:
7349 case TOKint32: case TOKuns32:
7350 case TOKint64: case TOKuns64:
7351 case TOKint128: case TOKuns128:
7352 case TOKfloat32: case TOKfloat64: case TOKfloat80:
7353 case TOKimaginary32: case TOKimaginary64: case TOKimaginary80:
7354 case TOKcomplex32: case TOKcomplex64: case TOKcomplex80:
7364 // or .identifier!( ... )
7365 if (token.value == TOKdot)
7367 if (peekNext() != TOKidentifier && peekNext() != TOKnew)
7369 error("identifier or new keyword expected following (...).");
7372 e = new TypeExp(loc, t);
7373 e = parsePostExp(e);
7377 e = parseUnaryExp();
7378 e = new CastExp(loc, e, t);
7379 error("C style cast illegal, use %s", e->toChars());
7388 e = parsePrimaryExp();
7389 e = parsePostExp(e);
7393 e = parsePrimaryExp();
7394 e = parsePostExp(e);
7399 // ^^ is right associative and has higher precedence than the unary operators
7400 while (token.value == TOKpow)
7403 Expression *e2 = parseUnaryExp();
7404 e = new PowExp(loc, e, e2);
7410 Expression *Parser::parseMulExp()
7414 Loc loc = token.loc;
7416 e = parseUnaryExp();
7419 switch (token.value)
7421 case TOKmul: nextToken(); e2 = parseUnaryExp(); e = new MulExp(loc,e,e2); continue;
7422 case TOKdiv: nextToken(); e2 = parseUnaryExp(); e = new DivExp(loc,e,e2); continue;
7423 case TOKmod: nextToken(); e2 = parseUnaryExp(); e = new ModExp(loc,e,e2); continue;
7433 Expression *Parser::parseAddExp()
7437 Loc loc = token.loc;
7442 switch (token.value)
7444 case TOKadd: nextToken(); e2 = parseMulExp(); e = new AddExp(loc,e,e2); continue;
7445 case TOKmin: nextToken(); e2 = parseMulExp(); e = new MinExp(loc,e,e2); continue;
7446 case TOKtilde: nextToken(); e2 = parseMulExp(); e = new CatExp(loc,e,e2); continue;
7456 Expression *Parser::parseShiftExp()
7460 Loc loc = token.loc;
7465 switch (token.value)
7467 case TOKshl: nextToken(); e2 = parseAddExp(); e = new ShlExp(loc,e,e2); continue;
7468 case TOKshr: nextToken(); e2 = parseAddExp(); e = new ShrExp(loc,e,e2); continue;
7469 case TOKushr: nextToken(); e2 = parseAddExp(); e = new UshrExp(loc,e,e2); continue;
7479 Expression *Parser::parseCmpExp()
7484 Loc loc = token.loc;
7486 e = parseShiftExp();
7487 TOK op = token.value;
7494 e2 = parseShiftExp();
7495 e = new EqualExp(op, loc, e, e2);
7503 // Attempt to identify '!is'
7505 if (t->value == TOKin)
7509 e2 = parseShiftExp();
7510 e = new InExp(loc, e, e2);
7511 e = new NotExp(loc, e);
7514 if (t->value != TOKis)
7517 op = TOKnotidentity;
7522 e2 = parseShiftExp();
7523 e = new IdentityExp(op, loc, e, e2);
7539 e2 = parseShiftExp();
7540 e = new CmpExp(op, loc, e, e2);
7545 e2 = parseShiftExp();
7546 e = new InExp(loc, e, e2);
7555 Expression *Parser::parseAndExp()
7557 Loc loc = token.loc;
7559 Expression *e = parseCmpExp();
7560 while (token.value == TOKand)
7562 checkParens(TOKand, e);
7564 Expression *e2 = parseCmpExp();
7565 checkParens(TOKand, e2);
7566 e = new AndExp(loc,e,e2);
7572 Expression *Parser::parseXorExp()
7574 Loc loc = token.loc;
7576 Expression *e = parseAndExp();
7577 while (token.value == TOKxor)
7579 checkParens(TOKxor, e);
7581 Expression *e2 = parseAndExp();
7582 checkParens(TOKxor, e2);
7583 e = new XorExp(loc, e, e2);
7588 Expression *Parser::parseOrExp()
7590 Loc loc = token.loc;
7592 Expression *e = parseXorExp();
7593 while (token.value == TOKor)
7595 checkParens(TOKor, e);
7597 Expression *e2 = parseXorExp();
7598 checkParens(TOKor, e2);
7599 e = new OrExp(loc, e, e2);
7604 Expression *Parser::parseAndAndExp()
7608 Loc loc = token.loc;
7611 while (token.value == TOKandand)
7615 e = new AndAndExp(loc, e, e2);
7620 Expression *Parser::parseOrOrExp()
7624 Loc loc = token.loc;
7626 e = parseAndAndExp();
7627 while (token.value == TOKoror)
7630 e2 = parseAndAndExp();
7631 e = new OrOrExp(loc, e, e2);
7636 Expression *Parser::parseCondExp()
7641 Loc loc = token.loc;
7644 if (token.value == TOKquestion)
7647 e1 = parseExpression();
7649 e2 = parseCondExp();
7650 e = new CondExp(loc, e, e1, e2);
7655 Expression *Parser::parseAssignExp()
7665 switch (token.value)
7667 case TOKassign: nextToken(); e2 = parseAssignExp(); e = new AssignExp(loc,e,e2); continue;
7668 case TOKaddass: nextToken(); e2 = parseAssignExp(); e = new AddAssignExp(loc,e,e2); continue;
7669 case TOKminass: nextToken(); e2 = parseAssignExp(); e = new MinAssignExp(loc,e,e2); continue;
7670 case TOKmulass: nextToken(); e2 = parseAssignExp(); e = new MulAssignExp(loc,e,e2); continue;
7671 case TOKdivass: nextToken(); e2 = parseAssignExp(); e = new DivAssignExp(loc,e,e2); continue;
7672 case TOKmodass: nextToken(); e2 = parseAssignExp(); e = new ModAssignExp(loc,e,e2); continue;
7673 case TOKpowass: nextToken(); e2 = parseAssignExp(); e = new PowAssignExp(loc,e,e2); continue;
7674 case TOKandass: nextToken(); e2 = parseAssignExp(); e = new AndAssignExp(loc,e,e2); continue;
7675 case TOKorass: nextToken(); e2 = parseAssignExp(); e = new OrAssignExp(loc,e,e2); continue;
7676 case TOKxorass: nextToken(); e2 = parseAssignExp(); e = new XorAssignExp(loc,e,e2); continue;
7677 case TOKshlass: nextToken(); e2 = parseAssignExp(); e = new ShlAssignExp(loc,e,e2); continue;
7678 case TOKshrass: nextToken(); e2 = parseAssignExp(); e = new ShrAssignExp(loc,e,e2); continue;
7679 case TOKushrass: nextToken(); e2 = parseAssignExp(); e = new UshrAssignExp(loc,e,e2); continue;
7680 case TOKcatass: nextToken(); e2 = parseAssignExp(); e = new CatAssignExp(loc,e,e2); continue;
7689 Expression *Parser::parseExpression()
7693 Loc loc = token.loc;
7695 //printf("Parser::parseExpression() loc = %d\n", loc.linnum);
7696 e = parseAssignExp();
7697 while (token.value == TOKcomma)
7700 e2 = parseAssignExp();
7701 e = new CommaExp(loc, e, e2, false);
7708 /*************************
7709 * Collect argument list.
7710 * Assume current token is ',', '(' or '['.
7713 Expressions *Parser::parseArguments()
7715 Expressions *arguments;
7719 arguments = new Expressions();
7720 if (token.value == TOKlbracket)
7721 endtok = TOKrbracket;
7727 while (token.value != endtok && token.value != TOKeof)
7729 arg = parseAssignExp();
7730 arguments->push(arg);
7731 if (token.value == endtok)
7740 /*******************************************
7743 Expression *Parser::parseNewExp(Expression *thisexp)
7746 Expressions *newargs;
7747 Expressions *arguments = NULL;
7748 Loc loc = token.loc;
7752 if (token.value == TOKlparen)
7754 newargs = parseArguments();
7757 // An anonymous nested class starts with "class"
7758 if (token.value == TOKclass)
7761 if (token.value == TOKlparen)
7762 arguments = parseArguments();
7764 BaseClasses *baseclasses = NULL;
7765 if (token.value != TOKlcurly)
7766 baseclasses = parseBaseClasses();
7768 Identifier *id = NULL;
7769 Dsymbols *members = NULL;
7771 if (token.value != TOKlcurly)
7773 error("{ members } expected for anonymous class");
7778 members = parseDeclDefs(0);
7779 if (token.value != TOKrcurly)
7780 error("class member expected");
7784 ClassDeclaration *cd = new ClassDeclaration(loc, id, baseclasses, members, false);
7785 Expression *e = new NewAnonClassExp(loc, thisexp, newargs, cd, arguments);
7790 StorageClass stc = parseTypeCtor();
7791 t = parseBasicType(true);
7792 t = parseBasicType2(t);
7794 if (t->ty == Taarray)
7796 TypeAArray *taa = (TypeAArray *)t;
7797 Type *index = taa->index;
7799 Expression *edim = typeToExpression(index);
7802 error("need size of rightmost array, not type %s", index->toChars());
7803 return new NullExp(loc);
7805 t = new TypeSArray(taa->next, edim);
7807 else if (t->ty == Tsarray)
7810 else if (token.value == TOKlparen)
7812 arguments = parseArguments();
7814 Expression *e = new NewExp(loc, thisexp, newargs, t, arguments);
7818 /**********************************************
7821 void Parser::addComment(Dsymbol *s, const utf8_t *blockComment)
7823 s->addComment(combineComments(blockComment, token.lineComment));
7824 token.lineComment = NULL;
7828 /**********************************
7829 * Set operator precedence for each operator.
7832 PREC precedence[TOKMAX];
7834 struct PrecedenceInitializer
7836 PrecedenceInitializer();
7839 static PrecedenceInitializer precedenceinitializer;
7841 PrecedenceInitializer::PrecedenceInitializer()
7843 for (size_t i = 0; i < TOKMAX; i++)
7844 precedence[i] = PREC_zero;
7846 precedence[TOKtype] = PREC_expr;
7847 precedence[TOKerror] = PREC_expr;
7849 precedence[TOKtypeof] = PREC_primary;
7850 precedence[TOKmixin] = PREC_primary;
7851 precedence[TOKimport] = PREC_primary;
7853 precedence[TOKdotvar] = PREC_primary;
7854 precedence[TOKscope] = PREC_primary;
7855 precedence[TOKidentifier] = PREC_primary;
7856 precedence[TOKthis] = PREC_primary;
7857 precedence[TOKsuper] = PREC_primary;
7858 precedence[TOKint64] = PREC_primary;
7859 precedence[TOKfloat64] = PREC_primary;
7860 precedence[TOKcomplex80] = PREC_primary;
7861 precedence[TOKnull] = PREC_primary;
7862 precedence[TOKstring] = PREC_primary;
7863 precedence[TOKarrayliteral] = PREC_primary;
7864 precedence[TOKassocarrayliteral] = PREC_primary;
7865 precedence[TOKclassreference] = PREC_primary;
7866 precedence[TOKfile] = PREC_primary;
7867 precedence[TOKfilefullpath] = PREC_primary;
7868 precedence[TOKline] = PREC_primary;
7869 precedence[TOKmodulestring] = PREC_primary;
7870 precedence[TOKfuncstring] = PREC_primary;
7871 precedence[TOKprettyfunc] = PREC_primary;
7872 precedence[TOKtypeid] = PREC_primary;
7873 precedence[TOKis] = PREC_primary;
7874 precedence[TOKassert] = PREC_primary;
7875 precedence[TOKhalt] = PREC_primary;
7876 precedence[TOKtemplate] = PREC_primary;
7877 precedence[TOKdsymbol] = PREC_primary;
7878 precedence[TOKfunction] = PREC_primary;
7879 precedence[TOKvar] = PREC_primary;
7880 precedence[TOKsymoff] = PREC_primary;
7881 precedence[TOKstructliteral] = PREC_primary;
7882 precedence[TOKarraylength] = PREC_primary;
7883 precedence[TOKdelegateptr] = PREC_primary;
7884 precedence[TOKdelegatefuncptr] = PREC_primary;
7885 precedence[TOKremove] = PREC_primary;
7886 precedence[TOKtuple] = PREC_primary;
7887 precedence[TOKtraits] = PREC_primary;
7888 precedence[TOKdefault] = PREC_primary;
7889 precedence[TOKoverloadset] = PREC_primary;
7890 precedence[TOKvoid] = PREC_primary;
7893 precedence[TOKdotti] = PREC_primary;
7894 precedence[TOKdotid] = PREC_primary;
7895 precedence[TOKdottd] = PREC_primary;
7896 precedence[TOKdot] = PREC_primary;
7897 precedence[TOKdottype] = PREC_primary;
7898 // precedence[TOKarrow] = PREC_primary;
7899 precedence[TOKplusplus] = PREC_primary;
7900 precedence[TOKminusminus] = PREC_primary;
7901 precedence[TOKpreplusplus] = PREC_primary;
7902 precedence[TOKpreminusminus] = PREC_primary;
7903 precedence[TOKcall] = PREC_primary;
7904 precedence[TOKslice] = PREC_primary;
7905 precedence[TOKarray] = PREC_primary;
7906 precedence[TOKindex] = PREC_primary;
7908 precedence[TOKdelegate] = PREC_unary;
7909 precedence[TOKaddress] = PREC_unary;
7910 precedence[TOKstar] = PREC_unary;
7911 precedence[TOKneg] = PREC_unary;
7912 precedence[TOKuadd] = PREC_unary;
7913 precedence[TOKnot] = PREC_unary;
7914 precedence[TOKtilde] = PREC_unary;
7915 precedence[TOKdelete] = PREC_unary;
7916 precedence[TOKnew] = PREC_unary;
7917 precedence[TOKnewanonclass] = PREC_unary;
7918 precedence[TOKcast] = PREC_unary;
7920 precedence[TOKvector] = PREC_unary;
7921 precedence[TOKpow] = PREC_pow;
7923 precedence[TOKmul] = PREC_mul;
7924 precedence[TOKdiv] = PREC_mul;
7925 precedence[TOKmod] = PREC_mul;
7927 precedence[TOKadd] = PREC_add;
7928 precedence[TOKmin] = PREC_add;
7929 precedence[TOKcat] = PREC_add;
7931 precedence[TOKshl] = PREC_shift;
7932 precedence[TOKshr] = PREC_shift;
7933 precedence[TOKushr] = PREC_shift;
7935 precedence[TOKlt] = PREC_rel;
7936 precedence[TOKle] = PREC_rel;
7937 precedence[TOKgt] = PREC_rel;
7938 precedence[TOKge] = PREC_rel;
7939 precedence[TOKunord] = PREC_rel;
7940 precedence[TOKlg] = PREC_rel;
7941 precedence[TOKleg] = PREC_rel;
7942 precedence[TOKule] = PREC_rel;
7943 precedence[TOKul] = PREC_rel;
7944 precedence[TOKuge] = PREC_rel;
7945 precedence[TOKug] = PREC_rel;
7946 precedence[TOKue] = PREC_rel;
7947 precedence[TOKin] = PREC_rel;
7949 /* Note that we changed precedence, so that < and != have the same
7950 * precedence. This change is in the parser, too.
7952 precedence[TOKequal] = PREC_rel;
7953 precedence[TOKnotequal] = PREC_rel;
7954 precedence[TOKidentity] = PREC_rel;
7955 precedence[TOKnotidentity] = PREC_rel;
7957 precedence[TOKand] = PREC_and;
7959 precedence[TOKxor] = PREC_xor;
7961 precedence[TOKor] = PREC_or;
7963 precedence[TOKandand] = PREC_andand;
7965 precedence[TOKoror] = PREC_oror;
7967 precedence[TOKquestion] = PREC_cond;
7969 precedence[TOKassign] = PREC_assign;
7970 precedence[TOKconstruct] = PREC_assign;
7971 precedence[TOKblit] = PREC_assign;
7972 precedence[TOKaddass] = PREC_assign;
7973 precedence[TOKminass] = PREC_assign;
7974 precedence[TOKcatass] = PREC_assign;
7975 precedence[TOKmulass] = PREC_assign;
7976 precedence[TOKdivass] = PREC_assign;
7977 precedence[TOKmodass] = PREC_assign;
7978 precedence[TOKpowass] = PREC_assign;
7979 precedence[TOKshlass] = PREC_assign;
7980 precedence[TOKshrass] = PREC_assign;
7981 precedence[TOKushrass] = PREC_assign;
7982 precedence[TOKandass] = PREC_assign;
7983 precedence[TOKorass] = PREC_assign;
7984 precedence[TOKxorass] = PREC_assign;
7986 precedence[TOKcomma] = PREC_expr;
7987 precedence[TOKdeclaration] = PREC_expr;
7989 precedence[TOKinterval] = PREC_assign;