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