1 /** 2 * Used to help transform statement AST into flow graph. 3 * 4 * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved 5 * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) 6 * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) 7 * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/stmtstate.d, _stmtstate.d) 8 * Documentation: https://dlang.org/phobos/dmd_stmtstate.html 9 * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/stmtstate.d 10 */ 11 12 module dmd.stmtstate; 13 14 import dmd.identifier; 15 import dmd.statement; 16 17 18 /************************************************ 19 * Used to traverse the statement AST to transform it into 20 * a flow graph. 21 * Keeps track of things like "where does the `break` go". 22 * Params: 23 * block = type of the flow graph node 24 */ 25 struct StmtState(block) 26 { 27 StmtState* prev; 28 Statement statement; 29 30 Identifier ident; 31 block* breakBlock; 32 block* contBlock; 33 block* switchBlock; 34 block* defaultBlock; 35 block* finallyBlock; 36 block* tryBlock; 37 38 this(StmtState* prev, Statement statement) 39 { 40 this.prev = prev; 41 this.statement = statement; 42 if (prev) 43 this.tryBlock = prev.tryBlock; 44 } 45 46 block* getBreakBlock(Identifier ident) 47 { 48 StmtState* bc; 49 if (ident) 50 { 51 Statement related = null; 52 block* ret = null; 53 for (bc = &this; bc; bc = bc.prev) 54 { 55 // The label for a breakBlock may actually be some levels up (e.g. 56 // on a try/finally wrapping a loop). We'll see if this breakBlock 57 // is the one to return once we reach that outer statement (which 58 // in many cases will be this same statement). 59 if (bc.breakBlock) 60 { 61 related = bc.statement.getRelatedLabeled(); 62 ret = bc.breakBlock; 63 } 64 if (bc.statement == related && bc.prev.ident == ident) 65 return ret; 66 } 67 } 68 else 69 { 70 for (bc = &this; bc; bc = bc.prev) 71 { 72 if (bc.breakBlock) 73 return bc.breakBlock; 74 } 75 } 76 return null; 77 } 78 79 block* getContBlock(Identifier ident) 80 { 81 StmtState* bc; 82 if (ident) 83 { 84 block* ret = null; 85 for (bc = &this; bc; bc = bc.prev) 86 { 87 // The label for a contBlock may actually be some levels up (e.g. 88 // on a try/finally wrapping a loop). We'll see if this contBlock 89 // is the one to return once we reach that outer statement (which 90 // in many cases will be this same statement). 91 if (bc.contBlock) 92 { 93 ret = bc.contBlock; 94 } 95 if (bc.prev && bc.prev.ident == ident) 96 return ret; 97 } 98 } 99 else 100 { 101 for (bc = &this; bc; bc = bc.prev) 102 { 103 if (bc.contBlock) 104 return bc.contBlock; 105 } 106 } 107 return null; 108 } 109 110 block* getSwitchBlock() 111 { 112 StmtState* bc; 113 for (bc = &this; bc; bc = bc.prev) 114 { 115 if (bc.switchBlock) 116 return bc.switchBlock; 117 } 118 return null; 119 } 120 121 block* getDefaultBlock() 122 { 123 StmtState* bc; 124 for (bc = &this; bc; bc = bc.prev) 125 { 126 if (bc.defaultBlock) 127 return bc.defaultBlock; 128 } 129 return null; 130 } 131 132 block* getFinallyBlock() 133 { 134 StmtState* bc; 135 for (bc = &this; bc; bc = bc.prev) 136 { 137 if (bc.finallyBlock) 138 return bc.finallyBlock; 139 } 140 return null; 141 } 142 }