source: src/CodeTools/ResolvProtoDump.cc @ 4d59ff9

ADTaaron-thesisarm-ehast-experimentalcleanup-dtorsdeferred_resnenumforall-pointer-decayjacob/cs343-translationjenkins-sandboxnew-astnew-ast-unique-exprno_listpersistent-indexerpthread-emulationqualifiedEnum
Last change on this file since 4d59ff9 was 4d59ff9, checked in by Aaron Moss <a3moss@…>, 6 years ago

Handle initializers and returns in RPDump

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