1 /** 2 * Defines AST nodes for statements. 3 * 4 * Specification: $(LINK2 https://dlang.org/spec/statement.html, Statements) 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/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.aggregate; 20 import dmd.arraytypes; 21 import dmd.attrib; 22 import dmd.astcodegen; 23 import dmd.ast_node; 24 import dmd.gluelayer; 25 import dmd.canthrow; 26 import dmd.cond; 27 import dmd.dclass; 28 import dmd.declaration; 29 import dmd.denum; 30 import dmd.dimport; 31 import dmd.dscope; 32 import dmd.dsymbol; 33 import dmd.dsymbolsem; 34 import dmd.dtemplate; 35 import dmd.errors; 36 import dmd.expression; 37 import dmd.expressionsem; 38 import dmd.func; 39 import dmd.globals; 40 import dmd.hdrgen; 41 import dmd.id; 42 import dmd.identifier; 43 import dmd.dinterpret; 44 import dmd.mtype; 45 import dmd.parse; 46 import dmd.root.outbuffer; 47 import dmd.root.rmem; 48 import dmd.root.rootobject; 49 import dmd.sapply; 50 import dmd.sideeffect; 51 import dmd.staticassert; 52 import dmd.tokens; 53 import dmd.visitor; 54 55 /** 56 * Returns: 57 * `TypeIdentifier` corresponding to `object.Throwable` 58 */ 59 TypeIdentifier getThrowable() 60 { 61 auto tid = Pool!TypeIdentifier.make(Loc.initial, Id.empty); 62 tid.addIdent(Id.object); 63 tid.addIdent(Id.Throwable); 64 return tid; 65 } 66 67 /** 68 * Returns: 69 * TypeIdentifier corresponding to `object.Exception` 70 */ 71 TypeIdentifier getException() 72 { 73 auto tid = Pool!TypeIdentifier.make(Loc.initial, Id.empty); 74 tid.addIdent(Id.object); 75 tid.addIdent(Id.Exception); 76 return tid; 77 } 78 79 /******************************** 80 * Identify Statement types with this enum rather than 81 * virtual functions. 82 */ 83 84 enum STMT : ubyte 85 { 86 Error, 87 Peel, 88 Exp, DtorExp, 89 Compile, 90 Compound, CompoundDeclaration, CompoundAsm, 91 UnrolledLoop, 92 Scope, 93 Forwarding, 94 While, 95 Do, 96 For, 97 Foreach, 98 ForeachRange, 99 If, 100 Conditional, 101 StaticForeach, 102 Pragma, 103 StaticAssert, 104 Switch, 105 Case, 106 CaseRange, 107 Default, 108 GotoDefault, 109 GotoCase, 110 SwitchError, 111 Return, 112 Break, 113 Continue, 114 Synchronized, 115 With, 116 TryCatch, 117 TryFinally, 118 ScopeGuard, 119 Throw, 120 Debug, 121 Goto, 122 Label, 123 Asm, InlineAsm, GccAsm, 124 Import, 125 } 126 127 128 /*********************************************************** 129 * Specification: http://dlang.org/spec/statement.html 130 */ 131 extern (C++) abstract class Statement : ASTNode 132 { 133 const Loc loc; 134 const STMT stmt; 135 136 override final DYNCAST dyncast() const 137 { 138 return DYNCAST.statement; 139 } 140 141 final extern (D) this(const ref Loc loc, STMT stmt) 142 { 143 this.loc = loc; 144 this.stmt = stmt; 145 // If this is an in{} contract scope statement (skip for determining 146 // inlineStatus of a function body for header content) 147 } 148 149 Statement syntaxCopy() 150 { 151 assert(0); 152 } 153 154 /************************************* 155 * Do syntax copy of an array of Statement's. 156 */ 157 static Statements* arraySyntaxCopy(Statements* a) 158 { 159 Statements* b = null; 160 if (a) 161 { 162 b = a.copy(); 163 foreach (i, s; *a) 164 { 165 (*b)[i] = s ? s.syntaxCopy() : null; 166 } 167 } 168 return b; 169 } 170 171 override final const(char)* toChars() const 172 { 173 HdrGenState hgs; 174 OutBuffer buf; 175 .toCBuffer(this, &buf, &hgs); 176 buf.writeByte(0); 177 return buf.extractSlice().ptr; 178 } 179 180 static if (__VERSION__ < 2092) 181 { 182 final void error(const(char)* format, ...) 183 { 184 va_list ap; 185 va_start(ap, format); 186 .verror(loc, format, ap); 187 va_end(ap); 188 } 189 190 final void warning(const(char)* format, ...) 191 { 192 va_list ap; 193 va_start(ap, format); 194 .vwarning(loc, format, ap); 195 va_end(ap); 196 } 197 198 final void deprecation(const(char)* format, ...) 199 { 200 va_list ap; 201 va_start(ap, format); 202 .vdeprecation(loc, format, ap); 203 va_end(ap); 204 } 205 } 206 else 207 { 208 pragma(printf) final void error(const(char)* format, ...) 209 { 210 va_list ap; 211 va_start(ap, format); 212 .verror(loc, format, ap); 213 va_end(ap); 214 } 215 216 pragma(printf) final void warning(const(char)* format, ...) 217 { 218 va_list ap; 219 va_start(ap, format); 220 .vwarning(loc, format, ap); 221 va_end(ap); 222 } 223 224 pragma(printf) final void deprecation(const(char)* format, ...) 225 { 226 va_list ap; 227 va_start(ap, format); 228 .vdeprecation(loc, format, ap); 229 va_end(ap); 230 } 231 } 232 233 Statement getRelatedLabeled() 234 { 235 return this; 236 } 237 238 /**************************** 239 * Determine if an enclosed `break` would apply to this 240 * statement, such as if it is a loop or switch statement. 241 * Returns: 242 * `true` if it does 243 */ 244 bool hasBreak() const pure nothrow 245 { 246 //printf("Statement::hasBreak()\n"); 247 return false; 248 } 249 250 /**************************** 251 * Determine if an enclosed `continue` would apply to this 252 * statement, such as if it is a loop statement. 253 * Returns: 254 * `true` if it does 255 */ 256 bool hasContinue() const pure nothrow 257 { 258 return false; 259 } 260 261 /********************************** 262 * Returns: 263 * `true` if statement uses exception handling 264 */ 265 final bool usesEH() 266 { 267 extern (C++) final class UsesEH : StoppableVisitor 268 { 269 alias visit = typeof(super).visit; 270 public: 271 override void visit(Statement s) 272 { 273 } 274 275 override void visit(TryCatchStatement s) 276 { 277 stop = true; 278 } 279 280 override void visit(TryFinallyStatement s) 281 { 282 stop = true; 283 } 284 285 override void visit(ScopeGuardStatement s) 286 { 287 stop = true; 288 } 289 290 override void visit(SynchronizedStatement s) 291 { 292 stop = true; 293 } 294 } 295 296 scope UsesEH ueh = new UsesEH(); 297 return walkPostorder(this, ueh); 298 } 299 300 /********************************** 301 * Returns: 302 * `true` if statement 'comes from' somewhere else, like a goto 303 */ 304 final bool comeFrom() 305 { 306 extern (C++) final class ComeFrom : StoppableVisitor 307 { 308 alias visit = typeof(super).visit; 309 public: 310 override void visit(Statement s) 311 { 312 } 313 314 override void visit(CaseStatement s) 315 { 316 stop = true; 317 } 318 319 override void visit(DefaultStatement s) 320 { 321 stop = true; 322 } 323 324 override void visit(LabelStatement s) 325 { 326 stop = true; 327 } 328 329 override void visit(AsmStatement s) 330 { 331 stop = true; 332 } 333 } 334 335 scope ComeFrom cf = new ComeFrom(); 336 return walkPostorder(this, cf); 337 } 338 339 /********************************** 340 * Returns: 341 * `true` if statement has executable code. 342 */ 343 final bool hasCode() 344 { 345 extern (C++) final class HasCode : StoppableVisitor 346 { 347 alias visit = typeof(super).visit; 348 public: 349 override void visit(Statement s) 350 { 351 stop = true; 352 } 353 354 override void visit(ExpStatement s) 355 { 356 if (s.exp !is null) 357 { 358 stop = s.exp.hasCode(); 359 } 360 } 361 362 override void visit(CompoundStatement s) 363 { 364 } 365 366 override void visit(ScopeStatement s) 367 { 368 } 369 370 override void visit(ImportStatement s) 371 { 372 } 373 } 374 375 scope HasCode hc = new HasCode(); 376 return walkPostorder(this, hc); 377 } 378 379 /**************************************** 380 * If this statement has code that needs to run in a finally clause 381 * at the end of the current scope, return that code in the form of 382 * a Statement. 383 * Params: 384 * sc = context 385 * sentry = set to code executed upon entry to the scope 386 * sexception = set to code executed upon exit from the scope via exception 387 * sfinally = set to code executed in finally block 388 * Returns: 389 * code to be run in the finally clause 390 */ 391 Statement scopeCode(Scope* sc, Statement* sentry, Statement* sexception, Statement* sfinally) 392 { 393 //printf("Statement::scopeCode()\n"); 394 *sentry = null; 395 *sexception = null; 396 *sfinally = null; 397 return this; 398 } 399 400 /********************************* 401 * Flatten out the scope by presenting the statement 402 * as an array of statements. 403 * Params: 404 * sc = context 405 * Returns: 406 * The array of `Statements`, or `null` if no flattening necessary 407 */ 408 Statements* flatten(Scope* sc) 409 { 410 return null; 411 } 412 413 /******************************* 414 * Find last statement in a sequence of statements. 415 * Returns: 416 * the last statement, or `null` if there isn't one 417 */ 418 inout(Statement) last() inout nothrow pure 419 { 420 return this; 421 } 422 423 /************************** 424 * Support Visitor Pattern 425 * Params: 426 * v = visitor 427 */ 428 override void accept(Visitor v) 429 { 430 v.visit(this); 431 } 432 433 /************************************ 434 * Does this statement end with a return statement? 435 * 436 * I.e. is it a single return statement or some compound statement 437 * that unconditionally hits a return statement. 438 * Returns: 439 * return statement it ends with, otherwise null 440 */ 441 pure nothrow @nogc 442 inout(ReturnStatement) endsWithReturnStatement() inout { return null; } 443 444 final pure inout nothrow @nogc: 445 446 /******************** 447 * A cheaper method of doing downcasting of Statements. 448 * Returns: 449 * the downcast statement if it can be downcasted, otherwise `null` 450 */ 451 inout(ErrorStatement) isErrorStatement() { return stmt == STMT.Error ? cast(typeof(return))this : null; } 452 inout(ScopeStatement) isScopeStatement() { return stmt == STMT.Scope ? cast(typeof(return))this : null; } 453 inout(ExpStatement) isExpStatement() { return stmt == STMT.Exp ? cast(typeof(return))this : null; } 454 inout(CompoundStatement) isCompoundStatement() { return stmt == STMT.Compound ? cast(typeof(return))this : null; } 455 inout(ReturnStatement) isReturnStatement() { return stmt == STMT.Return ? cast(typeof(return))this : null; } 456 inout(IfStatement) isIfStatement() { return stmt == STMT.If ? cast(typeof(return))this : null; } 457 inout(CaseStatement) isCaseStatement() { return stmt == STMT.Case ? cast(typeof(return))this : null; } 458 inout(DefaultStatement) isDefaultStatement() { return stmt == STMT.Default ? cast(typeof(return))this : null; } 459 inout(LabelStatement) isLabelStatement() { return stmt == STMT.Label ? cast(typeof(return))this : null; } 460 inout(GotoStatement) isGotoStatement() { return stmt == STMT.Goto ? cast(typeof(return))this : null; } 461 inout(GotoDefaultStatement) isGotoDefaultStatement() { return stmt == STMT.GotoDefault ? cast(typeof(return))this : null; } 462 inout(GotoCaseStatement) isGotoCaseStatement() { return stmt == STMT.GotoCase ? cast(typeof(return))this : null; } 463 inout(BreakStatement) isBreakStatement() { return stmt == STMT.Break ? cast(typeof(return))this : null; } 464 inout(DtorExpStatement) isDtorExpStatement() { return stmt == STMT.DtorExp ? cast(typeof(return))this : null; } 465 inout(ForwardingStatement) isForwardingStatement() { return stmt == STMT.Forwarding ? cast(typeof(return))this : null; } 466 inout(DoStatement) isDoStatement() { return stmt == STMT.Do ? cast(typeof(return))this : null; } 467 inout(WhileStatement) isWhileStatement() { return stmt == STMT.While ? cast(typeof(return))this : null; } 468 inout(ForStatement) isForStatement() { return stmt == STMT.For ? cast(typeof(return))this : null; } 469 inout(ForeachStatement) isForeachStatement() { return stmt == STMT.Foreach ? cast(typeof(return))this : null; } 470 inout(SwitchStatement) isSwitchStatement() { return stmt == STMT.Switch ? cast(typeof(return))this : null; } 471 inout(ContinueStatement) isContinueStatement() { return stmt == STMT.Continue ? cast(typeof(return))this : null; } 472 inout(WithStatement) isWithStatement() { return stmt == STMT.With ? cast(typeof(return))this : null; } 473 inout(TryCatchStatement) isTryCatchStatement() { return stmt == STMT.TryCatch ? cast(typeof(return))this : null; } 474 inout(ThrowStatement) isThrowStatement() { return stmt == STMT.Throw ? cast(typeof(return))this : null; } 475 inout(TryFinallyStatement) isTryFinallyStatement() { return stmt == STMT.TryFinally ? cast(typeof(return))this : null; } 476 inout(SwitchErrorStatement) isSwitchErrorStatement() { return stmt == STMT.SwitchError ? cast(typeof(return))this : null; } 477 inout(UnrolledLoopStatement) isUnrolledLoopStatement() { return stmt == STMT.UnrolledLoop ? cast(typeof(return))this : null; } 478 inout(ForeachRangeStatement) isForeachRangeStatement() { return stmt == STMT.ForeachRange ? cast(typeof(return))this : null; } 479 inout(CompoundDeclarationStatement) isCompoundDeclarationStatement() { return stmt == STMT.CompoundDeclaration ? cast(typeof(return))this : null; } 480 } 481 482 /*********************************************************** 483 * Any Statement that fails semantic() or has a component that is an ErrorExp or 484 * a TypeError should return an ErrorStatement from semantic(). 485 */ 486 extern (C++) final class ErrorStatement : Statement 487 { 488 extern (D) this() 489 { 490 super(Loc.initial, STMT.Error); 491 assert(global.gaggedErrors || global.errors); 492 } 493 494 override Statement syntaxCopy() 495 { 496 return this; 497 } 498 499 override void accept(Visitor v) 500 { 501 v.visit(this); 502 } 503 } 504 505 /*********************************************************** 506 */ 507 extern (C++) final class PeelStatement : Statement 508 { 509 Statement s; 510 511 extern (D) this(Statement s) 512 { 513 super(s.loc, STMT.Peel); 514 this.s = s; 515 } 516 517 override void accept(Visitor v) 518 { 519 v.visit(this); 520 } 521 } 522 523 /*********************************************************** 524 * Convert TemplateMixin members (== Dsymbols) to Statements. 525 */ 526 private Statement toStatement(Dsymbol s) 527 { 528 extern (C++) final class ToStmt : Visitor 529 { 530 alias visit = Visitor.visit; 531 public: 532 Statement result; 533 534 Statement visitMembers(Loc loc, Dsymbols* a) 535 { 536 if (!a) 537 return null; 538 539 auto statements = new Statements(); 540 foreach (s; *a) 541 { 542 statements.push(toStatement(s)); 543 } 544 return new CompoundStatement(loc, statements); 545 } 546 547 override void visit(Dsymbol s) 548 { 549 .error(Loc.initial, "Internal Compiler Error: cannot mixin %s `%s`\n", s.kind(), s.toChars()); 550 result = new ErrorStatement(); 551 } 552 553 override void visit(TemplateMixin tm) 554 { 555 auto a = new Statements(); 556 foreach (m; *tm.members) 557 { 558 Statement s = toStatement(m); 559 if (s) 560 a.push(s); 561 } 562 result = new CompoundStatement(tm.loc, a); 563 } 564 565 /* An actual declaration symbol will be converted to DeclarationExp 566 * with ExpStatement. 567 */ 568 Statement declStmt(Dsymbol s) 569 { 570 auto de = new DeclarationExp(s.loc, s); 571 de.type = Type.tvoid; // avoid repeated semantic 572 return new ExpStatement(s.loc, de); 573 } 574 575 override void visit(VarDeclaration d) 576 { 577 result = declStmt(d); 578 } 579 580 override void visit(AggregateDeclaration d) 581 { 582 result = declStmt(d); 583 } 584 585 override void visit(FuncDeclaration d) 586 { 587 result = declStmt(d); 588 } 589 590 override void visit(EnumDeclaration d) 591 { 592 result = declStmt(d); 593 } 594 595 override void visit(AliasDeclaration d) 596 { 597 result = declStmt(d); 598 } 599 600 override void visit(TemplateDeclaration d) 601 { 602 result = declStmt(d); 603 } 604 605 /* All attributes have been already picked by the semantic analysis of 606 * 'bottom' declarations (function, struct, class, etc). 607 * So we don't have to copy them. 608 */ 609 override void visit(StorageClassDeclaration d) 610 { 611 result = visitMembers(d.loc, d.decl); 612 } 613 614 override void visit(DeprecatedDeclaration d) 615 { 616 result = visitMembers(d.loc, d.decl); 617 } 618 619 override void visit(LinkDeclaration d) 620 { 621 result = visitMembers(d.loc, d.decl); 622 } 623 624 override void visit(ProtDeclaration d) 625 { 626 result = visitMembers(d.loc, d.decl); 627 } 628 629 override void visit(AlignDeclaration d) 630 { 631 result = visitMembers(d.loc, d.decl); 632 } 633 634 override void visit(UserAttributeDeclaration d) 635 { 636 result = visitMembers(d.loc, d.decl); 637 } 638 639 override void visit(ForwardingAttribDeclaration d) 640 { 641 result = visitMembers(d.loc, d.decl); 642 } 643 644 override void visit(StaticAssert s) 645 { 646 } 647 648 override void visit(Import s) 649 { 650 } 651 652 override void visit(PragmaDeclaration d) 653 { 654 } 655 656 override void visit(ConditionalDeclaration d) 657 { 658 result = visitMembers(d.loc, d.include(null)); 659 } 660 661 override void visit(StaticForeachDeclaration d) 662 { 663 assert(d.sfe && !!d.sfe.aggrfe ^ !!d.sfe.rangefe); 664 result = visitMembers(d.loc, d.include(null)); 665 } 666 667 override void visit(CompileDeclaration d) 668 { 669 result = visitMembers(d.loc, d.include(null)); 670 } 671 } 672 673 if (!s) 674 return null; 675 676 scope ToStmt v = new ToStmt(); 677 s.accept(v); 678 return v.result; 679 } 680 681 /*********************************************************** 682 * https://dlang.org/spec/statement.html#ExpressionStatement 683 */ 684 extern (C++) class ExpStatement : Statement 685 { 686 Expression exp; 687 688 final extern (D) this(const ref Loc loc, Expression exp) 689 { 690 super(loc, STMT.Exp); 691 this.exp = exp; 692 } 693 694 final extern (D) this(const ref Loc loc, Expression exp, STMT stmt) 695 { 696 super(loc, stmt); 697 this.exp = exp; 698 } 699 700 final extern (D) this(const ref Loc loc, Dsymbol declaration) 701 { 702 super(loc, STMT.Exp); 703 this.exp = new DeclarationExp(loc, declaration); 704 } 705 706 static ExpStatement create(Loc loc, Expression exp) 707 { 708 return new ExpStatement(loc, exp); 709 } 710 711 override Statement syntaxCopy() 712 { 713 return new ExpStatement(loc, exp ? exp.syntaxCopy() : null); 714 } 715 716 override final Statement scopeCode(Scope* sc, Statement* sentry, Statement* sexception, Statement* sfinally) 717 { 718 //printf("ExpStatement::scopeCode()\n"); 719 720 *sentry = null; 721 *sexception = null; 722 *sfinally = null; 723 724 if (exp && exp.op == TOK.declaration) 725 { 726 auto de = cast(DeclarationExp)exp; 727 auto v = de.declaration.isVarDeclaration(); 728 if (v && !v.isDataseg()) 729 { 730 if (v.needsScopeDtor()) 731 { 732 *sfinally = new DtorExpStatement(loc, v.edtor, v); 733 v.storage_class |= STC.nodtor; // don't add in dtor again 734 } 735 } 736 } 737 return this; 738 } 739 740 override final Statements* flatten(Scope* sc) 741 { 742 /* https://issues.dlang.org/show_bug.cgi?id=14243 743 * expand template mixin in statement scope 744 * to handle variable destructors. 745 */ 746 if (exp && exp.op == TOK.declaration) 747 { 748 Dsymbol d = (cast(DeclarationExp)exp).declaration; 749 if (TemplateMixin tm = d.isTemplateMixin()) 750 { 751 Expression e = exp.expressionSemantic(sc); 752 if (e.op == TOK.error || tm.errors) 753 { 754 auto a = new Statements(); 755 a.push(new ErrorStatement()); 756 return a; 757 } 758 assert(tm.members); 759 760 Statement s = toStatement(tm); 761 version (none) 762 { 763 OutBuffer buf; 764 buf.doindent = 1; 765 HdrGenState hgs; 766 hgs.hdrgen = true; 767 toCBuffer(s, &buf, &hgs); 768 printf("tm ==> s = %s\n", buf.peekChars()); 769 } 770 auto a = new Statements(); 771 a.push(s); 772 return a; 773 } 774 } 775 return null; 776 } 777 778 override void accept(Visitor v) 779 { 780 v.visit(this); 781 } 782 } 783 784 /*********************************************************** 785 */ 786 extern (C++) final class DtorExpStatement : ExpStatement 787 { 788 // Wraps an expression that is the destruction of 'var' 789 VarDeclaration var; 790 791 extern (D) this(const ref Loc loc, Expression exp, VarDeclaration var) 792 { 793 super(loc, exp, STMT.DtorExp); 794 this.var = var; 795 } 796 797 override Statement syntaxCopy() 798 { 799 return new DtorExpStatement(loc, exp ? exp.syntaxCopy() : null, var); 800 } 801 802 override void accept(Visitor v) 803 { 804 v.visit(this); 805 } 806 } 807 808 /*********************************************************** 809 * https://dlang.org/spec/statement.html#mixin-statement 810 */ 811 extern (C++) final class CompileStatement : Statement 812 { 813 Expressions* exps; 814 815 extern (D) this(const ref Loc loc, Expression exp) 816 { 817 Expressions* exps = new Expressions(); 818 exps.push(exp); 819 this(loc, exps); 820 } 821 822 extern (D) this(const ref Loc loc, Expressions* exps) 823 { 824 super(loc, STMT.Compile); 825 this.exps = exps; 826 } 827 828 override Statement syntaxCopy() 829 { 830 return new CompileStatement(loc, Expression.arraySyntaxCopy(exps)); 831 } 832 833 private Statements* compileIt(Scope* sc) 834 { 835 //printf("CompileStatement::compileIt() %s\n", exp.toChars()); 836 837 auto errorStatements() 838 { 839 auto a = new Statements(); 840 a.push(new ErrorStatement()); 841 return a; 842 } 843 844 845 OutBuffer buf; 846 if (expressionsToString(buf, sc, exps)) 847 return errorStatements(); 848 849 const errors = global.errors; 850 const len = buf.length; 851 buf.writeByte(0); 852 const str = buf.extractSlice()[0 .. len]; 853 scope p = new Parser!ASTCodegen(loc, sc._module, str, false); 854 p.nextToken(); 855 856 auto a = new Statements(); 857 while (p.token.value != TOK.endOfFile) 858 { 859 Statement s = p.parseStatement(ParseStatementFlags.semi | ParseStatementFlags.curlyScope); 860 p.reportDiagnostics(); 861 if (!s || global.errors != errors) 862 return errorStatements(); 863 a.push(s); 864 } 865 return a; 866 } 867 868 override Statements* flatten(Scope* sc) 869 { 870 //printf("CompileStatement::flatten() %s\n", exp.toChars()); 871 return compileIt(sc); 872 } 873 874 override void accept(Visitor v) 875 { 876 v.visit(this); 877 } 878 } 879 880 /*********************************************************** 881 */ 882 extern (C++) class CompoundStatement : Statement 883 { 884 Statements* statements; 885 886 /** 887 * Construct a `CompoundStatement` using an already existing 888 * array of `Statement`s 889 * 890 * Params: 891 * loc = Instantiation information 892 * statements = An array of `Statement`s, that will referenced by this class 893 */ 894 final extern (D) this(const ref Loc loc, Statements* statements) 895 { 896 super(loc, STMT.Compound); 897 this.statements = statements; 898 } 899 900 final extern (D) this(const ref Loc loc, Statements* statements, STMT stmt) 901 { 902 super(loc, stmt); 903 this.statements = statements; 904 } 905 906 /** 907 * Construct a `CompoundStatement` from an array of `Statement`s 908 * 909 * Params: 910 * loc = Instantiation information 911 * sts = A variadic array of `Statement`s, that will copied in this class 912 * The entries themselves will not be copied. 913 */ 914 final extern (D) this(const ref Loc loc, Statement[] sts...) 915 { 916 super(loc, STMT.Compound); 917 statements = new Statements(); 918 statements.reserve(sts.length); 919 foreach (s; sts) 920 statements.push(s); 921 } 922 923 static CompoundStatement create(Loc loc, Statement s1, Statement s2) 924 { 925 return new CompoundStatement(loc, s1, s2); 926 } 927 928 override Statement syntaxCopy() 929 { 930 return new CompoundStatement(loc, Statement.arraySyntaxCopy(statements)); 931 } 932 933 override Statements* flatten(Scope* sc) 934 { 935 return statements; 936 } 937 938 override final inout(ReturnStatement) endsWithReturnStatement() inout nothrow pure 939 { 940 foreach (s; *statements) 941 { 942 if (s) 943 { 944 if (inout rs = s.endsWithReturnStatement()) 945 return rs; 946 } 947 } 948 return null; 949 } 950 951 override final inout(Statement) last() inout nothrow pure 952 { 953 Statement s = null; 954 for (size_t i = statements.dim; i; --i) 955 { 956 s = cast(Statement)(*statements)[i - 1]; 957 if (s) 958 { 959 s = cast(Statement)s.last(); 960 if (s) 961 break; 962 } 963 } 964 return cast(inout)s; 965 } 966 967 override void accept(Visitor v) 968 { 969 v.visit(this); 970 } 971 } 972 973 /*********************************************************** 974 */ 975 extern (C++) final class CompoundDeclarationStatement : CompoundStatement 976 { 977 extern (D) this(const ref Loc loc, Statements* statements) 978 { 979 super(loc, statements, STMT.CompoundDeclaration); 980 } 981 982 override Statement syntaxCopy() 983 { 984 auto a = new Statements(statements.dim); 985 foreach (i, s; *statements) 986 { 987 (*a)[i] = s ? s.syntaxCopy() : null; 988 } 989 return new CompoundDeclarationStatement(loc, a); 990 } 991 992 override void accept(Visitor v) 993 { 994 v.visit(this); 995 } 996 } 997 998 /*********************************************************** 999 * The purpose of this is so that continue will go to the next 1000 * of the statements, and break will go to the end of the statements. 1001 */ 1002 extern (C++) final class UnrolledLoopStatement : Statement 1003 { 1004 Statements* statements; 1005 1006 extern (D) this(const ref Loc loc, Statements* statements) 1007 { 1008 super(loc, STMT.UnrolledLoop); 1009 this.statements = statements; 1010 } 1011 1012 override Statement syntaxCopy() 1013 { 1014 auto a = new Statements(statements.dim); 1015 foreach (i, s; *statements) 1016 { 1017 (*a)[i] = s ? s.syntaxCopy() : null; 1018 } 1019 return new UnrolledLoopStatement(loc, a); 1020 } 1021 1022 override bool hasBreak() const pure nothrow 1023 { 1024 return true; 1025 } 1026 1027 override bool hasContinue() const pure nothrow 1028 { 1029 return true; 1030 } 1031 1032 override void accept(Visitor v) 1033 { 1034 v.visit(this); 1035 } 1036 } 1037 1038 /*********************************************************** 1039 */ 1040 extern (C++) class ScopeStatement : Statement 1041 { 1042 Statement statement; 1043 Loc endloc; // location of closing curly bracket 1044 1045 extern (D) this(const ref Loc loc, Statement statement, Loc endloc) 1046 { 1047 super(loc, STMT.Scope); 1048 this.statement = statement; 1049 this.endloc = endloc; 1050 } 1051 override Statement syntaxCopy() 1052 { 1053 return new ScopeStatement(loc, statement ? statement.syntaxCopy() : null, endloc); 1054 } 1055 1056 override inout(ReturnStatement) endsWithReturnStatement() inout nothrow pure 1057 { 1058 if (statement) 1059 return statement.endsWithReturnStatement(); 1060 return null; 1061 } 1062 1063 override bool hasBreak() const pure nothrow 1064 { 1065 //printf("ScopeStatement::hasBreak() %s\n", toChars()); 1066 return statement ? statement.hasBreak() : false; 1067 } 1068 1069 override bool hasContinue() const pure nothrow 1070 { 1071 return statement ? statement.hasContinue() : false; 1072 } 1073 1074 override void accept(Visitor v) 1075 { 1076 v.visit(this); 1077 } 1078 } 1079 1080 /*********************************************************** 1081 * Statement whose symbol table contains foreach index variables in a 1082 * local scope and forwards other members to the parent scope. This 1083 * wraps a statement. 1084 * 1085 * Also see: `dmd.attrib.ForwardingAttribDeclaration` 1086 */ 1087 extern (C++) final class ForwardingStatement : Statement 1088 { 1089 /// The symbol containing the `static foreach` variables. 1090 ForwardingScopeDsymbol sym = null; 1091 /// The wrapped statement. 1092 Statement statement; 1093 1094 extern (D) this(const ref Loc loc, ForwardingScopeDsymbol sym, Statement statement) 1095 { 1096 super(loc, STMT.Forwarding); 1097 this.sym = sym; 1098 assert(statement); 1099 this.statement = statement; 1100 } 1101 1102 extern (D) this(const ref Loc loc, Statement statement) 1103 { 1104 auto sym = new ForwardingScopeDsymbol(null); 1105 sym.symtab = new DsymbolTable(); 1106 this(loc, sym, statement); 1107 } 1108 1109 override Statement syntaxCopy() 1110 { 1111 return new ForwardingStatement(loc, statement.syntaxCopy()); 1112 } 1113 1114 /*********************** 1115 * ForwardingStatements are distributed over the flattened 1116 * sequence of statements. This prevents flattening to be 1117 * "blocked" by a ForwardingStatement and is necessary, for 1118 * example, to support generating scope guards with `static 1119 * foreach`: 1120 * 1121 * static foreach(i; 0 .. 10) scope(exit) writeln(i); 1122 * writeln("this is printed first"); 1123 * // then, it prints 10, 9, 8, 7, ... 1124 */ 1125 1126 override Statements* flatten(Scope* sc) 1127 { 1128 if (!statement) 1129 { 1130 return null; 1131 } 1132 sc = sc.push(sym); 1133 auto a = statement.flatten(sc); 1134 sc = sc.pop(); 1135 if (!a) 1136 { 1137 return a; 1138 } 1139 auto b = new Statements(a.dim); 1140 foreach (i, s; *a) 1141 { 1142 (*b)[i] = s ? new ForwardingStatement(s.loc, sym, s) : null; 1143 } 1144 return b; 1145 } 1146 1147 override void accept(Visitor v) 1148 { 1149 v.visit(this); 1150 } 1151 } 1152 1153 1154 /*********************************************************** 1155 * https://dlang.org/spec/statement.html#while-statement 1156 */ 1157 extern (C++) final class WhileStatement : Statement 1158 { 1159 Expression condition; 1160 Statement _body; 1161 Loc endloc; // location of closing curly bracket 1162 1163 extern (D) this(const ref Loc loc, Expression condition, Statement _body, Loc endloc) 1164 { 1165 super(loc, STMT.While); 1166 this.condition = condition; 1167 this._body = _body; 1168 this.endloc = endloc; 1169 } 1170 1171 override Statement syntaxCopy() 1172 { 1173 return new WhileStatement(loc, 1174 condition.syntaxCopy(), 1175 _body ? _body.syntaxCopy() : null, 1176 endloc); 1177 } 1178 1179 override bool hasBreak() const pure nothrow 1180 { 1181 return true; 1182 } 1183 1184 override bool hasContinue() const pure nothrow 1185 { 1186 return true; 1187 } 1188 1189 override void accept(Visitor v) 1190 { 1191 v.visit(this); 1192 } 1193 } 1194 1195 /*********************************************************** 1196 * https://dlang.org/spec/statement.html#do-statement 1197 */ 1198 extern (C++) final class DoStatement : Statement 1199 { 1200 Statement _body; 1201 Expression condition; 1202 Loc endloc; // location of ';' after while 1203 1204 extern (D) this(const ref Loc loc, Statement _body, Expression condition, Loc endloc) 1205 { 1206 super(loc, STMT.Do); 1207 this._body = _body; 1208 this.condition = condition; 1209 this.endloc = endloc; 1210 } 1211 1212 override Statement syntaxCopy() 1213 { 1214 return new DoStatement(loc, 1215 _body ? _body.syntaxCopy() : null, 1216 condition.syntaxCopy(), 1217 endloc); 1218 } 1219 1220 override bool hasBreak() const pure nothrow 1221 { 1222 return true; 1223 } 1224 1225 override bool hasContinue() const pure nothrow 1226 { 1227 return true; 1228 } 1229 1230 override void accept(Visitor v) 1231 { 1232 v.visit(this); 1233 } 1234 } 1235 1236 /*********************************************************** 1237 * https://dlang.org/spec/statement.html#for-statement 1238 */ 1239 extern (C++) final class ForStatement : Statement 1240 { 1241 Statement _init; 1242 Expression condition; 1243 Expression increment; 1244 Statement _body; 1245 Loc endloc; // location of closing curly bracket 1246 1247 // When wrapped in try/finally clauses, this points to the outermost one, 1248 // which may have an associated label. Internal break/continue statements 1249 // treat that label as referring to this loop. 1250 Statement relatedLabeled; 1251 1252 extern (D) this(const ref Loc loc, Statement _init, Expression condition, Expression increment, Statement _body, Loc endloc) 1253 { 1254 super(loc, STMT.For); 1255 this._init = _init; 1256 this.condition = condition; 1257 this.increment = increment; 1258 this._body = _body; 1259 this.endloc = endloc; 1260 } 1261 1262 override Statement syntaxCopy() 1263 { 1264 return new ForStatement(loc, 1265 _init ? _init.syntaxCopy() : null, 1266 condition ? condition.syntaxCopy() : null, 1267 increment ? increment.syntaxCopy() : null, 1268 _body.syntaxCopy(), 1269 endloc); 1270 } 1271 1272 override Statement scopeCode(Scope* sc, Statement* sentry, Statement* sexception, Statement* sfinally) 1273 { 1274 //printf("ForStatement::scopeCode()\n"); 1275 Statement.scopeCode(sc, sentry, sexception, sfinally); 1276 return this; 1277 } 1278 1279 override Statement getRelatedLabeled() 1280 { 1281 return relatedLabeled ? relatedLabeled : this; 1282 } 1283 1284 override bool hasBreak() const pure nothrow 1285 { 1286 //printf("ForStatement::hasBreak()\n"); 1287 return true; 1288 } 1289 1290 override bool hasContinue() const pure nothrow 1291 { 1292 return true; 1293 } 1294 1295 override void accept(Visitor v) 1296 { 1297 v.visit(this); 1298 } 1299 } 1300 1301 /*********************************************************** 1302 * https://dlang.org/spec/statement.html#foreach-statement 1303 */ 1304 extern (C++) final class ForeachStatement : Statement 1305 { 1306 TOK op; // TOK.foreach_ or TOK.foreach_reverse_ 1307 Parameters* parameters; // array of Parameters, one for each ForeachType 1308 Expression aggr; // ForeachAggregate 1309 Statement _body; // NoScopeNonEmptyStatement 1310 Loc endloc; // location of closing curly bracket 1311 1312 VarDeclaration key; 1313 VarDeclaration value; 1314 1315 FuncDeclaration func; // function we're lexically in 1316 1317 Statements* cases; // put breaks, continues, gotos and returns here 1318 ScopeStatements* gotos; // forward referenced goto's go here 1319 1320 extern (D) this(const ref Loc loc, TOK op, Parameters* parameters, Expression aggr, Statement _body, Loc endloc) 1321 { 1322 super(loc, STMT.Foreach); 1323 this.op = op; 1324 this.parameters = parameters; 1325 this.aggr = aggr; 1326 this._body = _body; 1327 this.endloc = endloc; 1328 } 1329 1330 override Statement syntaxCopy() 1331 { 1332 return new ForeachStatement(loc, op, 1333 Parameter.arraySyntaxCopy(parameters), 1334 aggr.syntaxCopy(), 1335 _body ? _body.syntaxCopy() : null, 1336 endloc); 1337 } 1338 1339 override bool hasBreak() const pure nothrow 1340 { 1341 return true; 1342 } 1343 1344 override bool hasContinue() const pure nothrow 1345 { 1346 return true; 1347 } 1348 1349 override void accept(Visitor v) 1350 { 1351 v.visit(this); 1352 } 1353 } 1354 1355 /*********************************************************** 1356 * https://dlang.org/spec/statement.html#foreach-range-statement 1357 */ 1358 extern (C++) final class ForeachRangeStatement : Statement 1359 { 1360 TOK op; // TOK.foreach_ or TOK.foreach_reverse_ 1361 Parameter prm; // loop index variable 1362 Expression lwr; 1363 Expression upr; 1364 Statement _body; 1365 Loc endloc; // location of closing curly bracket 1366 1367 VarDeclaration key; 1368 1369 extern (D) this(const ref Loc loc, TOK op, Parameter prm, Expression lwr, Expression upr, Statement _body, Loc endloc) 1370 { 1371 super(loc, STMT.ForeachRange); 1372 this.op = op; 1373 this.prm = prm; 1374 this.lwr = lwr; 1375 this.upr = upr; 1376 this._body = _body; 1377 this.endloc = endloc; 1378 } 1379 1380 override Statement syntaxCopy() 1381 { 1382 return new ForeachRangeStatement(loc, op, prm.syntaxCopy(), lwr.syntaxCopy(), upr.syntaxCopy(), _body ? _body.syntaxCopy() : null, endloc); 1383 } 1384 1385 override bool hasBreak() const pure nothrow 1386 { 1387 return true; 1388 } 1389 1390 override bool hasContinue() const pure nothrow 1391 { 1392 return true; 1393 } 1394 1395 override void accept(Visitor v) 1396 { 1397 v.visit(this); 1398 } 1399 } 1400 1401 /*********************************************************** 1402 * https://dlang.org/spec/statement.html#if-statement 1403 */ 1404 extern (C++) final class IfStatement : Statement 1405 { 1406 Parameter prm; 1407 Expression condition; 1408 Statement ifbody; 1409 Statement elsebody; 1410 VarDeclaration match; // for MatchExpression results 1411 Loc endloc; // location of closing curly bracket 1412 1413 extern (D) this(const ref Loc loc, Parameter prm, Expression condition, Statement ifbody, Statement elsebody, Loc endloc) 1414 { 1415 super(loc, STMT.If); 1416 this.prm = prm; 1417 this.condition = condition; 1418 this.ifbody = ifbody; 1419 this.elsebody = elsebody; 1420 this.endloc = endloc; 1421 } 1422 1423 override Statement syntaxCopy() 1424 { 1425 return new IfStatement(loc, 1426 prm ? prm.syntaxCopy() : null, 1427 condition.syntaxCopy(), 1428 ifbody ? ifbody.syntaxCopy() : null, 1429 elsebody ? elsebody.syntaxCopy() : null, 1430 endloc); 1431 } 1432 1433 override void accept(Visitor v) 1434 { 1435 v.visit(this); 1436 } 1437 } 1438 1439 /*********************************************************** 1440 * https://dlang.org/spec/version.html#ConditionalStatement 1441 */ 1442 extern (C++) final class ConditionalStatement : Statement 1443 { 1444 Condition condition; 1445 Statement ifbody; 1446 Statement elsebody; 1447 1448 extern (D) this(const ref Loc loc, Condition condition, Statement ifbody, Statement elsebody) 1449 { 1450 super(loc, STMT.Conditional); 1451 this.condition = condition; 1452 this.ifbody = ifbody; 1453 this.elsebody = elsebody; 1454 } 1455 1456 override Statement syntaxCopy() 1457 { 1458 return new ConditionalStatement(loc, condition.syntaxCopy(), ifbody.syntaxCopy(), elsebody ? elsebody.syntaxCopy() : null); 1459 } 1460 1461 override Statements* flatten(Scope* sc) 1462 { 1463 Statement s; 1464 1465 //printf("ConditionalStatement::flatten()\n"); 1466 if (condition.include(sc)) 1467 { 1468 DebugCondition dc = condition.isDebugCondition(); 1469 if (dc) 1470 { 1471 s = new DebugStatement(loc, ifbody); 1472 debugThrowWalker(ifbody); 1473 } 1474 else 1475 s = ifbody; 1476 } 1477 else 1478 s = elsebody; 1479 1480 auto a = new Statements(); 1481 a.push(s); 1482 return a; 1483 } 1484 1485 override void accept(Visitor v) 1486 { 1487 v.visit(this); 1488 } 1489 } 1490 1491 /** 1492 Marks all occurring ThrowStatements as internalThrows. 1493 This is intended to be called from a DebugStatement as it allows 1494 to mark all its nodes as nothrow. 1495 1496 Params: 1497 s = AST Node to traverse 1498 */ 1499 private void debugThrowWalker(Statement s) 1500 { 1501 1502 extern(C++) final class DebugWalker : SemanticTimeTransitiveVisitor 1503 { 1504 alias visit = SemanticTimeTransitiveVisitor.visit; 1505 public: 1506 1507 override void visit(ThrowStatement s) 1508 { 1509 s.internalThrow = true; 1510 } 1511 1512 override void visit(CallExp s) 1513 { 1514 s.inDebugStatement = true; 1515 } 1516 } 1517 1518 scope walker = new DebugWalker(); 1519 s.accept(walker); 1520 } 1521 1522 /*********************************************************** 1523 * https://dlang.org/spec/version.html#StaticForeachStatement 1524 * Static foreach statements, like: 1525 * void main() 1526 * { 1527 * static foreach(i; 0 .. 10) 1528 * { 1529 * pragma(msg, i); 1530 * } 1531 * } 1532 */ 1533 extern (C++) final class StaticForeachStatement : Statement 1534 { 1535 StaticForeach sfe; 1536 1537 extern (D) this(const ref Loc loc, StaticForeach sfe) 1538 { 1539 super(loc, STMT.StaticForeach); 1540 this.sfe = sfe; 1541 } 1542 1543 override Statement syntaxCopy() 1544 { 1545 return new StaticForeachStatement(loc, sfe.syntaxCopy()); 1546 } 1547 1548 override Statements* flatten(Scope* sc) 1549 { 1550 sfe.prepare(sc); 1551 if (sfe.ready()) 1552 { 1553 import dmd.statementsem; 1554 auto s = makeTupleForeach!(true, false)(sc, sfe.aggrfe, sfe.needExpansion); 1555 auto result = s.flatten(sc); 1556 if (result) 1557 { 1558 return result; 1559 } 1560 result = new Statements(); 1561 result.push(s); 1562 return result; 1563 } 1564 else 1565 { 1566 auto result = new Statements(); 1567 result.push(new ErrorStatement()); 1568 return result; 1569 } 1570 } 1571 1572 override void accept(Visitor v) 1573 { 1574 v.visit(this); 1575 } 1576 } 1577 1578 /*********************************************************** 1579 * https://dlang.org/spec/statement.html#pragma-statement 1580 */ 1581 extern (C++) final class PragmaStatement : Statement 1582 { 1583 const Identifier ident; 1584 Expressions* args; // array of Expression's 1585 Statement _body; 1586 1587 extern (D) this(const ref Loc loc, const Identifier ident, Expressions* args, Statement _body) 1588 { 1589 super(loc, STMT.Pragma); 1590 this.ident = ident; 1591 this.args = args; 1592 this._body = _body; 1593 } 1594 1595 override Statement syntaxCopy() 1596 { 1597 return new PragmaStatement(loc, ident, Expression.arraySyntaxCopy(args), _body ? _body.syntaxCopy() : null); 1598 } 1599 1600 override void accept(Visitor v) 1601 { 1602 v.visit(this); 1603 } 1604 } 1605 1606 /*********************************************************** 1607 * https://dlang.org/spec/version.html#StaticAssert 1608 */ 1609 extern (C++) final class StaticAssertStatement : Statement 1610 { 1611 StaticAssert sa; 1612 1613 extern (D) this(StaticAssert sa) 1614 { 1615 super(sa.loc, STMT.StaticAssert); 1616 this.sa = sa; 1617 } 1618 1619 override Statement syntaxCopy() 1620 { 1621 return new StaticAssertStatement(cast(StaticAssert)sa.syntaxCopy(null)); 1622 } 1623 1624 override void accept(Visitor v) 1625 { 1626 v.visit(this); 1627 } 1628 } 1629 1630 /*********************************************************** 1631 * https://dlang.org/spec/statement.html#switch-statement 1632 */ 1633 extern (C++) final class SwitchStatement : Statement 1634 { 1635 Expression condition; /// switch(condition) 1636 Statement _body; /// 1637 bool isFinal; /// https://dlang.org/spec/statement.html#final-switch-statement 1638 1639 DefaultStatement sdefault; /// default: 1640 Statement tryBody; /// set to TryCatchStatement or TryFinallyStatement if in _body portion 1641 TryFinallyStatement tf; /// set if in the 'finally' block of a TryFinallyStatement 1642 GotoCaseStatements gotoCases; /// array of unresolved GotoCaseStatement's 1643 CaseStatements* cases; /// array of CaseStatement's 1644 int hasNoDefault; /// !=0 if no default statement 1645 int hasVars; /// !=0 if has variable case values 1646 VarDeclaration lastVar; /// last observed variable declaration in this statement 1647 1648 extern (D) this(const ref Loc loc, Expression condition, Statement _body, bool isFinal) 1649 { 1650 super(loc, STMT.Switch); 1651 this.condition = condition; 1652 this._body = _body; 1653 this.isFinal = isFinal; 1654 } 1655 1656 override Statement syntaxCopy() 1657 { 1658 return new SwitchStatement(loc, condition.syntaxCopy(), _body.syntaxCopy(), isFinal); 1659 } 1660 1661 override bool hasBreak() const pure nothrow 1662 { 1663 return true; 1664 } 1665 1666 /************************************ 1667 * Returns: 1668 * true if error 1669 */ 1670 extern (D) bool checkLabel() 1671 { 1672 /* 1673 * Checks the scope of a label for existing variable declaration. 1674 * Params: 1675 * vd = last variable declared before this case/default label 1676 * Returns: `true` if the variables declared in this label would be skipped. 1677 */ 1678 bool checkVar(VarDeclaration vd) 1679 { 1680 for (auto v = vd; v && v != lastVar; v = v.lastVar) 1681 { 1682 if (v.isDataseg() || (v.storage_class & (STC.manifest | STC.temp)) || v._init.isVoidInitializer()) 1683 continue; 1684 if (vd.ident == Id.withSym) 1685 error("`switch` skips declaration of `with` temporary at %s", v.loc.toChars()); 1686 else 1687 error("`switch` skips declaration of variable `%s` at %s", v.toPrettyChars(), v.loc.toChars()); 1688 return true; 1689 } 1690 return false; 1691 } 1692 1693 enum error = true; 1694 1695 if (sdefault && checkVar(sdefault.lastVar)) 1696 return !error; // return error once fully deprecated 1697 1698 foreach (scase; *cases) 1699 { 1700 if (scase && checkVar(scase.lastVar)) 1701 return !error; // return error once fully deprecated 1702 } 1703 return !error; 1704 } 1705 1706 override void accept(Visitor v) 1707 { 1708 v.visit(this); 1709 } 1710 } 1711 1712 /*********************************************************** 1713 * https://dlang.org/spec/statement.html#CaseStatement 1714 */ 1715 extern (C++) final class CaseStatement : Statement 1716 { 1717 Expression exp; 1718 Statement statement; 1719 1720 int index; // which case it is (since we sort this) 1721 VarDeclaration lastVar; 1722 void* extra; // for use by Statement_toIR() 1723 1724 extern (D) this(const ref Loc loc, Expression exp, Statement statement) 1725 { 1726 super(loc, STMT.Case); 1727 this.exp = exp; 1728 this.statement = statement; 1729 } 1730 1731 override Statement syntaxCopy() 1732 { 1733 return new CaseStatement(loc, exp.syntaxCopy(), statement.syntaxCopy()); 1734 } 1735 1736 override void accept(Visitor v) 1737 { 1738 v.visit(this); 1739 } 1740 } 1741 1742 /*********************************************************** 1743 * https://dlang.org/spec/statement.html#CaseRangeStatement 1744 */ 1745 extern (C++) final class CaseRangeStatement : Statement 1746 { 1747 Expression first; 1748 Expression last; 1749 Statement statement; 1750 1751 extern (D) this(const ref Loc loc, Expression first, Expression last, Statement statement) 1752 { 1753 super(loc, STMT.CaseRange); 1754 this.first = first; 1755 this.last = last; 1756 this.statement = statement; 1757 } 1758 1759 override Statement syntaxCopy() 1760 { 1761 return new CaseRangeStatement(loc, first.syntaxCopy(), last.syntaxCopy(), statement.syntaxCopy()); 1762 } 1763 1764 override void accept(Visitor v) 1765 { 1766 v.visit(this); 1767 } 1768 } 1769 1770 /*********************************************************** 1771 * https://dlang.org/spec/statement.html#DefaultStatement 1772 */ 1773 extern (C++) final class DefaultStatement : Statement 1774 { 1775 Statement statement; 1776 1777 VarDeclaration lastVar; 1778 1779 extern (D) this(const ref Loc loc, Statement statement) 1780 { 1781 super(loc, STMT.Default); 1782 this.statement = statement; 1783 } 1784 1785 override Statement syntaxCopy() 1786 { 1787 return new DefaultStatement(loc, statement.syntaxCopy()); 1788 } 1789 1790 override void accept(Visitor v) 1791 { 1792 v.visit(this); 1793 } 1794 } 1795 1796 /*********************************************************** 1797 * https://dlang.org/spec/statement.html#GotoStatement 1798 */ 1799 extern (C++) final class GotoDefaultStatement : Statement 1800 { 1801 SwitchStatement sw; 1802 1803 extern (D) this(const ref Loc loc) 1804 { 1805 super(loc, STMT.GotoDefault); 1806 } 1807 1808 override Statement syntaxCopy() 1809 { 1810 return new GotoDefaultStatement(loc); 1811 } 1812 1813 override void accept(Visitor v) 1814 { 1815 v.visit(this); 1816 } 1817 } 1818 1819 /*********************************************************** 1820 * https://dlang.org/spec/statement.html#GotoStatement 1821 */ 1822 extern (C++) final class GotoCaseStatement : Statement 1823 { 1824 Expression exp; // null, or which case to goto 1825 1826 CaseStatement cs; // case statement it resolves to 1827 1828 extern (D) this(const ref Loc loc, Expression exp) 1829 { 1830 super(loc, STMT.GotoCase); 1831 this.exp = exp; 1832 } 1833 1834 override Statement syntaxCopy() 1835 { 1836 return new GotoCaseStatement(loc, exp ? exp.syntaxCopy() : null); 1837 } 1838 1839 override void accept(Visitor v) 1840 { 1841 v.visit(this); 1842 } 1843 } 1844 1845 /*********************************************************** 1846 */ 1847 extern (C++) final class SwitchErrorStatement : Statement 1848 { 1849 Expression exp; 1850 1851 extern (D) this(const ref Loc loc) 1852 { 1853 super(loc, STMT.SwitchError); 1854 } 1855 1856 final extern (D) this(const ref Loc loc, Expression exp) 1857 { 1858 super(loc, STMT.SwitchError); 1859 this.exp = exp; 1860 } 1861 1862 override void accept(Visitor v) 1863 { 1864 v.visit(this); 1865 } 1866 } 1867 1868 /*********************************************************** 1869 * https://dlang.org/spec/statement.html#return-statement 1870 */ 1871 extern (C++) final class ReturnStatement : Statement 1872 { 1873 Expression exp; 1874 size_t caseDim; 1875 1876 extern (D) this(const ref Loc loc, Expression exp) 1877 { 1878 super(loc, STMT.Return); 1879 this.exp = exp; 1880 } 1881 1882 override Statement syntaxCopy() 1883 { 1884 return new ReturnStatement(loc, exp ? exp.syntaxCopy() : null); 1885 } 1886 1887 override inout(ReturnStatement) endsWithReturnStatement() inout nothrow pure 1888 { 1889 return this; 1890 } 1891 1892 override void accept(Visitor v) 1893 { 1894 v.visit(this); 1895 } 1896 } 1897 1898 /*********************************************************** 1899 * https://dlang.org/spec/statement.html#break-statement 1900 */ 1901 extern (C++) final class BreakStatement : Statement 1902 { 1903 Identifier ident; 1904 1905 extern (D) this(const ref Loc loc, Identifier ident) 1906 { 1907 super(loc, STMT.Break); 1908 this.ident = ident; 1909 } 1910 1911 override Statement syntaxCopy() 1912 { 1913 return new BreakStatement(loc, ident); 1914 } 1915 1916 override void accept(Visitor v) 1917 { 1918 v.visit(this); 1919 } 1920 } 1921 1922 /*********************************************************** 1923 * https://dlang.org/spec/statement.html#continue-statement 1924 */ 1925 extern (C++) final class ContinueStatement : Statement 1926 { 1927 Identifier ident; 1928 1929 extern (D) this(const ref Loc loc, Identifier ident) 1930 { 1931 super(loc, STMT.Continue); 1932 this.ident = ident; 1933 } 1934 1935 override Statement syntaxCopy() 1936 { 1937 return new ContinueStatement(loc, ident); 1938 } 1939 1940 override void accept(Visitor v) 1941 { 1942 v.visit(this); 1943 } 1944 } 1945 1946 /*********************************************************** 1947 * https://dlang.org/spec/statement.html#SynchronizedStatement 1948 */ 1949 extern (C++) final class SynchronizedStatement : Statement 1950 { 1951 Expression exp; 1952 Statement _body; 1953 1954 extern (D) this(const ref Loc loc, Expression exp, Statement _body) 1955 { 1956 super(loc, STMT.Synchronized); 1957 this.exp = exp; 1958 this._body = _body; 1959 } 1960 1961 override Statement syntaxCopy() 1962 { 1963 return new SynchronizedStatement(loc, exp ? exp.syntaxCopy() : null, _body ? _body.syntaxCopy() : null); 1964 } 1965 1966 override bool hasBreak() const pure nothrow 1967 { 1968 return false; //true; 1969 } 1970 1971 override bool hasContinue() const pure nothrow 1972 { 1973 return false; //true; 1974 } 1975 1976 override void accept(Visitor v) 1977 { 1978 v.visit(this); 1979 } 1980 } 1981 1982 /*********************************************************** 1983 * https://dlang.org/spec/statement.html#with-statement 1984 */ 1985 extern (C++) final class WithStatement : Statement 1986 { 1987 Expression exp; 1988 Statement _body; 1989 VarDeclaration wthis; 1990 Loc endloc; 1991 1992 extern (D) this(const ref Loc loc, Expression exp, Statement _body, Loc endloc) 1993 { 1994 super(loc, STMT.With); 1995 this.exp = exp; 1996 this._body = _body; 1997 this.endloc = endloc; 1998 } 1999 2000 override Statement syntaxCopy() 2001 { 2002 return new WithStatement(loc, exp.syntaxCopy(), _body ? _body.syntaxCopy() : null, endloc); 2003 } 2004 2005 override void accept(Visitor v) 2006 { 2007 v.visit(this); 2008 } 2009 } 2010 2011 /*********************************************************** 2012 * https://dlang.org/spec/statement.html#try-statement 2013 */ 2014 extern (C++) final class TryCatchStatement : Statement 2015 { 2016 Statement _body; 2017 Catches* catches; 2018 2019 Statement tryBody; /// set to enclosing TryCatchStatement or TryFinallyStatement if in _body portion 2020 2021 extern (D) this(const ref Loc loc, Statement _body, Catches* catches) 2022 { 2023 super(loc, STMT.TryCatch); 2024 this._body = _body; 2025 this.catches = catches; 2026 } 2027 2028 override Statement syntaxCopy() 2029 { 2030 auto a = new Catches(catches.dim); 2031 foreach (i, c; *catches) 2032 { 2033 (*a)[i] = c.syntaxCopy(); 2034 } 2035 return new TryCatchStatement(loc, _body.syntaxCopy(), a); 2036 } 2037 2038 override bool hasBreak() const pure nothrow 2039 { 2040 return false; 2041 } 2042 2043 override void accept(Visitor v) 2044 { 2045 v.visit(this); 2046 } 2047 } 2048 2049 /*********************************************************** 2050 * https://dlang.org/spec/statement.html#Catch 2051 */ 2052 extern (C++) final class Catch : RootObject 2053 { 2054 const Loc loc; 2055 Type type; 2056 Identifier ident; 2057 Statement handler; 2058 2059 VarDeclaration var; 2060 bool errors; // set if semantic processing errors 2061 2062 // was generated by the compiler, wasn't present in source code 2063 bool internalCatch; 2064 2065 extern (D) this(const ref Loc loc, Type type, Identifier ident, Statement handler) 2066 { 2067 //printf("Catch(%s, loc = %s)\n", id.toChars(), loc.toChars()); 2068 this.loc = loc; 2069 this.type = type; 2070 this.ident = ident; 2071 this.handler = handler; 2072 } 2073 2074 Catch syntaxCopy() 2075 { 2076 auto c = new Catch(loc, type ? type.syntaxCopy() : getThrowable(), ident, (handler ? handler.syntaxCopy() : null)); 2077 c.internalCatch = internalCatch; 2078 return c; 2079 } 2080 } 2081 2082 /*********************************************************** 2083 * https://dlang.org/spec/statement.html#try-statement 2084 */ 2085 extern (C++) final class TryFinallyStatement : Statement 2086 { 2087 Statement _body; 2088 Statement finalbody; 2089 2090 Statement tryBody; /// set to enclosing TryCatchStatement or TryFinallyStatement if in _body portion 2091 bool bodyFallsThru; /// true if _body falls through to finally 2092 2093 extern (D) this(const ref Loc loc, Statement _body, Statement finalbody) 2094 { 2095 super(loc, STMT.TryFinally); 2096 this._body = _body; 2097 this.finalbody = finalbody; 2098 this.bodyFallsThru = true; // assume true until statementSemantic() 2099 } 2100 2101 static TryFinallyStatement create(Loc loc, Statement _body, Statement finalbody) 2102 { 2103 return new TryFinallyStatement(loc, _body, finalbody); 2104 } 2105 2106 override Statement syntaxCopy() 2107 { 2108 return new TryFinallyStatement(loc, _body.syntaxCopy(), finalbody.syntaxCopy()); 2109 } 2110 2111 override bool hasBreak() const pure nothrow 2112 { 2113 return false; //true; 2114 } 2115 2116 override bool hasContinue() const pure nothrow 2117 { 2118 return false; //true; 2119 } 2120 2121 override void accept(Visitor v) 2122 { 2123 v.visit(this); 2124 } 2125 } 2126 2127 /*********************************************************** 2128 * https://dlang.org/spec/statement.html#scope-guard-statement 2129 */ 2130 extern (C++) final class ScopeGuardStatement : Statement 2131 { 2132 TOK tok; 2133 Statement statement; 2134 2135 extern (D) this(const ref Loc loc, TOK tok, Statement statement) 2136 { 2137 super(loc, STMT.ScopeGuard); 2138 this.tok = tok; 2139 this.statement = statement; 2140 } 2141 2142 override Statement syntaxCopy() 2143 { 2144 return new ScopeGuardStatement(loc, tok, statement.syntaxCopy()); 2145 } 2146 2147 override Statement scopeCode(Scope* sc, Statement* sentry, Statement* sexception, Statement* sfinally) 2148 { 2149 //printf("ScopeGuardStatement::scopeCode()\n"); 2150 *sentry = null; 2151 *sexception = null; 2152 *sfinally = null; 2153 2154 Statement s = new PeelStatement(statement); 2155 2156 switch (tok) 2157 { 2158 case TOK.onScopeExit: 2159 *sfinally = s; 2160 break; 2161 2162 case TOK.onScopeFailure: 2163 *sexception = s; 2164 break; 2165 2166 case TOK.onScopeSuccess: 2167 { 2168 /* Create: 2169 * sentry: bool x = false; 2170 * sexception: x = true; 2171 * sfinally: if (!x) statement; 2172 */ 2173 auto v = copyToTemp(0, "__os", IntegerExp.createBool(false)); 2174 v.dsymbolSemantic(sc); 2175 *sentry = new ExpStatement(loc, v); 2176 2177 Expression e = IntegerExp.createBool(true); 2178 e = new AssignExp(Loc.initial, new VarExp(Loc.initial, v), e); 2179 *sexception = new ExpStatement(Loc.initial, e); 2180 2181 e = new VarExp(Loc.initial, v); 2182 e = new NotExp(Loc.initial, e); 2183 *sfinally = new IfStatement(Loc.initial, null, e, s, null, Loc.initial); 2184 2185 break; 2186 } 2187 default: 2188 assert(0); 2189 } 2190 return null; 2191 } 2192 2193 override void accept(Visitor v) 2194 { 2195 v.visit(this); 2196 } 2197 } 2198 2199 /*********************************************************** 2200 * https://dlang.org/spec/statement.html#throw-statement 2201 */ 2202 extern (C++) final class ThrowStatement : Statement 2203 { 2204 Expression exp; 2205 2206 // was generated by the compiler, wasn't present in source code 2207 bool internalThrow; 2208 2209 extern (D) this(const ref Loc loc, Expression exp) 2210 { 2211 super(loc, STMT.Throw); 2212 this.exp = exp; 2213 } 2214 2215 override Statement syntaxCopy() 2216 { 2217 auto s = new ThrowStatement(loc, exp.syntaxCopy()); 2218 s.internalThrow = internalThrow; 2219 return s; 2220 } 2221 2222 override void accept(Visitor v) 2223 { 2224 v.visit(this); 2225 } 2226 } 2227 2228 /*********************************************************** 2229 */ 2230 extern (C++) final class DebugStatement : Statement 2231 { 2232 Statement statement; 2233 2234 extern (D) this(const ref Loc loc, Statement statement) 2235 { 2236 super(loc, STMT.Debug); 2237 this.statement = statement; 2238 } 2239 2240 override Statement syntaxCopy() 2241 { 2242 return new DebugStatement(loc, statement ? statement.syntaxCopy() : null); 2243 } 2244 2245 override Statements* flatten(Scope* sc) 2246 { 2247 Statements* a = statement ? statement.flatten(sc) : null; 2248 if (a) 2249 { 2250 foreach (ref s; *a) 2251 { 2252 s = new DebugStatement(loc, s); 2253 } 2254 } 2255 return a; 2256 } 2257 2258 override void accept(Visitor v) 2259 { 2260 v.visit(this); 2261 } 2262 } 2263 2264 /*********************************************************** 2265 * https://dlang.org/spec/statement.html#goto-statement 2266 */ 2267 extern (C++) final class GotoStatement : Statement 2268 { 2269 Identifier ident; 2270 LabelDsymbol label; 2271 Statement tryBody; /// set to TryCatchStatement or TryFinallyStatement if in _body portion 2272 TryFinallyStatement tf; 2273 ScopeGuardStatement os; 2274 VarDeclaration lastVar; 2275 2276 extern (D) this(const ref Loc loc, Identifier ident) 2277 { 2278 super(loc, STMT.Goto); 2279 this.ident = ident; 2280 } 2281 2282 override Statement syntaxCopy() 2283 { 2284 return new GotoStatement(loc, ident); 2285 } 2286 2287 extern (D) bool checkLabel() 2288 { 2289 if (!label.statement) 2290 return true; // error should have been issued for this already 2291 2292 if (label.statement.os != os) 2293 { 2294 if (os && os.tok == TOK.onScopeFailure && !label.statement.os) 2295 { 2296 // Jump out from scope(failure) block is allowed. 2297 } 2298 else 2299 { 2300 if (label.statement.os) 2301 error("cannot `goto` in to `%s` block", Token.toChars(label.statement.os.tok)); 2302 else 2303 error("cannot `goto` out of `%s` block", Token.toChars(os.tok)); 2304 return true; 2305 } 2306 } 2307 2308 if (label.statement.tf != tf) 2309 { 2310 error("cannot `goto` in or out of `finally` block"); 2311 return true; 2312 } 2313 2314 Statement stbnext; 2315 for (auto stb = tryBody; stb != label.statement.tryBody; stb = stbnext) 2316 { 2317 if (!stb) 2318 { 2319 error("cannot `goto` into `try` block"); 2320 return true; 2321 } 2322 if (auto stf = stb.isTryFinallyStatement()) 2323 stbnext = stf.tryBody; 2324 else if (auto stc = stb.isTryCatchStatement()) 2325 stbnext = stc.tryBody; 2326 else 2327 assert(0); 2328 } 2329 2330 VarDeclaration vd = label.statement.lastVar; 2331 if (!vd || vd.isDataseg() || (vd.storage_class & STC.manifest)) 2332 return false; 2333 2334 VarDeclaration last = lastVar; 2335 while (last && last != vd) 2336 last = last.lastVar; 2337 if (last == vd) 2338 { 2339 // All good, the label's scope has no variables 2340 } 2341 else if (vd.storage_class & STC.exptemp) 2342 { 2343 // Lifetime ends at end of expression, so no issue with skipping the statement 2344 } 2345 else if (vd.ident == Id.withSym) 2346 { 2347 error("`goto` skips declaration of `with` temporary at %s", vd.loc.toChars()); 2348 return true; 2349 } 2350 else 2351 { 2352 error("`goto` skips declaration of variable `%s` at %s", vd.toPrettyChars(), vd.loc.toChars()); 2353 return true; 2354 } 2355 2356 return false; 2357 } 2358 2359 override void accept(Visitor v) 2360 { 2361 v.visit(this); 2362 } 2363 } 2364 2365 /*********************************************************** 2366 * https://dlang.org/spec/statement.html#LabeledStatement 2367 */ 2368 extern (C++) final class LabelStatement : Statement 2369 { 2370 Identifier ident; 2371 Statement statement; 2372 2373 Statement tryBody; /// set to TryCatchStatement or TryFinallyStatement if in _body portion 2374 TryFinallyStatement tf; 2375 ScopeGuardStatement os; 2376 VarDeclaration lastVar; 2377 Statement gotoTarget; // interpret 2378 void* extra; // used by Statement_toIR() 2379 bool breaks; // someone did a 'break ident' 2380 2381 extern (D) this(const ref Loc loc, Identifier ident, Statement statement) 2382 { 2383 super(loc, STMT.Label); 2384 this.ident = ident; 2385 this.statement = statement; 2386 } 2387 2388 override Statement syntaxCopy() 2389 { 2390 return new LabelStatement(loc, ident, statement ? statement.syntaxCopy() : null); 2391 } 2392 2393 override Statements* flatten(Scope* sc) 2394 { 2395 Statements* a = null; 2396 if (statement) 2397 { 2398 a = statement.flatten(sc); 2399 if (a) 2400 { 2401 if (!a.dim) 2402 { 2403 a.push(new ExpStatement(loc, cast(Expression)null)); 2404 } 2405 2406 // reuse 'this' LabelStatement 2407 this.statement = (*a)[0]; 2408 (*a)[0] = this; 2409 } 2410 } 2411 return a; 2412 } 2413 2414 override Statement scopeCode(Scope* sc, Statement* sentry, Statement* sexit, Statement* sfinally) 2415 { 2416 //printf("LabelStatement::scopeCode()\n"); 2417 if (statement) 2418 statement = statement.scopeCode(sc, sentry, sexit, sfinally); 2419 else 2420 { 2421 *sentry = null; 2422 *sexit = null; 2423 *sfinally = null; 2424 } 2425 return this; 2426 } 2427 2428 override void accept(Visitor v) 2429 { 2430 v.visit(this); 2431 } 2432 } 2433 2434 /*********************************************************** 2435 */ 2436 extern (C++) final class LabelDsymbol : Dsymbol 2437 { 2438 LabelStatement statement; 2439 2440 bool deleted; // set if rewritten to return in foreach delegate 2441 bool iasm; // set if used by inline assembler 2442 2443 extern (D) this(Identifier ident) 2444 { 2445 super(ident); 2446 } 2447 2448 static LabelDsymbol create(Identifier ident) 2449 { 2450 return new LabelDsymbol(ident); 2451 } 2452 2453 // is this a LabelDsymbol()? 2454 override LabelDsymbol isLabel() 2455 { 2456 return this; 2457 } 2458 2459 override void accept(Visitor v) 2460 { 2461 v.visit(this); 2462 } 2463 } 2464 2465 /*********************************************************** 2466 * https://dlang.org/spec/statement.html#asm 2467 */ 2468 extern (C++) class AsmStatement : Statement 2469 { 2470 Token* tokens; 2471 2472 extern (D) this(const ref Loc loc, Token* tokens) 2473 { 2474 super(loc, STMT.Asm); 2475 this.tokens = tokens; 2476 } 2477 2478 extern (D) this(const ref Loc loc, Token* tokens, STMT stmt) 2479 { 2480 super(loc, stmt); 2481 this.tokens = tokens; 2482 } 2483 2484 override Statement syntaxCopy() 2485 { 2486 return new AsmStatement(loc, tokens); 2487 } 2488 2489 override void accept(Visitor v) 2490 { 2491 v.visit(this); 2492 } 2493 } 2494 2495 /*********************************************************** 2496 * https://dlang.org/spec/iasm.html 2497 */ 2498 extern (C++) final class InlineAsmStatement : AsmStatement 2499 { 2500 code* asmcode; 2501 uint asmalign; // alignment of this statement 2502 uint regs; // mask of registers modified (must match regm_t in back end) 2503 bool refparam; // true if function parameter is referenced 2504 bool naked; // true if function is to be naked 2505 2506 extern (D) this(const ref Loc loc, Token* tokens) 2507 { 2508 super(loc, tokens, STMT.InlineAsm); 2509 } 2510 2511 override Statement syntaxCopy() 2512 { 2513 return new InlineAsmStatement(loc, tokens); 2514 } 2515 2516 override void accept(Visitor v) 2517 { 2518 v.visit(this); 2519 } 2520 } 2521 2522 /*********************************************************** 2523 * https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html 2524 * Assembler instructions with D expression operands. 2525 */ 2526 extern (C++) final class GccAsmStatement : AsmStatement 2527 { 2528 StorageClass stc; // attributes of the asm {} block 2529 Expression insn; // string expression that is the template for assembler code 2530 Expressions* args; // input and output operands of the statement 2531 uint outputargs; // of the operands in 'args', the number of output operands 2532 Identifiers* names; // list of symbolic names for the operands 2533 Expressions* constraints; // list of string constants specifying constraints on operands 2534 Expressions* clobbers; // list of string constants specifying clobbers and scratch registers 2535 Identifiers* labels; // list of goto labels 2536 GotoStatements* gotos; // of the goto labels, the equivalent statements they represent 2537 2538 extern (D) this(const ref Loc loc, Token* tokens) 2539 { 2540 super(loc, tokens, STMT.GccAsm); 2541 } 2542 2543 override Statement syntaxCopy() 2544 { 2545 return new GccAsmStatement(loc, tokens); 2546 } 2547 2548 override void accept(Visitor v) 2549 { 2550 v.visit(this); 2551 } 2552 } 2553 2554 /*********************************************************** 2555 * a complete asm {} block 2556 */ 2557 extern (C++) final class CompoundAsmStatement : CompoundStatement 2558 { 2559 StorageClass stc; // postfix attributes like nothrow/pure/@trusted 2560 2561 extern (D) this(const ref Loc loc, Statements* statements, StorageClass stc) 2562 { 2563 super(loc, statements, STMT.CompoundAsm); 2564 this.stc = stc; 2565 } 2566 2567 override CompoundAsmStatement syntaxCopy() 2568 { 2569 auto a = new Statements(statements.dim); 2570 foreach (i, s; *statements) 2571 { 2572 (*a)[i] = s ? s.syntaxCopy() : null; 2573 } 2574 return new CompoundAsmStatement(loc, a, stc); 2575 } 2576 2577 override Statements* flatten(Scope* sc) 2578 { 2579 return null; 2580 } 2581 2582 override void accept(Visitor v) 2583 { 2584 v.visit(this); 2585 } 2586 } 2587 2588 /*********************************************************** 2589 * https://dlang.org/spec/module.html#ImportDeclaration 2590 */ 2591 extern (C++) final class ImportStatement : Statement 2592 { 2593 Dsymbols* imports; // Array of Import's 2594 2595 extern (D) this(const ref Loc loc, Dsymbols* imports) 2596 { 2597 super(loc, STMT.Import); 2598 this.imports = imports; 2599 } 2600 2601 override Statement syntaxCopy() 2602 { 2603 auto m = new Dsymbols(imports.dim); 2604 foreach (i, s; *imports) 2605 { 2606 (*m)[i] = s.syntaxCopy(null); 2607 } 2608 return new ImportStatement(loc, m); 2609 } 2610 2611 override void accept(Visitor v) 2612 { 2613 v.visit(this); 2614 } 2615 }