source: src/CodeTools/ResolvProtoDump.cc@ 88001dd

Last change on this file since 88001dd was fc134a48, checked in by JiadaL <j82liang@…>, 3 years ago

Implement the struct enum

  • Property mode set to 100644
File size: 22.6 KB
RevLine 
[3b3491b6]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
[60a8062]11// Last Modified By : Peter A. Buhr
12// Last Modified On : Sat Feb 15 13:50:11 2020
13// Update Count : 3
[3b3491b6]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>
[40cd873]25#include <utility>
[3b3491b6]26#include <vector>
27
28#include "Common/PassVisitor.h"
[4d59ff9]29#include "Common/utility.h"
[3b3491b6]30#include "CodeGen/OperatorTable.h"
31#include "SynTree/Declaration.h"
32#include "SynTree/Expression.h"
[4d59ff9]33#include "SynTree/Initializer.h"
[3b3491b6]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> {
[a4a000d]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
[3b3491b6]47
48 public:
49 /// Default constructor for root ProtoDump
[a4a000d]50 ProtoDump() : decls(), exprs(), subs(), closed(), parent(nullptr), rtnType(nullptr) {}
[3b3491b6]51
52 /// Child constructor
[a2dbcff1]53 ProtoDump(const ProtoDump* p, Type* r)
[a4a000d]54 : decls(), exprs(), subs(), closed(p->closed), parent(p), rtnType(r) {}
[4d59ff9]55
56 // Fix copy issues
[a2dbcff1]57 ProtoDump(const ProtoDump& o)
58 : decls(o.decls), exprs(o.exprs), subs(o.subs), closed(o.closed), parent(o.parent),
[4d59ff9]59 rtnType(maybeClone(o.rtnType.get())) {}
60 ProtoDump( ProtoDump&& ) = default;
61
[a4a000d]62 ProtoDump& operator= (const ProtoDump& o) {
[4d59ff9]63 if ( this == &o ) return *this;
64
65 decls = o.decls;
66 exprs = o.exprs;
67 subs = o.subs;
[a4a000d]68 closed = o.closed;
[4d59ff9]69 parent = o.parent;
70 rtnType.reset( maybeClone(o.rtnType.get()) );
[a2dbcff1]71
[4d59ff9]72 return *this;
73 }
[a2dbcff1]74 ProtoDump& operator= (ProtoDump&&) = delete;
[3b3491b6]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 ) {
[b181639]91 if ( ! s.empty() ) { exprs.emplace_back( s ); }
[3b3491b6]92 }
93
94 /// adds a new subscope to this scope, returning a reference
[40cd873]95 void addSub( PassVisitor<ProtoDump>&& sub ) {
96 subs.emplace_back( std::move(sub.pass) );
[3b3491b6]97 }
[a2dbcff1]98
[3b3491b6]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>
[a2dbcff1]104 static void build( V& visitor, const std::list< Type* >& tys, std::stringstream& ss,
[3b3491b6]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>
[a2dbcff1]123 static void buildAsTuple( V& visitor, const std::list< Type* >& tys,
[3b3491b6]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);
[a2dbcff1]164 } else if ( name.compare( "_constructor" ) == 0
[3b3491b6]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
[a2dbcff1]175 static void rp_name( const std::string& name, std::stringstream& ss,
[3b3491b6]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
[60a8062]184 const CodeGen::OperatorInfo * opInfo = CodeGen::operatorLookup( name );
185 if ( opInfo ) {
[3b3491b6]186 ss << new_prefix(pre, "");
[60a8062]187 op_name( opInfo->outputName, ss );
[3b3491b6]188 return;
[a2dbcff1]189 }
190
[3b3491b6]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 }
[a2dbcff1]197
[4c42a5f]198 // default to just name, with first character in lowercase
[a2dbcff1]199 ss << pre
[4c42a5f]200 << (char)std::tolower( static_cast<unsigned char>(name[0]) )
201 << (name.c_str() + 1);
[3b3491b6]202 }
203
204 /// ensures type inst names are uppercase
205 static void ti_name( const std::string& name, std::stringstream& ss ) {
[bb0f974]206 // replace built-in wide character types with named types
207 if ( name == "char16_t" || name == "char32_t" || name == "wchar_t" ) {
208 ss << "#" << name;
209 return;
210 }
211
212 // strip leading underscore
[4c42a5f]213 unsigned i = 0;
214 while ( i < name.size() && name[i] == '_' ) { ++i; }
215 if ( i == name.size() ) {
216 ss << "Anon";
217 return;
218 }
[bb0f974]219
220 std::string stripped = name.substr(i);
221 // strip trailing "_generic_" from autogen names (avoids some user-generation issues)
222 char generic[] = "_generic_"; size_t n_generic = sizeof(generic) - 1;
[a2dbcff1]223 if ( stripped.size() >= n_generic
[bb0f974]224 && stripped.substr( stripped.size() - n_generic ) == generic ) {
225 stripped.resize( stripped.size() - n_generic );
226 }
227
228 // uppercase first character
229 ss << (char)std::toupper( static_cast<unsigned char>(stripped[0]) )
230 << (stripped.c_str() + 1);
[3b3491b6]231 }
232
233 /// Visitor for printing types
234 struct TypePrinter : public WithShortCircuiting, WithVisitorRef<TypePrinter>, WithGuards {
[a4a000d]235 std::stringstream& ss; ///< Output to print to
236 const std::unordered_set<std::string>& closed; ///< Closed type variables
237 unsigned depth; ///< Depth of nesting from root type
[3b3491b6]238
[a2dbcff1]239 TypePrinter( const std::unordered_set<std::string>& closed, std::stringstream& ss )
[a4a000d]240 : ss(ss), closed(closed), depth(0) {}
[3b3491b6]241
242 // basic type represented as integer type
243 // TODO maybe hard-code conversion graph and make named type
244 void previsit( BasicType* bt ) { ss << (int)bt->get_kind(); }
245
[4c42a5f]246 // pointers (except function pointers) represented as generic type
247 void previsit( PointerType* pt ) {
248 if ( ! dynamic_cast<FunctionType*>(pt->base) ) { ss << "#$ptr<"; ++depth; }
249 }
250 void postvisit( PointerType* pt ) {
251 if ( ! dynamic_cast<FunctionType*>(pt->base) ) { --depth; ss << '>'; }
252 }
[3b3491b6]253
[4c42a5f]254 // arrays represented as generic pointers
[b181639]255 void previsit( ArrayType* at ) {
[4c42a5f]256 ss << "#$ptr<";
[b181639]257 ++depth;
258 at->base->accept( *visitor );
259 --depth;
260 ss << '>';
261 visit_children = false;
262 }
[3b3491b6]263
264 // ignore top-level reference types, they're mostly transparent to resolution
265 void previsit( ReferenceType* ) {
266 if ( depth > 0 ) { ss << "#$ref<"; }
267 ++depth;
268 }
269 void postvisit( ReferenceType* ) {
270 --depth;
271 if ( depth > 0 ) { ss << '>'; }
272 }
273
[4c42a5f]274 // print function types using prototype syntax
[3b3491b6]275 void previsit( FunctionType* ft ) {
[4c42a5f]276 ss << '[';
[3b3491b6]277 ++depth;
[4c42a5f]278 build( *visitor, from_decls( ft->returnVals ), ss, preceded );
279 ss << " : ";
280 build( *visitor, from_decls( ft->parameters ), ss, terminated );
[3b3491b6]281 --depth;
[4c42a5f]282 ss << ']';
[3b3491b6]283 visit_children = false;
284 }
285
286 private:
287 // prints aggregate type name as NamedType with optional paramters
288 void handleAggregate( ReferenceToType* at ) {
289 ss << '#' << at->name;
290 if ( ! at->parameters.empty() ) {
291 ss << '<';
292 ++depth;
293 build( *visitor, from_exprs( at->parameters ), ss );
294 --depth;
295 ss << '>';
296 }
297 visit_children = false;
298 }
299
300 public:
301 // handle aggregate types using NamedType
302 void previsit( StructInstType* st ) { handleAggregate( st ); }
303 void previsit( UnionInstType* ut ) { handleAggregate( ut ); }
304
305 // replace enums with int
[fc134a48]306 void previsit( EnumInstType* ) {
307 // TODO: add the meaningful representation of typed int
308 ss << (int)BasicType::SignedInt;
309 }
[3b3491b6]310
311 void previsit( TypeInstType* vt ) {
[a4a000d]312 // print closed variables as named types
313 if ( closed.count( vt->name ) ) { ss << '#' << vt->name; }
314 // otherwise make sure first letter is capitalized
315 else { ti_name( vt->name, ss ); }
[3b3491b6]316 }
317
318 // flattens empty and singleton tuples
319 void previsit( TupleType* tt ) {
320 ++depth;
321 buildAsTuple( *visitor, tt->types, ss );
322 --depth;
323 visit_children = false;
324 }
325
[04bdc26]326 // TODO support variable args for functions
327 void previsit( VarArgsType* ) {
328 // only include varargs for top level (argument type)
329 if ( depth == 0 ) { ss << "#$varargs"; }
330 }
[3b3491b6]331
332 // replace 0 and 1 with int
333 // TODO support 0 and 1 with their proper type names and conversions
334 void previsit( ZeroType* ) { ss << (int)BasicType::SignedInt; }
335 void previsit( OneType* ) { ss << (int)BasicType::SignedInt; }
336
337 // only print void type if not at top level
338 void previsit( VoidType* ) {
339 if ( depth > 0 ) { ss << "#void"; }
340 }
341 };
[a2dbcff1]342
[3b3491b6]343 /// builds description of function
344 void build( const std::string& name, FunctionType* fnTy, std::stringstream& ss ) {
[a4a000d]345 PassVisitor<TypePrinter> printTy{ closed, ss };
346 // print return values
[3b3491b6]347 build( printTy, from_decls( fnTy->returnVals ), ss, terminated );
[a4a000d]348 // print name
[3b3491b6]349 rp_name( name, ss );
[a4a000d]350 // print parameters
[3b3491b6]351 build( printTy, from_decls( fnTy->parameters ), ss, preceded );
[a4a000d]352 // print assertions
353 for ( TypeDecl* tyvar : fnTy->forall ) {
354 for ( DeclarationWithType* assn : tyvar->assertions ) {
[a2dbcff1]355 ss << " | ";
[a4a000d]356 build( assn->name, assn->get_type(), ss );
357 }
358 }
[3b3491b6]359 }
360
361 /// builds description of a variable (falls back to function if function type)
362 void build( const std::string& name, Type* ty, std::stringstream& ss ) {
363 // ignore top-level references
364 Type *norefs = ty->stripReferences();
[a2dbcff1]365
[3b3491b6]366 // fall back to function declaration if function type
367 if ( PointerType* pTy = dynamic_cast< PointerType* >(norefs) ) {
368 if ( FunctionType* fnTy = dynamic_cast< FunctionType* >(pTy->base) ) {
369 build( name, fnTy, ss );
370 return;
371 }
372 } else if ( FunctionType* fnTy = dynamic_cast< FunctionType* >(norefs) ) {
373 build( name, fnTy, ss );
374 return;
375 }
376
[4c42a5f]377 // print variable declaration in prototype syntax
[a4a000d]378 PassVisitor<TypePrinter> printTy{ closed, ss };
[3b3491b6]379 norefs->accept( printTy );
[4c42a5f]380 ss << " &";
[3b3491b6]381 rp_name( name, ss );
382 }
383
384 /// builds description of a field access
385 void build( const std::string& name, AggregateDecl* agg, Type* ty, std::stringstream& ss ) {
386 // ignore top-level references
387 Type *norefs = ty->stripReferences();
388
389 // print access as new field name
[a4a000d]390 PassVisitor<TypePrinter> printTy{ closed, ss };
[3b3491b6]391 norefs->accept( printTy );
392 ss << ' ';
393 rp_name( name, ss, "$field_" );
394 ss << " #" << agg->name;
395 // handle type parameters
396 if ( ! agg->parameters.empty() ) {
397 ss << '<';
398 auto it = agg->parameters.begin();
399 while (true) {
400 ti_name( (*it)->name, ss );
401 if ( ++it == agg->parameters.end() ) break;
402 ss << ' ';
403 }
404 ss << '>';
405 }
406 }
407
408 /// Visitor for printing expressions
409 struct ExprPrinter : WithShortCircuiting, WithVisitorRef<ExprPrinter> {
410 // TODO change interface to generate multiple expression candidates
[a4a000d]411 const std::unordered_set<std::string>& closed; ///< set of closed type vars
412 std::stringstream& ss; ///< Output to print to
[3b3491b6]413
[a2dbcff1]414 ExprPrinter( const std::unordered_set<std::string>& closed, std::stringstream& ss )
[a4a000d]415 : closed(closed), ss(ss) {}
[3b3491b6]416
[4c42a5f]417 /// Names handled as name expressions
[3b3491b6]418 void previsit( NameExpr* expr ) {
[4c42a5f]419 ss << '&';
[3b3491b6]420 rp_name( expr->name, ss );
421 }
422
[bb0f974]423 /// Handle already-resolved variables as type constants
424 void previsit( VariableExpr* expr ) {
425 PassVisitor<TypePrinter> tyPrinter{ closed, ss };
426 expr->var->get_type()->accept( tyPrinter );
427 visit_children = false;
428 }
429
[3b3491b6]430 /// Calls handled as calls
431 void previsit( UntypedExpr* expr ) {
432 // TODO handle name extraction more generally
433 NameExpr* name = dynamic_cast<NameExpr*>(expr->function);
434
435 // fall back on just resolving call to function name
436 // TODO incorporate function type into resolv-proto
437 if ( ! name ) {
438 expr->function->accept( *visitor );
439 visit_children = false;
440 return;
441 }
442
443 rp_name( name->name, ss );
444 if ( expr->args.empty() ) {
445 ss << "()";
446 } else {
447 ss << "( ";
448 auto it = expr->args.begin();
449 while (true) {
450 (*it)->accept( *visitor );
451 if ( ++it == expr->args.end() ) break;
452 ss << ' ';
453 }
454 ss << " )";
455 }
456 visit_children = false;
457 }
458
[bb0f974]459 /// Already-resolved calls reduced to their type constant
460 void previsit( ApplicationExpr* expr ) {
461 PassVisitor<TypePrinter> tyPrinter{ closed, ss };
462 expr->result->accept( tyPrinter );
[4c42a5f]463 visit_children = false;
464 }
465
[3b3491b6]466 /// Address-of handled as operator
467 void previsit( AddressExpr* expr ) {
468 ss << "$addr( ";
469 expr->arg->accept( *visitor );
470 ss << " )";
471 visit_children = false;
472 }
473
[b181639]474 /// Casts replaced with result type
475 /// TODO put cast target functions in, and add second expression for target
476 void previsit( CastExpr* cast ) {
[a4a000d]477 PassVisitor<TypePrinter> tyPrinter{ closed, ss };
[b181639]478 cast->result->accept( tyPrinter );
479 visit_children = false;
480 }
[a2dbcff1]481
[3b3491b6]482 /// Member access handled as function from aggregate to member
483 void previsit( UntypedMemberExpr* expr ) {
484 // TODO handle name extraction more generally
485 NameExpr* name = dynamic_cast<NameExpr*>(expr->member);
486
487 // fall back on just resolving call to member name
488 // TODO incorporate function type into resolv-proto
489 if ( ! name ) {
490 expr->member->accept( *visitor );
491 visit_children = false;
492 return;
493 }
494
495 rp_name( name->name, ss, "$field_" );
496 ss << "( ";
497 expr->aggregate->accept( *visitor );
498 ss << " )";
499 visit_children = false;
500 }
501
502 /// Constant expression replaced by its type
503 void previsit( ConstantExpr* expr ) {
[a4a000d]504 PassVisitor<TypePrinter> tyPrinter{ closed, ss };
[3b3491b6]505 expr->constant.get_type()->accept( tyPrinter );
506 visit_children = false;
507 }
508
509 /// sizeof( ... ), alignof( ... ), offsetof( ... ) replaced by unsigned long constant
510 /// TODO extra expression to resolve argument
511 void previsit( SizeofExpr* ) {
512 ss << (int)BasicType::LongUnsignedInt;
513 visit_children = false;
514 }
515 void previsit( AlignofExpr* ) {
516 ss << (int)BasicType::LongUnsignedInt;
517 visit_children = false;
518 }
519 void previsit( UntypedOffsetofExpr* ) {
520 ss << (int)BasicType::LongUnsignedInt;
521 visit_children = false;
522 }
523
524 /// Logical expressions represented as operators
525 void previsit( LogicalExpr* expr ) {
526 ss << '$' << ( expr->get_isAnd() ? "and" : "or" ) << "( ";
527 expr->arg1->accept( *visitor );
528 ss << ' ';
529 expr->arg2->accept( *visitor );
530 ss << " )";
531 visit_children = false;
532 }
533
534 /// Conditional expression represented as operator
535 void previsit( ConditionalExpr* expr ) {
536 ss << "$if( ";
537 expr->arg1->accept( *visitor );
538 ss << ' ';
539 expr->arg2->accept( *visitor );
540 ss << ' ';
541 expr->arg3->accept( *visitor );
542 ss << " )";
543 visit_children = false;
544 }
545
546 /// Comma expression represented as operator
547 void previsit( CommaExpr* expr ) {
548 ss << "$seq( ";
549 expr->arg1->accept( *visitor );
550 ss << ' ';
551 expr->arg2->accept( *visitor );
552 ss << " )";
553 visit_children = false;
554 }
555
556 // TODO handle ignored ImplicitCopyCtorExpr and below
557 };
558
[4d59ff9]559 void build( Initializer* init, std::stringstream& ss ) {
560 if ( SingleInit* si = dynamic_cast<SingleInit*>(init) ) {
[a4a000d]561 PassVisitor<ExprPrinter> exprPrinter{ closed, ss };
[4d59ff9]562 si->value->accept( exprPrinter );
563 ss << ' ';
564 } else if ( ListInit* li = dynamic_cast<ListInit*>(init) ) {
565 for ( Initializer* it : li->initializers ) {
566 build( it, ss );
567 }
568 }
569 }
570
571 /// Adds an object initializer to the list of expressions
572 void build( const std::string& name, Initializer* init, std::stringstream& ss ) {
[bb0f974]573 ss << "$constructor( &";
[4d59ff9]574 rp_name( name, ss );
[bb0f974]575 ss << ' ';
[4d59ff9]576 build( init, ss );
577 ss << ')';
578 }
579
580 /// Adds a return expression to the list of expressions
581 void build( Type* rtnType, Expression* expr, std::stringstream& ss ) {
582 ss << "$constructor( ";
[a4a000d]583 PassVisitor<TypePrinter> tyPrinter{ closed, ss };
[4d59ff9]584 rtnType->accept( tyPrinter );
585 ss << ' ';
[a4a000d]586 PassVisitor<ExprPrinter> exprPrinter{ closed, ss };
[4d59ff9]587 expr->accept( exprPrinter );
588 ss << " )";
589 }
590
[3b3491b6]591 /// Adds all named declarations in a list to the local scope
592 void addAll( const std::list<DeclarationWithType*>& decls ) {
593 for ( auto decl : decls ) {
594 // skip anonymous decls
595 if ( decl->name.empty() ) continue;
596
597 // handle objects
598 if ( ObjectDecl* obj = dynamic_cast< ObjectDecl* >( decl ) ) {
599 previsit( obj );
600 }
601 }
602 }
603
604 /// encode field access as function
605 void addAggregateFields( AggregateDecl* agg ) {
606 // make field names functions
607 for ( Declaration* member : agg->members ) {
608 if ( ObjectDecl* obj = dynamic_cast< ObjectDecl* >(member) ) {
609 std::stringstream ss;
610 build( obj->name, agg, obj->type, ss );
611 addDecl( ss.str() );
612 }
613 }
614
615 visit_children = false;
616 }
617
618 public:
619 void previsit( ObjectDecl *obj ) {
620 // add variable as declaration
621 std::stringstream ss;
622 build( obj->name, obj->type, ss );
623 addDecl( ss.str() );
[4d59ff9]624
625 // add initializer as expression if applicable
626 if ( obj->init ) {
627 std::stringstream ss;
628 build( obj->name, obj->init, ss );
629 addExpr( ss.str() );
630 }
[3b3491b6]631 }
632
633 void previsit( FunctionDecl *decl ) {
[4c42a5f]634 // skip decls with ftype parameters
635 for ( TypeDecl* tyvar : decl->type->forall ) {
636 if ( tyvar->get_kind() == TypeDecl::Ftype ) {
637 visit_children = false;
638 return;
639 }
640 }
641
[3b3491b6]642 // add function as declaration
643 std::stringstream ss;
644 build( decl->name, decl->type, ss );
645 addDecl( ss.str() );
646
647 // add body if available
648 if ( decl->statements ) {
[4d59ff9]649 std::list<Type*> rtns = from_decls( decl->type->returnVals );
650 Type* rtn = nullptr;
651 if ( rtns.size() == 1 ) {
652 if ( ! dynamic_cast<VoidType*>(rtns.front()) ) rtn = rtns.front()->clone();
653 } else if ( rtns.size() > 1 ) {
654 rtn = new TupleType{ Type::Qualifiers{}, rtns };
655 }
656 PassVisitor<ProtoDump> body{ this, rtn };
[a4a000d]657
658 for ( TypeDecl* tyvar : decl->type->forall ) {
659 // add set of "closed" types to body so that it can print them as NamedType
660 body.pass.closed.insert( tyvar->name );
661
662 // add assertions to local scope as declarations as well
663 for ( DeclarationWithType* assn : tyvar->assertions ) {
664 assn->accept( body );
665 }
666 }
[a2dbcff1]667
[3b3491b6]668 // add named parameters and returns to local scope
669 body.pass.addAll( decl->type->returnVals );
670 body.pass.addAll( decl->type->parameters );
671
672 // add contents of function to new scope
673 decl->statements->accept( body );
[40cd873]674
675 // store sub-scope
676 addSub( std::move(body) );
[3b3491b6]677 }
678
679 visit_children = false;
680 }
681
682 void previsit( StructDecl* sd ) { addAggregateFields(sd); }
683 void previsit( UnionDecl* ud ) { addAggregateFields(ud); }
[a2dbcff1]684
[3b3491b6]685 void previsit( EnumDecl* ed ) {
[a2dbcff1]686 std::unique_ptr<Type> eType =
[3b3491b6]687 std::make_unique<BasicType>( Type::Qualifiers{}, BasicType::SignedInt );
[a2dbcff1]688
[3b3491b6]689 // add field names directly to enclosing scope
690 for ( Declaration* member : ed->members ) {
691 if ( ObjectDecl* obj = dynamic_cast< ObjectDecl* >(member) ) {
692 previsit(obj);
693 }
694 }
695
696 visit_children = false;
697 }
698
[4d59ff9]699 void previsit( ReturnStmt* stmt ) {
700 // do nothing for void-returning functions or statements returning nothing
701 if ( ! rtnType || ! stmt->expr ) return;
702
703 // otherwise construct the return type from the expression
704 std::stringstream ss;
705 build( rtnType.get(), stmt->expr, ss );
706 addExpr( ss.str() );
707 visit_children = false;
708 }
709
[bb0f974]710 void previsit( AsmStmt* ) {
711 // skip asm statements
712 visit_children = false;
713 }
714
[3b3491b6]715 void previsit( Expression* expr ) {
716 std::stringstream ss;
[a4a000d]717 PassVisitor<ExprPrinter> exPrinter{ closed, ss };
[3b3491b6]718 expr->accept( exPrinter );
719 addExpr( ss.str() );
720 visit_children = false;
721 }
722
[a4a000d]723 /// Print non-prelude global declarations for resolv proto
724 void printGlobals() const {
[bb0f974]725 std::cout << "#$ptr<T> $addr T" << std::endl; // &?
[a4a000d]726 int i = (int)BasicType::SignedInt;
727 std::cout << i << " $and " << i << ' ' << i << std::endl; // ?&&?
728 std::cout << i << " $or " << i << ' ' << i << std::endl; // ?||?
729 std::cout << "T $if " << i << " T T" << std::endl; // ternary operator
730 std::cout << "T $seq X T" << std::endl; // ?,?
731 }
732
[3b3491b6]733 public:
734 /// Prints this ProtoDump instance
735 void print(unsigned indent = 0) const {
[a4a000d]736 // print globals at root level
737 if ( ! parent ) printGlobals();
[3b3491b6]738 // print decls
[a4a000d]739 std::string tab( indent, '\t' );
[3b3491b6]740 for ( const std::string& d : decls ) {
741 std::cout << tab << d << std::endl;
742 }
743 // print divider
[4d59ff9]744 std::cout << '\n' << tab << "%%\n" << std::endl;
[3b3491b6]745 // print top-level expressions
746 for ( const std::string& e : exprs ) {
747 std::cout << tab << e << std::endl;
748 }
749 // print child scopes
750 ++indent;
[bc179fd3]751 for ( const ProtoDump & s : subs ) {
[3b3491b6]752 std::cout << tab << '{' << std::endl;
[bc179fd3]753 s.print( indent );
[3b3491b6]754 std::cout << tab << '}' << std::endl;
755 }
756 }
757 };
758
759 void dumpAsResolvProto( std::list< Declaration * > &translationUnit ) {
760 PassVisitor<ProtoDump> dump;
761 acceptAll( translationUnit, dump );
762 dump.pass.print();
763 }
764
765} // namespace CodeTools
766
767// Local Variables: //
768// tab-width: 4 //
769// mode: c++ //
770// compile-command: "make install" //
771// End: //
Note: See TracBrowser for help on using the repository browser.