source: src/CodeTools/ResolvProtoDump.cc @ 60a8062

ADTarm-ehast-experimentalenumforall-pointer-decayjacob/cs343-translationjenkins-sandboxnew-astnew-ast-unique-exprpthread-emulationqualifiedEnum
Last change on this file since 60a8062 was 60a8062, checked in by Peter A. Buhr <pabuhr@…>, 4 years ago

rewrite most of OperatorTable? and change caller modules to use new interface

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