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 }