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