source: src/Common/ResolvProtoDump.cpp @ f3f009f

Last change on this file since f3f009f was 9feb34b, checked in by Andrew Beach <ajbeach@…>, 20 months ago

Moved toString and toCString to a new header. Updated includes. cassert was somehow getting instances of toString before but that stopped working so I embedded the new smaller include.

  • Property mode set to 100644
File size: 21.5 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.cpp -- Prints AST as instances for resolv-proto.
8//
9// Author           : Andrew Beach
10// Created On       : Wed Oct  6 14:10:00 2021
11// Last Modified By : Andrew Beach
12// Last Modified On : Tue Oct 18 11:23:00 2021
13// Update Count     : 0
14//
15
16#include "ResolvProtoDump.hpp"
17
18#include <cctype>
19#include <iostream>
20#include <set>
21#include <sstream>
22#include <unordered_set>
23
24#include "AST/Copy.hpp"
25#include "AST/Pass.hpp"
26#include "AST/TranslationUnit.hpp"
27#include "AST/Type.hpp"
28#include "CodeGen/OperatorTable.h"
29
30namespace {
31
32/// Add a prefix to an existing name.
33std::string add_prefix( const std::string & prefix, const char * added ) {
34        if ( prefix.empty() ) {
35                return std::string("$") + added;
36        } else {
37                return prefix + added;
38        }
39}
40
41/// Shortens operator names.
42std::string op_name( const std::string & name ) {
43        if ( name.compare( 0, 10, "_operator_" ) == 0 ) {
44                return name.substr( 10 );
45        } else if ( name.compare( "_constructor" ) == 0
46                        || name.compare( "_destructor" ) == 0 ) {
47                return name.substr( 1 );
48        } else if ( name.compare( 0, 11, "__operator_" ) == 0 ) {
49                return name.substr( 11 );
50        } else {
51                return name;
52        }
53}
54
55/// Get the resolv-proto names for operators.
56std::string rp_name( const std::string & name, std::string && pre = "" ) {
57        // Check for anonymous names.
58        if ( name.empty() ) {
59                return add_prefix( pre, "anon" );
60        }
61
62        // Replace operator names.
63        const CodeGen::OperatorInfo * opInfo = CodeGen::operatorLookup( name );
64        if ( nullptr != opInfo ) {
65                return add_prefix( pre, "" ) + op_name( opInfo->outputName );
66        }
67
68        // Replace return value prefix.
69        if ( name.compare( 0, 8, "_retval_" ) == 0 ) {
70                return add_prefix( pre, "rtn_" ) + op_name( name.substr( 8 ) );
71        }
72
73        // Default to just name, with first character in lowercase.
74        if ( std::isupper( name[0] ) ) {
75                std::string copy = name;
76                copy[0] = std::tolower( copy[0] );
77                return pre + copy;
78        }
79        return pre + name;
80}
81
82/// Normalise a type instance name.
83std::string ti_name( const std::string & name ) {
84        // Replace built-in names
85        if ( name == "char16_t" || name == "char32_t" || name == "wchar_t" ) {
86                return std::string("#") + name;
87        }
88
89        // Strip leadng underscores.
90        unsigned i = 0;
91        while ( i < name.size() && name[i] == '_' ) { ++i; }
92        if ( i == name.size() ) {
93                return "Anon";
94        }
95
96        std::string stripped = name.substr( i );
97        // Strip trailing generic from autogen names ()
98        static char generic[] = "_generic_";
99        static size_t n_generic = sizeof(generic) - 1;
100        if ( stripped.size() >= n_generic
101                        && stripped.substr( stripped.size() - n_generic ) == generic ) {
102                stripped.resize( stripped.size() - n_generic );
103        }
104
105        // Uppercase first character.
106        stripped[0] = std::toupper( stripped[0] );
107        return stripped;
108}
109
110std::vector<ast::ptr<ast::Type>> to_types(
111                const std::vector<ast::ptr<ast::Expr>> & data ) {
112        std::vector<ast::ptr<ast::Type>> ret_val;
113        ret_val.reserve( data.size() );
114        for ( auto entry : data ) {
115                if ( auto * typeExpr = entry.as<ast::TypeExpr>() ) {
116                        ret_val.emplace_back( typeExpr->type );
117                }
118        }
119        return ret_val;
120}
121
122enum class septype { separated, terminated, preceded };
123
124template<typename V>
125void build(
126                V & visitor,
127                const std::vector<ast::ptr<ast::Type>> & types,
128                std::stringstream & ss,
129                septype mode );
130
131template<typename V>
132void buildAsTuple(
133                V & visitor, const std::vector<ast::ptr<ast::Type>> & types,
134                std::stringstream & ss );
135
136struct TypePrinter : public ast::WithShortCircuiting, ast::WithVisitorRef<TypePrinter> {
137        /// Accumulator for the printed type.
138        std::stringstream ss;
139        /// Closed type variables.
140        const std::unordered_set<std::string> & closed;
141        /// Depth of nesting from root type.
142        unsigned depth;
143
144        TypePrinter( const std::unordered_set<std::string> & closed ) :
145                ss(), closed(closed), depth(0)
146        {}
147
148        std::string result() const {
149                return ss.str();
150        }
151
152        // Basic type represented as an integer type.
153        // TODO: Maybe hard-code conversion graph and make named type.
154        void previsit( const ast::BasicType * type ) {
155                ss << (int)type->kind;
156        }
157
158        // Pointers (except function pointers) are represented as generic type.
159        void previsit( const ast::PointerType * type ) {
160                if ( nullptr == type->base.as<ast::FunctionType>() ) {
161                        ss << "#$ptr<";
162                        ++depth;
163                }
164        }
165        void postvisit( const ast::PointerType * type ) {
166                if ( nullptr == type->base.as<ast::FunctionType>() ) {
167                        --depth;
168                        ss << '>';
169                }
170        }
171
172        // Arrays repersented as pointers.
173        void previsit( const ast::ArrayType * type ) {
174                ss << "#$ptr<";
175                ++depth;
176                type->base->accept( *visitor );
177                --depth;
178                ss << '>';
179                visit_children = false;
180        }
181
182        // Ignore top-level references as they are mostly transparent to resolution.
183        void previsit( const ast::ReferenceType * ) {
184                if ( !atTopLevel() ) { ss << "#$ref<"; }
185                ++depth;
186        }
187        void postvisit( const ast::ReferenceType * ) {
188                --depth;
189                if ( !atTopLevel() ) { ss << '>'; }
190        }
191
192        void previsit( const ast::FunctionType * type ) {
193                ss << '[';
194                ++depth;
195                build( *visitor, type->returns, ss, septype::preceded );
196                ss << " : ";
197                build( *visitor, type->params, ss, septype::terminated );
198                --depth;
199                ss << ']';
200                visit_children = false;
201        }
202
203private:
204        bool atTopLevel() const {
205                return 0 == depth;
206        }
207
208        void handleAggregate( const ast::BaseInstType * type ) {
209                ss << '#' << type->name;
210                if ( !type->params.empty() ) {
211                        ss << '<';
212                        ++depth;
213                        build( *visitor, to_types( type->params ), ss, septype::separated );
214                        --depth;
215                        ss << '>';
216                }
217                visit_children = false;
218        }
219public:
220
221        void previsit( const ast::StructInstType * type ) {
222                handleAggregate( type );
223        }
224
225        void previsit( const ast::UnionInstType * type ) {
226                handleAggregate( type );
227        }
228
229        void previsit( const ast::EnumInstType * ) {
230                // TODO: Add the meaningful text representation of typed enum
231                ss << (int)ast::BasicType::SignedInt;
232        }
233
234        void previsit( const ast::TypeInstType * type ) {
235                // Print closed variables as named types.
236                if ( closed.count( type->name ) ) {
237                        ss << '#' << type->name;
238                // Otherwise normalize the name.
239                } else {
240                        ss << ti_name( type->name );
241                }
242        }
243
244        void previsit( const ast::TupleType * tupleType ) {
245                ++depth;
246                buildAsTuple( *visitor, tupleType->types, ss );
247                --depth;
248                visit_children = false;
249        }
250
251        void previsit( const ast::VarArgsType * ) {
252                if ( atTopLevel() ) ss << "#$varargs";
253        }
254
255        // TODO: Support 0 and 1 with their type names and conversions.
256        void previsit( const ast::ZeroType * ) {
257                ss << (int)ast::BasicType::SignedInt;
258        }
259
260        void previsit( const ast::OneType * ) {
261                ss << (int)ast::BasicType::SignedInt;
262        }
263
264        void previsit( const ast::VoidType * ) {
265                if ( !atTopLevel() ) {
266                        ss << "#void";
267                }
268        }
269};
270
271struct ExprPrinter : public ast::WithShortCircuiting, ast::WithVisitorRef<ExprPrinter> {
272        // TODO: Change interface to generate multiple expression canditates.
273        /// Accumulator of the printed expression.
274        std::stringstream ss;
275        /// Set of closed type variables.
276        const std::unordered_set<std::string> & closed;
277
278        ExprPrinter( const std::unordered_set<std::string> & closed ) :
279                ss(), closed( closed )
280        {}
281
282        std::string result() const {
283                return ss.str();
284        }
285
286        void previsit( const ast::NameExpr * expr ) {
287                ss << '&' << rp_name( expr->name );
288        }
289
290        /// Handle already resolved variables as type constants.
291        void previsit( const ast::VariableExpr * expr ) {
292                ss << ast::Pass<TypePrinter>::read( expr->var->get_type(), closed );
293                visit_children = false;
294        }
295
296        void previsit( const ast::UntypedExpr * expr ) {
297                // TODO: Handle name extraction more generally.
298                const ast::NameExpr * name = expr->func.as<ast::NameExpr>();
299
300                // TODO: Incorporate function type into resolv-proto.
301                if ( !name ) {
302                        expr->func->accept( *visitor );
303                        visit_children = false;
304                        return;
305                }
306
307                ss << rp_name( name->name );
308                if ( expr->args.empty() ) {
309                        ss << "()";
310                } else {
311                        ss << "( ";
312                        auto it = expr->args.begin();
313                        while (true) {
314                                (*it)->accept( *visitor );
315                                if ( ++it == expr->args.end() ) break;
316                                ss << ' ';
317                        }
318                        ss << " )";
319                }
320                visit_children = false;
321        }
322
323        void previsit( const ast::ApplicationExpr * expr ) {
324                ss << ast::Pass<TypePrinter>::read( static_cast<const ast::Expr *>( expr ), closed );
325                visit_children = false;
326        }
327
328        void previsit( const ast::AddressExpr * expr ) {
329                ss << "$addr( ";
330                expr->arg->accept( *visitor );
331                ss << " )";
332                visit_children = false;
333        }
334
335        void previsit( const ast::CastExpr * expr ) {
336                ss << ast::Pass<TypePrinter>::read( expr->result.get(), closed );
337                visit_children = false;
338        }
339
340        /// Member access handled as function from aggregate to member.
341        void previsit( const ast::UntypedMemberExpr * expr ) {
342                // TODO: Handle name extraction more generally.
343                const ast::NameExpr * name = expr->member.as<ast::NameExpr>();
344
345                // TODO: Incorporate function type into resolve-proto.
346                if ( !name ) {
347                        expr->member->accept( *visitor );
348                        visit_children = false;
349                        return;
350                }
351
352                ss << rp_name( name->name, "$field_" );
353                ss << "( ";
354                expr->aggregate->accept( *visitor );
355                ss << " )";
356                visit_children = false;
357        }
358
359        /// Constant expression replaced by its type.
360        void previsit( const ast::ConstantExpr * expr ) {
361                ss << ast::Pass<TypePrinter>::read( static_cast<const ast::Expr *>( expr ), closed );
362                visit_children = false;
363        }
364
365        /// sizeof, alignof, & offsetof are replaced by constant type.
366        // TODO: Extra expression to resolve argument.
367        void previsit( const ast::SizeofExpr * ) {
368                ss << (int)ast::BasicType::LongUnsignedInt;
369                visit_children = false;
370        }
371        void previsit( const ast::AlignofExpr * ) {
372                ss << (int)ast::BasicType::LongUnsignedInt;
373                visit_children = false;
374        }
375        void previsit( const ast::UntypedOffsetofExpr * ) {
376                ss << (int)ast::BasicType::LongUnsignedInt;
377                visit_children = false;
378        }
379
380        /// Logical expressions represented as operators.
381        void previsit( const ast::LogicalExpr * expr ) {
382                ss << ( (ast::AndExpr == expr->isAnd) ? "$and( " : "$or( " );
383                expr->arg1->accept( *visitor );
384                ss << ' ';
385                expr->arg2->accept( *visitor );
386                ss << " )";
387                visit_children = false;
388        }
389
390        /// Conditional expression represented as an operator.
391        void previsit( const ast::ConditionalExpr * expr ) {
392                ss << "$if( ";
393                expr->arg1->accept( *visitor );
394                ss << ' ';
395                expr->arg2->accept( *visitor );
396                ss << ' ';
397                expr->arg3->accept( *visitor );
398                ss << " )";
399                visit_children = false;
400        }
401
402        /// Comma expression represented as on operator.
403        void previsit( const ast::CommaExpr * expr ) {
404                ss << "$seq( ";
405                expr->arg1->accept( *visitor );
406                ss << ' ';
407                expr->arg2->accept( *visitor );
408                ss << " )";
409                visit_children = false;
410        }
411
412        // TODO: Handle ignored ImplicitCopyCtorExpr and below.
413};
414
415template<typename V>
416void build(
417                V & visitor,
418                const std::vector<ast::ptr<ast::Type>> & types,
419                std::stringstream & ss,
420                septype mode ) {
421        if ( types.empty() ) return;
422
423        if ( septype::preceded == mode ) { ss << ' '; }
424
425        auto it = types.begin();
426        (*it)->accept( visitor );
427
428        while ( ++it != types.end() ) {
429                ss << ' ';
430                (*it)->accept( visitor );
431        }
432
433        if ( septype::terminated == mode ) { ss << ' '; }
434}
435
436std::string buildType(
437                const std::string & name, const ast::Type * type,
438                const std::unordered_set<std::string> & closed );
439
440/// Build a string representing a function type.
441std::string buildFunctionType(
442                const std::string & name, const ast::FunctionType * type,
443                const std::unordered_set<std::string> & closed ) {
444        ast::Pass<TypePrinter> printer( closed );
445        std::stringstream & ss = printer.core.ss;
446
447        build( printer, type->returns, ss, septype::terminated );
448        ss << rp_name( name );
449        build( printer, type->params, ss, septype::preceded );
450        for ( const auto & assertion : type->assertions ) {
451                auto var = assertion->var;
452                ss << " | " << buildType( var->name, var->get_type(), closed );
453        }
454        return ss.str();
455}
456
457/// Build a description of a type.
458std::string buildType(
459                const std::string & name, const ast::Type * type,
460                const std::unordered_set<std::string> & closed ) {
461        const ast::Type * norefs = type->stripReferences();
462
463        if ( const auto & ptrType = dynamic_cast<const ast::PointerType *>( norefs ) ) {
464                if ( const auto & funcType = ptrType->base.as<ast::FunctionType>() ) {
465                        return buildFunctionType( name, funcType, closed );
466                }
467        } else if ( const auto & funcType = dynamic_cast<const ast::FunctionType *>( norefs ) ) {
468                return buildFunctionType( name, funcType, closed );
469        }
470
471        std::stringstream ss;
472        ss << ast::Pass<TypePrinter>::read( norefs, closed );
473        ss << " &" << rp_name( name );
474        return ss.str();
475}
476
477/// Builds description of a field access.
478std::string buildAggregateDecl( const std::string & name,
479                const ast::AggregateDecl * agg, const ast::Type * type,
480                const std::unordered_set<std::string> & closed ) {
481        const ast::Type * norefs = type->stripReferences();
482        std::stringstream ss;
483
484        ss << ast::Pass<TypePrinter>::read( norefs, closed ) << ' ';
485        ss << rp_name( name, "$field_" );
486        ss << " #" << agg->name;
487        if ( !agg->params.empty() ) {
488                ss << '<';
489                auto it = agg->params.begin();
490                while (true) {
491                        ss << ti_name( (*it)->name );
492                        if ( ++it == agg->params.end() ) break;
493                        ss << ' ';
494                }
495                ss << '>';
496        }
497        return ss.str();
498}
499
500template<typename V>
501void buildAsTuple(
502                V & visitor, const std::vector<ast::ptr<ast::Type>> & types,
503                std::stringstream & ss ) {
504        switch ( types.size() ) {
505        case 0:
506                ss << "#void";
507                break;
508        case 1:
509                types.front()->accept( visitor );
510                break;
511        default:
512                ss << "#$" << types.size() << '<';
513                build( visitor, types, ss, septype::separated );
514                ss << '>';
515                break;
516        }
517}
518
519/// Adds a return
520std::string buildReturn(
521                const ast::Type * returnType,
522                const ast::Expr * expr,
523                const std::unordered_set<std::string> & closed ) {
524        std::stringstream ss;
525        ss << "$constructor( ";
526        ss << ast::Pass<TypePrinter>::read( returnType, closed );
527        ss << ' ';
528        ss << ast::Pass<ExprPrinter>::read( expr, closed );
529        ss << " )";
530        return ss.str();
531}
532
533void buildInitComponent(
534                std::stringstream & out, const ast::Init * init,
535                const std::unordered_set<std::string> & closed ) {
536        if ( const auto * s = dynamic_cast<const ast::SingleInit *>( init ) ) {
537                out << ast::Pass<ExprPrinter>::read( s->value.get(), closed ) << ' ';
538        } else if ( const auto * l = dynamic_cast<const ast::ListInit *>( init ) ) {
539                for ( const auto & it : l->initializers ) {
540                        buildInitComponent( out, it, closed );
541                }
542        }
543}
544
545/// Build a representation of an initializer.
546std::string buildInitializer(
547                const std::string & name, const ast::Init * init,
548                const std::unordered_set<std::string> & closed ) {
549        std::stringstream ss;
550        ss << "$constructor( &";
551        ss << rp_name( name );
552        ss << ' ';
553        buildInitComponent( ss, init, closed );
554        ss << ')';
555        return ss.str();
556}
557
558/// Visitor for collecting and printing resolver prototype output.
559class ProtoDump : public ast::WithShortCircuiting, ast::WithVisitorRef<ProtoDump> {
560        /// Declarations in this scope.
561        // Set is used for ordering of printing.
562        std::set<std::string> decls;
563        /// Expressions in this scope.
564        std::vector<std::string> exprs;
565        /// Sub-scopes
566        std::vector<ProtoDump> subs;
567        /// Closed type variables
568        std::unordered_set<std::string> closed;
569        /// Outer lexical scope
570        const ProtoDump * parent;
571        /// Return type for this scope
572        ast::ptr<ast::Type> returnType;
573
574        /// Is the declaration in this scope or a parent scope?
575        bool hasDecl( const std::string & decl ) const {
576                return decls.count( decl ) || (parent && parent->hasDecl( decl ));
577        }
578
579        /// Adds a declaration to this scope if it is new.
580        void addDecl( const std::string & decl ) {
581                if ( !hasDecl( decl ) ) decls.insert( decl );
582        }
583
584        /// Adds a new expression to this scope.
585        void addExpr( const std::string & expr ) {
586                if ( !expr.empty() ) exprs.emplace_back( expr );
587        }
588
589        /// Adds a new scope as a child scope.
590        void addSub( ast::Pass<ProtoDump> && pass ) {
591                subs.emplace_back( std::move( pass.core ) );
592        }
593
594        /// Adds all named declaration in a list to the local scope.
595        void addAll( const std::vector<ast::ptr<ast::DeclWithType>> & decls ) {
596                for ( auto decl : decls ) {
597                        // Skip anonymous decls.
598                        if ( decl->name.empty() ) continue;
599
600                        if ( const auto & obj = decl.as<ast::ObjectDecl>() ) {
601                                previsit( obj );
602                        }
603                }
604        }
605
606public:
607        ProtoDump() :
608                parent( nullptr ), returnType( nullptr )
609        {}
610
611        ProtoDump( const ProtoDump * parent, const ast::Type * returnType ) :
612                closed( parent->closed ), parent( parent ), returnType( returnType )
613        {}
614
615        ProtoDump( const ProtoDump & other ) :
616                decls( other.decls ), exprs( other.exprs ), subs( other.subs ),
617                closed( other.closed ), parent( other.parent ),
618                returnType( other.returnType )
619        {}
620
621        ProtoDump( ProtoDump && ) = default;
622
623        ProtoDump & operator=( const ProtoDump & ) = delete;
624        ProtoDump & operator=( ProtoDump && ) = delete;
625
626        void previsit( const ast::ObjectDecl * decl ) {
627                // Add variable as declaration.
628                addDecl( buildType( decl->name, decl->type, closed ) );
629
630                // Add initializer as expression if applicable.
631                if ( decl->init ) {
632                        addExpr( buildInitializer( decl->name, decl->init, closed ) );
633                }
634        }
635
636        void previsit( const ast::FunctionDecl * decl ) {
637                visit_children = false;
638
639                // Skips declarations with ftype parameters.
640                for ( const auto & typeDecl : decl->type->forall ) {
641                        if ( ast::TypeDecl::Ftype == typeDecl->kind ) {
642                                return;
643                        }
644                }
645
646                // Add function as declaration.
647                // NOTE: I'm not sure why the assertions are only present on the
648                // declaration and not the function type. Is that an error?
649                ast::FunctionType * new_type = ast::shallowCopy( decl->type.get() );
650                for ( const ast::ptr<ast::DeclWithType> & assertion : decl->assertions ) {
651                        new_type->assertions.push_back(
652                                new ast::VariableExpr( assertion->location , assertion )
653                        );
654                }
655                addDecl( buildFunctionType( decl->name, new_type, closed ) );
656                delete new_type;
657
658                // Add information body if available.
659                if ( !decl->stmts ) return;
660                const std::vector<ast::ptr<ast::Type>> & returns =
661                                decl->type->returns;
662
663                // Add the return statement.
664                ast::ptr<ast::Type> retType = nullptr;
665                if ( 1 == returns.size() ) {
666                        if ( !returns.front().as<ast::VoidType>() ) {
667                                retType = returns.front();
668                        }
669                } else if ( 1 < returns.size() ) {
670                        retType = new ast::TupleType( copy( returns ) );
671                }
672                ast::Pass<ProtoDump> body( this, retType.get() );
673
674                // Handle the forall clause (type parameters and assertions).
675                for ( const ast::ptr<ast::TypeDecl> & typeDecl : decl->type_params ) {
676                        // Add set of "closed" types to body so that it can print them as NamedType.
677                        body.core.closed.insert( typeDecl->name );
678
679                        // Add assertions to local scope as declarations as well.
680                        for ( const ast::DeclWithType * assertion : typeDecl->assertions ) {
681                                assertion->accept( body );
682                        }
683                }
684
685                // NOTE: Related to the last NOTE; this is where the assertions are now.
686                for ( const ast::ptr<ast::DeclWithType> & assertion : decl->assertions ) {
687                        assertion->accept( body );
688                }
689
690                // Add named parameters and returns to local scope.
691                body.core.addAll( decl->returns );
692                body.core.addAll( decl->params );
693
694                // Add contents of the function to a new scope.
695                decl->stmts->accept( body );
696
697                // Store sub-scope
698                addSub( std::move( body ) );
699        }
700
701private:
702        void addAggregateFields( const ast::AggregateDecl * agg ) {
703                for ( const auto & member : agg->members ) {
704                        if ( const ast::ObjectDecl * obj = member.as<ast::ObjectDecl>() ) {
705                                addDecl( buildAggregateDecl( obj->name, agg, obj->type, closed ) );
706                        }
707                }
708                visit_children = false;
709        }
710
711public:
712
713        void previsit( const ast::StructDecl * decl ) {
714                addAggregateFields( decl );
715        }
716
717        void previsit( const ast::UnionDecl * decl ) {
718                addAggregateFields( decl );
719        }
720
721        void previsit( const ast::EnumDecl * decl ) {
722                for ( const auto & member : decl->members ) {
723                        if ( const auto * obj = member.as<ast::ObjectDecl>() ) {
724                                previsit( obj );
725                        }
726                }
727
728                visit_children = false;
729        }
730
731        void previsit( const ast::ReturnStmt * stmt ) {
732                // Do nothing for void-returning functions or statements returning nothing.
733                if ( !returnType || !stmt->expr ) return;
734
735                // Otherwise constuct the return type from the expression.
736                addExpr( buildReturn( returnType.get(), stmt->expr, closed ) );
737                visit_children = false;
738        }
739
740        void previsit( const ast::AsmStmt * ) {
741                // Skip asm statements.
742                visit_children = false;
743        }
744
745        void previsit( const ast::Expr * expr ) {
746                addExpr( ast::Pass<ExprPrinter>::read( expr, closed ) );
747                visit_children = false;
748        }
749
750private:
751        /// Print the pesudo-declarations not in any scope.
752        void printGlobal( std::ostream & out ) const {
753                // &? Address of operator.
754                out << "#$ptr<T> $addr T" << std::endl;
755                const int intId = (int)ast::BasicType::SignedInt;
756                // ?&&? ?||? ?: Logical operators.
757                out << intId << " $and " << intId << ' ' << intId << std::endl;
758                out << intId << " $or " << intId << ' ' << intId << std::endl;
759                out << "T $if " << intId << " T T" << std::endl;
760                // ?,? Sequencing.
761                out << "T $seq X T" << std::endl;
762        }
763
764        /// Print everything in this scope and its child scopes.
765        void printLocal( std::ostream & out, unsigned indent ) const {
766                const std::string tab( indent, '\t' );
767
768                // Print Declarations:
769                for ( const std::string & decl : decls ) {
770                        out << tab << decl << std::endl;
771                }
772
773                // Print Divider:
774                out << '\n' << tab << "%%\n" << std::endl;
775
776                // Print Top-Level Expressions:
777                for ( const std::string & expr : exprs ) {
778                        out << tab << expr << std::endl;
779                }
780
781                // Print Children Scopes:
782                ++indent;
783                for ( const ProtoDump & sub : subs ) {
784                        out << tab << '{' << std::endl;
785                        sub.printLocal( out, indent );
786                        out << tab << '}' << std::endl;
787                }
788        }
789public:
790        /// Start printing, the collected information.
791        void print( std::ostream & out ) const {
792                printGlobal( out );
793                printLocal( out, 0 );
794        }
795};
796
797} // namespace
798
799void dumpAsResolverProto( ast::TranslationUnit & transUnit ) {
800        ast::Pass<ProtoDump> dump;
801        accept_all( transUnit, dump );
802        dump.core.print( std::cout );
803}
804
805// Local Variables: //
806// tab-width: 4 //
807// mode: c++ //
808// compile-command: "make install" //
809// End: //
Note: See TracBrowser for help on using the repository browser.