1 /*
2  * Copyright (c) Facebook, Inc. and its affiliates.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <thrift/compiler/ast/visitor.h>
18 
19 namespace apache {
20 namespace thrift {
21 namespace compiler {
22 
traverse(t_program * const program)23 void visitor::traverse(t_program* const program) {
24   visit_and_recurse(program);
25 }
26 
visit(t_program * const)27 bool visitor::visit(t_program* const /* program */) {
28   return true;
29 }
30 
visit(t_service * const)31 bool visitor::visit(t_service* const /* service */) {
32   return true;
33 }
34 
visit(t_enum * const)35 bool visitor::visit(t_enum* const /* tenum */) {
36   return true;
37 }
38 
visit(t_struct * const)39 bool visitor::visit(t_struct* const /* tstruct */) {
40   return true;
41 }
42 
visit(t_field * const)43 bool visitor::visit(t_field* const /* tfield */) {
44   return true;
45 }
46 
visit(t_const * const)47 bool visitor::visit(t_const* const /* tconst */) {
48   return true;
49 }
50 
visit_and_recurse(t_program * const program)51 void visitor::visit_and_recurse(t_program* const program) {
52   if (visit(program)) {
53     recurse(program);
54   }
55 }
56 
visit_and_recurse(t_service * const service)57 void visitor::visit_and_recurse(t_service* const service) {
58   if (visit(service)) {
59     recurse(service);
60   }
61 }
62 
visit_and_recurse(t_enum * const tenum)63 void visitor::visit_and_recurse(t_enum* const tenum) {
64   if (visit(tenum)) {
65     recurse(tenum);
66   }
67 }
68 
visit_and_recurse(t_struct * const tstruct)69 void visitor::visit_and_recurse(t_struct* const tstruct) {
70   if (visit(tstruct)) {
71     recurse(tstruct);
72   }
73 }
74 
visit_and_recurse(t_field * const tfield)75 void visitor::visit_and_recurse(t_field* const tfield) {
76   if (visit(tfield)) {
77     recurse(tfield);
78   }
79 }
80 
visit_and_recurse(t_const * const tconst)81 void visitor::visit_and_recurse(t_const* const tconst) {
82   if (visit(tconst)) {
83     recurse(tconst);
84   }
85 }
86 
recurse(t_program * const program)87 void visitor::recurse(t_program* const program) {
88   for (auto* const service : program->services()) {
89     visit_and_recurse(service);
90   }
91   for (auto* const tenum : program->enums()) {
92     visit_and_recurse(tenum);
93   }
94   for (auto* tstruct : program->structs()) {
95     visit_and_recurse(tstruct);
96   }
97   for (auto* texception : program->exceptions()) {
98     visit_and_recurse(texception);
99   }
100   for (auto* tconst : program->consts()) {
101     visit_and_recurse(tconst);
102   }
103 }
104 
recurse(t_service * const)105 void visitor::recurse(t_service* const /* service */) {
106   // partial implementation - that's the end of the line for now
107 }
108 
recurse(t_enum * const)109 void visitor::recurse(t_enum* const /* tenum */) {
110   // partial implementation - that's the end of the line for now
111 }
112 
recurse(t_struct * const tstruct)113 void visitor::recurse(t_struct* const tstruct) {
114   for (auto* tfield : tstruct->get_members()) {
115     visit_and_recurse(tfield);
116   }
117 }
118 
recurse(t_field * const)119 void visitor::recurse(t_field* const /* tfield */) {
120   // partial implementation - that's the end of the line for now
121 }
122 
recurse(t_const * const)123 void visitor::recurse(t_const* const /* tconst */) {
124   // partial implementation - that's the end of the line for now
125 }
126 
interleaved_visitor(std::vector<visitor * > visitors)127 interleaved_visitor::interleaved_visitor(std::vector<visitor*> visitors)
128     : visitor(), visitors_(std::move(visitors)) {}
129 
visit_and_recurse(t_program * const program)130 void interleaved_visitor::visit_and_recurse(t_program* const program) {
131   visit_and_recurse_gen(program);
132 }
133 
visit_and_recurse(t_service * const service)134 void interleaved_visitor::visit_and_recurse(t_service* const service) {
135   visit_and_recurse_gen(service);
136 }
137 
visit_and_recurse(t_enum * const tenum)138 void interleaved_visitor::visit_and_recurse(t_enum* const tenum) {
139   visit_and_recurse_gen(tenum);
140 }
141 
visit_and_recurse(t_struct * const tstruct)142 void interleaved_visitor::visit_and_recurse(t_struct* const tstruct) {
143   visit_and_recurse_gen(tstruct);
144 }
145 
visit_and_recurse(t_field * const tfield)146 void interleaved_visitor::visit_and_recurse(t_field* const tfield) {
147   visit_and_recurse_gen(tfield);
148 }
149 
visit_and_recurse(t_const * const tconst)150 void interleaved_visitor::visit_and_recurse(t_const* const tconst) {
151   visit_and_recurse_gen(tconst);
152 }
153 
154 template <typename Visitee>
visit_and_recurse_gen(Visitee * const visitee)155 void interleaved_visitor::visit_and_recurse_gen(Visitee* const visitee) {
156   // track the set of visitors which return true from visit()
157   auto rec_mask = std::vector<bool>(visitors_.size());
158   auto any = false;
159   for (size_t i = 0; i < visitors_.size(); ++i) {
160     auto const rec = rec_mask_[i] && visitors_[i]->visit(visitee);
161     rec_mask[i] = rec;
162     any = any || rec;
163   }
164   // only recurse with the set of visitors which return true from visit()
165   if (any) {
166     std::swap(rec_mask_, rec_mask);
167     recurse(visitee);
168     std::swap(rec_mask_, rec_mask);
169   }
170 }
171 
172 } // namespace compiler
173 } // namespace thrift
174 } // namespace apache
175