1 /**
2  * Utility to visit every variable in an expression.
3  *
4  * Copyright:   Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
5  * Authors:     $(LINK2 http://www.digitalmars.com, Walter Bright)
6  * License:     $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
7  * Source:      $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/foreachvar.d, _foreachvar.d)
8  * Documentation:  https://dlang.org/phobos/dmd_foreachvar.html
9  * Coverage:    https://codecov.io/gh/dlang/dmd/src/master/src/dmd/foreachvar.d
10  */
11 
12 module dmd.foreachvar;
13 
14 import core.stdc.stdio;
15 import core.stdc.stdlib;
16 import core.stdc.string;
17 
18 import dmd.apply;
19 import dmd.arraytypes;
20 import dmd.attrib;
21 import dmd.dclass;
22 import dmd.declaration;
23 import dmd.dstruct;
24 import dmd.dsymbol;
25 import dmd.dsymbolsem;
26 import dmd.dtemplate;
27 import dmd.errors;
28 import dmd.expression;
29 import dmd.func;
30 import dmd.id;
31 import dmd.identifier;
32 import dmd.init;
33 import dmd.initsem;
34 import dmd.mtype;
35 import dmd.printast;
36 import dmd.root.array;
37 import dmd.root.rootobject;
38 import dmd.statement;
39 import dmd.tokens;
40 import dmd.visitor;
41 
42 /*********************************************
43  * Visit each Expression in e, and call dgVar() on each variable declared in it.
44  * Params:
45  *      e = expression tree to visit
46  *      dgVar = call when a variable is declared
47  */
48 void foreachVar(Expression e, void delegate(VarDeclaration) dgVar)
49 {
50     if (!e)
51         return;
52 
53     extern (C++) final class VarWalker : StoppableVisitor
54     {
55         alias visit = typeof(super).visit;
56         extern (D) void delegate(VarDeclaration) dgVar;
57 
58         extern (D) this(void delegate(VarDeclaration) dgVar)
59         {
60             this.dgVar = dgVar;
61         }
62 
63         override void visit(Expression e)
64         {
65         }
66 
67         override void visit(ErrorExp e)
68         {
69         }
70 
71         override void visit(DeclarationExp e)
72         {
73             VarDeclaration v = e.declaration.isVarDeclaration();
74             if (!v)
75                 return;
76             if (TupleDeclaration td = v.toAlias().isTupleDeclaration())
77             {
78                 if (!td.objects)
79                     return;
80                 foreach (o; *td.objects)
81                 {
82                     Expression ex = isExpression(o);
83                     DsymbolExp s = ex ? ex.isDsymbolExp() : null;
84                     assert(s);
85                     VarDeclaration v2 = s.s.isVarDeclaration();
86                     assert(v2);
87                     dgVar(v2);
88                 }
89             }
90             else
91                 dgVar(v);
92             Dsymbol s = v.toAlias();
93             if (s == v && !v.isStatic() && v._init)
94             {
95                 if (auto ie = v._init.isExpInitializer())
96                     ie.exp.foreachVar(dgVar);
97             }
98         }
99 
100         override void visit(IndexExp e)
101         {
102             if (e.lengthVar)
103                 dgVar(e.lengthVar);
104         }
105 
106         override void visit(SliceExp e)
107         {
108             if (e.lengthVar)
109                 dgVar(e.lengthVar);
110         }
111     }
112 
113     scope VarWalker v = new VarWalker(dgVar);
114     walkPostorder(e, v);
115 }
116 
117 /***************
118  * Transitively walk Statement s, pass Expressions to dgExp(), VarDeclarations to dgVar().
119  * Params:
120  *      s = Statement to traverse
121  *      dgExp = delegate to pass found Expressions to
122  *      dgVar = delegate to pass found VarDeclarations to
123  */
124 void foreachExpAndVar(Statement s,
125         void delegate(Expression) dgExp,
126         void delegate(VarDeclaration) dgVar)
127 {
128     void visit(Statement s)
129     {
130         void visitExp(ExpStatement s)
131         {
132             if (s.exp)
133                 dgExp(s.exp);
134         }
135 
136         void visitDtorExp(DtorExpStatement s)
137         {
138             if (s.exp)
139                 dgExp(s.exp);
140         }
141 
142         void visitIf(IfStatement s)
143         {
144             dgExp(s.condition);
145             visit(s.ifbody);
146             visit(s.elsebody);
147         }
148 
149         void visitDo(DoStatement s)
150         {
151             dgExp(s.condition);
152             visit(s._body);
153         }
154 
155         void visitFor(ForStatement s)
156         {
157             visit(s._init);
158             if (s.condition)
159                 dgExp(s.condition);
160             if (s.increment)
161                 dgExp(s.increment);
162             visit(s._body);
163         }
164 
165         void visitSwitch(SwitchStatement s)
166         {
167             dgExp(s.condition);
168             // Note that the body contains the Case and Default
169             // statements, so we only need to compile the expressions
170             foreach (cs; *s.cases)
171             {
172                 dgExp(cs.exp);
173             }
174             visit(s._body);
175         }
176 
177         void visitCase(CaseStatement s)
178         {
179             visit(s.statement);
180         }
181 
182         void visitReturn(ReturnStatement s)
183         {
184             if (s.exp)
185                 dgExp(s.exp);
186         }
187 
188         void visitCompound(CompoundStatement s)
189         {
190             if (s.statements)
191             {
192                 foreach (s2; *s.statements)
193                 {
194                     visit(s2);
195                 }
196             }
197         }
198 
199         void visitCompoundDeclaration(CompoundDeclarationStatement s)
200         {
201             visitCompound(s);
202         }
203 
204         void visitUnrolledLoop(UnrolledLoopStatement s)
205         {
206             foreach (s2; *s.statements)
207             {
208                 visit(s2);
209             }
210         }
211 
212         void visitScope(ScopeStatement s)
213         {
214             visit(s.statement);
215         }
216 
217         void visitDefault(DefaultStatement s)
218         {
219             visit(s.statement);
220         }
221 
222         void visitWith(WithStatement s)
223         {
224             // If it is with(Enum) {...}, just execute the body.
225             if (s.exp.op == TOK.scope_ || s.exp.op == TOK.type)
226             {
227             }
228             else
229             {
230                 dgVar(s.wthis);
231                 dgExp(s.exp);
232             }
233             visit(s._body);
234         }
235 
236         void visitTryCatch(TryCatchStatement s)
237         {
238             visit(s._body);
239             foreach (ca; *s.catches)
240             {
241                 if (ca.var)
242                     dgVar(ca.var);
243                 visit(ca.handler);
244             }
245         }
246 
247         void visitTryFinally(TryFinallyStatement s)
248         {
249             visit(s._body);
250             visit(s.finalbody);
251         }
252 
253         void visitThrow(ThrowStatement s)
254         {
255             dgExp(s.exp);
256         }
257 
258         void visitLabel(LabelStatement s)
259         {
260             visit(s.statement);
261         }
262 
263         if (!s)
264             return;
265 
266         final switch (s.stmt)
267         {
268             case STMT.Exp:                 visitExp(s.isExpStatement()); break;
269             case STMT.DtorExp:             visitDtorExp(s.isDtorExpStatement()); break;
270             case STMT.Compound:            visitCompound(s.isCompoundStatement()); break;
271             case STMT.CompoundDeclaration: visitCompoundDeclaration(s.isCompoundDeclarationStatement()); break;
272             case STMT.UnrolledLoop:        visitUnrolledLoop(s.isUnrolledLoopStatement()); break;
273             case STMT.Scope:               visitScope(s.isScopeStatement()); break;
274             case STMT.Do:                  visitDo(s.isDoStatement()); break;
275             case STMT.For:                 visitFor(s.isForStatement()); break;
276             case STMT.If:                  visitIf(s.isIfStatement()); break;
277             case STMT.Switch:              visitSwitch(s.isSwitchStatement()); break;
278             case STMT.Case:                visitCase(s.isCaseStatement()); break;
279             case STMT.Default:             visitDefault(s.isDefaultStatement()); break;
280             case STMT.Return:              visitReturn(s.isReturnStatement()); break;
281             case STMT.With:                visitWith(s.isWithStatement()); break;
282             case STMT.TryCatch:            visitTryCatch(s.isTryCatchStatement()); break;
283             case STMT.TryFinally:          visitTryFinally(s.isTryFinallyStatement()); break;
284             case STMT.Throw:               visitThrow(s.isThrowStatement()); break;
285             case STMT.Label:               visitLabel(s.isLabelStatement()); break;
286 
287             case STMT.CompoundAsm:
288             case STMT.Asm:
289             case STMT.InlineAsm:
290             case STMT.GccAsm:
291 
292             case STMT.Break:
293             case STMT.Continue:
294             case STMT.GotoDefault:
295             case STMT.GotoCase:
296             case STMT.SwitchError:
297             case STMT.Goto:
298             case STMT.Pragma:
299             case STMT.Import:
300             case STMT.Error:
301                 break;          // ignore these
302 
303             case STMT.ScopeGuard:
304             case STMT.Foreach:
305             case STMT.ForeachRange:
306             case STMT.Debug:
307             case STMT.CaseRange:
308             case STMT.StaticForeach:
309             case STMT.StaticAssert:
310             case STMT.Conditional:
311             case STMT.While:
312             case STMT.Forwarding:
313             case STMT.Compile:
314             case STMT.Peel:
315             case STMT.Synchronized:
316                 assert(0);              // should have been rewritten
317         }
318     }
319 
320     visit(s);
321 }
322