Line | Branch | Exec | Source |
---|---|---|---|
1 | // Copyright Contributors to the OpenVDB Project | ||
2 | // SPDX-License-Identifier: MPL-2.0 | ||
3 | |||
4 | /// @file ast/PrintTree.cc | ||
5 | |||
6 | #include "AST.h" | ||
7 | #include "PrintTree.h" | ||
8 | #include "Tokens.h" | ||
9 | #include "Visitor.h" | ||
10 | |||
11 | #include <ostream> | ||
12 | |||
13 | namespace openvdb { | ||
14 | OPENVDB_USE_VERSION_NAMESPACE | ||
15 | namespace OPENVDB_VERSION_NAME { | ||
16 | |||
17 | namespace ax { | ||
18 | namespace ast { | ||
19 | |||
20 | struct PrintVisitor : public ast::Visitor<PrintVisitor> | ||
21 | { | ||
22 | PrintVisitor(std::ostream& os, | ||
23 | const bool numberStatements = true, | ||
24 | const char* indent = " ") | ||
25 | ✗ | : mOs(os) | |
26 | , mLevel(0) | ||
27 | ✗ | , mStatementNumber(numberStatements ? 0 : -1) | |
28 | ✗ | , mIndent(indent) {} | |
29 | ~PrintVisitor() = default; | ||
30 | |||
31 | using ast::Visitor<PrintVisitor>::traverse; | ||
32 | using ast::Visitor<PrintVisitor>::visit; | ||
33 | |||
34 | inline bool postOrderNodes() const { return false; } | ||
35 | |||
36 | inline void indent() { | ||
37 | ✗ | for (int i(0); i < mLevel; ++i) mOs << mIndent; | |
38 | } | ||
39 | |||
40 | ✗ | bool traverse(NodeType<ast::StatementList>* stmntl) { | |
41 | ✗ | this->visit(stmntl); | |
42 | |||
43 | const size_t children = stmntl->children(); | ||
44 | ✗ | ++mLevel; | |
45 | ✗ | if (children == 0) { | |
46 | indent(); | ||
47 | ✗ | mOs << "<empty>\n"; | |
48 | } | ||
49 | else { | ||
50 | ✗ | for (size_t i = 0; i < children; ++i) { | |
51 | indent(); | ||
52 | ✗ | if (mStatementNumber >= 0) { | |
53 | ✗ | mOs << '[' << mStatementNumber++ << "] "; | |
54 | } | ||
55 | ✗ | this->derived().traverse(stmntl->child(i)); | |
56 | ✗ | mOs << '\n'; | |
57 | } | ||
58 | } | ||
59 | ✗ | --mLevel; | |
60 | ✗ | return true; | |
61 | } | ||
62 | |||
63 | ✗ | bool traverse(NodeType<ast::Block>* block) { | |
64 | indent(); | ||
65 | ✗ | this->visit(block); | |
66 | |||
67 | const size_t children = block->children(); | ||
68 | ✗ | ++mLevel; | |
69 | ✗ | if (children == 0) { | |
70 | indent(); | ||
71 | ✗ | mOs << "<empty>\n"; | |
72 | } | ||
73 | else { | ||
74 | ✗ | for (size_t i = 0; i < children; ++i) { | |
75 | indent(); | ||
76 | ✗ | if (mStatementNumber >= 0) { | |
77 | ✗ | mOs << '[' << mStatementNumber++ << "] "; | |
78 | } | ||
79 | ✗ | this->derived().traverse(block->child(i)); | |
80 | ✗ | mOs << '\n'; | |
81 | } | ||
82 | } | ||
83 | ✗ | --mLevel; | |
84 | ✗ | return true; | |
85 | } | ||
86 | |||
87 | ✗ | bool traverse(NodeType<ast::CommaOperator>* comma) { | |
88 | ✗ | this->visit(comma); | |
89 | const size_t children = comma->children(); | ||
90 | ✗ | ++mLevel; | |
91 | ✗ | if (children == 0) { | |
92 | indent(); | ||
93 | ✗ | mOs << "<empty>\n"; | |
94 | } | ||
95 | else { | ||
96 | ✗ | for (size_t i = 0; i < children; ++i) { | |
97 | indent(); | ||
98 | ✗ | this->derived().traverse(comma->child(i)); | |
99 | } | ||
100 | } | ||
101 | ✗ | --mLevel; | |
102 | ✗ | return true; | |
103 | } | ||
104 | |||
105 | ✗ | bool traverse(NodeType<ast::ConditionalStatement>* cond) { | |
106 | ✗ | this->visit(cond); | |
107 | ✗ | ++mLevel; | |
108 | |||
109 | indent(); | ||
110 | ✗ | mOs << "condition:\n"; | |
111 | |||
112 | ✗ | ++mLevel; | |
113 | indent(); | ||
114 | ✗ | this->traverse(cond->condition()); | |
115 | ✗ | --mLevel; | |
116 | |||
117 | indent(); | ||
118 | ✗ | mOs << "branch [true]:\n"; | |
119 | |||
120 | ✗ | this->traverse(cond->trueBranch()); | |
121 | |||
122 | ✗ | if (cond->hasFalse()) { | |
123 | indent(); | ||
124 | ✗ | mOs << "branch [false]:\n"; | |
125 | |||
126 | ✗ | this->traverse(cond->falseBranch()); | |
127 | } | ||
128 | ✗ | --mLevel; | |
129 | ✗ | return true; | |
130 | } | ||
131 | |||
132 | ✗ | bool traverse(NodeType<ast::TernaryOperator>* tern) { | |
133 | ✗ | this->visit(tern); | |
134 | ✗ | ++mLevel; | |
135 | |||
136 | indent(); | ||
137 | ✗ | mOs << "condition:\n"; | |
138 | |||
139 | ✗ | ++mLevel; | |
140 | indent(); | ||
141 | ✗ | this->traverse(tern->condition()); | |
142 | ✗ | --mLevel; | |
143 | |||
144 | indent(); | ||
145 | ✗ | mOs << "true:\n"; | |
146 | ✗ | if (tern->hasTrue()) { | |
147 | ✗ | ++mLevel; | |
148 | indent(); | ||
149 | ✗ | this->traverse(tern->trueBranch()); | |
150 | ✗ | --mLevel; | |
151 | } | ||
152 | |||
153 | indent(); | ||
154 | ✗ | mOs << "false:\n"; | |
155 | ✗ | ++mLevel; | |
156 | indent(); | ||
157 | ✗ | this->traverse(tern->falseBranch()); | |
158 | ✗ | --mLevel; | |
159 | |||
160 | ✗ | --mLevel; | |
161 | ✗ | return true; | |
162 | } | ||
163 | |||
164 | |||
165 | ✗ | bool traverse(NodeType<ast::Loop>* loop) { | |
166 | ✗ | this->visit(loop); | |
167 | ✗ | ++mLevel; | |
168 | |||
169 | ✗ | if (loop->hasInit()) { | |
170 | indent(); | ||
171 | ✗ | mOs << "init:\n"; | |
172 | |||
173 | ✗ | ++mLevel; | |
174 | indent(); | ||
175 | ✗ | this->traverse(loop->initial()); | |
176 | ✗ | --mLevel; | |
177 | } | ||
178 | |||
179 | indent(); | ||
180 | ✗ | mOs << "conditional:\n"; | |
181 | |||
182 | ✗ | ++mLevel; | |
183 | indent(); | ||
184 | ✗ | this->traverse(loop->condition()); | |
185 | ✗ | --mLevel; | |
186 | |||
187 | ✗ | if (loop->hasIter()) { | |
188 | indent(); | ||
189 | ✗ | mOs << "iterator:\n"; | |
190 | ✗ | ++mLevel; | |
191 | indent(); | ||
192 | ✗ | this->traverse(loop->iteration()); | |
193 | ✗ | --mLevel; | |
194 | } | ||
195 | |||
196 | indent(); | ||
197 | ✗ | mOs << "body:\n"; | |
198 | ✗ | this->traverse(loop->body()); | |
199 | |||
200 | ✗ | --mLevel; | |
201 | ✗ | return true; | |
202 | } | ||
203 | |||
204 | ✗ | bool traverse(NodeType<ast::AssignExpression>* asgn) { | |
205 | ✗ | this->visit(asgn); | |
206 | ✗ | ++mLevel; | |
207 | indent(); | ||
208 | ✗ | this->traverse(asgn->lhs()); | |
209 | indent(); | ||
210 | ✗ | this->traverse(asgn->rhs()); | |
211 | ✗ | --mLevel; | |
212 | ✗ | return true; | |
213 | } | ||
214 | |||
215 | ✗ | bool traverse(NodeType<ast::DeclareLocal>* asgn) { | |
216 | ✗ | this->visit(asgn); | |
217 | ✗ | ++mLevel; | |
218 | indent(); | ||
219 | this->traverse(asgn->local()); | ||
220 | ✗ | if(asgn->hasInit()) { | |
221 | indent(); | ||
222 | ✗ | mOs << "init:\n"; | |
223 | ✗ | ++mLevel; | |
224 | indent(); | ||
225 | ✗ | this->traverse(asgn->init()); | |
226 | ✗ | --mLevel; | |
227 | } | ||
228 | ✗ | --mLevel; | |
229 | ✗ | return true; | |
230 | } | ||
231 | |||
232 | ✗ | bool traverse(NodeType<ast::Crement>* crmt) { | |
233 | ✗ | this->visit(crmt); | |
234 | ✗ | ++mLevel; | |
235 | indent(); | ||
236 | ✗ | this->traverse(crmt->expression()); | |
237 | ✗ | --mLevel; | |
238 | ✗ | return true; | |
239 | } | ||
240 | |||
241 | ✗ | bool traverse(NodeType<ast::UnaryOperator>* unry) { | |
242 | ✗ | this->visit(unry); | |
243 | ✗ | ++mLevel; | |
244 | indent(); | ||
245 | ✗ | this->traverse(unry->expression()); | |
246 | ✗ | --mLevel; | |
247 | ✗ | return true; | |
248 | } | ||
249 | |||
250 | ✗ | bool traverse(NodeType<ast::BinaryOperator>* bin) { | |
251 | ✗ | this->visit(bin); | |
252 | ✗ | ++mLevel; | |
253 | indent(); | ||
254 | ✗ | this->traverse(bin->lhs()); | |
255 | indent(); | ||
256 | ✗ | this->traverse(bin->rhs()); | |
257 | ✗ | --mLevel; | |
258 | ✗ | return true; | |
259 | } | ||
260 | |||
261 | ✗ | bool traverse(NodeType<ast::Cast>* cast) { | |
262 | ✗ | this->visit(cast); | |
263 | ✗ | ++mLevel; | |
264 | indent(); | ||
265 | ✗ | this->traverse(cast->expression()); | |
266 | ✗ | --mLevel; | |
267 | ✗ | return true; | |
268 | } | ||
269 | |||
270 | ✗ | bool traverse(NodeType<ast::FunctionCall>* call) { | |
271 | ✗ | this->visit(call); | |
272 | const size_t children = call->children(); | ||
273 | ✗ | ++mLevel; | |
274 | ✗ | if (children == 0) { | |
275 | indent(); | ||
276 | ✗ | mOs << "<empty>\n"; | |
277 | } | ||
278 | else { | ||
279 | ✗ | for (size_t i = 0; i < children; ++i) { | |
280 | indent(); | ||
281 | ✗ | this->derived().traverse(call->child(i)); | |
282 | } | ||
283 | } | ||
284 | ✗ | --mLevel; | |
285 | ✗ | return true; | |
286 | } | ||
287 | |||
288 | ✗ | bool traverse(NodeType<ast::ArrayPack>* pack) { | |
289 | ✗ | this->visit(pack); | |
290 | const size_t children = pack->children(); | ||
291 | ✗ | ++mLevel; | |
292 | ✗ | if (children == 0) { | |
293 | indent(); | ||
294 | ✗ | mOs << "<empty>\n"; | |
295 | } | ||
296 | else { | ||
297 | ✗ | for (size_t i = 0; i < children; ++i) { | |
298 | indent(); | ||
299 | ✗ | this->derived().traverse(pack->child(i)); | |
300 | } | ||
301 | } | ||
302 | ✗ | --mLevel; | |
303 | ✗ | return true; | |
304 | } | ||
305 | |||
306 | ✗ | bool traverse(NodeType<ast::ArrayUnpack>* pack) { | |
307 | ✗ | this->visit(pack); | |
308 | ✗ | ++mLevel; | |
309 | indent(); | ||
310 | ✗ | mOs << "expression: "; | |
311 | ✗ | this->traverse(pack->expression()); | |
312 | indent(); | ||
313 | ✗ | mOs << "component(s) : "; | |
314 | ✗ | this->traverse(pack->component0()); | |
315 | ✗ | this->traverse(pack->component1()); | |
316 | ✗ | --mLevel; | |
317 | ✗ | return true; | |
318 | } | ||
319 | |||
320 | bool visit(const ast::StatementList* node); | ||
321 | bool visit(const ast::Block* node); | ||
322 | bool visit(const ast::ConditionalStatement* node); | ||
323 | bool visit(const ast::Loop* node); | ||
324 | bool visit(const ast::Keyword* node); | ||
325 | bool visit(const ast::AssignExpression* node); | ||
326 | bool visit(const ast::Crement* node); | ||
327 | bool visit(const ast::CommaOperator* node); | ||
328 | bool visit(const ast::UnaryOperator* node); | ||
329 | bool visit(const ast::BinaryOperator* node); | ||
330 | bool visit(const ast::TernaryOperator* node); | ||
331 | bool visit(const ast::Cast* node); | ||
332 | bool visit(const ast::FunctionCall* node); | ||
333 | bool visit(const ast::Attribute* node); | ||
334 | bool visit(const ast::ExternalVariable* node); | ||
335 | bool visit(const ast::DeclareLocal* node); | ||
336 | bool visit(const ast::Local* node); | ||
337 | bool visit(const ast::ArrayUnpack* node); | ||
338 | bool visit(const ast::ArrayPack* node); | ||
339 | |||
340 | bool visit(const ast::Value<bool>* node) { | ||
341 | ✗ | return this->visitValue(node); | |
342 | } | ||
343 | bool visit(const ast::Value<int16_t>* node) { | ||
344 | ✗ | return this->visitValue(node); | |
345 | } | ||
346 | bool visit(const ast::Value<int32_t>* node) { | ||
347 | ✗ | return this->visitValue(node); | |
348 | } | ||
349 | bool visit(const ast::Value<int64_t>* node) { | ||
350 | ✗ | return this->visitValue(node); | |
351 | } | ||
352 | bool visit(const ast::Value<float>* node) { | ||
353 | ✗ | return this->visitValue(node); | |
354 | } | ||
355 | bool visit(const ast::Value<double>* node) { | ||
356 | ✗ | return this->visitValue(node); | |
357 | } | ||
358 | bool visit(const ast::Value<std::string>* node) { | ||
359 | ✗ | return this->visitValue(node); | |
360 | } | ||
361 | |||
362 | protected: | ||
363 | template <typename T> | ||
364 | bool visitValue(const ast::Value<T>* node); | ||
365 | |||
366 | private: | ||
367 | std::ostream& mOs; | ||
368 | int mLevel; | ||
369 | int64_t mStatementNumber; | ||
370 | const char* mIndent; | ||
371 | }; | ||
372 | |||
373 | ✗ | bool PrintVisitor::visit(const ast::StatementList* node) | |
374 | { | ||
375 | ✗ | mOs << node->nodename() << ": " << node->size() << " statement(s)" << '\n'; | |
376 | ✗ | return true; | |
377 | } | ||
378 | |||
379 | |||
380 | ✗ | bool PrintVisitor::visit(const ast::Block* node) | |
381 | { | ||
382 | ✗ | mOs << node->nodename() << ": " << node->size() << " statement(s)" << '\n'; | |
383 | ✗ | return true; | |
384 | } | ||
385 | |||
386 | ✗ | bool PrintVisitor::visit(const ast::ConditionalStatement* node) | |
387 | { | ||
388 | ✗ | mOs << node->nodename() << ": " << (node->hasFalse() ? "two branches " : "one branch") << '\n'; | |
389 | ✗ | return true; | |
390 | } | ||
391 | |||
392 | ✗ | bool PrintVisitor::visit(const ast::AssignExpression* node) | |
393 | { | ||
394 | ✗ | mOs << node->nodename() << ": " << tokens::operatorNameFromToken(node->operation()); | |
395 | ✗ | if (node->isCompound()) mOs << '='; | |
396 | ✗ | mOs << '\n'; | |
397 | ✗ | return true; | |
398 | } | ||
399 | |||
400 | ✗ | bool PrintVisitor::visit(const ast::Loop* node) | |
401 | { | ||
402 | ✗ | mOs << tokens::loopNameFromToken(node->loopType()) <<" "<< node->nodename() << ":" << '\n'; | |
403 | ✗ | return true; | |
404 | } | ||
405 | |||
406 | ✗ | bool PrintVisitor::visit(const ast::Keyword* node) | |
407 | { | ||
408 | ✗ | mOs << node->nodename() << ": " << tokens::keywordNameFromToken(node->keyword()) << '\n'; | |
409 | ✗ | return true; | |
410 | } | ||
411 | |||
412 | ✗ | bool PrintVisitor::visit(const ast::Crement* node) | |
413 | { | ||
414 | ✗ | mOs << node->nodename() << ':'; | |
415 | ✗ | if (node->post()) mOs << " post-"; | |
416 | ✗ | else mOs << " pre-"; | |
417 | ✗ | if (node->increment()) mOs << "increment"; | |
418 | ✗ | else mOs << "decrement"; | |
419 | ✗ | mOs << '\n'; | |
420 | ✗ | return true; | |
421 | } | ||
422 | |||
423 | ✗ | bool PrintVisitor::visit(const ast::CommaOperator* node) | |
424 | { | ||
425 | ✗ | mOs << node->nodename() << ": " << node->size() << " element(s)" << '\n'; | |
426 | ✗ | return true; | |
427 | } | ||
428 | |||
429 | ✗ | bool PrintVisitor::visit(const ast::UnaryOperator* node) | |
430 | { | ||
431 | ✗ | mOs << node->nodename() << ": " << tokens::operatorNameFromToken(node->operation()) << '\n'; | |
432 | ✗ | return true; | |
433 | } | ||
434 | |||
435 | ✗ | bool PrintVisitor::visit(const ast::BinaryOperator* node) | |
436 | { | ||
437 | ✗ | mOs << node->nodename() << ": " << tokens::operatorNameFromToken(node->operation()) << '\n'; | |
438 | ✗ | return true; | |
439 | } | ||
440 | |||
441 | ✗ | bool PrintVisitor::visit(const ast::TernaryOperator* node) | |
442 | { | ||
443 | ✗ | mOs << node->nodename() << ":\n"; | |
444 | ✗ | return true; | |
445 | } | ||
446 | |||
447 | ✗ | bool PrintVisitor::visit(const ast::Cast* node) | |
448 | { | ||
449 | ✗ | mOs << node->nodename() << ": " << tokens::typeStringFromToken(node->type()) << '\n'; | |
450 | ✗ | return true; | |
451 | } | ||
452 | |||
453 | ✗ | bool PrintVisitor::visit(const ast::FunctionCall* node) | |
454 | { | ||
455 | ✗ | mOs << node->nodename() << ": " << node->name() << '\n'; | |
456 | ✗ | return true; | |
457 | } | ||
458 | |||
459 | ✗ | bool PrintVisitor::visit(const ast::Attribute* node) | |
460 | { | ||
461 | ✗ | mOs << node->nodename() << ": " << node->symbolseparator() | |
462 | ✗ | << '(' << node->typestr() << (node->inferred() ? " - inferred": "") | |
463 | ✗ | << ") " << node->name() << '\n'; | |
464 | ✗ | return true; | |
465 | } | ||
466 | |||
467 | ✗ | bool PrintVisitor::visit(const ast::DeclareLocal* node) | |
468 | { | ||
469 | ✗ | mOs << node->nodename() << ": "<< node->typestr() << '\n'; | |
470 | ✗ | return true; | |
471 | } | ||
472 | |||
473 | ✗ | bool PrintVisitor::visit(const ast::Local* node) | |
474 | { | ||
475 | ✗ | mOs << node->nodename() << ' ' << node->name() << '\n'; | |
476 | ✗ | return true; | |
477 | } | ||
478 | |||
479 | ✗ | bool PrintVisitor::visit(const ast::ArrayUnpack* node) | |
480 | { | ||
481 | ✗ | mOs << node->nodename() << '\n'; | |
482 | ✗ | return true; | |
483 | } | ||
484 | |||
485 | ✗ | bool PrintVisitor::visit(const ast::ArrayPack* node) | |
486 | { | ||
487 | ✗ | mOs << node->nodename() << ": " << node->children() << " element(s)" << '\n'; | |
488 | ✗ | return true; | |
489 | } | ||
490 | |||
491 | ✗ | bool PrintVisitor::visit(const ast::ExternalVariable* node) | |
492 | { | ||
493 | ✗ | mOs << node->nodename() << ": " << node->symbolseparator() | |
494 | ✗ | << '(' << node->typestr() << ") " << node->name() << '\n'; | |
495 | ✗ | return true; | |
496 | } | ||
497 | |||
498 | template <typename T> | ||
499 | ✗ | bool PrintVisitor::visitValue(const ast::Value<T>* node) | |
500 | { | ||
501 | ✗ | mOs << node->nodename() << ": " << node->value() << '\n'; | |
502 | ✗ | return true; | |
503 | } | ||
504 | |||
505 | |||
506 | //////////////////////////////////////////////////////////////////////////////// | ||
507 | |||
508 | |||
509 | ✗ | void print(const ast::Node& node, | |
510 | const bool numberStatements, | ||
511 | std::ostream& os, | ||
512 | const char* indent) | ||
513 | { | ||
514 | PrintVisitor visitor(os, numberStatements, indent); | ||
515 | ✗ | visitor.traverse(&node); | |
516 | } | ||
517 | |||
518 | |||
519 | //////////////////////////////////////////////////////////////////////////////// | ||
520 | //////////////////////////////////////////////////////////////////////////////// | ||
521 | |||
522 | struct ReprintVisitor : public ast::Visitor<ReprintVisitor> | ||
523 | { | ||
524 | ReprintVisitor(std::ostream& os, const char* indent = " ") | ||
525 | 15 | : mOs(os) | |
526 | , mLevel(0) | ||
527 | 15 | , mIndent(indent) {} | |
528 | ~ReprintVisitor() = default; | ||
529 | |||
530 | using ast::Visitor<ReprintVisitor>::traverse; | ||
531 | using ast::Visitor<ReprintVisitor>::visit; | ||
532 | |||
533 | inline bool postOrderNodes() const { return false; } | ||
534 | |||
535 | inline void indent() { | ||
536 |
10/10✓ Branch 0 taken 6 times.
✓ Branch 1 taken 2 times.
✓ Branch 3 taken 5 times.
✓ Branch 4 taken 3 times.
✓ Branch 6 taken 23 times.
✓ Branch 7 taken 28 times.
✓ Branch 9 taken 96 times.
✓ Branch 10 taken 73 times.
✓ Branch 12 taken 23 times.
✓ Branch 13 taken 28 times.
|
287 | for (int i = 0; i < mLevel; ++i) mOs << mIndent; |
537 | } | ||
538 | |||
539 | 28 | bool traverse(NodeType<ast::Block>* block) { | |
540 | const size_t children = block->children(); | ||
541 | indent(); | ||
542 | 28 | mOs << '{' << '\n'; | |
543 | 28 | ++mLevel; | |
544 |
2/2✓ Branch 0 taken 73 times.
✓ Branch 1 taken 28 times.
|
101 | for (size_t i = 0; i < children; ++i) { |
545 | indent(); | ||
546 | 73 | this->derived().traverse(block->child(i)); | |
547 | 73 | const auto type = block->child(i)->nodetype(); | |
548 | 73 | if (type != ast::Node::ConditionalStatementNode && | |
549 |
2/2✓ Branch 0 taken 63 times.
✓ Branch 1 taken 10 times.
|
73 | type != ast::Node::LoopNode) { |
550 | 63 | mOs << ';' << '\n'; | |
551 | } | ||
552 | } | ||
553 | 28 | --mLevel; | |
554 | indent(); | ||
555 | 28 | mOs << '}' << '\n'; | |
556 | 28 | return true; | |
557 | } | ||
558 | |||
559 |
1/2✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
|
5 | bool traverse(NodeType<ast::StatementList>* stmtl) { |
560 | const size_t children = stmtl->children(); | ||
561 |
1/2✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
|
5 | if (children == 0) return true; |
562 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
|
5 | if (children == 1) { |
563 | ✗ | this->derived().traverse(stmtl->child(0)); | |
564 | ✗ | mOs << ';'; | |
565 | ✗ | return true; | |
566 | } | ||
567 | |||
568 | // multiple statments | ||
569 | |||
570 |
1/2✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
|
5 | if (stmtl->child(0)->nodetype() == ast::Node::DeclareLocalNode) { |
571 | // it's a declaration list, manually handle the child nodes. | ||
572 | // This is to handle declarations within loop inits such as | ||
573 | // "for (int a = 0, b = 1;;)". Without this, it would be | ||
574 | // reprinted as "for (int a=0; int b=1; ;;)" | ||
575 | |||
576 | // visit the first child completely | ||
577 | 5 | this->derived().traverse(stmtl->child(0)); | |
578 | |||
579 |
2/2✓ Branch 0 taken 5 times.
✓ Branch 1 taken 5 times.
|
10 | for (size_t i = 1; i < children; ++i) { |
580 | // all child statements should be declare locals | ||
581 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
|
5 | assert(stmtl->child(i)->nodetype() == |
582 | ast::Node::DeclareLocalNode); | ||
583 | |||
584 | 5 | mOs << ", "; | |
585 | 5 | this->derived().traverse(stmtl->child(i)->child(0)); // local | |
586 | 5 | auto* init = stmtl->child(i)->child(1); // init | |
587 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 4 times.
|
5 | if (init) { |
588 | 1 | mOs << " = "; | |
589 | 1 | this->derived().traverse(init); | |
590 | } | ||
591 | } | ||
592 | return true; | ||
593 | } | ||
594 | |||
595 | // otherwise traverse as normal | ||
596 | |||
597 | ✗ | for (size_t i = 0; i < children; ++i) { | |
598 | ✗ | this->derived().traverse(stmtl->child(i)); | |
599 | ✗ | if (i != children-1) mOs << ';' << ' '; | |
600 | } | ||
601 | return true; | ||
602 | } | ||
603 | |||
604 | 9 | bool traverse(NodeType<ast::CommaOperator>* exprl) { | |
605 | 9 | mOs << '('; | |
606 | const size_t children = exprl->children(); | ||
607 |
2/2✓ Branch 0 taken 21 times.
✓ Branch 1 taken 9 times.
|
30 | for (size_t i = 0; i < children; ++i) { |
608 | 21 | this->derived().traverse(exprl->child(i)); | |
609 |
2/2✓ Branch 0 taken 12 times.
✓ Branch 1 taken 9 times.
|
21 | if (i != children-1) mOs << ',' << ' '; |
610 | } | ||
611 | 9 | mOs << ')'; | |
612 | 9 | return true; | |
613 | } | ||
614 | |||
615 | 4 | bool traverse(NodeType<ast::ConditionalStatement>* cond) { | |
616 | 4 | mOs << "if ("; | |
617 | 4 | this->traverse(cond->condition()); | |
618 | 4 | mOs << ")\n"; | |
619 | 4 | this->traverse(cond->trueBranch()); | |
620 | |||
621 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1 times.
|
4 | if (cond->hasFalse()) { |
622 | indent(); | ||
623 | 3 | mOs << "else\n"; | |
624 | 3 | this->traverse(cond->falseBranch()); | |
625 | } | ||
626 | 4 | return true; | |
627 | } | ||
628 | |||
629 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 4 times.
|
6 | bool traverse(NodeType<ast::Loop>* loop) { |
630 | const ast::tokens::LoopToken loopType = loop->loopType(); | ||
631 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 4 times.
|
6 | if (loopType == ast::tokens::LoopToken::FOR) { |
632 | 2 | mOs << "for ("; | |
633 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | if (loop->hasInit()) this->traverse(loop->initial()); |
634 | 2 | mOs << "; "; | |
635 | 2 | this->traverse(loop->condition()); | |
636 | 2 | mOs << "; "; | |
637 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | if (loop->hasIter()) this->traverse(loop->iteration()); |
638 | 2 | mOs << ")\n"; | |
639 | 2 | this->traverse(loop->body()); | |
640 | } | ||
641 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
|
4 | else if (loopType == ast::tokens::LoopToken::DO) { |
642 | 2 | mOs << "do\n"; | |
643 | 2 | this->traverse(loop->body()); | |
644 | indent(); | ||
645 | 2 | mOs << "while ("; | |
646 | 2 | this->traverse(loop->condition()); | |
647 | 2 | mOs << ")\n"; | |
648 | } | ||
649 | else { | ||
650 | 2 | mOs << "while ("; | |
651 | 2 | this->traverse(loop->condition()); | |
652 | 2 | mOs << ")\n"; | |
653 | 2 | this->traverse(loop->body()); | |
654 | } | ||
655 | 6 | return true; | |
656 | } | ||
657 | |||
658 | 16 | bool traverse(NodeType<ast::AssignExpression>* asgn) { | |
659 | 16 | this->traverse(asgn->lhs()); | |
660 | 16 | this->visit(asgn); | |
661 | 16 | this->traverse(asgn->rhs()); | |
662 | 16 | return true; | |
663 | } | ||
664 | |||
665 | 8 | bool traverse(NodeType<ast::DeclareLocal>* decl) { | |
666 | 8 | this->visit(decl); | |
667 | 8 | this->visit(decl->local()); | |
668 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 7 times.
|
8 | if (decl->hasInit()) { |
669 | 1 | mOs <<" = "; | |
670 | 1 | this->traverse(decl->init()); | |
671 | } | ||
672 | 8 | return true; | |
673 | } | ||
674 | |||
675 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 2 times.
|
6 | bool traverse(NodeType<ast::Crement>* crmt) { |
676 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 2 times.
|
6 | if (crmt->pre()) this->visit(crmt); |
677 | 6 | this->traverse(crmt->expression()); | |
678 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 4 times.
|
6 | if (crmt->post()) this->visit(crmt); |
679 | 6 | return true; | |
680 | } | ||
681 | |||
682 | ✗ | bool traverse(NodeType<ast::UnaryOperator>* unry) { | |
683 | ✗ | this->visit(unry); | |
684 | ✗ | this->traverse(unry->expression()); | |
685 | ✗ | return true; | |
686 | } | ||
687 | |||
688 | 28 | bool traverse(NodeType<ast::BinaryOperator>* bin) { | |
689 | // The AST currently doesn't store what expressions were encapsulated | ||
690 | // by parenthesis and instead infers precedences from the token order | ||
691 | // set out in the parser. This means that traversal determines precedence. | ||
692 | // Unfortunately, statements like "a+b+c" and "a+(b+c)" both get re-printed | ||
693 | // as "a+b+c". For now, every binary expression is encapsulated to | ||
694 | // ensure the operation order is preserved, resulting in (a+(b+c)) for | ||
695 | // the above example. | ||
696 | 28 | mOs << '('; | |
697 | 28 | this->traverse(bin->lhs()); | |
698 | 28 | this->visit(bin); | |
699 | 28 | this->traverse(bin->rhs()); | |
700 | 28 | mOs << ')'; | |
701 | 28 | return true; | |
702 | } | ||
703 | |||
704 | 4 | bool traverse(NodeType<ast::TernaryOperator>* tern) { | |
705 | 4 | this->traverse(tern->condition()); | |
706 | 4 | mOs << " ?"; | |
707 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1 times.
|
4 | if (tern->hasTrue()) { |
708 | 3 | mOs << ' '; | |
709 | 3 | this->traverse(tern->trueBranch()); | |
710 | 3 | mOs << ' '; | |
711 | } | ||
712 | 4 | mOs << ": "; | |
713 | 4 | this->traverse(tern->falseBranch()); | |
714 | 4 | return true; | |
715 | } | ||
716 | |||
717 | ✗ | bool traverse(NodeType<ast::Cast>* cast) { | |
718 | ✗ | this->visit(cast); | |
719 | ✗ | mOs << '('; | |
720 | ✗ | this->traverse(cast->expression()); | |
721 | ✗ | mOs << ')'; | |
722 | ✗ | return true; | |
723 | } | ||
724 | |||
725 | ✗ | bool traverse(NodeType<ast::FunctionCall>* call) { | |
726 | ✗ | this->visit(call); | |
727 | ✗ | mOs << '('; | |
728 | const size_t children = call->children(); | ||
729 | ✗ | for (size_t i = 0; i < children; ++i) { | |
730 | ✗ | this->derived().traverse(call->child(i)); | |
731 | ✗ | if (i != children-1) mOs << ',' << ' '; | |
732 | } | ||
733 | ✗ | mOs << ')'; | |
734 | ✗ | return true; | |
735 | } | ||
736 | |||
737 | 3 | bool traverse(NodeType<ast::ArrayPack>* pack) { | |
738 | 3 | mOs << '{'; | |
739 | const size_t children = pack->children(); | ||
740 |
2/2✓ Branch 0 taken 8 times.
✓ Branch 1 taken 3 times.
|
11 | for (size_t i = 0; i < children; ++i) { |
741 | 8 | this->derived().traverse(pack->child(i)); | |
742 |
2/2✓ Branch 0 taken 5 times.
✓ Branch 1 taken 3 times.
|
8 | if (i != children-1) mOs << ',' << ' '; |
743 | } | ||
744 | 3 | mOs << '}'; | |
745 | 3 | return true; | |
746 | } | ||
747 | |||
748 | 9 | bool traverse(NodeType<ast::ArrayUnpack>* pack) { | |
749 | 9 | this->traverse(pack->expression()); | |
750 | 9 | mOs << '['; | |
751 | 9 | this->traverse(pack->component0()); | |
752 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 7 times.
|
9 | if (pack->component1()) { |
753 | 2 | mOs << ',' << ' '; | |
754 | 2 | this->traverse(pack->component1()); | |
755 | } | ||
756 | 9 | mOs << ']'; | |
757 | 9 | return true; | |
758 | } | ||
759 | |||
760 | bool visit(const ast::AssignExpression* node); | ||
761 | bool visit(const ast::Crement* node); | ||
762 | bool visit(const ast::UnaryOperator* node); | ||
763 | bool visit(const ast::BinaryOperator* node); | ||
764 | bool visit(const ast::Cast* node); | ||
765 | bool visit(const ast::FunctionCall* node); | ||
766 | bool visit(const ast::Attribute* node); | ||
767 | bool visit(const ast::ExternalVariable* node); | ||
768 | bool visit(const ast::DeclareLocal* node); | ||
769 | bool visit(const ast::Local* node); | ||
770 | bool visit(const ast::Keyword* node); | ||
771 | |||
772 | bool visit(const ast::Value<bool>* node) { | ||
773 | 4 | return this->visitValue(node); | |
774 | } | ||
775 | bool visit(const ast::Value<int16_t>* node) { | ||
776 | ✗ | return this->visitValue(node); | |
777 | } | ||
778 | bool visit(const ast::Value<int32_t>* node) { | ||
779 | 22 | return this->visitValue(node); | |
780 | } | ||
781 | bool visit(const ast::Value<int64_t>* node) { | ||
782 | ✗ | return this->visitValue(node); | |
783 | } | ||
784 | bool visit(const ast::Value<float>* node) { | ||
785 | ✗ | return this->visitValue(node); | |
786 | } | ||
787 | bool visit(const ast::Value<double>* node) { | ||
788 | ✗ | return this->visitValue(node); | |
789 | } | ||
790 | bool visit(const ast::Value<std::string>* node) { | ||
791 | ✗ | return this->visitValue(node); | |
792 | } | ||
793 | |||
794 | protected: | ||
795 | template <typename T> | ||
796 | bool visitValue(const ast::Value<T>* node); | ||
797 | private: | ||
798 | std::ostream& mOs; | ||
799 | int mLevel; | ||
800 | const char* mIndent; | ||
801 | }; | ||
802 | |||
803 | |||
804 | 16 | bool ReprintVisitor::visit(const ast::AssignExpression* node) | |
805 | { | ||
806 |
2/2✓ Branch 2 taken 10 times.
✓ Branch 3 taken 6 times.
|
32 | mOs << ' ' << tokens::operatorNameFromToken(node->operation()); |
807 |
2/2✓ Branch 0 taken 10 times.
✓ Branch 1 taken 6 times.
|
16 | if (node->isCompound()) mOs << '='; |
808 | 16 | mOs << ' '; | |
809 | 16 | return true; | |
810 | } | ||
811 | |||
812 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3 times.
|
6 | bool ReprintVisitor::visit(const ast::Crement* node) |
813 | { | ||
814 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3 times.
|
6 | if (node->increment()) mOs << "++"; |
815 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3 times.
|
6 | if (node->decrement()) mOs << "--"; |
816 | 6 | return true; | |
817 | } | ||
818 | |||
819 | ✗ | bool ReprintVisitor::visit(const ast::UnaryOperator* node) | |
820 | { | ||
821 | ✗ | mOs << tokens::operatorNameFromToken(node->operation()); | |
822 | ✗ | return true; | |
823 | } | ||
824 | |||
825 | 28 | bool ReprintVisitor::visit(const ast::BinaryOperator* node) | |
826 | { | ||
827 | 56 | mOs << ' ' << tokens::operatorNameFromToken(node->operation()) << ' '; | |
828 | 28 | return true; | |
829 | } | ||
830 | |||
831 | ✗ | bool ReprintVisitor::visit(const ast::Cast* node) | |
832 | { | ||
833 | ✗ | mOs << node->typestr(); | |
834 | ✗ | return true; | |
835 | } | ||
836 | |||
837 | ✗ | bool ReprintVisitor::visit(const ast::FunctionCall* node) | |
838 | { | ||
839 | ✗ | mOs << node->name(); | |
840 | ✗ | return true; | |
841 | } | ||
842 | |||
843 | 5 | bool ReprintVisitor::visit(const ast::Attribute* node) | |
844 | { | ||
845 |
1/2✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
|
10 | mOs << node->typestr() << node->symbolseparator() << node->name(); |
846 | 5 | return true; | |
847 | } | ||
848 | |||
849 | 8 | bool ReprintVisitor::visit(const ast::DeclareLocal* node) | |
850 | { | ||
851 |
1/2✓ Branch 2 taken 8 times.
✗ Branch 3 not taken.
|
16 | mOs << node->typestr() << " "; |
852 | 8 | return true; | |
853 | } | ||
854 | |||
855 | 122 | bool ReprintVisitor::visit(const ast::Local* node) | |
856 | { | ||
857 | 122 | mOs << node->name(); | |
858 | 122 | return true; | |
859 | } | ||
860 | |||
861 | 3 | bool ReprintVisitor::visit(const ast::Keyword* node) | |
862 | { | ||
863 | 3 | mOs << tokens::keywordNameFromToken(node->keyword()); | |
864 | 3 | return true; | |
865 | } | ||
866 | |||
867 | 5 | bool ReprintVisitor::visit(const ast::ExternalVariable* node) | |
868 | { | ||
869 |
1/2✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
|
10 | mOs << node->typestr() << node->symbolseparator() << node->name(); |
870 | 5 | return true; | |
871 | } | ||
872 | |||
873 | template <typename T> | ||
874 | 52 | bool ReprintVisitor::visitValue(const ast::Value<T>* node) | |
875 | { | ||
876 | 8 | if (std::is_same<T, bool>::value) mOs << std::boolalpha; | |
877 | ✗ | if (std::is_same<T, std::string>::value) mOs << '"'; | |
878 | 52 | mOs << node->value(); | |
879 | 8 | if (std::is_same<T, bool>::value) mOs << std::noboolalpha; | |
880 | ✗ | if (std::is_same<T, std::string>::value) mOs << '"'; | |
881 | ✗ | if (std::is_same<T, int16_t>::value) mOs << 's'; | |
882 | ✗ | if (std::is_same<T, int64_t>::value) mOs << 'l'; | |
883 | ✗ | if (std::is_same<T, float>::value) mOs << 'f'; | |
884 | 52 | return true; | |
885 | } | ||
886 | |||
887 | //////////////////////////////////////////////////////////////////////////////// | ||
888 | |||
889 | |||
890 | 15 | void reprint(const ast::Node& node, std::ostream& os, const char* indent) | |
891 | { | ||
892 | ReprintVisitor visitor(os, indent); | ||
893 | 15 | visitor.traverse(&node); | |
894 | 15 | } | |
895 | |||
896 | |||
897 | } // namespace ast | ||
898 | } // namespace ax | ||
899 | |||
900 | } // namespace OPENVDB_VERSION_NAME | ||
901 | } // namespace openvdb | ||
902 | |||
903 | |||
904 |