1 /** 2 * Defines AST nodes for statements. 3 * 4 * Specification: $(LINK2 https://dlang.org/spec/statement.html, Statements) 5 * 6 * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved 7 * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) 8 * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) 9 * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/statement.d, _statement.d) 10 * Documentation: https://dlang.org/phobos/dmd_statement.html 11 * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/statement.d 12 */ 13 14 module dmd.statement; 15 16 import core.stdc.stdarg; 17 import core.stdc.stdio; 18 19 import dmd.arraytypes; 20 import dmd.astenums; 21 import dmd.ast_node; 22 import dmd.errors; 23 import dmd.gluelayer; 24 import dmd.cond; 25 import dmd.declaration; 26 import dmd.dsymbol; 27 import dmd.expression; 28 import dmd.func; 29 import dmd.globals; 30 import dmd.hdrgen; 31 import dmd.id; 32 import dmd.identifier; 33 import dmd.location; 34 import dmd.mtype; 35 import dmd.common.outbuffer; 36 import dmd.rootobject; 37 import dmd.sapply; 38 import dmd.staticassert; 39 import dmd.tokens; 40 import dmd.visitor; 41 42 /*********************************************************** 43 * Specification: https://dlang.org/spec/statement.html 44 */ 45 extern (C++) abstract class Statement : ASTNode 46 { 47 const Loc loc; 48 const STMT stmt; 49 50 override final DYNCAST dyncast() const 51 { 52 return DYNCAST.statement; 53 } 54 55 final extern (D) this(const ref Loc loc, STMT stmt) @safe 56 { 57 this.loc = loc; 58 this.stmt = stmt; 59 // If this is an in{} contract scope statement (skip for determining 60 // inlineStatus of a function body for header content) 61 } 62 63 Statement syntaxCopy() 64 { 65 assert(0); 66 } 67 68 /************************************* 69 * Do syntax copy of an array of Statement's. 70 */ 71 static Statements* arraySyntaxCopy(Statements* a) 72 { 73 Statements* b = null; 74 if (a) 75 { 76 b = a.copy(); 77 foreach (i, s; *a) 78 { 79 (*b)[i] = s ? s.syntaxCopy() : null; 80 } 81 } 82 return b; 83 } 84 85 Statement getRelatedLabeled() 86 { 87 return this; 88 } 89 90 /**************************** 91 * Determine if an enclosed `break` would apply to this 92 * statement, such as if it is a loop or switch statement. 93 * Returns: 94 * `true` if it does 95 */ 96 bool hasBreak() const pure nothrow 97 { 98 //printf("Statement::hasBreak()\n"); 99 return false; 100 } 101 102 /**************************** 103 * Determine if an enclosed `continue` would apply to this 104 * statement, such as if it is a loop statement. 105 * Returns: 106 * `true` if it does 107 */ 108 bool hasContinue() const pure nothrow 109 { 110 return false; 111 } 112 113 /********************************** 114 * Returns: 115 * `true` if statement uses exception handling 116 */ 117 extern (D) final bool usesEH() 118 { 119 extern (C++) final class UsesEH : StoppableVisitor 120 { 121 alias visit = typeof(super).visit; 122 public: 123 override void visit(Statement s) 124 { 125 } 126 127 override void visit(TryCatchStatement s) 128 { 129 stop = true; 130 } 131 132 override void visit(TryFinallyStatement s) 133 { 134 stop = true; 135 } 136 137 override void visit(ScopeGuardStatement s) 138 { 139 stop = true; 140 } 141 142 override void visit(SynchronizedStatement s) 143 { 144 stop = true; 145 } 146 } 147 148 scope UsesEH ueh = new UsesEH(); 149 return walkPostorder(this, ueh); 150 } 151 152 /********************************** 153 * Returns: 154 * `true` if statement 'comes from' somewhere else, like a goto 155 */ 156 extern (D) final bool comeFrom() 157 { 158 extern (C++) final class ComeFrom : StoppableVisitor 159 { 160 alias visit = typeof(super).visit; 161 public: 162 override void visit(Statement s) 163 { 164 } 165 166 override void visit(CaseStatement s) 167 { 168 stop = true; 169 } 170 171 override void visit(DefaultStatement s) 172 { 173 stop = true; 174 } 175 176 override void visit(LabelStatement s) 177 { 178 stop = true; 179 } 180 181 override void visit(AsmStatement s) 182 { 183 stop = true; 184 } 185 } 186 187 scope ComeFrom cf = new ComeFrom(); 188 return walkPostorder(this, cf); 189 } 190 191 /********************************** 192 * Returns: 193 * `true` if statement has executable code. 194 */ 195 extern (D) final bool hasCode() 196 { 197 extern (C++) final class HasCode : StoppableVisitor 198 { 199 alias visit = typeof(super).visit; 200 public: 201 override void visit(Statement s) 202 { 203 stop = true; 204 } 205 206 override void visit(ExpStatement s) 207 { 208 if (s.exp !is null) 209 { 210 stop = s.exp.hasCode(); 211 } 212 } 213 214 override void visit(CompoundStatement s) 215 { 216 } 217 218 override void visit(ScopeStatement s) 219 { 220 } 221 222 override void visit(ImportStatement s) 223 { 224 } 225 226 override void visit(CaseStatement s) 227 { 228 } 229 230 override void visit(DefaultStatement s) 231 { 232 } 233 234 override void visit(LabelStatement s) 235 { 236 } 237 } 238 239 scope HasCode hc = new HasCode(); 240 return walkPostorder(this, hc); 241 } 242 243 /******************************* 244 * Find last statement in a sequence of statements. 245 * Returns: 246 * the last statement, or `null` if there isn't one 247 */ 248 inout(Statement) last() inout nothrow pure 249 { 250 return this; 251 } 252 253 /************************** 254 * Support Visitor Pattern 255 * Params: 256 * v = visitor 257 */ 258 override void accept(Visitor v) 259 { 260 v.visit(this); 261 } 262 263 /************************************ 264 * Does this statement end with a return statement? 265 * 266 * I.e. is it a single return statement or some compound statement 267 * that unconditionally hits a return statement. 268 * Returns: 269 * return statement it ends with, otherwise null 270 */ 271 pure nothrow @nogc 272 inout(ReturnStatement) endsWithReturnStatement() inout { return null; } 273 274 final pure inout nothrow @nogc @safe: 275 276 /******************** 277 * A cheaper method of doing downcasting of Statements. 278 * Returns: 279 * the downcast statement if it can be downcasted, otherwise `null` 280 */ 281 inout(ErrorStatement) isErrorStatement() { return stmt == STMT.Error ? cast(typeof(return))this : null; } 282 inout(PeelStatement) isPeelStatement() { return stmt == STMT.Peel ? cast(typeof(return))this : null; } 283 inout(ScopeStatement) isScopeStatement() { return stmt == STMT.Scope ? cast(typeof(return))this : null; } 284 inout(ExpStatement) isExpStatement() { return stmt == STMT.Exp ? cast(typeof(return))this : null; } 285 inout(CompoundStatement) isCompoundStatement() { return stmt == STMT.Compound ? cast(typeof(return))this : null; } 286 inout(ReturnStatement) isReturnStatement() { return stmt == STMT.Return ? cast(typeof(return))this : null; } 287 inout(IfStatement) isIfStatement() { return stmt == STMT.If ? cast(typeof(return))this : null; } 288 inout(ConditionalStatement) isConditionalStatement() { return stmt == STMT.Conditional ? cast(typeof(return))this : null; } 289 inout(StaticForeachStatement) isStaticForeachStatement() { return stmt == STMT.StaticForeach ? cast(typeof(return))this : null; } 290 inout(CaseStatement) isCaseStatement() { return stmt == STMT.Case ? cast(typeof(return))this : null; } 291 inout(DefaultStatement) isDefaultStatement() { return stmt == STMT.Default ? cast(typeof(return))this : null; } 292 inout(LabelStatement) isLabelStatement() { return stmt == STMT.Label ? cast(typeof(return))this : null; } 293 inout(GotoStatement) isGotoStatement() { return stmt == STMT.Goto ? cast(typeof(return))this : null; } 294 inout(GotoDefaultStatement) isGotoDefaultStatement() { return stmt == STMT.GotoDefault ? cast(typeof(return))this : null; } 295 inout(GotoCaseStatement) isGotoCaseStatement() { return stmt == STMT.GotoCase ? cast(typeof(return))this : null; } 296 inout(BreakStatement) isBreakStatement() { return stmt == STMT.Break ? cast(typeof(return))this : null; } 297 inout(DtorExpStatement) isDtorExpStatement() { return stmt == STMT.DtorExp ? cast(typeof(return))this : null; } 298 inout(MixinStatement) isMixinStatement() { return stmt == STMT.Mixin ? cast(typeof(return))this : null; } 299 inout(ForwardingStatement) isForwardingStatement() { return stmt == STMT.Forwarding ? cast(typeof(return))this : null; } 300 inout(DoStatement) isDoStatement() { return stmt == STMT.Do ? cast(typeof(return))this : null; } 301 inout(WhileStatement) isWhileStatement() { return stmt == STMT.While ? cast(typeof(return))this : null; } 302 inout(ForStatement) isForStatement() { return stmt == STMT.For ? cast(typeof(return))this : null; } 303 inout(ForeachStatement) isForeachStatement() { return stmt == STMT.Foreach ? cast(typeof(return))this : null; } 304 inout(SwitchStatement) isSwitchStatement() { return stmt == STMT.Switch ? cast(typeof(return))this : null; } 305 inout(ContinueStatement) isContinueStatement() { return stmt == STMT.Continue ? cast(typeof(return))this : null; } 306 inout(WithStatement) isWithStatement() { return stmt == STMT.With ? cast(typeof(return))this : null; } 307 inout(TryCatchStatement) isTryCatchStatement() { return stmt == STMT.TryCatch ? cast(typeof(return))this : null; } 308 inout(ThrowStatement) isThrowStatement() { return stmt == STMT.Throw ? cast(typeof(return))this : null; } 309 inout(DebugStatement) isDebugStatement() { return stmt == STMT.Debug ? cast(typeof(return))this : null; } 310 inout(TryFinallyStatement) isTryFinallyStatement() { return stmt == STMT.TryFinally ? cast(typeof(return))this : null; } 311 inout(ScopeGuardStatement) isScopeGuardStatement() { return stmt == STMT.ScopeGuard ? cast(typeof(return))this : null; } 312 inout(SwitchErrorStatement) isSwitchErrorStatement() { return stmt == STMT.SwitchError ? cast(typeof(return))this : null; } 313 inout(UnrolledLoopStatement) isUnrolledLoopStatement() { return stmt == STMT.UnrolledLoop ? cast(typeof(return))this : null; } 314 inout(ForeachRangeStatement) isForeachRangeStatement() { return stmt == STMT.ForeachRange ? cast(typeof(return))this : null; } 315 inout(CompoundDeclarationStatement) isCompoundDeclarationStatement() { return stmt == STMT.CompoundDeclaration ? cast(typeof(return))this : null; } 316 inout(CompoundAsmStatement) isCompoundAsmStatement() { return stmt == STMT.CompoundAsm ? cast(typeof(return))this : null; } 317 inout(PragmaStatement) isPragmaStatement() { return stmt == STMT.Pragma ? cast(typeof(return))this : null; } 318 inout(StaticAssertStatement) isStaticAssertStatement() { return stmt == STMT.StaticAssert ? cast(typeof(return))this : null; } 319 inout(CaseRangeStatement) isCaseRangeStatement() { return stmt == STMT.CaseRange ? cast(typeof(return))this : null; } 320 inout(SynchronizedStatement) isSynchronizedStatement() { return stmt == STMT.Synchronized ? cast(typeof(return))this : null; } 321 inout(AsmStatement) isAsmStatement() { return stmt == STMT.Asm ? cast(typeof(return))this : null; } 322 inout(InlineAsmStatement) isInlineAsmStatement() { return stmt == STMT.InlineAsm ? cast(typeof(return))this : null; } 323 inout(GccAsmStatement) isGccAsmStatement() { return stmt == STMT.GccAsm ? cast(typeof(return))this : null; } 324 inout(ImportStatement) isImportStatement() { return stmt == STMT.Import ? cast(typeof(return))this : null; } 325 } 326 327 /*********************************************************** 328 * Any Statement that fails semantic() or has a component that is an ErrorExp or 329 * a TypeError should return an ErrorStatement from semantic(). 330 */ 331 extern (C++) final class ErrorStatement : Statement 332 { 333 extern (D) this() 334 { 335 super(Loc.initial, STMT.Error); 336 assert(global.gaggedErrors || global.errors); 337 } 338 339 override ErrorStatement syntaxCopy() 340 { 341 return this; 342 } 343 344 override void accept(Visitor v) 345 { 346 v.visit(this); 347 } 348 } 349 350 /*********************************************************** 351 */ 352 extern (C++) final class PeelStatement : Statement 353 { 354 Statement s; 355 356 extern (D) this(Statement s) @safe 357 { 358 super(s.loc, STMT.Peel); 359 this.s = s; 360 } 361 362 override void accept(Visitor v) 363 { 364 v.visit(this); 365 } 366 } 367 368 369 /*********************************************************** 370 * https://dlang.org/spec/statement.html#ExpressionStatement 371 */ 372 extern (C++) class ExpStatement : Statement 373 { 374 Expression exp; 375 376 final extern (D) this(const ref Loc loc, Expression exp) @safe 377 { 378 super(loc, STMT.Exp); 379 this.exp = exp; 380 } 381 382 final extern (D) this(const ref Loc loc, Expression exp, STMT stmt) @safe 383 { 384 super(loc, stmt); 385 this.exp = exp; 386 } 387 388 final extern (D) this(const ref Loc loc, Dsymbol declaration) @safe 389 { 390 super(loc, STMT.Exp); 391 this.exp = new DeclarationExp(loc, declaration); 392 } 393 394 static ExpStatement create(const ref Loc loc, Expression exp) @safe 395 { 396 return new ExpStatement(loc, exp); 397 } 398 399 override ExpStatement syntaxCopy() 400 { 401 return new ExpStatement(loc, exp ? exp.syntaxCopy() : null); 402 } 403 404 override void accept(Visitor v) 405 { 406 v.visit(this); 407 } 408 } 409 410 /*********************************************************** 411 */ 412 extern (C++) final class DtorExpStatement : ExpStatement 413 { 414 // Wraps an expression that is the destruction of 'var' 415 VarDeclaration var; 416 417 extern (D) this(const ref Loc loc, Expression exp, VarDeclaration var) @safe 418 { 419 super(loc, exp, STMT.DtorExp); 420 this.var = var; 421 } 422 423 override DtorExpStatement syntaxCopy() 424 { 425 return new DtorExpStatement(loc, exp ? exp.syntaxCopy() : null, var); 426 } 427 428 override void accept(Visitor v) 429 { 430 v.visit(this); 431 } 432 } 433 434 /*********************************************************** 435 * https://dlang.org/spec/statement.html#mixin-statement 436 */ 437 // Note: was called CompileStatement 438 extern (C++) final class MixinStatement : Statement 439 { 440 Expressions* exps; 441 442 extern (D) this(const ref Loc loc, Expression exp) 443 { 444 Expressions* exps = new Expressions(); 445 exps.push(exp); 446 this(loc, exps); 447 } 448 449 extern (D) this(const ref Loc loc, Expressions* exps) @safe 450 { 451 super(loc, STMT.Mixin); 452 this.exps = exps; 453 } 454 455 override MixinStatement syntaxCopy() 456 { 457 return new MixinStatement(loc, Expression.arraySyntaxCopy(exps)); 458 } 459 460 override void accept(Visitor v) 461 { 462 v.visit(this); 463 } 464 } 465 466 /*********************************************************** 467 */ 468 extern (C++) class CompoundStatement : Statement 469 { 470 Statements* statements; 471 472 /** 473 * Construct a `CompoundStatement` using an already existing 474 * array of `Statement`s 475 * 476 * Params: 477 * loc = Instantiation information 478 * statements = An array of `Statement`s, that will referenced by this class 479 */ 480 final extern (D) this(const ref Loc loc, Statements* statements) @safe 481 { 482 super(loc, STMT.Compound); 483 this.statements = statements; 484 } 485 486 final extern (D) this(const ref Loc loc, Statements* statements, STMT stmt) @safe 487 { 488 super(loc, stmt); 489 this.statements = statements; 490 } 491 492 /** 493 * Construct a `CompoundStatement` from an array of `Statement`s 494 * 495 * Params: 496 * loc = Instantiation information 497 * sts = A variadic array of `Statement`s, that will copied in this class 498 * The entries themselves will not be copied. 499 */ 500 final extern (D) this(const ref Loc loc, Statement[] sts...) 501 { 502 super(loc, STMT.Compound); 503 statements = new Statements(); 504 statements.reserve(sts.length); 505 foreach (s; sts) 506 statements.push(s); 507 } 508 509 static CompoundStatement create(const ref Loc loc, Statement s1, Statement s2) 510 { 511 return new CompoundStatement(loc, s1, s2); 512 } 513 514 override CompoundStatement syntaxCopy() 515 { 516 return new CompoundStatement(loc, Statement.arraySyntaxCopy(statements)); 517 } 518 519 override final inout(ReturnStatement) endsWithReturnStatement() inout nothrow pure 520 { 521 foreach (s; *statements) 522 { 523 if (s) 524 { 525 if (inout rs = s.endsWithReturnStatement()) 526 return rs; 527 } 528 } 529 return null; 530 } 531 532 override final inout(Statement) last() inout nothrow pure 533 { 534 Statement s = null; 535 for (size_t i = statements.length; i; --i) 536 { 537 s = cast(Statement)(*statements)[i - 1]; 538 if (s) 539 { 540 s = cast(Statement)s.last(); 541 if (s) 542 break; 543 } 544 } 545 return cast(inout)s; 546 } 547 548 override void accept(Visitor v) 549 { 550 v.visit(this); 551 } 552 } 553 554 /*********************************************************** 555 */ 556 extern (C++) final class CompoundDeclarationStatement : CompoundStatement 557 { 558 extern (D) this(const ref Loc loc, Statements* statements) @safe 559 { 560 super(loc, statements, STMT.CompoundDeclaration); 561 } 562 563 override CompoundDeclarationStatement syntaxCopy() 564 { 565 return new CompoundDeclarationStatement(loc, Statement.arraySyntaxCopy(statements)); 566 } 567 568 override void accept(Visitor v) 569 { 570 v.visit(this); 571 } 572 } 573 574 /*********************************************************** 575 * The purpose of this is so that continue will go to the next 576 * of the statements, and break will go to the end of the statements. 577 */ 578 extern (C++) final class UnrolledLoopStatement : Statement 579 { 580 Statements* statements; 581 582 extern (D) this(const ref Loc loc, Statements* statements) @safe 583 { 584 super(loc, STMT.UnrolledLoop); 585 this.statements = statements; 586 } 587 588 override UnrolledLoopStatement syntaxCopy() 589 { 590 return new UnrolledLoopStatement(loc, Statement.arraySyntaxCopy(statements)); 591 } 592 593 override bool hasBreak() const pure nothrow 594 { 595 return true; 596 } 597 598 override bool hasContinue() const pure nothrow 599 { 600 return true; 601 } 602 603 override void accept(Visitor v) 604 { 605 v.visit(this); 606 } 607 } 608 609 /*********************************************************** 610 */ 611 extern (C++) final class ScopeStatement : Statement 612 { 613 Statement statement; 614 Loc endloc; // location of closing curly bracket 615 616 extern (D) this(const ref Loc loc, Statement statement, Loc endloc) @safe 617 { 618 super(loc, STMT.Scope); 619 this.statement = statement; 620 this.endloc = endloc; 621 } 622 623 override ScopeStatement syntaxCopy() 624 { 625 return new ScopeStatement(loc, statement ? statement.syntaxCopy() : null, endloc); 626 } 627 628 override inout(ReturnStatement) endsWithReturnStatement() inout nothrow pure 629 { 630 if (statement) 631 return statement.endsWithReturnStatement(); 632 return null; 633 } 634 635 override bool hasBreak() const pure nothrow 636 { 637 //printf("ScopeStatement::hasBreak() %s\n", toChars()); 638 return statement ? statement.hasBreak() : false; 639 } 640 641 override bool hasContinue() const pure nothrow 642 { 643 return statement ? statement.hasContinue() : false; 644 } 645 646 override void accept(Visitor v) 647 { 648 v.visit(this); 649 } 650 } 651 652 /*********************************************************** 653 * Statement whose symbol table contains foreach index variables in a 654 * local scope and forwards other members to the parent scope. This 655 * wraps a statement. 656 * 657 * Also see: `dmd.attrib.ForwardingAttribDeclaration` 658 */ 659 extern (C++) final class ForwardingStatement : Statement 660 { 661 /// The symbol containing the `static foreach` variables. 662 ForwardingScopeDsymbol sym = null; 663 /// The wrapped statement. 664 Statement statement; 665 666 extern (D) this(const ref Loc loc, ForwardingScopeDsymbol sym, Statement statement) @safe 667 { 668 super(loc, STMT.Forwarding); 669 this.sym = sym; 670 assert(statement); 671 this.statement = statement; 672 } 673 674 extern (D) this(const ref Loc loc, Statement statement) @safe 675 { 676 auto sym = new ForwardingScopeDsymbol(); 677 sym.symtab = new DsymbolTable(); 678 this(loc, sym, statement); 679 } 680 681 override ForwardingStatement syntaxCopy() 682 { 683 return new ForwardingStatement(loc, statement.syntaxCopy()); 684 } 685 686 override void accept(Visitor v) 687 { 688 v.visit(this); 689 } 690 } 691 692 693 /*********************************************************** 694 * https://dlang.org/spec/statement.html#while-statement 695 */ 696 extern (C++) final class WhileStatement : Statement 697 { 698 Parameter param; 699 Expression condition; 700 Statement _body; 701 Loc endloc; // location of closing curly bracket 702 703 extern (D) this(const ref Loc loc, Expression condition, Statement _body, Loc endloc, Parameter param = null) @safe 704 { 705 super(loc, STMT.While); 706 this.condition = condition; 707 this._body = _body; 708 this.endloc = endloc; 709 this.param = param; 710 } 711 712 override WhileStatement syntaxCopy() 713 { 714 return new WhileStatement(loc, 715 condition.syntaxCopy(), 716 _body ? _body.syntaxCopy() : null, 717 endloc, param ? param.syntaxCopy() : null); 718 } 719 720 override bool hasBreak() const pure nothrow 721 { 722 return true; 723 } 724 725 override bool hasContinue() const pure nothrow 726 { 727 return true; 728 } 729 730 override void accept(Visitor v) 731 { 732 v.visit(this); 733 } 734 } 735 736 /*********************************************************** 737 * https://dlang.org/spec/statement.html#do-statement 738 */ 739 extern (C++) final class DoStatement : Statement 740 { 741 Statement _body; 742 Expression condition; 743 Loc endloc; // location of ';' after while 744 745 extern (D) this(const ref Loc loc, Statement _body, Expression condition, Loc endloc) @safe 746 { 747 super(loc, STMT.Do); 748 this._body = _body; 749 this.condition = condition; 750 this.endloc = endloc; 751 } 752 753 override DoStatement syntaxCopy() 754 { 755 return new DoStatement(loc, 756 _body ? _body.syntaxCopy() : null, 757 condition.syntaxCopy(), 758 endloc); 759 } 760 761 override bool hasBreak() const pure nothrow 762 { 763 return true; 764 } 765 766 override bool hasContinue() const pure nothrow 767 { 768 return true; 769 } 770 771 override void accept(Visitor v) 772 { 773 v.visit(this); 774 } 775 } 776 777 /*********************************************************** 778 * https://dlang.org/spec/statement.html#for-statement 779 */ 780 extern (C++) final class ForStatement : Statement 781 { 782 Statement _init; 783 Expression condition; 784 Expression increment; 785 Statement _body; 786 Loc endloc; // location of closing curly bracket 787 788 // When wrapped in try/finally clauses, this points to the outermost one, 789 // which may have an associated label. Internal break/continue statements 790 // treat that label as referring to this loop. 791 Statement relatedLabeled; 792 793 extern (D) this(const ref Loc loc, Statement _init, Expression condition, Expression increment, Statement _body, Loc endloc) @safe 794 { 795 super(loc, STMT.For); 796 this._init = _init; 797 this.condition = condition; 798 this.increment = increment; 799 this._body = _body; 800 this.endloc = endloc; 801 } 802 803 override ForStatement syntaxCopy() 804 { 805 return new ForStatement(loc, 806 _init ? _init.syntaxCopy() : null, 807 condition ? condition.syntaxCopy() : null, 808 increment ? increment.syntaxCopy() : null, 809 _body.syntaxCopy(), 810 endloc); 811 } 812 813 override Statement getRelatedLabeled() 814 { 815 return relatedLabeled ? relatedLabeled : this; 816 } 817 818 override bool hasBreak() const pure nothrow 819 { 820 //printf("ForStatement::hasBreak()\n"); 821 return true; 822 } 823 824 override bool hasContinue() const pure nothrow 825 { 826 return true; 827 } 828 829 override void accept(Visitor v) 830 { 831 v.visit(this); 832 } 833 } 834 835 /*********************************************************** 836 * https://dlang.org/spec/statement.html#foreach-statement 837 */ 838 extern (C++) final class ForeachStatement : Statement 839 { 840 TOK op; // TOK.foreach_ or TOK.foreach_reverse_ 841 Parameters* parameters; // array of Parameters, one for each ForeachType 842 Expression aggr; // ForeachAggregate 843 Statement _body; // NoScopeNonEmptyStatement 844 Loc endloc; // location of closing curly bracket 845 846 VarDeclaration key; 847 VarDeclaration value; 848 849 FuncDeclaration func; // function we're lexically in 850 851 Statements* cases; // put breaks, continues, gotos and returns here 852 ScopeStatements* gotos; // forward referenced goto's go here 853 854 extern (D) this(const ref Loc loc, TOK op, Parameters* parameters, Expression aggr, Statement _body, Loc endloc) @safe 855 { 856 super(loc, STMT.Foreach); 857 this.op = op; 858 this.parameters = parameters; 859 this.aggr = aggr; 860 this._body = _body; 861 this.endloc = endloc; 862 } 863 864 override ForeachStatement syntaxCopy() 865 { 866 return new ForeachStatement(loc, op, 867 Parameter.arraySyntaxCopy(parameters), 868 aggr.syntaxCopy(), 869 _body ? _body.syntaxCopy() : null, 870 endloc); 871 } 872 873 override bool hasBreak() const pure nothrow 874 { 875 return true; 876 } 877 878 override bool hasContinue() const pure nothrow 879 { 880 return true; 881 } 882 883 override void accept(Visitor v) 884 { 885 v.visit(this); 886 } 887 } 888 889 /*********************************************************** 890 * https://dlang.org/spec/statement.html#foreach-range-statement 891 */ 892 extern (C++) final class ForeachRangeStatement : Statement 893 { 894 TOK op; // TOK.foreach_ or TOK.foreach_reverse_ 895 Parameter prm; // loop index variable 896 Expression lwr; 897 Expression upr; 898 Statement _body; 899 Loc endloc; // location of closing curly bracket 900 901 VarDeclaration key; 902 903 extern (D) this(const ref Loc loc, TOK op, Parameter prm, Expression lwr, Expression upr, Statement _body, Loc endloc) @safe 904 { 905 super(loc, STMT.ForeachRange); 906 this.op = op; 907 this.prm = prm; 908 this.lwr = lwr; 909 this.upr = upr; 910 this._body = _body; 911 this.endloc = endloc; 912 } 913 914 override ForeachRangeStatement syntaxCopy() 915 { 916 return new ForeachRangeStatement(loc, op, prm.syntaxCopy(), lwr.syntaxCopy(), upr.syntaxCopy(), _body ? _body.syntaxCopy() : null, endloc); 917 } 918 919 override bool hasBreak() const pure nothrow 920 { 921 return true; 922 } 923 924 override bool hasContinue() const pure nothrow 925 { 926 return true; 927 } 928 929 override void accept(Visitor v) 930 { 931 v.visit(this); 932 } 933 } 934 935 /*********************************************************** 936 * https://dlang.org/spec/statement.html#if-statement 937 */ 938 extern (C++) final class IfStatement : Statement 939 { 940 Parameter prm; 941 Expression condition; 942 Statement ifbody; 943 Statement elsebody; 944 VarDeclaration match; // for MatchExpression results 945 Loc endloc; // location of closing curly bracket 946 947 extern (D) this(const ref Loc loc, Parameter prm, Expression condition, Statement ifbody, Statement elsebody, Loc endloc) @safe 948 { 949 super(loc, STMT.If); 950 this.prm = prm; 951 this.condition = condition; 952 this.ifbody = ifbody; 953 this.elsebody = elsebody; 954 this.endloc = endloc; 955 } 956 957 override IfStatement syntaxCopy() 958 { 959 return new IfStatement(loc, 960 prm ? prm.syntaxCopy() : null, 961 condition.syntaxCopy(), 962 ifbody ? ifbody.syntaxCopy() : null, 963 elsebody ? elsebody.syntaxCopy() : null, 964 endloc); 965 } 966 967 override void accept(Visitor v) 968 { 969 v.visit(this); 970 } 971 972 /****** 973 * Returns: true if `if (__ctfe)` 974 */ 975 bool isIfCtfeBlock() 976 { 977 if (auto cv = condition.isVarExp()) 978 return cv.var.ident == Id.ctfe; 979 return false; 980 } 981 } 982 983 /*********************************************************** 984 * https://dlang.org/spec/version.html#ConditionalStatement 985 */ 986 extern (C++) final class ConditionalStatement : Statement 987 { 988 Condition condition; 989 Statement ifbody; 990 Statement elsebody; 991 992 extern (D) this(const ref Loc loc, Condition condition, Statement ifbody, Statement elsebody) @safe 993 { 994 super(loc, STMT.Conditional); 995 this.condition = condition; 996 this.ifbody = ifbody; 997 this.elsebody = elsebody; 998 } 999 1000 override ConditionalStatement syntaxCopy() 1001 { 1002 return new ConditionalStatement(loc, condition.syntaxCopy(), ifbody.syntaxCopy(), elsebody ? elsebody.syntaxCopy() : null); 1003 } 1004 1005 override void accept(Visitor v) 1006 { 1007 v.visit(this); 1008 } 1009 } 1010 1011 1012 /*********************************************************** 1013 * https://dlang.org/spec/version.html#StaticForeachStatement 1014 * Static foreach statements, like: 1015 * void main() 1016 * { 1017 * static foreach(i; 0 .. 10) 1018 * { 1019 * pragma(msg, i); 1020 * } 1021 * } 1022 */ 1023 extern (C++) final class StaticForeachStatement : Statement 1024 { 1025 StaticForeach sfe; 1026 1027 extern (D) this(const ref Loc loc, StaticForeach sfe) @safe 1028 { 1029 super(loc, STMT.StaticForeach); 1030 this.sfe = sfe; 1031 } 1032 1033 override StaticForeachStatement syntaxCopy() 1034 { 1035 return new StaticForeachStatement(loc, sfe.syntaxCopy()); 1036 } 1037 1038 override void accept(Visitor v) 1039 { 1040 v.visit(this); 1041 } 1042 } 1043 1044 /*********************************************************** 1045 * https://dlang.org/spec/statement.html#pragma-statement 1046 */ 1047 extern (C++) final class PragmaStatement : Statement 1048 { 1049 const Identifier ident; 1050 Expressions* args; // array of Expression's 1051 Statement _body; 1052 1053 extern (D) this(const ref Loc loc, const Identifier ident, Expressions* args, Statement _body) @safe 1054 { 1055 super(loc, STMT.Pragma); 1056 this.ident = ident; 1057 this.args = args; 1058 this._body = _body; 1059 } 1060 1061 override PragmaStatement syntaxCopy() 1062 { 1063 return new PragmaStatement(loc, ident, Expression.arraySyntaxCopy(args), _body ? _body.syntaxCopy() : null); 1064 } 1065 1066 override void accept(Visitor v) 1067 { 1068 v.visit(this); 1069 } 1070 } 1071 1072 /*********************************************************** 1073 * https://dlang.org/spec/version.html#StaticAssert 1074 */ 1075 extern (C++) final class StaticAssertStatement : Statement 1076 { 1077 StaticAssert sa; 1078 1079 extern (D) this(StaticAssert sa) @safe 1080 { 1081 super(sa.loc, STMT.StaticAssert); 1082 this.sa = sa; 1083 } 1084 1085 override StaticAssertStatement syntaxCopy() 1086 { 1087 return new StaticAssertStatement(sa.syntaxCopy(null)); 1088 } 1089 1090 override void accept(Visitor v) 1091 { 1092 v.visit(this); 1093 } 1094 } 1095 1096 /*********************************************************** 1097 * https://dlang.org/spec/statement.html#switch-statement 1098 */ 1099 extern (C++) final class SwitchStatement : Statement 1100 { 1101 Parameter param; 1102 Expression condition; /// switch(condition) 1103 Statement _body; /// 1104 bool isFinal; /// https://dlang.org/spec/statement.html#final-switch-statement 1105 Loc endloc; 1106 1107 bool hasDefault; /// true if has default statement 1108 bool hasVars; /// true if has variable case values 1109 DefaultStatement sdefault; /// default: 1110 Statement tryBody; /// set to TryCatchStatement or TryFinallyStatement if in _body portion 1111 TryFinallyStatement tf; /// set if in the 'finally' block of a TryFinallyStatement 1112 GotoCaseStatements gotoCases; /// array of unresolved GotoCaseStatement's 1113 CaseStatements* cases; /// array of CaseStatement's 1114 VarDeclaration lastVar; /// last observed variable declaration in this statement 1115 1116 extern (D) this(const ref Loc loc, Parameter param, Expression condition, Statement _body, bool isFinal, Loc endloc) 1117 { 1118 super(loc, STMT.Switch); 1119 this.param = param; 1120 this.condition = condition; 1121 this._body = _body; 1122 this.isFinal = isFinal; 1123 this.endloc = endloc; 1124 } 1125 1126 override SwitchStatement syntaxCopy() 1127 { 1128 return new SwitchStatement(loc, 1129 param ? param.syntaxCopy() : null, 1130 condition.syntaxCopy(), 1131 _body.syntaxCopy(), 1132 isFinal, 1133 endloc); 1134 } 1135 1136 override bool hasBreak() const pure nothrow 1137 { 1138 return true; 1139 } 1140 1141 override void accept(Visitor v) 1142 { 1143 v.visit(this); 1144 } 1145 } 1146 1147 /*********************************************************** 1148 * https://dlang.org/spec/statement.html#CaseStatement 1149 */ 1150 extern (C++) final class CaseStatement : Statement 1151 { 1152 Expression exp; 1153 Statement statement; 1154 1155 int index; // which case it is (since we sort this) 1156 VarDeclaration lastVar; 1157 void* extra; // for use by Statement_toIR() 1158 1159 extern (D) this(const ref Loc loc, Expression exp, Statement statement) @safe 1160 { 1161 super(loc, STMT.Case); 1162 this.exp = exp; 1163 this.statement = statement; 1164 } 1165 1166 override CaseStatement syntaxCopy() 1167 { 1168 return new CaseStatement(loc, exp.syntaxCopy(), statement.syntaxCopy()); 1169 } 1170 1171 override void accept(Visitor v) 1172 { 1173 v.visit(this); 1174 } 1175 } 1176 1177 /*********************************************************** 1178 * https://dlang.org/spec/statement.html#CaseRangeStatement 1179 */ 1180 extern (C++) final class CaseRangeStatement : Statement 1181 { 1182 Expression first; 1183 Expression last; 1184 Statement statement; 1185 1186 extern (D) this(const ref Loc loc, Expression first, Expression last, Statement statement) @safe 1187 { 1188 super(loc, STMT.CaseRange); 1189 this.first = first; 1190 this.last = last; 1191 this.statement = statement; 1192 } 1193 1194 override CaseRangeStatement syntaxCopy() 1195 { 1196 return new CaseRangeStatement(loc, first.syntaxCopy(), last.syntaxCopy(), statement.syntaxCopy()); 1197 } 1198 1199 override void accept(Visitor v) 1200 { 1201 v.visit(this); 1202 } 1203 } 1204 1205 /*********************************************************** 1206 * https://dlang.org/spec/statement.html#DefaultStatement 1207 */ 1208 extern (C++) final class DefaultStatement : Statement 1209 { 1210 Statement statement; 1211 1212 VarDeclaration lastVar; 1213 1214 extern (D) this(const ref Loc loc, Statement statement) @safe 1215 { 1216 super(loc, STMT.Default); 1217 this.statement = statement; 1218 } 1219 1220 override DefaultStatement syntaxCopy() 1221 { 1222 return new DefaultStatement(loc, statement.syntaxCopy()); 1223 } 1224 1225 override void accept(Visitor v) 1226 { 1227 v.visit(this); 1228 } 1229 } 1230 1231 /*********************************************************** 1232 * https://dlang.org/spec/statement.html#GotoStatement 1233 */ 1234 extern (C++) final class GotoDefaultStatement : Statement 1235 { 1236 SwitchStatement sw; 1237 1238 extern (D) this(const ref Loc loc) @safe 1239 { 1240 super(loc, STMT.GotoDefault); 1241 } 1242 1243 override GotoDefaultStatement syntaxCopy() 1244 { 1245 return new GotoDefaultStatement(loc); 1246 } 1247 1248 override void accept(Visitor v) 1249 { 1250 v.visit(this); 1251 } 1252 } 1253 1254 /*********************************************************** 1255 * https://dlang.org/spec/statement.html#GotoStatement 1256 */ 1257 extern (C++) final class GotoCaseStatement : Statement 1258 { 1259 Expression exp; // null, or which case to goto 1260 1261 CaseStatement cs; // case statement it resolves to 1262 1263 extern (D) this(const ref Loc loc, Expression exp) @safe 1264 { 1265 super(loc, STMT.GotoCase); 1266 this.exp = exp; 1267 } 1268 1269 override GotoCaseStatement syntaxCopy() 1270 { 1271 return new GotoCaseStatement(loc, exp ? exp.syntaxCopy() : null); 1272 } 1273 1274 override void accept(Visitor v) 1275 { 1276 v.visit(this); 1277 } 1278 } 1279 1280 /*********************************************************** 1281 */ 1282 extern (C++) final class SwitchErrorStatement : Statement 1283 { 1284 Expression exp; 1285 1286 extern (D) this(const ref Loc loc) @safe 1287 { 1288 super(loc, STMT.SwitchError); 1289 } 1290 1291 final extern (D) this(const ref Loc loc, Expression exp) @safe 1292 { 1293 super(loc, STMT.SwitchError); 1294 this.exp = exp; 1295 } 1296 1297 override void accept(Visitor v) 1298 { 1299 v.visit(this); 1300 } 1301 } 1302 1303 /*********************************************************** 1304 * https://dlang.org/spec/statement.html#return-statement 1305 */ 1306 extern (C++) final class ReturnStatement : Statement 1307 { 1308 Expression exp; 1309 size_t caseDim; 1310 1311 extern (D) this(const ref Loc loc, Expression exp) @safe 1312 { 1313 super(loc, STMT.Return); 1314 this.exp = exp; 1315 } 1316 1317 override ReturnStatement syntaxCopy() 1318 { 1319 return new ReturnStatement(loc, exp ? exp.syntaxCopy() : null); 1320 } 1321 1322 override inout(ReturnStatement) endsWithReturnStatement() inout nothrow pure 1323 { 1324 return this; 1325 } 1326 1327 override void accept(Visitor v) 1328 { 1329 v.visit(this); 1330 } 1331 } 1332 1333 /*********************************************************** 1334 * https://dlang.org/spec/statement.html#break-statement 1335 */ 1336 extern (C++) final class BreakStatement : Statement 1337 { 1338 Identifier ident; 1339 1340 extern (D) this(const ref Loc loc, Identifier ident) @safe 1341 { 1342 super(loc, STMT.Break); 1343 this.ident = ident; 1344 } 1345 1346 override BreakStatement syntaxCopy() 1347 { 1348 return new BreakStatement(loc, ident); 1349 } 1350 1351 override void accept(Visitor v) 1352 { 1353 v.visit(this); 1354 } 1355 } 1356 1357 /*********************************************************** 1358 * https://dlang.org/spec/statement.html#continue-statement 1359 */ 1360 extern (C++) final class ContinueStatement : Statement 1361 { 1362 Identifier ident; 1363 1364 extern (D) this(const ref Loc loc, Identifier ident) @safe 1365 { 1366 super(loc, STMT.Continue); 1367 this.ident = ident; 1368 } 1369 1370 override ContinueStatement syntaxCopy() 1371 { 1372 return new ContinueStatement(loc, ident); 1373 } 1374 1375 override void accept(Visitor v) 1376 { 1377 v.visit(this); 1378 } 1379 } 1380 1381 /*********************************************************** 1382 * https://dlang.org/spec/statement.html#SynchronizedStatement 1383 */ 1384 extern (C++) final class SynchronizedStatement : Statement 1385 { 1386 Expression exp; 1387 Statement _body; 1388 1389 extern (D) this(const ref Loc loc, Expression exp, Statement _body) @safe 1390 { 1391 super(loc, STMT.Synchronized); 1392 this.exp = exp; 1393 this._body = _body; 1394 } 1395 1396 override SynchronizedStatement syntaxCopy() 1397 { 1398 return new SynchronizedStatement(loc, exp ? exp.syntaxCopy() : null, _body ? _body.syntaxCopy() : null); 1399 } 1400 1401 override bool hasBreak() const pure nothrow 1402 { 1403 return false; //true; 1404 } 1405 1406 override bool hasContinue() const pure nothrow 1407 { 1408 return false; //true; 1409 } 1410 1411 override void accept(Visitor v) 1412 { 1413 v.visit(this); 1414 } 1415 } 1416 1417 /*********************************************************** 1418 * https://dlang.org/spec/statement.html#with-statement 1419 */ 1420 extern (C++) final class WithStatement : Statement 1421 { 1422 Expression exp; 1423 Statement _body; 1424 VarDeclaration wthis; 1425 Loc endloc; 1426 1427 extern (D) this(const ref Loc loc, Expression exp, Statement _body, Loc endloc) @safe 1428 { 1429 super(loc, STMT.With); 1430 this.exp = exp; 1431 this._body = _body; 1432 this.endloc = endloc; 1433 } 1434 1435 override WithStatement syntaxCopy() 1436 { 1437 return new WithStatement(loc, exp.syntaxCopy(), _body ? _body.syntaxCopy() : null, endloc); 1438 } 1439 1440 override void accept(Visitor v) 1441 { 1442 v.visit(this); 1443 } 1444 } 1445 1446 /*********************************************************** 1447 * https://dlang.org/spec/statement.html#try-statement 1448 */ 1449 extern (C++) final class TryCatchStatement : Statement 1450 { 1451 Statement _body; 1452 Catches* catches; 1453 1454 Statement tryBody; /// set to enclosing TryCatchStatement or TryFinallyStatement if in _body portion 1455 1456 extern (D) this(const ref Loc loc, Statement _body, Catches* catches) @safe 1457 { 1458 super(loc, STMT.TryCatch); 1459 this._body = _body; 1460 this.catches = catches; 1461 } 1462 1463 override TryCatchStatement syntaxCopy() 1464 { 1465 auto a = new Catches(catches.length); 1466 foreach (i, c; *catches) 1467 { 1468 (*a)[i] = c.syntaxCopy(); 1469 } 1470 return new TryCatchStatement(loc, _body.syntaxCopy(), a); 1471 } 1472 1473 override bool hasBreak() const pure nothrow 1474 { 1475 return false; 1476 } 1477 1478 override void accept(Visitor v) 1479 { 1480 v.visit(this); 1481 } 1482 } 1483 1484 /*********************************************************** 1485 * https://dlang.org/spec/statement.html#Catch 1486 */ 1487 extern (C++) final class Catch : RootObject 1488 { 1489 const Loc loc; 1490 Type type; 1491 Identifier ident; 1492 Statement handler; 1493 1494 VarDeclaration var; 1495 bool errors; // set if semantic processing errors 1496 1497 // was generated by the compiler, wasn't present in source code 1498 bool internalCatch; 1499 1500 extern (D) this(const ref Loc loc, Type type, Identifier ident, Statement handler) @safe 1501 { 1502 //printf("Catch(%s, loc = %s)\n", id.toChars(), loc.toChars()); 1503 this.loc = loc; 1504 this.type = type; 1505 this.ident = ident; 1506 this.handler = handler; 1507 } 1508 1509 Catch syntaxCopy() 1510 { 1511 auto c = new Catch(loc, type ? type.syntaxCopy() : getThrowable(), ident, (handler ? handler.syntaxCopy() : null)); 1512 c.internalCatch = internalCatch; 1513 return c; 1514 } 1515 } 1516 1517 /*********************************************************** 1518 * https://dlang.org/spec/statement.html#try-statement 1519 */ 1520 extern (C++) final class TryFinallyStatement : Statement 1521 { 1522 Statement _body; 1523 Statement finalbody; 1524 1525 Statement tryBody; /// set to enclosing TryCatchStatement or TryFinallyStatement if in _body portion 1526 bool bodyFallsThru; /// true if _body falls through to finally 1527 1528 extern (D) this(const ref Loc loc, Statement _body, Statement finalbody) @safe 1529 { 1530 super(loc, STMT.TryFinally); 1531 this._body = _body; 1532 this.finalbody = finalbody; 1533 this.bodyFallsThru = true; // assume true until statementSemantic() 1534 } 1535 1536 static TryFinallyStatement create(const ref Loc loc, Statement _body, Statement finalbody) @safe 1537 { 1538 return new TryFinallyStatement(loc, _body, finalbody); 1539 } 1540 1541 override TryFinallyStatement syntaxCopy() 1542 { 1543 return new TryFinallyStatement(loc, _body.syntaxCopy(), finalbody.syntaxCopy()); 1544 } 1545 1546 override bool hasBreak() const pure nothrow 1547 { 1548 return false; //true; 1549 } 1550 1551 override bool hasContinue() const pure nothrow 1552 { 1553 return false; //true; 1554 } 1555 1556 override void accept(Visitor v) 1557 { 1558 v.visit(this); 1559 } 1560 } 1561 1562 /*********************************************************** 1563 * https://dlang.org/spec/statement.html#scope-guard-statement 1564 */ 1565 extern (C++) final class ScopeGuardStatement : Statement 1566 { 1567 TOK tok; 1568 Statement statement; 1569 1570 extern (D) this(const ref Loc loc, TOK tok, Statement statement) @safe 1571 { 1572 super(loc, STMT.ScopeGuard); 1573 this.tok = tok; 1574 this.statement = statement; 1575 } 1576 1577 override ScopeGuardStatement syntaxCopy() 1578 { 1579 return new ScopeGuardStatement(loc, tok, statement.syntaxCopy()); 1580 } 1581 1582 override void accept(Visitor v) 1583 { 1584 v.visit(this); 1585 } 1586 } 1587 1588 /*********************************************************** 1589 * https://dlang.org/spec/statement.html#throw-statement 1590 */ 1591 extern (C++) final class ThrowStatement : Statement 1592 { 1593 Expression exp; 1594 1595 // was generated by the compiler, wasn't present in source code 1596 bool internalThrow; 1597 1598 extern (D) this(const ref Loc loc, Expression exp) @safe 1599 { 1600 super(loc, STMT.Throw); 1601 this.exp = exp; 1602 } 1603 1604 override ThrowStatement syntaxCopy() 1605 { 1606 auto s = new ThrowStatement(loc, exp.syntaxCopy()); 1607 s.internalThrow = internalThrow; 1608 return s; 1609 } 1610 1611 override void accept(Visitor v) 1612 { 1613 v.visit(this); 1614 } 1615 } 1616 1617 /*********************************************************** 1618 */ 1619 extern (C++) final class DebugStatement : Statement 1620 { 1621 Statement statement; 1622 1623 extern (D) this(const ref Loc loc, Statement statement) @safe 1624 { 1625 super(loc, STMT.Debug); 1626 this.statement = statement; 1627 } 1628 1629 override DebugStatement syntaxCopy() 1630 { 1631 return new DebugStatement(loc, statement ? statement.syntaxCopy() : null); 1632 } 1633 1634 override void accept(Visitor v) 1635 { 1636 v.visit(this); 1637 } 1638 } 1639 1640 /*********************************************************** 1641 * https://dlang.org/spec/statement.html#goto-statement 1642 */ 1643 extern (C++) final class GotoStatement : Statement 1644 { 1645 Identifier ident; 1646 LabelDsymbol label; 1647 Statement tryBody; /// set to TryCatchStatement or TryFinallyStatement if in _body portion 1648 TryFinallyStatement tf; 1649 ScopeGuardStatement os; 1650 VarDeclaration lastVar; 1651 bool inCtfeBlock; /// set if goto is inside an `if (__ctfe)` block 1652 1653 extern (D) this(const ref Loc loc, Identifier ident) @safe 1654 { 1655 super(loc, STMT.Goto); 1656 this.ident = ident; 1657 } 1658 1659 override GotoStatement syntaxCopy() 1660 { 1661 return new GotoStatement(loc, ident); 1662 } 1663 1664 override void accept(Visitor v) 1665 { 1666 v.visit(this); 1667 } 1668 } 1669 1670 /*********************************************************** 1671 * https://dlang.org/spec/statement.html#LabeledStatement 1672 */ 1673 extern (C++) final class LabelStatement : Statement 1674 { 1675 Identifier ident; 1676 Statement statement; 1677 1678 Statement tryBody; /// set to TryCatchStatement or TryFinallyStatement if in _body portion 1679 TryFinallyStatement tf; 1680 ScopeGuardStatement os; 1681 VarDeclaration lastVar; 1682 Statement gotoTarget; // interpret 1683 void* extra; // used by Statement_toIR() 1684 bool breaks; // someone did a 'break ident' 1685 bool inCtfeBlock; // inside a block dominated by `if (__ctfe)` 1686 1687 extern (D) this(const ref Loc loc, Identifier ident, Statement statement) @safe 1688 { 1689 super(loc, STMT.Label); 1690 this.ident = ident; 1691 this.statement = statement; 1692 } 1693 1694 override LabelStatement syntaxCopy() 1695 { 1696 return new LabelStatement(loc, ident, statement ? statement.syntaxCopy() : null); 1697 } 1698 1699 override void accept(Visitor v) 1700 { 1701 v.visit(this); 1702 } 1703 } 1704 1705 /*********************************************************** 1706 */ 1707 extern (C++) final class LabelDsymbol : Dsymbol 1708 { 1709 LabelStatement statement; 1710 1711 bool deleted; // set if rewritten to return in foreach delegate 1712 bool iasm; // set if used by inline assembler 1713 1714 // set if label was defined multiple times, to avoid duplicate errors 1715 // can be removed if generic error message deduplication is implemented 1716 bool duplicated; 1717 1718 extern (D) this(Identifier ident, const ref Loc loc = Loc.initial) @safe 1719 { 1720 super(loc, ident); 1721 } 1722 1723 static LabelDsymbol create(Identifier ident) @safe 1724 { 1725 return new LabelDsymbol(ident); 1726 } 1727 1728 // is this a LabelDsymbol()? 1729 override LabelDsymbol isLabel() 1730 { 1731 return this; 1732 } 1733 1734 override void accept(Visitor v) 1735 { 1736 v.visit(this); 1737 } 1738 } 1739 1740 /*********************************************************** 1741 * https://dlang.org/spec/statement.html#asm 1742 */ 1743 extern (C++) class AsmStatement : Statement 1744 { 1745 Token* tokens; 1746 bool caseSensitive; // for register names 1747 1748 extern (D) this(const ref Loc loc, Token* tokens) @safe 1749 { 1750 super(loc, STMT.Asm); 1751 this.tokens = tokens; 1752 } 1753 1754 extern (D) this(const ref Loc loc, Token* tokens, STMT stmt) @safe 1755 { 1756 super(loc, stmt); 1757 this.tokens = tokens; 1758 } 1759 1760 override AsmStatement syntaxCopy() 1761 { 1762 return new AsmStatement(loc, tokens); 1763 } 1764 1765 override void accept(Visitor v) 1766 { 1767 v.visit(this); 1768 } 1769 } 1770 1771 /*********************************************************** 1772 * https://dlang.org/spec/iasm.html 1773 */ 1774 extern (C++) final class InlineAsmStatement : AsmStatement 1775 { 1776 code* asmcode; 1777 uint asmalign; // alignment of this statement 1778 uint regs; // mask of registers modified (must match regm_t in back end) 1779 bool refparam; // true if function parameter is referenced 1780 bool naked; // true if function is to be naked 1781 1782 extern (D) this(const ref Loc loc, Token* tokens) @safe 1783 { 1784 super(loc, tokens, STMT.InlineAsm); 1785 } 1786 1787 override InlineAsmStatement syntaxCopy() 1788 { 1789 return new InlineAsmStatement(loc, tokens); 1790 } 1791 1792 override void accept(Visitor v) 1793 { 1794 v.visit(this); 1795 } 1796 } 1797 1798 /*********************************************************** 1799 * https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html 1800 * Assembler instructions with D expression operands. 1801 */ 1802 extern (C++) final class GccAsmStatement : AsmStatement 1803 { 1804 StorageClass stc; // attributes of the asm {} block 1805 Expression insn; // string expression that is the template for assembler code 1806 Expressions* args; // input and output operands of the statement 1807 uint outputargs; // of the operands in 'args', the number of output operands 1808 Identifiers* names; // list of symbolic names for the operands 1809 Expressions* constraints; // list of string constants specifying constraints on operands 1810 Expressions* clobbers; // list of string constants specifying clobbers and scratch registers 1811 Identifiers* labels; // list of goto labels 1812 GotoStatements* gotos; // of the goto labels, the equivalent statements they represent 1813 1814 extern (D) this(const ref Loc loc, Token* tokens) @safe 1815 { 1816 super(loc, tokens, STMT.GccAsm); 1817 } 1818 1819 override GccAsmStatement syntaxCopy() 1820 { 1821 return new GccAsmStatement(loc, tokens); 1822 } 1823 1824 override void accept(Visitor v) 1825 { 1826 v.visit(this); 1827 } 1828 } 1829 1830 /*********************************************************** 1831 * a complete asm {} block 1832 */ 1833 extern (C++) final class CompoundAsmStatement : CompoundStatement 1834 { 1835 StorageClass stc; // postfix attributes like nothrow/pure/@trusted 1836 1837 extern (D) this(const ref Loc loc, Statements* statements, StorageClass stc) @safe 1838 { 1839 super(loc, statements, STMT.CompoundAsm); 1840 this.stc = stc; 1841 } 1842 1843 override CompoundAsmStatement syntaxCopy() 1844 { 1845 return new CompoundAsmStatement(loc, Statement.arraySyntaxCopy(statements), stc); 1846 } 1847 1848 override void accept(Visitor v) 1849 { 1850 v.visit(this); 1851 } 1852 } 1853 1854 /*********************************************************** 1855 * https://dlang.org/spec/module.html#ImportDeclaration 1856 */ 1857 extern (C++) final class ImportStatement : Statement 1858 { 1859 Dsymbols* imports; // Array of Import's 1860 1861 extern (D) this(const ref Loc loc, Dsymbols* imports) @safe 1862 { 1863 super(loc, STMT.Import); 1864 this.imports = imports; 1865 } 1866 1867 override ImportStatement syntaxCopy() 1868 { 1869 auto m = new Dsymbols(imports.length); 1870 foreach (i, s; *imports) 1871 { 1872 (*m)[i] = s.syntaxCopy(null); 1873 } 1874 return new ImportStatement(loc, m); 1875 } 1876 1877 override void accept(Visitor v) 1878 { 1879 v.visit(this); 1880 } 1881 } 1882 1883 1884 mixin template VisitStatement(Result) 1885 { 1886 Result VisitStatement(Statement s) 1887 { 1888 final switch (s.stmt) 1889 { 1890 case STMT.Error: mixin(visitStmtCase("Error")); 1891 case STMT.Scope: mixin(visitStmtCase("Scope")); 1892 case STMT.Exp: mixin(visitStmtCase("Exp")); 1893 case STMT.Compound: mixin(visitStmtCase("Compound")); 1894 case STMT.Return: mixin(visitStmtCase("Return")); 1895 case STMT.If: mixin(visitStmtCase("If")); 1896 case STMT.Conditional: mixin(visitStmtCase("Conditional")); 1897 case STMT.StaticForeach: mixin(visitStmtCase("StaticForeach")); 1898 case STMT.Case: mixin(visitStmtCase("Case")); 1899 case STMT.Default: mixin(visitStmtCase("Default")); 1900 case STMT.Label: mixin(visitStmtCase("Label")); 1901 case STMT.Goto: mixin(visitStmtCase("Goto")); 1902 case STMT.GotoDefault: mixin(visitStmtCase("GotoDefault")); 1903 case STMT.GotoCase: mixin(visitStmtCase("GotoCase")); 1904 case STMT.Break: mixin(visitStmtCase("Break")); 1905 case STMT.DtorExp: mixin(visitStmtCase("DtorExp")); 1906 case STMT.Mixin: mixin(visitStmtCase("Mixin")); 1907 case STMT.Forwarding: mixin(visitStmtCase("Forwarding")); 1908 case STMT.Do: mixin(visitStmtCase("Do")); 1909 case STMT.While: mixin(visitStmtCase("While")); 1910 case STMT.For: mixin(visitStmtCase("For")); 1911 case STMT.Foreach: mixin(visitStmtCase("Foreach")); 1912 case STMT.Switch: mixin(visitStmtCase("Switch")); 1913 case STMT.Continue: mixin(visitStmtCase("Continue")); 1914 case STMT.With: mixin(visitStmtCase("With")); 1915 case STMT.TryCatch: mixin(visitStmtCase("TryCatch")); 1916 case STMT.Throw: mixin(visitStmtCase("Throw")); 1917 case STMT.Debug: mixin(visitStmtCase("Debug")); 1918 case STMT.TryFinally: mixin(visitStmtCase("TryFinally")); 1919 case STMT.ScopeGuard: mixin(visitStmtCase("ScopeGuard")); 1920 case STMT.SwitchError: mixin(visitStmtCase("SwitchError")); 1921 case STMT.UnrolledLoop: mixin(visitStmtCase("UnrolledLoop")); 1922 case STMT.ForeachRange: mixin(visitStmtCase("ForeachRange")); 1923 case STMT.CompoundDeclaration: mixin(visitStmtCase("CompoundDeclaration")); 1924 case STMT.Peel: mixin(visitStmtCase("Peel")); 1925 case STMT.CompoundAsm: mixin(visitStmtCase("CompoundAsm")); 1926 case STMT.Pragma: mixin(visitStmtCase("Pragma")); 1927 case STMT.StaticAssert: mixin(visitStmtCase("StaticAssert")); 1928 case STMT.CaseRange: mixin(visitStmtCase("CaseRange")); 1929 case STMT.Synchronized: mixin(visitStmtCase("Synchronized")); 1930 case STMT.Asm: mixin(visitStmtCase("Asm")); 1931 case STMT.InlineAsm: mixin(visitStmtCase("InlineAsm")); 1932 case STMT.GccAsm: mixin(visitStmtCase("GccAsm")); 1933 case STMT.Import: mixin(visitStmtCase("Import")); 1934 } 1935 } 1936 } 1937 1938 /**************************************** 1939 * CTFE-only helper function for VisitInitializer. 1940 * Params: 1941 * handler = string for the name of the visit handler 1942 * Returns: boilerplate code for a case 1943 */ 1944 pure string visitStmtCase(string handler) @safe 1945 { 1946 if (__ctfe) 1947 { 1948 return 1949 " 1950 enum isVoid = is(Result == void); 1951 auto sx = s.is"~handler~"Statement(); 1952 static if (__traits(compiles, visit"~handler~"(sx))) 1953 { 1954 static if (isVoid) 1955 { 1956 visit"~handler~"(sx); 1957 return; 1958 } 1959 else 1960 { 1961 if (Result r = visit"~handler~"(sx)) 1962 return r; 1963 return Result.init; 1964 } 1965 } 1966 else static if (__traits(compiles, visitDefaultCase(s))) 1967 { 1968 static if (isVoid) 1969 { 1970 visitDefaultCase(sx); 1971 return; 1972 } 1973 else 1974 { 1975 if (Result r = visitDefaultCase(s)) 1976 return r; 1977 return Result.init; 1978 } 1979 } 1980 else 1981 static assert(0, "~handler~"); 1982 "; 1983 } 1984 assert(0); 1985 }