source: src/CodeTools/ResolvProtoDump.cc@ 9ad5ee1

ADT aaron-thesis arm-eh ast-experimental cleanup-dtors deferred_resn enum forall-pointer-decay jacob/cs343-translation jenkins-sandbox new-ast new-ast-unique-expr no_list persistent-indexer pthread-emulation qualifiedEnum
Last change on this file since 9ad5ee1 was 4c42a5f, checked in by Aaron Moss <a3moss@…>, 7 years ago

Add function pointer types and variable decls and expressions to RPDump

  • Property mode set to 100644
File size: 21.4 KB
Line 
1//
2// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
3//
4// The contents of this file are covered under the licence agreement in the
5// file "LICENCE" distributed with Cforall.
6//
7// ResolvProtoDump.cc -- Translates CFA resolver instances into resolv-proto instances
8//
9// Author : Aaron Moss
10// Created On : Tue Sep 11 09:04:00 2018
11// Last Modified By : Aaron Moss
12// Last Modified On : Tue Sep 11 09:04:00 2018
13// Update Count : 1
14//
15
16#include <algorithm>
17#include <cctype>
18#include <iostream>
19#include <memory>
20#include <list>
21#include <set>
22#include <sstream>
23#include <string>
24#include <unordered_set>
25#include <utility>
26#include <vector>
27
28#include "Common/PassVisitor.h"
29#include "Common/utility.h"
30#include "CodeGen/OperatorTable.h"
31#include "SynTree/Declaration.h"
32#include "SynTree/Expression.h"
33#include "SynTree/Initializer.h"
34#include "SynTree/Statement.h"
35#include "SynTree/Type.h"
36
37namespace CodeTools {
38
39 /// Visitor for dumping resolver prototype output
40 class ProtoDump : public WithShortCircuiting, public WithVisitorRef<ProtoDump> {
41 std::set<std::string> decls; ///< Declarations in this scope
42 std::vector<std::string> exprs; ///< Expressions in this scope
43 std::vector<ProtoDump> subs; ///< Sub-scopes
44 std::unordered_set<std::string> closed; ///< Closed type variables
45 const ProtoDump* parent; ///< Outer lexical scope
46 std::unique_ptr<Type> rtnType; ///< Return type for this scope
47
48 public:
49 /// Default constructor for root ProtoDump
50 ProtoDump() : decls(), exprs(), subs(), closed(), parent(nullptr), rtnType(nullptr) {}
51
52 /// Child constructor
53 ProtoDump(const ProtoDump* p, Type* r)
54 : decls(), exprs(), subs(), closed(p->closed), parent(p), rtnType(r) {}
55
56 // Fix copy issues
57 ProtoDump(const ProtoDump& o)
58 : decls(o.decls), exprs(o.exprs), subs(o.subs), closed(o.closed), parent(o.parent),
59 rtnType(maybeClone(o.rtnType.get())) {}
60 ProtoDump( ProtoDump&& ) = default;
61
62 ProtoDump& operator= (const ProtoDump& o) {
63 if ( this == &o ) return *this;
64
65 decls = o.decls;
66 exprs = o.exprs;
67 subs = o.subs;
68 closed = o.closed;
69 parent = o.parent;
70 rtnType.reset( maybeClone(o.rtnType.get()) );
71
72 return *this;
73 }
74 ProtoDump& operator= (ProtoDump&&) = default;
75
76 private:
77 /// checks if this declaration is contained in the scope or one of its parents
78 bool hasDecl( const std::string& s ) const {
79 if ( decls.count( s ) ) return true;
80 if ( parent ) return parent->hasDecl( s );
81 return false;
82 }
83
84 /// adds a new declaration to this scope, providing it does not already exist
85 void addDecl( const std::string& s ) {
86 if ( ! hasDecl( s ) ) decls.insert( s );
87 }
88
89 /// adds a new expression to this scope
90 void addExpr( const std::string& s ) {
91 if ( ! s.empty() ) { exprs.emplace_back( s ); }
92 }
93
94 /// adds a new subscope to this scope, returning a reference
95 void addSub( PassVisitor<ProtoDump>&& sub ) {
96 subs.emplace_back( std::move(sub.pass) );
97 }
98
99 /// Whether lists should be separated, terminated, or preceded by their separator
100 enum septype { separated, terminated, preceded };
101
102 /// builds space-separated list of types
103 template<typename V>
104 static void build( V& visitor, const std::list< Type* >& tys, std::stringstream& ss,
105 septype mode = separated ) {
106 if ( tys.empty() ) return;
107
108 if ( mode == preceded ) { ss << ' '; }
109
110 auto it = tys.begin();
111 (*it)->accept( visitor );
112
113 while ( ++it != tys.end() ) {
114 ss << ' ';
115 (*it)->accept( visitor );
116 }
117
118 if ( mode == terminated ) { ss << ' '; }
119 }
120
121 /// builds list of types wrapped as tuple type
122 template<typename V>
123 static void buildAsTuple( V& visitor, const std::list< Type* >& tys,
124 std::stringstream& ss ) {
125 switch ( tys.size() ) {
126 case 0: ss << "#void"; break;
127 case 1: tys.front()->accept( visitor ); break;
128 default:
129 ss << "#$" << tys.size() << '<';
130 build( visitor, tys, ss );
131 ss << '>';
132 break;
133 }
134 }
135
136 /// gets types from DWT list
137 static std::list< Type* > from_decls( const std::list< DeclarationWithType* >& decls ) {
138 std::list< Type* > tys;
139 for ( auto decl : decls ) { tys.emplace_back( decl->get_type() ); }
140 return tys;
141 }
142
143 /// gets types from TypeExpr list
144 static std::list< Type* > from_exprs( const std::list< Expression* >& exprs ) {
145 std::list< Type* > tys;
146 for ( auto expr : exprs ) {
147 if ( TypeExpr* tyExpr = dynamic_cast<TypeExpr*>(expr) ) {
148 tys.emplace_back( tyExpr->type );
149 }
150 }
151 return tys;
152 }
153
154 /// builds prefixes for rp_name
155 static std::string new_prefix( const std::string& old, const char* added ) {
156 if ( old.empty() ) return std::string{"$"} + added;
157 return old + added;
158 }
159
160 /// shortens operator names
161 static void op_name( const std::string& name, std::stringstream& ss ) {
162 if ( name.compare( 0, 10, "_operator_" ) == 0 ) {
163 ss << name.substr(10);
164 } else if ( name.compare( "_constructor" ) == 0
165 || name.compare( "_destructor" ) == 0 ) {
166 ss << name.substr(1);
167 } else if ( name.compare( 0, 11, "__operator_" ) == 0 ) {
168 ss << name.substr(11);
169 } else {
170 ss << name;
171 }
172 }
173
174 /// replaces operators with resolv-proto names
175 static void rp_name( const std::string& name, std::stringstream& ss,
176 std::string&& pre = "" ) {
177 // safety check for anonymous names
178 if ( name.empty() ) {
179 ss << new_prefix(pre, "anon");
180 return;
181 }
182
183 // replace operator names
184 CodeGen::OperatorInfo info;
185 if ( CodeGen::operatorLookup( name, info ) ) {
186 ss << new_prefix(pre, "");
187 op_name( info.outputName, ss );
188 return;
189 }
190
191 // replace retval names
192 if ( name.compare( 0, 8, "_retval_" ) == 0 ) {
193 ss << new_prefix(pre, "rtn_");
194 op_name( name.substr(8), ss );
195 return;
196 }
197
198 // default to just name, with first character in lowercase
199 ss << pre
200 << (char)std::tolower( static_cast<unsigned char>(name[0]) )
201 << (name.c_str() + 1);
202 }
203
204 /// ensures type inst names are uppercase
205 static void ti_name( const std::string& name, std::stringstream& ss ) {
206 unsigned i = 0;
207 while ( i < name.size() && name[i] == '_' ) { ++i; }
208 if ( i == name.size() ) {
209 ss << "Anon";
210 return;
211 }
212 ss << (char)std::toupper( static_cast<unsigned char>(name[i]) )
213 << (name.c_str() + i + 1);
214 }
215
216 /// Visitor for printing types
217 struct TypePrinter : public WithShortCircuiting, WithVisitorRef<TypePrinter>, WithGuards {
218 std::stringstream& ss; ///< Output to print to
219 const std::unordered_set<std::string>& closed; ///< Closed type variables
220 unsigned depth; ///< Depth of nesting from root type
221
222 TypePrinter( const std::unordered_set<std::string>& closed, std::stringstream& ss )
223 : ss(ss), closed(closed), depth(0) {}
224
225 // basic type represented as integer type
226 // TODO maybe hard-code conversion graph and make named type
227 void previsit( BasicType* bt ) { ss << (int)bt->get_kind(); }
228
229 // pointers (except function pointers) represented as generic type
230 void previsit( PointerType* pt ) {
231 if ( ! dynamic_cast<FunctionType*>(pt->base) ) { ss << "#$ptr<"; ++depth; }
232 }
233 void postvisit( PointerType* pt ) {
234 if ( ! dynamic_cast<FunctionType*>(pt->base) ) { --depth; ss << '>'; }
235 }
236
237 // arrays represented as generic pointers
238 void previsit( ArrayType* at ) {
239 ss << "#$ptr<";
240 ++depth;
241 at->base->accept( *visitor );
242 --depth;
243 ss << '>';
244 visit_children = false;
245 }
246
247 // ignore top-level reference types, they're mostly transparent to resolution
248 void previsit( ReferenceType* ) {
249 if ( depth > 0 ) { ss << "#$ref<"; }
250 ++depth;
251 }
252 void postvisit( ReferenceType* ) {
253 --depth;
254 if ( depth > 0 ) { ss << '>'; }
255 }
256
257 // print function types using prototype syntax
258 void previsit( FunctionType* ft ) {
259 ss << '[';
260 ++depth;
261 build( *visitor, from_decls( ft->returnVals ), ss, preceded );
262 ss << " : ";
263 build( *visitor, from_decls( ft->parameters ), ss, terminated );
264 --depth;
265 ss << ']';
266 visit_children = false;
267 }
268
269 private:
270 // prints aggregate type name as NamedType with optional paramters
271 void handleAggregate( ReferenceToType* at ) {
272 ss << '#' << at->name;
273 if ( ! at->parameters.empty() ) {
274 ss << '<';
275 ++depth;
276 build( *visitor, from_exprs( at->parameters ), ss );
277 --depth;
278 ss << '>';
279 }
280 visit_children = false;
281 }
282
283 public:
284 // handle aggregate types using NamedType
285 void previsit( StructInstType* st ) { handleAggregate( st ); }
286 void previsit( UnionInstType* ut ) { handleAggregate( ut ); }
287
288 // replace enums with int
289 void previsit( EnumInstType* ) { ss << (int)BasicType::SignedInt; }
290
291 void previsit( TypeInstType* vt ) {
292 // print closed variables as named types
293 if ( closed.count( vt->name ) ) { ss << '#' << vt->name; }
294 // otherwise make sure first letter is capitalized
295 else { ti_name( vt->name, ss ); }
296 }
297
298 // flattens empty and singleton tuples
299 void previsit( TupleType* tt ) {
300 ++depth;
301 buildAsTuple( *visitor, tt->types, ss );
302 --depth;
303 visit_children = false;
304 }
305
306 // TODO support VarArgsType
307
308 // replace 0 and 1 with int
309 // TODO support 0 and 1 with their proper type names and conversions
310 void previsit( ZeroType* ) { ss << (int)BasicType::SignedInt; }
311 void previsit( OneType* ) { ss << (int)BasicType::SignedInt; }
312
313 // only print void type if not at top level
314 void previsit( VoidType* ) {
315 if ( depth > 0 ) { ss << "#void"; }
316 }
317 };
318
319 /// builds description of function
320 void build( const std::string& name, FunctionType* fnTy, std::stringstream& ss ) {
321 PassVisitor<TypePrinter> printTy{ closed, ss };
322 // print return values
323 build( printTy, from_decls( fnTy->returnVals ), ss, terminated );
324 // print name
325 rp_name( name, ss );
326 // print parameters
327 build( printTy, from_decls( fnTy->parameters ), ss, preceded );
328 // print assertions
329 for ( TypeDecl* tyvar : fnTy->forall ) {
330 for ( DeclarationWithType* assn : tyvar->assertions ) {
331 ss << " | ";
332 build( assn->name, assn->get_type(), ss );
333 }
334 }
335 }
336
337 /// builds description of a variable (falls back to function if function type)
338 void build( const std::string& name, Type* ty, std::stringstream& ss ) {
339 // ignore top-level references
340 Type *norefs = ty->stripReferences();
341
342 // fall back to function declaration if function type
343 if ( PointerType* pTy = dynamic_cast< PointerType* >(norefs) ) {
344 if ( FunctionType* fnTy = dynamic_cast< FunctionType* >(pTy->base) ) {
345 build( name, fnTy, ss );
346 return;
347 }
348 } else if ( FunctionType* fnTy = dynamic_cast< FunctionType* >(norefs) ) {
349 build( name, fnTy, ss );
350 return;
351 }
352
353 // print variable declaration in prototype syntax
354 PassVisitor<TypePrinter> printTy{ closed, ss };
355 norefs->accept( printTy );
356 ss << " &";
357 rp_name( name, ss );
358 }
359
360 /// builds description of a field access
361 void build( const std::string& name, AggregateDecl* agg, Type* ty, std::stringstream& ss ) {
362 // ignore top-level references
363 Type *norefs = ty->stripReferences();
364
365 // print access as new field name
366 PassVisitor<TypePrinter> printTy{ closed, ss };
367 norefs->accept( printTy );
368 ss << ' ';
369 rp_name( name, ss, "$field_" );
370 ss << " #" << agg->name;
371 // handle type parameters
372 if ( ! agg->parameters.empty() ) {
373 ss << '<';
374 auto it = agg->parameters.begin();
375 while (true) {
376 ti_name( (*it)->name, ss );
377 if ( ++it == agg->parameters.end() ) break;
378 ss << ' ';
379 }
380 ss << '>';
381 }
382 }
383
384 /// Visitor for printing expressions
385 struct ExprPrinter : WithShortCircuiting, WithVisitorRef<ExprPrinter> {
386 // TODO change interface to generate multiple expression candidates
387 const std::unordered_set<std::string>& closed; ///< set of closed type vars
388 std::stringstream& ss; ///< Output to print to
389
390 ExprPrinter( const std::unordered_set<std::string>& closed, std::stringstream& ss )
391 : closed(closed), ss(ss) {}
392
393 /// Names handled as name expressions
394 void previsit( NameExpr* expr ) {
395 ss << '&';
396 rp_name( expr->name, ss );
397 }
398
399 /// Calls handled as calls
400 void previsit( UntypedExpr* expr ) {
401 // TODO handle name extraction more generally
402 NameExpr* name = dynamic_cast<NameExpr*>(expr->function);
403
404 // fall back on just resolving call to function name
405 // TODO incorporate function type into resolv-proto
406 if ( ! name ) {
407 expr->function->accept( *visitor );
408 visit_children = false;
409 return;
410 }
411
412 rp_name( name->name, ss );
413 if ( expr->args.empty() ) {
414 ss << "()";
415 } else {
416 ss << "( ";
417 auto it = expr->args.begin();
418 while (true) {
419 (*it)->accept( *visitor );
420 if ( ++it == expr->args.end() ) break;
421 ss << ' ';
422 }
423 ss << " )";
424 }
425 visit_children = false;
426 }
427
428 /// Already-resolved calls skipped
429 void previsit( ApplicationExpr* ) {
430 visit_children = false;
431 }
432
433 /// Address-of handled as operator
434 void previsit( AddressExpr* expr ) {
435 ss << "$addr( ";
436 expr->arg->accept( *visitor );
437 ss << " )";
438 visit_children = false;
439 }
440
441 /// Casts replaced with result type
442 /// TODO put cast target functions in, and add second expression for target
443 void previsit( CastExpr* cast ) {
444 PassVisitor<TypePrinter> tyPrinter{ closed, ss };
445 cast->result->accept( tyPrinter );
446 visit_children = false;
447 }
448
449 /// Member access handled as function from aggregate to member
450 void previsit( UntypedMemberExpr* expr ) {
451 // TODO handle name extraction more generally
452 NameExpr* name = dynamic_cast<NameExpr*>(expr->member);
453
454 // fall back on just resolving call to member name
455 // TODO incorporate function type into resolv-proto
456 if ( ! name ) {
457 expr->member->accept( *visitor );
458 visit_children = false;
459 return;
460 }
461
462 rp_name( name->name, ss, "$field_" );
463 ss << "( ";
464 expr->aggregate->accept( *visitor );
465 ss << " )";
466 visit_children = false;
467 }
468
469 /// Constant expression replaced by its type
470 void previsit( ConstantExpr* expr ) {
471 PassVisitor<TypePrinter> tyPrinter{ closed, ss };
472 expr->constant.get_type()->accept( tyPrinter );
473 visit_children = false;
474 }
475
476 /// sizeof( ... ), alignof( ... ), offsetof( ... ) replaced by unsigned long constant
477 /// TODO extra expression to resolve argument
478 void previsit( SizeofExpr* ) {
479 ss << (int)BasicType::LongUnsignedInt;
480 visit_children = false;
481 }
482 void previsit( AlignofExpr* ) {
483 ss << (int)BasicType::LongUnsignedInt;
484 visit_children = false;
485 }
486 void previsit( UntypedOffsetofExpr* ) {
487 ss << (int)BasicType::LongUnsignedInt;
488 visit_children = false;
489 }
490
491 /// Logical expressions represented as operators
492 void previsit( LogicalExpr* expr ) {
493 ss << '$' << ( expr->get_isAnd() ? "and" : "or" ) << "( ";
494 expr->arg1->accept( *visitor );
495 ss << ' ';
496 expr->arg2->accept( *visitor );
497 ss << " )";
498 visit_children = false;
499 }
500
501 /// Conditional expression represented as operator
502 void previsit( ConditionalExpr* expr ) {
503 ss << "$if( ";
504 expr->arg1->accept( *visitor );
505 ss << ' ';
506 expr->arg2->accept( *visitor );
507 ss << ' ';
508 expr->arg3->accept( *visitor );
509 ss << " )";
510 visit_children = false;
511 }
512
513 /// Comma expression represented as operator
514 void previsit( CommaExpr* expr ) {
515 ss << "$seq( ";
516 expr->arg1->accept( *visitor );
517 ss << ' ';
518 expr->arg2->accept( *visitor );
519 ss << " )";
520 visit_children = false;
521 }
522
523 // TODO handle ignored ImplicitCopyCtorExpr and below
524 };
525
526 void build( Initializer* init, std::stringstream& ss ) {
527 if ( SingleInit* si = dynamic_cast<SingleInit*>(init) ) {
528 PassVisitor<ExprPrinter> exprPrinter{ closed, ss };
529 si->value->accept( exprPrinter );
530 ss << ' ';
531 } else if ( ListInit* li = dynamic_cast<ListInit*>(init) ) {
532 for ( Initializer* it : li->initializers ) {
533 build( it, ss );
534 ss << ' ';
535 }
536 }
537 }
538
539 /// Adds an object initializer to the list of expressions
540 void build( const std::string& name, Initializer* init, std::stringstream& ss ) {
541 ss << "$constructor( ";
542 rp_name( name, ss );
543 ss << "() ";
544 build( init, ss );
545 ss << ')';
546 }
547
548 /// Adds a return expression to the list of expressions
549 void build( Type* rtnType, Expression* expr, std::stringstream& ss ) {
550 ss << "$constructor( ";
551 PassVisitor<TypePrinter> tyPrinter{ closed, ss };
552 rtnType->accept( tyPrinter );
553 ss << ' ';
554 PassVisitor<ExprPrinter> exprPrinter{ closed, ss };
555 expr->accept( exprPrinter );
556 ss << " )";
557 }
558
559 /// Adds all named declarations in a list to the local scope
560 void addAll( const std::list<DeclarationWithType*>& decls ) {
561 for ( auto decl : decls ) {
562 // skip anonymous decls
563 if ( decl->name.empty() ) continue;
564
565 // handle objects
566 if ( ObjectDecl* obj = dynamic_cast< ObjectDecl* >( decl ) ) {
567 previsit( obj );
568 }
569 }
570 }
571
572 /// encode field access as function
573 void addAggregateFields( AggregateDecl* agg ) {
574 // make field names functions
575 for ( Declaration* member : agg->members ) {
576 if ( ObjectDecl* obj = dynamic_cast< ObjectDecl* >(member) ) {
577 std::stringstream ss;
578 build( obj->name, agg, obj->type, ss );
579 addDecl( ss.str() );
580 }
581 }
582
583 visit_children = false;
584 }
585
586 public:
587 void previsit( ObjectDecl *obj ) {
588 // add variable as declaration
589 std::stringstream ss;
590 build( obj->name, obj->type, ss );
591 addDecl( ss.str() );
592
593 // add initializer as expression if applicable
594 if ( obj->init ) {
595 std::stringstream ss;
596 build( obj->name, obj->init, ss );
597 addExpr( ss.str() );
598 }
599 }
600
601 void previsit( FunctionDecl *decl ) {
602 // skip decls with ftype parameters
603 for ( TypeDecl* tyvar : decl->type->forall ) {
604 if ( tyvar->get_kind() == TypeDecl::Ftype ) {
605 visit_children = false;
606 return;
607 }
608 }
609
610 // add function as declaration
611 std::stringstream ss;
612 build( decl->name, decl->type, ss );
613 addDecl( ss.str() );
614
615 // add body if available
616 if ( decl->statements ) {
617 std::list<Type*> rtns = from_decls( decl->type->returnVals );
618 Type* rtn = nullptr;
619 if ( rtns.size() == 1 ) {
620 if ( ! dynamic_cast<VoidType*>(rtns.front()) ) rtn = rtns.front()->clone();
621 } else if ( rtns.size() > 1 ) {
622 rtn = new TupleType{ Type::Qualifiers{}, rtns };
623 }
624 PassVisitor<ProtoDump> body{ this, rtn };
625
626 for ( TypeDecl* tyvar : decl->type->forall ) {
627 // add set of "closed" types to body so that it can print them as NamedType
628 body.pass.closed.insert( tyvar->name );
629
630 // add assertions to local scope as declarations as well
631 for ( DeclarationWithType* assn : tyvar->assertions ) {
632 assn->accept( body );
633 }
634 }
635
636 // add named parameters and returns to local scope
637 body.pass.addAll( decl->type->returnVals );
638 body.pass.addAll( decl->type->parameters );
639
640 // add contents of function to new scope
641 decl->statements->accept( body );
642
643 // store sub-scope
644 addSub( std::move(body) );
645 }
646
647 visit_children = false;
648 }
649
650 void previsit( StructDecl* sd ) { addAggregateFields(sd); }
651 void previsit( UnionDecl* ud ) { addAggregateFields(ud); }
652
653 void previsit( EnumDecl* ed ) {
654 std::unique_ptr<Type> eType =
655 std::make_unique<BasicType>( Type::Qualifiers{}, BasicType::SignedInt );
656
657 // add field names directly to enclosing scope
658 for ( Declaration* member : ed->members ) {
659 if ( ObjectDecl* obj = dynamic_cast< ObjectDecl* >(member) ) {
660 previsit(obj);
661 }
662 }
663
664 visit_children = false;
665 }
666
667 void previsit( ReturnStmt* stmt ) {
668 // do nothing for void-returning functions or statements returning nothing
669 if ( ! rtnType || ! stmt->expr ) return;
670
671 // otherwise construct the return type from the expression
672 std::stringstream ss;
673 build( rtnType.get(), stmt->expr, ss );
674 addExpr( ss.str() );
675 visit_children = false;
676 }
677
678 void previsit( Expression* expr ) {
679 std::stringstream ss;
680 PassVisitor<ExprPrinter> exPrinter{ closed, ss };
681 expr->accept( exPrinter );
682 addExpr( ss.str() );
683 visit_children = false;
684 }
685
686 /// Print non-prelude global declarations for resolv proto
687 void printGlobals() const {
688 std::cout << "#ptr<T> $addr T" << std::endl; // &?
689 int i = (int)BasicType::SignedInt;
690 std::cout << i << " $and " << i << ' ' << i << std::endl; // ?&&?
691 std::cout << i << " $or " << i << ' ' << i << std::endl; // ?||?
692 std::cout << "T $if " << i << " T T" << std::endl; // ternary operator
693 std::cout << "T $seq X T" << std::endl; // ?,?
694 }
695
696 public:
697 /// Prints this ProtoDump instance
698 void print(unsigned indent = 0) const {
699 // print globals at root level
700 if ( ! parent ) printGlobals();
701 // print decls
702 std::string tab( indent, '\t' );
703 for ( const std::string& d : decls ) {
704 std::cout << tab << d << std::endl;
705 }
706 // print divider
707 std::cout << '\n' << tab << "%%\n" << std::endl;
708 // print top-level expressions
709 for ( const std::string& e : exprs ) {
710 std::cout << tab << e << std::endl;
711 }
712 // print child scopes
713 ++indent;
714 for ( const PassVisitor<ProtoDump>& s : subs ) {
715 std::cout << tab << '{' << std::endl;
716 s.pass.print( indent );
717 std::cout << tab << '}' << std::endl;
718 }
719 }
720 };
721
722 void dumpAsResolvProto( std::list< Declaration * > &translationUnit ) {
723 PassVisitor<ProtoDump> dump;
724 acceptAll( translationUnit, dump );
725 dump.pass.print();
726 }
727
728} // namespace CodeTools
729
730// Local Variables: //
731// tab-width: 4 //
732// mode: c++ //
733// compile-command: "make install" //
734// End: //
Note: See TracBrowser for help on using the repository browser.