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.postordervisitor; 13 14 import dmd.arraytypes; 15 import dmd.dtemplate; 16 import dmd.expression; 17 import dmd.root.array; 18 import dmd.visitor; 19 20 bool walkPostorder(Expression e, StoppableVisitor v) 21 { 22 scope PostorderExpressionVisitor pv = new PostorderExpressionVisitor(v); 23 e.accept(pv); 24 return v.stop; 25 } 26 27 /************************************** 28 * An Expression tree walker that will visit each Expression e in the tree, 29 * in depth-first evaluation order, and call fp(e,param) on it. 30 * fp() signals whether the walking continues with its return value: 31 * Returns: 32 * 0 continue 33 * 1 done 34 * It's a bit slower than using virtual functions, but more encapsulated and less brittle. 35 * Creating an iterator for this would be much more complex. 36 */ 37 private extern (C++) final class PostorderExpressionVisitor : StoppableVisitor 38 { 39 alias visit = typeof(super).visit; 40 public: 41 StoppableVisitor v; 42 43 extern (D) this(StoppableVisitor v) scope @safe 44 { 45 this.v = v; 46 } 47 48 bool doCond(Expression e) 49 { 50 if (!stop && e) 51 e.accept(this); 52 return stop; 53 } 54 55 extern(D) bool doCond(Expression[] e) 56 { 57 for (size_t i = 0; i < e.length && !stop; i++) 58 doCond(e[i]); 59 return stop; 60 } 61 62 bool applyTo(Expression e) 63 { 64 e.accept(v); 65 stop = v.stop; 66 return true; 67 } 68 69 override void visit(Expression e) 70 { 71 applyTo(e); 72 } 73 74 override void visit(NewExp e) 75 { 76 //printf("NewExp::apply(): %s\n", toChars()); 77 doCond(e.thisexp) || doCond(e.arguments.peekSlice()) || applyTo(e); 78 } 79 80 override void visit(NewAnonClassExp e) 81 { 82 //printf("NewAnonClassExp::apply(): %s\n", toChars()); 83 doCond(e.thisexp) || doCond(e.arguments.peekSlice()) || applyTo(e); 84 } 85 86 override void visit(TypeidExp e) 87 { 88 doCond(isExpression(e.obj)) || applyTo(e); 89 } 90 91 override void visit(UnaExp e) 92 { 93 doCond(e.e1) || applyTo(e); 94 } 95 96 override void visit(BinExp e) 97 { 98 doCond(e.e1) || doCond(e.e2) || applyTo(e); 99 } 100 101 override void visit(AssertExp e) 102 { 103 //printf("CallExp::apply(apply_fp_t fp, void *param): %s\n", toChars()); 104 doCond(e.e1) || doCond(e.msg) || applyTo(e); 105 } 106 107 override void visit(CallExp e) 108 { 109 //printf("CallExp::apply(apply_fp_t fp, void *param): %s\n", toChars()); 110 doCond(e.e1) || doCond(e.arguments.peekSlice()) || applyTo(e); 111 } 112 113 override void visit(ArrayExp e) 114 { 115 //printf("ArrayExp::apply(apply_fp_t fp, void *param): %s\n", toChars()); 116 doCond(e.e1) || doCond(e.arguments.peekSlice()) || applyTo(e); 117 } 118 119 override void visit(SliceExp e) 120 { 121 doCond(e.e1) || doCond(e.lwr) || doCond(e.upr) || applyTo(e); 122 } 123 124 override void visit(ArrayLiteralExp e) 125 { 126 doCond(e.basis) || doCond(e.elements.peekSlice()) || applyTo(e); 127 } 128 129 override void visit(AssocArrayLiteralExp e) 130 { 131 doCond(e.keys.peekSlice()) || doCond(e.values.peekSlice()) || applyTo(e); 132 } 133 134 override void visit(StructLiteralExp e) 135 { 136 if (e.stageflags & stageApply) 137 return; 138 const old = e.stageflags; 139 e.stageflags |= stageApply; 140 doCond(e.elements.peekSlice()) || applyTo(e); 141 e.stageflags = old; 142 } 143 144 override void visit(TupleExp e) 145 { 146 doCond(e.e0) || doCond(e.exps.peekSlice()) || applyTo(e); 147 } 148 149 override void visit(CondExp e) 150 { 151 doCond(e.econd) || doCond(e.e1) || doCond(e.e2) || applyTo(e); 152 } 153 }