1 /** 2 * A depth-first visitor for expressions. 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/apply.d, _apply.d) 8 * Documentation: https://dlang.org/phobos/dmd_apply.html 9 * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/apply.d 10 */ 11 12 module dmd.apply; 13 14 import dmd.arraytypes; 15 import dmd.dsymbol; 16 import dmd.dsymbolsem; 17 import dmd.dtemplate; 18 import dmd.expression; 19 import dmd.root.array; 20 import dmd.visitor; 21 22 bool walkPostorder(Expression e, StoppableVisitor v) 23 { 24 scope PostorderExpressionVisitor pv = new PostorderExpressionVisitor(v); 25 e.accept(pv); 26 return v.stop; 27 } 28 29 /********************************* 30 * Iterate this dsymbol or members of this scoped dsymbol, then 31 * call `fp` with the found symbol and `params`. 32 * Params: 33 * symbol = the dsymbol or parent of members to call fp on 34 * fp = function pointer to process the iterated symbol. 35 * If it returns nonzero, the iteration will be aborted. 36 * params = any parameters passed to fp. 37 * Returns: 38 * nonzero if the iteration is aborted by the return value of fp, 39 * or 0 if it's completed. 40 */ 41 int apply(FP, Params...)(Dsymbol symbol, FP fp, Params params) 42 { 43 if (auto nd = symbol.isNspace()) 44 { 45 return nd.members.foreachDsymbol( (s) { return s && s.apply(fp, params); } ); 46 } 47 if (auto ad = symbol.isAttribDeclaration()) 48 { 49 return ad.include(ad._scope).foreachDsymbol( (s) { return s && s.apply(fp, params); } ); 50 } 51 if (auto tm = symbol.isTemplateMixin()) 52 { 53 if (tm._scope) // if fwd reference 54 dsymbolSemantic(tm, null); // try to resolve it 55 56 return tm.members.foreachDsymbol( (s) { return s && s.apply(fp, params); } ); 57 } 58 59 return fp(symbol, params); 60 } 61 62 /************************************** 63 * An Expression tree walker that will visit each Expression e in the tree, 64 * in depth-first evaluation order, and call fp(e,param) on it. 65 * fp() signals whether the walking continues with its return value: 66 * Returns: 67 * 0 continue 68 * 1 done 69 * It's a bit slower than using virtual functions, but more encapsulated and less brittle. 70 * Creating an iterator for this would be much more complex. 71 */ 72 private extern (C++) final class PostorderExpressionVisitor : StoppableVisitor 73 { 74 alias visit = typeof(super).visit; 75 public: 76 StoppableVisitor v; 77 78 extern (D) this(StoppableVisitor v) scope 79 { 80 this.v = v; 81 } 82 83 bool doCond(Expression e) 84 { 85 if (!stop && e) 86 e.accept(this); 87 return stop; 88 } 89 90 extern(D) bool doCond(Expression[] e) 91 { 92 for (size_t i = 0; i < e.length && !stop; i++) 93 doCond(e[i]); 94 return stop; 95 } 96 97 bool applyTo(Expression e) 98 { 99 e.accept(v); 100 stop = v.stop; 101 return true; 102 } 103 104 override void visit(Expression e) 105 { 106 applyTo(e); 107 } 108 109 override void visit(NewExp e) 110 { 111 //printf("NewExp::apply(): %s\n", toChars()); 112 doCond(e.thisexp) || doCond(e.arguments.peekSlice()) || applyTo(e); 113 } 114 115 override void visit(NewAnonClassExp e) 116 { 117 //printf("NewAnonClassExp::apply(): %s\n", toChars()); 118 doCond(e.thisexp) || doCond(e.arguments.peekSlice()) || applyTo(e); 119 } 120 121 override void visit(TypeidExp e) 122 { 123 doCond(isExpression(e.obj)) || applyTo(e); 124 } 125 126 override void visit(UnaExp e) 127 { 128 doCond(e.e1) || applyTo(e); 129 } 130 131 override void visit(BinExp e) 132 { 133 doCond(e.e1) || doCond(e.e2) || applyTo(e); 134 } 135 136 override void visit(AssertExp e) 137 { 138 //printf("CallExp::apply(apply_fp_t fp, void *param): %s\n", toChars()); 139 doCond(e.e1) || doCond(e.msg) || applyTo(e); 140 } 141 142 override void visit(CallExp e) 143 { 144 //printf("CallExp::apply(apply_fp_t fp, void *param): %s\n", toChars()); 145 doCond(e.e1) || doCond(e.arguments.peekSlice()) || applyTo(e); 146 } 147 148 override void visit(ArrayExp e) 149 { 150 //printf("ArrayExp::apply(apply_fp_t fp, void *param): %s\n", toChars()); 151 doCond(e.e1) || doCond(e.arguments.peekSlice()) || applyTo(e); 152 } 153 154 override void visit(SliceExp e) 155 { 156 doCond(e.e1) || doCond(e.lwr) || doCond(e.upr) || applyTo(e); 157 } 158 159 override void visit(ArrayLiteralExp e) 160 { 161 doCond(e.basis) || doCond(e.elements.peekSlice()) || applyTo(e); 162 } 163 164 override void visit(AssocArrayLiteralExp e) 165 { 166 doCond(e.keys.peekSlice()) || doCond(e.values.peekSlice()) || applyTo(e); 167 } 168 169 override void visit(StructLiteralExp e) 170 { 171 if (e.stageflags & stageApply) 172 return; 173 const old = e.stageflags; 174 e.stageflags |= stageApply; 175 doCond(e.elements.peekSlice()) || applyTo(e); 176 e.stageflags = old; 177 } 178 179 override void visit(TupleExp e) 180 { 181 doCond(e.e0) || doCond(e.exps.peekSlice()) || applyTo(e); 182 } 183 184 override void visit(CondExp e) 185 { 186 doCond(e.econd) || doCond(e.e1) || doCond(e.e2) || applyTo(e); 187 } 188 }