source: src/CodeTools/ResolvProtoDump.cc @ 3b3491b

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

Add first draft of resolver prototype dumper

  • Property mode set to 100644
File size: 16.5 KB
RevLine 
[3b3491b]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 <vector>
26
27#include "Common/PassVisitor.h"
28#include "CodeGen/OperatorTable.h"
29#include "SynTree/Declaration.h"
30#include "SynTree/Expression.h"
31#include "SynTree/Statement.h"
32#include "SynTree/Type.h"
33
34namespace CodeTools {
35
36        /// Visitor for dumping resolver prototype output
37        class ProtoDump : public WithShortCircuiting, public WithVisitorRef<ProtoDump> {
38                std::set<std::string> decls;               ///< Declarations in this scope
39                std::set<std::string> exprs;               ///< Expressions in this scope
40                std::vector<PassVisitor<ProtoDump>> subs;  ///< Sub-scopes
41                const ProtoDump* parent;                   ///< Outer lexical scope
42
43        public:
44                /// Default constructor for root ProtoDump
45                ProtoDump() : decls(), exprs(), subs(), parent(nullptr) {}
46
47                /// Child constructor
48                ProtoDump(const ProtoDump& p) : decls(), exprs(), subs(), parent(&p) {}
49
50        private:
51                /// checks if this declaration is contained in the scope or one of its parents
52                bool hasDecl( const std::string& s ) const {
53                        if ( decls.count( s ) ) return true;
54                        if ( parent ) return parent->hasDecl( s );
55                        return false;
56                }
57
58                /// adds a new declaration to this scope, providing it does not already exist
59                void addDecl( const std::string& s ) {
60                        if ( ! hasDecl( s ) ) decls.insert( s );
61                }
62
63                /// adds a new expression to this scope
64                void addExpr( const std::string& s ) {
65                        if ( ! s.empty() ) { exprs.insert( s ); }
66                }
67
68                /// adds a new subscope to this scope, returning a reference
69                PassVisitor<ProtoDump>& addSub() {
70                        subs.emplace_back( *this );
71                        return subs.back();
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* ) { ss << "#$arr<"; ++depth; }
201                        void postvisit( ArrayType* ) { --depth; ss << '>'; }
202
203                        // ignore top-level reference types, they're mostly transparent to resolution
204                        void previsit( ReferenceType* ) {
205                                if ( depth > 0 ) { ss << "#$ref<"; }
206                                ++depth;
207                        }
208                        void postvisit( ReferenceType* ) {
209                                --depth;
210                                if ( depth > 0 ) { ss << '>'; }
211                        }
212
213                        // encode function type as a 2-param generic type
214                        // TODO handle forall functions
215                        void previsit( FunctionType* ft ) {
216                                ss << "#$fn<";
217                                ++depth;
218                                buildAsTuple( *visitor, from_decls( ft->returnVals ), ss );
219                                ss << ' ';
220                                buildAsTuple( *visitor, from_decls( ft->parameters ), ss );
221                                --depth;
222                                ss << '>';
223                                visit_children = false;
224                        }
225
226                private:
227                        // prints aggregate type name as NamedType with optional paramters
228                        void handleAggregate( ReferenceToType* at ) {
229                                ss << '#' << at->name;
230                                if ( ! at->parameters.empty() ) {
231                                        ss << '<';
232                                        ++depth;
233                                        build( *visitor, from_exprs( at->parameters ), ss );
234                                        --depth;
235                                        ss << '>';
236                                }
237                                visit_children = false;
238                        }
239
240                public:
241                        // handle aggregate types using NamedType
242                        void previsit( StructInstType* st ) { handleAggregate( st ); }
243                        void previsit( UnionInstType* ut ) { handleAggregate( ut ); }
244
245                        // replace enums with int
246                        void previsit( EnumInstType* ) { ss << (int)BasicType::SignedInt; }
247
248                        // make sure first letter of TypeInstType is capitalized
249                        void previsit( TypeInstType* vt ) {
250                                ti_name( vt->name, ss );
251                        }
252
253                        // flattens empty and singleton tuples
254                        void previsit( TupleType* tt ) {
255                                ++depth;
256                                buildAsTuple( *visitor, tt->types, ss );
257                                --depth;
258                                visit_children = false;
259                        }
260
261                        // TODO support VarArgsType
262
263                        // replace 0 and 1 with int
264                        // TODO support 0 and 1 with their proper type names and conversions
265                        void previsit( ZeroType* ) { ss << (int)BasicType::SignedInt; }
266                        void previsit( OneType* ) { ss << (int)BasicType::SignedInt; }
267
268                        // only print void type if not at top level
269                        void previsit( VoidType* ) {
270                                if ( depth > 0 ) { ss << "#void"; }
271                        }
272                };
273       
274                /// builds description of function
275                void build( const std::string& name, FunctionType* fnTy, std::stringstream& ss ) {
276                        PassVisitor<TypePrinter> printTy{ ss };
277                        build( printTy, from_decls( fnTy->returnVals ), ss, terminated );
278                        rp_name( name, ss );
279                        build( printTy, from_decls( fnTy->parameters ), ss, preceded );
280                        // TODO handle assertions
281                }
282
283                /// builds description of a variable (falls back to function if function type)
284                void build( const std::string& name, Type* ty, std::stringstream& ss ) {
285                        // ignore top-level references
286                        Type *norefs = ty->stripReferences();
287                       
288                        // fall back to function declaration if function type
289                        if ( PointerType* pTy = dynamic_cast< PointerType* >(norefs) ) {
290                                if ( FunctionType* fnTy = dynamic_cast< FunctionType* >(pTy->base) ) {
291                                        build( name, fnTy, ss );
292                                        return;
293                                }
294                        } else if ( FunctionType* fnTy = dynamic_cast< FunctionType* >(norefs) ) {
295                                build( name, fnTy, ss );
296                                return;
297                        }
298
299                        // print variable declaration as zero-arg function
300                        PassVisitor<TypePrinter> printTy{ ss };
301                        norefs->accept( printTy );
302                        ss << ' ';
303                        rp_name( name, ss );
304                }
305
306                /// builds description of a field access
307                void build( const std::string& name, AggregateDecl* agg, Type* ty, std::stringstream& ss ) {
308                        // ignore top-level references
309                        Type *norefs = ty->stripReferences();
310
311                        // print access as new field name
312                        PassVisitor<TypePrinter> printTy{ ss };
313                        norefs->accept( printTy );
314                        ss << ' ';
315                        rp_name( name, ss, "$field_" );
316                        ss << " #" << agg->name;
317                        // handle type parameters
318                        if ( ! agg->parameters.empty() ) {
319                                ss << '<';
320                                auto it = agg->parameters.begin();
321                                while (true) {
322                                        ti_name( (*it)->name, ss );
323                                        if ( ++it == agg->parameters.end() ) break;
324                                        ss << ' ';
325                                }
326                                ss << '>';
327                        }
328                }
329
330                /// Visitor for printing expressions
331                struct ExprPrinter : WithShortCircuiting, WithVisitorRef<ExprPrinter> {
332                        // TODO change interface to generate multiple expression candidates
333
334                        std::stringstream& ss;  ///< Output to print to
335
336                        ExprPrinter( std::stringstream& ss ) : ss(ss) {}
337
338                        /// Names handled as nullary function calls
339                        void previsit( NameExpr* expr ) {
340                                rp_name( expr->name, ss );
341                                ss << "()";
342                        }
343
344                        /// Calls handled as calls
345                        void previsit( UntypedExpr* expr ) {
346                                // TODO handle name extraction more generally
347                                NameExpr* name = dynamic_cast<NameExpr*>(expr->function);
348
349                                // fall back on just resolving call to function name
350                                // TODO incorporate function type into resolv-proto
351                                if ( ! name ) {
352                                        expr->function->accept( *visitor );
353                                        visit_children = false;
354                                        return;
355                                }
356
357                                rp_name( name->name, ss );
358                                if ( expr->args.empty() ) {
359                                        ss << "()";
360                                } else {
361                                        ss << "( ";
362                                        auto it = expr->args.begin();
363                                        while (true) {
364                                                (*it)->accept( *visitor );
365                                                if ( ++it == expr->args.end() ) break;
366                                                ss << ' ';
367                                        }
368                                        ss << " )";
369                                }
370                                visit_children = false;
371                        }
372
373                        /// Address-of handled as operator
374                        void previsit( AddressExpr* expr ) {
375                                // TODO global function to implement this
376                                ss << "$addr( ";
377                                expr->arg->accept( *visitor );
378                                ss << " )";
379                                visit_children = false;
380                        }
381
382                        /// Casts replaced with arguments
383                        /// TODO put casts in resolv-proto
384                       
385                        /// Member access handled as function from aggregate to member
386                        void previsit( UntypedMemberExpr* expr ) {
387                                // TODO handle name extraction more generally
388                                NameExpr* name = dynamic_cast<NameExpr*>(expr->member);
389
390                                // fall back on just resolving call to member name
391                                // TODO incorporate function type into resolv-proto
392                                if ( ! name ) {
393                                        expr->member->accept( *visitor );
394                                        visit_children = false;
395                                        return;
396                                }
397
398                                rp_name( name->name, ss, "$field_" );
399                                ss << "( ";
400                                expr->aggregate->accept( *visitor );
401                                ss << " )";
402                                visit_children = false;
403                        }
404
405                        /// Constant expression replaced by its type
406                        void previsit( ConstantExpr* expr ) {
407                                PassVisitor<TypePrinter> tyPrinter{ ss };
408                                expr->constant.get_type()->accept( tyPrinter );
409                                visit_children = false;
410                        }
411
412                        /// sizeof( ... ), alignof( ... ), offsetof( ... ) replaced by unsigned long constant
413                        /// TODO extra expression to resolve argument
414                        void previsit( SizeofExpr* ) {
415                                ss << (int)BasicType::LongUnsignedInt;
416                                visit_children = false;
417                        }
418                        void previsit( AlignofExpr* ) {
419                                ss << (int)BasicType::LongUnsignedInt;
420                                visit_children = false;
421                        }
422                        void previsit( UntypedOffsetofExpr* ) {
423                                ss << (int)BasicType::LongUnsignedInt;
424                                visit_children = false;
425                        }
426
427                        /// Logical expressions represented as operators
428                        void previsit( LogicalExpr* expr ) {
429                                // TODO global functions for these
430                                ss << '$' << ( expr->get_isAnd() ? "and" : "or" ) << "( ";
431                                expr->arg1->accept( *visitor );
432                                ss << ' ';
433                                expr->arg2->accept( *visitor );
434                                ss << " )";
435                                visit_children = false;
436                        }
437
438                        /// Conditional expression represented as operator
439                        void previsit( ConditionalExpr* expr ) {
440                                // TODO global function for this
441                                ss << "$if( ";
442                                expr->arg1->accept( *visitor );
443                                ss << ' ';
444                                expr->arg2->accept( *visitor );
445                                ss << ' ';
446                                expr->arg3->accept( *visitor );
447                                ss << " )";
448                                visit_children = false;
449                        }
450
451                        /// Comma expression represented as operator
452                        void previsit( CommaExpr* expr ) {
453                                // TODO global function for this
454                                ss << "$seq( ";
455                                expr->arg1->accept( *visitor );
456                                ss << ' ';
457                                expr->arg2->accept( *visitor );
458                                ss << " )";
459                                visit_children = false;
460                        }
461
462                        // TODO handle ignored ImplicitCopyCtorExpr and below
463                };
464
465                /// Adds all named declarations in a list to the local scope
466                void addAll( const std::list<DeclarationWithType*>& decls ) {
467                        for ( auto decl : decls ) {
468                                // skip anonymous decls
469                                if ( decl->name.empty() ) continue;
470
471                                // handle objects
472                                if ( ObjectDecl* obj = dynamic_cast< ObjectDecl* >( decl ) ) {
473                                        previsit( obj );
474                                }
475                        }
476                }
477
478                /// encode field access as function
479                void addAggregateFields( AggregateDecl* agg ) {
480                        // make field names functions
481                        for ( Declaration* member : agg->members ) {
482                                if ( ObjectDecl* obj = dynamic_cast< ObjectDecl* >(member) ) {
483                                        std::stringstream ss;
484                                        build( obj->name, agg, obj->type, ss );
485                                        addDecl( ss.str() );
486                                }
487                        }
488
489                        visit_children = false;
490                }
491
492        public:
493                void previsit( ObjectDecl *obj ) {
494                        // add variable as declaration
495                        std::stringstream ss;
496                        build( obj->name, obj->type, ss );
497                        addDecl( ss.str() );
498                }
499
500                void previsit( FunctionDecl *decl ) {
501                        // add function as declaration
502                        std::stringstream ss;
503                        build( decl->name, decl->type, ss );
504                        addDecl( ss.str() );
505
506                        // add body if available
507                        if ( decl->statements ) {
508                                PassVisitor<ProtoDump>& body = addSub();
509                               
510                                // add named parameters and returns to local scope
511                                body.pass.addAll( decl->type->returnVals );
512                                body.pass.addAll( decl->type->parameters );
513                               
514                                // TODO add assertions to local scope
515
516                                // TODO add set of "closed" types to body so that it can print them as NamedType
517
518                                // add contents of function to new scope
519                                decl->statements->accept( body );
520                        }
521
522                        visit_children = false;
523                }
524
525                void previsit( StructDecl* sd ) { addAggregateFields(sd); }
526                void previsit( UnionDecl* ud ) { addAggregateFields(ud); }
527               
528                void previsit( EnumDecl* ed ) {
529                        std::unique_ptr<Type> eType = 
530                                std::make_unique<BasicType>( Type::Qualifiers{}, BasicType::SignedInt );
531                       
532                        // add field names directly to enclosing scope
533                        for ( Declaration* member : ed->members ) {
534                                if ( ObjectDecl* obj = dynamic_cast< ObjectDecl* >(member) ) {
535                                        previsit(obj);
536                                }
537                        }
538
539                        visit_children = false;
540                }
541
542                void previsit( Expression* expr ) {
543                        std::stringstream ss;
544                        PassVisitor<ExprPrinter> exPrinter{ss};
545                        expr->accept( exPrinter );
546                        addExpr( ss.str() );
547                        visit_children = false;
548                }
549
550        public:
551                /// Prints this ProtoDump instance
552                void print(unsigned indent = 0) const {
553                        std::string tab( indent, '\t' );
554                        // print decls
555                        for ( const std::string& d : decls ) {
556                                std::cout << tab << d << std::endl;
557                        }
558                        // print divider
559                        std::cout << tab << "%%" << std::endl;
560                        // print top-level expressions
561                        for ( const std::string& e : exprs ) {
562                                std::cout << tab << e << std::endl;
563                        }
564                        // print child scopes
565                        ++indent;
566                        for ( const PassVisitor<ProtoDump>& s : subs ) {
567                                std::cout << tab << '{' << std::endl;
568                                s.pass.print( indent );
569                                std::cout << tab << '}' << std::endl;
570                        }
571                }
572        };
573
574        void dumpAsResolvProto( std::list< Declaration * > &translationUnit ) {
575                PassVisitor<ProtoDump> dump;
576                acceptAll( translationUnit, dump );
577                dump.pass.print();
578        }
579
580}  // namespace CodeTools
581
582// Local Variables: //
583// tab-width: 4 //
584// mode: c++ //
585// compile-command: "make install" //
586// End: //
Note: See TracBrowser for help on using the repository browser.