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 }