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