source: src/CodeTools/ResolvProtoDump.cc @ 40cd873

aaron-thesisarm-ehcleanup-dtorsdeferred_resnjacob/cs343-translationjenkins-sandboxnew-astnew-ast-unique-exprno_listpersistent-indexer
Last change on this file since 40cd873 was 40cd873, checked in by Aaron Moss <a3moss@…>, 3 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.