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