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