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