1 /**
2  * Provides a depth-first statement visitor.
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/sparse.d, _sparse.d)
8  * Documentation:  https://dlang.org/phobos/dmd_sapply.html
9  * Coverage:    https://codecov.io/gh/dlang/dmd/src/master/src/dmd/sapply.d
10  */
11 
12 module dmd.sapply;
13 
14 import dmd.statement;
15 import dmd.visitor;
16 
17 bool walkPostorder(Statement s, StoppableVisitor v)
18 {
19     scope PostorderStatementVisitor pv = new PostorderStatementVisitor(v);
20     s.accept(pv);
21     return v.stop;
22 }
23 
24 /**************************************
25  * A Statement tree walker that will visit each Statement s in the tree,
26  * in depth-first evaluation order, and call fp(s,param) on it.
27  * fp() signals whether the walking continues with its return value:
28  * Returns:
29  *      0       continue
30  *      1       done
31  * It's a bit slower than using virtual functions, but more encapsulated and less brittle.
32  * Creating an iterator for this would be much more complex.
33  */
34 private extern (C++) final class PostorderStatementVisitor : StoppableVisitor
35 {
36     alias visit = typeof(super).visit;
37 public:
38     StoppableVisitor v;
39 
40     extern (D) this(StoppableVisitor v) scope @safe
41     {
42         this.v = v;
43     }
44 
45     bool doCond(Statement s)
46     {
47         if (!stop && s)
48             s.accept(this);
49         return stop;
50     }
51 
52     bool applyTo(Statement s)
53     {
54         s.accept(v);
55         stop = v.stop;
56         return true;
57     }
58 
59     override void visit(Statement s)
60     {
61         applyTo(s);
62     }
63 
64     override void visit(PeelStatement s)
65     {
66         doCond(s.s) || applyTo(s);
67     }
68 
69     override void visit(CompoundStatement s)
70     {
71         for (size_t i = 0; i < s.statements.length; i++)
72             if (doCond((*s.statements)[i]))
73                 return;
74         applyTo(s);
75     }
76 
77     override void visit(UnrolledLoopStatement s)
78     {
79         for (size_t i = 0; i < s.statements.length; i++)
80             if (doCond((*s.statements)[i]))
81                 return;
82         applyTo(s);
83     }
84 
85     override void visit(ScopeStatement s)
86     {
87         doCond(s.statement) || applyTo(s);
88     }
89 
90     override void visit(WhileStatement s)
91     {
92         doCond(s._body) || applyTo(s);
93     }
94 
95     override void visit(DoStatement s)
96     {
97         doCond(s._body) || applyTo(s);
98     }
99 
100     override void visit(ForStatement s)
101     {
102         doCond(s._init) || doCond(s._body) || applyTo(s);
103     }
104 
105     override void visit(ForeachStatement s)
106     {
107         doCond(s._body) || applyTo(s);
108     }
109 
110     override void visit(ForeachRangeStatement s)
111     {
112         doCond(s._body) || applyTo(s);
113     }
114 
115     override void visit(IfStatement s)
116     {
117         doCond(s.ifbody) || doCond(s.elsebody) || applyTo(s);
118     }
119 
120     override void visit(PragmaStatement s)
121     {
122         doCond(s._body) || applyTo(s);
123     }
124 
125     override void visit(SwitchStatement s)
126     {
127         doCond(s._body) || applyTo(s);
128     }
129 
130     override void visit(CaseStatement s)
131     {
132         doCond(s.statement) || applyTo(s);
133     }
134 
135     override void visit(DefaultStatement s)
136     {
137         doCond(s.statement) || applyTo(s);
138     }
139 
140     override void visit(SynchronizedStatement s)
141     {
142         doCond(s._body) || applyTo(s);
143     }
144 
145     override void visit(WithStatement s)
146     {
147         doCond(s._body) || applyTo(s);
148     }
149 
150     override void visit(TryCatchStatement s)
151     {
152         if (doCond(s._body))
153             return;
154         for (size_t i = 0; i < s.catches.length; i++)
155             if (doCond((*s.catches)[i].handler))
156                 return;
157         applyTo(s);
158     }
159 
160     override void visit(TryFinallyStatement s)
161     {
162         doCond(s._body) || doCond(s.finalbody) || applyTo(s);
163     }
164 
165     override void visit(ScopeGuardStatement s)
166     {
167         doCond(s.statement) || applyTo(s);
168     }
169 
170     override void visit(DebugStatement s)
171     {
172         doCond(s.statement) || applyTo(s);
173     }
174 
175     override void visit(LabelStatement s)
176     {
177         doCond(s.statement) || applyTo(s);
178     }
179 }