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