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