source: src/CodeTools/ResolvProtoDump.cc@ b499c18

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 b499c18 was 40cd873, checked in by Aaron Moss <a3moss@…>, 7 years ago

Fix gcc-5 support for ResolvProtoDump

  • Property mode set to 100644
File size: 16.8 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 "CodeGen/OperatorTable.h"
30#include "SynTree/Declaration.h"
31#include "SynTree/Expression.h"
32#include "SynTree/Statement.h"
33#include "SynTree/Type.h"
34
35namespace CodeTools {
36
37 /// Visitor for dumping resolver prototype output
38 class ProtoDump : public WithShortCircuiting, public WithVisitorRef<ProtoDump> {
39 std::set<std::string> decls; ///< Declarations in this scope
40 std::vector<std::string> exprs; ///< Expressions in this scope
41 std::vector<ProtoDump> subs; ///< Sub-scopes
42 const ProtoDump* parent; ///< Outer lexical scope
43
44 public:
45 /// Default constructor for root ProtoDump
46 ProtoDump() : decls(), exprs(), subs(), parent(nullptr) {}
47
48 /// Child constructor
49 ProtoDump(const ProtoDump* p) : decls(), exprs(), subs(), parent(p) {}
50
51 private:
52 /// checks if this declaration is contained in the scope or one of its parents
53 bool hasDecl( const std::string& s ) const {
54 if ( decls.count( s ) ) return true;
55 if ( parent ) return parent->hasDecl( s );
56 return false;
57 }
58
59 /// adds a new declaration to this scope, providing it does not already exist
60 void addDecl( const std::string& s ) {
61 if ( ! hasDecl( s ) ) decls.insert( s );
62 }
63
64 /// adds a new expression to this scope
65 void addExpr( const std::string& s ) {
66 if ( ! s.empty() ) { exprs.emplace_back( s ); }
67 }
68
69 /// adds a new subscope to this scope, returning a reference
70 void addSub( PassVisitor<ProtoDump>&& sub ) {
71 subs.emplace_back( std::move(sub.pass) );
72 }
73
74 /// Whether lists should be separated, terminated, or preceded by their separator
75 enum septype { separated, terminated, preceded };
76
77 /// builds space-separated list of types
78 template<typename V>
79 static void build( V& visitor, const std::list< Type* >& tys, std::stringstream& ss,
80 septype mode = separated ) {
81 if ( tys.empty() ) return;
82
83 if ( mode == preceded ) { ss << ' '; }
84
85 auto it = tys.begin();
86 (*it)->accept( visitor );
87
88 while ( ++it != tys.end() ) {
89 ss << ' ';
90 (*it)->accept( visitor );
91 }
92
93 if ( mode == terminated ) { ss << ' '; }
94 }
95
96 /// builds list of types wrapped as tuple type
97 template<typename V>
98 static void buildAsTuple( V& visitor, const std::list< Type* >& tys,
99 std::stringstream& ss ) {
100 switch ( tys.size() ) {
101 case 0: ss << "#void"; break;
102 case 1: tys.front()->accept( visitor ); break;
103 default:
104 ss << "#$" << tys.size() << '<';
105 build( visitor, tys, ss );
106 ss << '>';
107 break;
108 }
109 }
110
111 /// gets types from DWT list
112 static std::list< Type* > from_decls( const std::list< DeclarationWithType* >& decls ) {
113 std::list< Type* > tys;
114 for ( auto decl : decls ) { tys.emplace_back( decl->get_type() ); }
115 return tys;
116 }
117
118 /// gets types from TypeExpr list
119 static std::list< Type* > from_exprs( const std::list< Expression* >& exprs ) {
120 std::list< Type* > tys;
121 for ( auto expr : exprs ) {
122 if ( TypeExpr* tyExpr = dynamic_cast<TypeExpr*>(expr) ) {
123 tys.emplace_back( tyExpr->type );
124 }
125 }
126 return tys;
127 }
128
129 /// builds prefixes for rp_name
130 static std::string new_prefix( const std::string& old, const char* added ) {
131 if ( old.empty() ) return std::string{"$"} + added;
132 return old + added;
133 }
134
135 /// shortens operator names
136 static void op_name( const std::string& name, std::stringstream& ss ) {
137 if ( name.compare( 0, 10, "_operator_" ) == 0 ) {
138 ss << name.substr(10);
139 } else if ( name.compare( "_constructor" ) == 0
140 || name.compare( "_destructor" ) == 0 ) {
141 ss << name.substr(1);
142 } else if ( name.compare( 0, 11, "__operator_" ) == 0 ) {
143 ss << name.substr(11);
144 } else {
145 ss << name;
146 }
147 }
148
149 /// replaces operators with resolv-proto names
150 static void rp_name( const std::string& name, std::stringstream& ss,
151 std::string&& pre = "" ) {
152 // safety check for anonymous names
153 if ( name.empty() ) {
154 ss << new_prefix(pre, "anon");
155 return;
156 }
157
158 // replace operator names
159 CodeGen::OperatorInfo info;
160 if ( CodeGen::operatorLookup( name, info ) ) {
161 ss << new_prefix(pre, "");
162 op_name( info.outputName, ss );
163 return;
164 }
165
166 // replace retval names
167 if ( name.compare( 0, 8, "_retval_" ) == 0 ) {
168 ss << new_prefix(pre, "rtn_");
169 op_name( name.substr(8), ss );
170 return;
171 }
172
173 // default to just name
174 ss << pre << name;
175 }
176
177 /// ensures type inst names are uppercase
178 static void ti_name( const std::string& name, std::stringstream& ss ) {
179 ss << (char)std::toupper( static_cast<unsigned char>(name[0]) )
180 << (name.c_str() + 1);
181 }
182
183 /// Visitor for printing types
184 struct TypePrinter : public WithShortCircuiting, WithVisitorRef<TypePrinter>, WithGuards {
185 std::stringstream& ss; ///< Output to print to
186 unsigned depth; ///< Depth of nesting from root type
187
188 TypePrinter( std::stringstream& ss ) : ss(ss), depth(0) {}
189
190 // basic type represented as integer type
191 // TODO maybe hard-code conversion graph and make named type
192 void previsit( BasicType* bt ) { ss << (int)bt->get_kind(); }
193
194 // pointers represented as generic type
195 // TODO except pointer to function
196 void previsit( PointerType* ) { ss << "#$ptr<"; ++depth; }
197 void postvisit( PointerType* ) { --depth; ss << '>'; }
198
199 // arrays represented as generic type
200 void previsit( ArrayType* at ) {
201 ss << "#$arr<";
202 ++depth;
203 at->base->accept( *visitor );
204 --depth;
205 ss << '>';
206 visit_children = false;
207 }
208
209 // ignore top-level reference types, they're mostly transparent to resolution
210 void previsit( ReferenceType* ) {
211 if ( depth > 0 ) { ss << "#$ref<"; }
212 ++depth;
213 }
214 void postvisit( ReferenceType* ) {
215 --depth;
216 if ( depth > 0 ) { ss << '>'; }
217 }
218
219 // encode function type as a 2-param generic type
220 // TODO handle forall functions
221 void previsit( FunctionType* ft ) {
222 ss << "#$fn<";
223 ++depth;
224 buildAsTuple( *visitor, from_decls( ft->returnVals ), ss );
225 ss << ' ';
226 buildAsTuple( *visitor, from_decls( ft->parameters ), ss );
227 --depth;
228 ss << '>';
229 visit_children = false;
230 }
231
232 private:
233 // prints aggregate type name as NamedType with optional paramters
234 void handleAggregate( ReferenceToType* at ) {
235 ss << '#' << at->name;
236 if ( ! at->parameters.empty() ) {
237 ss << '<';
238 ++depth;
239 build( *visitor, from_exprs( at->parameters ), ss );
240 --depth;
241 ss << '>';
242 }
243 visit_children = false;
244 }
245
246 public:
247 // handle aggregate types using NamedType
248 void previsit( StructInstType* st ) { handleAggregate( st ); }
249 void previsit( UnionInstType* ut ) { handleAggregate( ut ); }
250
251 // replace enums with int
252 void previsit( EnumInstType* ) { ss << (int)BasicType::SignedInt; }
253
254 // make sure first letter of TypeInstType is capitalized
255 void previsit( TypeInstType* vt ) {
256 ti_name( vt->name, ss );
257 }
258
259 // flattens empty and singleton tuples
260 void previsit( TupleType* tt ) {
261 ++depth;
262 buildAsTuple( *visitor, tt->types, ss );
263 --depth;
264 visit_children = false;
265 }
266
267 // TODO support VarArgsType
268
269 // replace 0 and 1 with int
270 // TODO support 0 and 1 with their proper type names and conversions
271 void previsit( ZeroType* ) { ss << (int)BasicType::SignedInt; }
272 void previsit( OneType* ) { ss << (int)BasicType::SignedInt; }
273
274 // only print void type if not at top level
275 void previsit( VoidType* ) {
276 if ( depth > 0 ) { ss << "#void"; }
277 }
278 };
279
280 /// builds description of function
281 void build( const std::string& name, FunctionType* fnTy, std::stringstream& ss ) {
282 PassVisitor<TypePrinter> printTy{ ss };
283 build( printTy, from_decls( fnTy->returnVals ), ss, terminated );
284 rp_name( name, ss );
285 build( printTy, from_decls( fnTy->parameters ), ss, preceded );
286 // TODO handle assertions
287 }
288
289 /// builds description of a variable (falls back to function if function type)
290 void build( const std::string& name, Type* ty, std::stringstream& ss ) {
291 // ignore top-level references
292 Type *norefs = ty->stripReferences();
293
294 // fall back to function declaration if function type
295 if ( PointerType* pTy = dynamic_cast< PointerType* >(norefs) ) {
296 if ( FunctionType* fnTy = dynamic_cast< FunctionType* >(pTy->base) ) {
297 build( name, fnTy, ss );
298 return;
299 }
300 } else if ( FunctionType* fnTy = dynamic_cast< FunctionType* >(norefs) ) {
301 build( name, fnTy, ss );
302 return;
303 }
304
305 // print variable declaration as zero-arg function
306 PassVisitor<TypePrinter> printTy{ ss };
307 norefs->accept( printTy );
308 ss << ' ';
309 rp_name( name, ss );
310 }
311
312 /// builds description of a field access
313 void build( const std::string& name, AggregateDecl* agg, Type* ty, std::stringstream& ss ) {
314 // ignore top-level references
315 Type *norefs = ty->stripReferences();
316
317 // print access as new field name
318 PassVisitor<TypePrinter> printTy{ ss };
319 norefs->accept( printTy );
320 ss << ' ';
321 rp_name( name, ss, "$field_" );
322 ss << " #" << agg->name;
323 // handle type parameters
324 if ( ! agg->parameters.empty() ) {
325 ss << '<';
326 auto it = agg->parameters.begin();
327 while (true) {
328 ti_name( (*it)->name, ss );
329 if ( ++it == agg->parameters.end() ) break;
330 ss << ' ';
331 }
332 ss << '>';
333 }
334 }
335
336 /// Visitor for printing expressions
337 struct ExprPrinter : WithShortCircuiting, WithVisitorRef<ExprPrinter> {
338 // TODO change interface to generate multiple expression candidates
339
340 std::stringstream& ss; ///< Output to print to
341
342 ExprPrinter( std::stringstream& ss ) : ss(ss) {}
343
344 /// Names handled as nullary function calls
345 void previsit( NameExpr* expr ) {
346 rp_name( expr->name, ss );
347 ss << "()";
348 }
349
350 /// Calls handled as calls
351 void previsit( UntypedExpr* expr ) {
352 // TODO handle name extraction more generally
353 NameExpr* name = dynamic_cast<NameExpr*>(expr->function);
354
355 // fall back on just resolving call to function name
356 // TODO incorporate function type into resolv-proto
357 if ( ! name ) {
358 expr->function->accept( *visitor );
359 visit_children = false;
360 return;
361 }
362
363 rp_name( name->name, ss );
364 if ( expr->args.empty() ) {
365 ss << "()";
366 } else {
367 ss << "( ";
368 auto it = expr->args.begin();
369 while (true) {
370 (*it)->accept( *visitor );
371 if ( ++it == expr->args.end() ) break;
372 ss << ' ';
373 }
374 ss << " )";
375 }
376 visit_children = false;
377 }
378
379 /// Address-of handled as operator
380 void previsit( AddressExpr* expr ) {
381 // TODO global function to implement this
382 ss << "$addr( ";
383 expr->arg->accept( *visitor );
384 ss << " )";
385 visit_children = false;
386 }
387
388 /// Casts replaced with result type
389 /// TODO put cast target functions in, and add second expression for target
390 void previsit( CastExpr* cast ) {
391 PassVisitor<TypePrinter> tyPrinter{ ss };
392 cast->result->accept( tyPrinter );
393 visit_children = false;
394 }
395
396 /// Member access handled as function from aggregate to member
397 void previsit( UntypedMemberExpr* expr ) {
398 // TODO handle name extraction more generally
399 NameExpr* name = dynamic_cast<NameExpr*>(expr->member);
400
401 // fall back on just resolving call to member name
402 // TODO incorporate function type into resolv-proto
403 if ( ! name ) {
404 expr->member->accept( *visitor );
405 visit_children = false;
406 return;
407 }
408
409 rp_name( name->name, ss, "$field_" );
410 ss << "( ";
411 expr->aggregate->accept( *visitor );
412 ss << " )";
413 visit_children = false;
414 }
415
416 /// Constant expression replaced by its type
417 void previsit( ConstantExpr* expr ) {
418 PassVisitor<TypePrinter> tyPrinter{ ss };
419 expr->constant.get_type()->accept( tyPrinter );
420 visit_children = false;
421 }
422
423 /// sizeof( ... ), alignof( ... ), offsetof( ... ) replaced by unsigned long constant
424 /// TODO extra expression to resolve argument
425 void previsit( SizeofExpr* ) {
426 ss << (int)BasicType::LongUnsignedInt;
427 visit_children = false;
428 }
429 void previsit( AlignofExpr* ) {
430 ss << (int)BasicType::LongUnsignedInt;
431 visit_children = false;
432 }
433 void previsit( UntypedOffsetofExpr* ) {
434 ss << (int)BasicType::LongUnsignedInt;
435 visit_children = false;
436 }
437
438 /// Logical expressions represented as operators
439 void previsit( LogicalExpr* expr ) {
440 // TODO global functions for these
441 ss << '$' << ( expr->get_isAnd() ? "and" : "or" ) << "( ";
442 expr->arg1->accept( *visitor );
443 ss << ' ';
444 expr->arg2->accept( *visitor );
445 ss << " )";
446 visit_children = false;
447 }
448
449 /// Conditional expression represented as operator
450 void previsit( ConditionalExpr* expr ) {
451 // TODO global function for this
452 ss << "$if( ";
453 expr->arg1->accept( *visitor );
454 ss << ' ';
455 expr->arg2->accept( *visitor );
456 ss << ' ';
457 expr->arg3->accept( *visitor );
458 ss << " )";
459 visit_children = false;
460 }
461
462 /// Comma expression represented as operator
463 void previsit( CommaExpr* expr ) {
464 // TODO global function for this
465 ss << "$seq( ";
466 expr->arg1->accept( *visitor );
467 ss << ' ';
468 expr->arg2->accept( *visitor );
469 ss << " )";
470 visit_children = false;
471 }
472
473 // TODO handle ignored ImplicitCopyCtorExpr and below
474 };
475
476 /// Adds all named declarations in a list to the local scope
477 void addAll( const std::list<DeclarationWithType*>& decls ) {
478 for ( auto decl : decls ) {
479 // skip anonymous decls
480 if ( decl->name.empty() ) continue;
481
482 // handle objects
483 if ( ObjectDecl* obj = dynamic_cast< ObjectDecl* >( decl ) ) {
484 previsit( obj );
485 }
486 }
487 }
488
489 /// encode field access as function
490 void addAggregateFields( AggregateDecl* agg ) {
491 // make field names functions
492 for ( Declaration* member : agg->members ) {
493 if ( ObjectDecl* obj = dynamic_cast< ObjectDecl* >(member) ) {
494 std::stringstream ss;
495 build( obj->name, agg, obj->type, ss );
496 addDecl( ss.str() );
497 }
498 }
499
500 visit_children = false;
501 }
502
503 public:
504 void previsit( ObjectDecl *obj ) {
505 // add variable as declaration
506 std::stringstream ss;
507 build( obj->name, obj->type, ss );
508 addDecl( ss.str() );
509 }
510
511 void previsit( FunctionDecl *decl ) {
512 // add function as declaration
513 std::stringstream ss;
514 build( decl->name, decl->type, ss );
515 addDecl( ss.str() );
516
517 // add body if available
518 if ( decl->statements ) {
519 PassVisitor<ProtoDump> body{ this };
520
521 // add named parameters and returns to local scope
522 body.pass.addAll( decl->type->returnVals );
523 body.pass.addAll( decl->type->parameters );
524
525 // TODO add assertions to local scope
526
527 // TODO add set of "closed" types to body so that it can print them as NamedType
528
529 // add contents of function to new scope
530 decl->statements->accept( body );
531
532 // store sub-scope
533 addSub( std::move(body) );
534 }
535
536 visit_children = false;
537 }
538
539 void previsit( StructDecl* sd ) { addAggregateFields(sd); }
540 void previsit( UnionDecl* ud ) { addAggregateFields(ud); }
541
542 void previsit( EnumDecl* ed ) {
543 std::unique_ptr<Type> eType =
544 std::make_unique<BasicType>( Type::Qualifiers{}, BasicType::SignedInt );
545
546 // add field names directly to enclosing scope
547 for ( Declaration* member : ed->members ) {
548 if ( ObjectDecl* obj = dynamic_cast< ObjectDecl* >(member) ) {
549 previsit(obj);
550 }
551 }
552
553 visit_children = false;
554 }
555
556 void previsit( Expression* expr ) {
557 std::stringstream ss;
558 PassVisitor<ExprPrinter> exPrinter{ss};
559 expr->accept( exPrinter );
560 addExpr( ss.str() );
561 visit_children = false;
562 }
563
564 public:
565 /// Prints this ProtoDump instance
566 void print(unsigned indent = 0) const {
567 std::string tab( indent, '\t' );
568 // print decls
569 for ( const std::string& d : decls ) {
570 std::cout << tab << d << std::endl;
571 }
572 // print divider
573 std::cout << tab << "%%" << std::endl;
574 // print top-level expressions
575 for ( const std::string& e : exprs ) {
576 std::cout << tab << e << std::endl;
577 }
578 // print child scopes
579 ++indent;
580 for ( const PassVisitor<ProtoDump>& s : subs ) {
581 std::cout << tab << '{' << std::endl;
582 s.pass.print( indent );
583 std::cout << tab << '}' << std::endl;
584 }
585 }
586 };
587
588 void dumpAsResolvProto( std::list< Declaration * > &translationUnit ) {
589 PassVisitor<ProtoDump> dump;
590 acceptAll( translationUnit, dump );
591 dump.pass.print();
592 }
593
594} // namespace CodeTools
595
596// Local Variables: //
597// tab-width: 4 //
598// mode: c++ //
599// compile-command: "make install" //
600// End: //
Note: See TracBrowser for help on using the repository browser.