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