1 /** 2 * Utility to visit every variable in an expression. 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/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.arraytypes; 19 import dmd.astenums; 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.postordervisitor; 36 import dmd.printast; 37 import dmd.root.array; 38 import dmd.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 */ 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) scope @safe 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 */ 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.Mixin: 303 case STMT.Peel: 304 case STMT.Synchronized: 305 assert(0); // should have been rewritten 306 } 307 } 308 309 visit(s); 310 }