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