// // Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo // // The contents of this file are covered under the licence agreement in the // file "LICENCE" distributed with Cforall. // // Print.cpp -- // // Author : Thierry Delisle // Created On : Tue May 21 16:20:15 2019 // Last Modified By : // Last Modified On : // Update Count : // #include "Print.hpp" #include "Decl.hpp" #include "Expr.hpp" #include "Stmt.hpp" #include "Type.hpp" #include "TypeSubstitution.hpp" #include "Common/utility.h" // for group_iterate using namespace std; namespace ast { template constexpr auto make_array(T&&... values) -> array { return array{ forward(values)... }; } class Printer : public Visitor { public: ostream & os; Indenter indent; bool short_mode; Printer(ostream & os, Indenter indent, bool short_mode) : os( os ), indent( indent ), short_mode(short_mode) {} private: template< typename C > void printAll( const C & c ) { for ( const auto & i : c ) { if ( i ) { os << indent; i->accept( *this ); // need an endl after each element because it's not // easy to know when each individual item should end os << endl; } // if } // for } static const char* Names[]; struct Names { static constexpr auto FuncSpecifiers = make_array( "inline", "_Noreturn", "fortran" ); static constexpr auto StorageClasses = make_array( "extern", "static", "auto", "register", "_Thread_local" ); static constexpr auto Qualifiers = make_array( "const", "restrict", "volatile", "lvalue", "mutex", "_Atomic" ); }; template void print(const storage_t & storage, const array & Names ) { if ( storage.any() ) { for ( size_t i = 0; i < Names.size(); i += 1 ) { if ( storage[i] ) { os << Names[i] << ' '; } } } } void print( const ast::Function::Specs & specs ) { print(specs, Names::FuncSpecifiers); } void print( const ast::Storage::Classes & storage ) { print(storage, Names::StorageClasses); } void print( const ast::CV::Qualifiers & qualifiers ) { print(qualifiers, Names::Qualifiers); } void print( const ast::ParameterizedType::ForallList & forall ) { if ( forall.empty() ) return; os << "forall" << std::endl; ++indent; printAll( forall ); os << indent; --indent; } void print( const std::vector> & attrs ) { if ( attrs.empty() ) return; os << "with attributes" << std::endl; ++indent; printAll( attrs ); --indent; } void print( const std::vector> & params ) { if ( params.empty() ) return; os << std::endl << indent << "... with parameters" << std::endl; ++indent; printAll( params ); --indent; } void preprint( const ast::Type * node ) { print( node->qualifiers ); } void preprint( const ast::ParameterizedType * node ) { print( node->forall ); print( node->qualifiers ); } void preprint( const ast::ReferenceToType * node ) { print( node->forall ); print( node->attributes ); print( node->qualifiers ); } void print( const ast::AggregateDecl * node ) { os << node->typeString() << " " << node->name << ":"; if ( node->linkage != Linkage::Cforall ) { os << " " << Linkage::name( node->linkage ); } // if os << " with body : " << (node->body ? "yes " : "no "); if ( ! node->params.empty() ) { os << endl << indent << "... with parameters" << endl; ++indent; printAll( node->params ); --indent; } // if if ( ! node->members.empty() ) { os << endl << indent << "... with members" << endl; ++indent; printAll( node->members ); --indent; } // if if ( ! node->attributes.empty() ) { os << endl << indent << "... with attributes" << endl; ++indent; printAll( node->attributes ); --indent; } // if os << endl; } void print( const ast::NamedTypeDecl * node ) { if ( !node->name.empty() ) os << node->name << ": "; if ( node->linkage != Linkage::Cforall ) { os << Linkage::name( node->linkage ) << " "; } // if print( node->storage ); os << node->typeString(); if ( node->base ) { os << " for "; ++indent; node->base->accept( *this ); --indent; } // if if ( ! node->params.empty() ) { os << endl << indent << "... with parameters" << endl; ++indent; printAll( node->params ); --indent; } // if if ( ! node->assertions.empty() ) { os << endl << indent << "... with assertions" << endl; ++indent; printAll( node->assertions ); --indent; } // if } public: virtual const ast::DeclWithType * visit( const ast::ObjectDecl * node ) { if ( !node->name.empty() ) os << node->name << ": "; if ( node->linkage != Linkage::Cforall ) { os << Linkage::name( node->linkage ) << " "; } // if print( node->storage ); if ( node->type ) { node->type->accept( *this ); } else { os << " untyped entity "; } // if if ( node->init ) { os << " with initializer (" << ( node->init->maybeConstructed ? "maybe constructed" : "not constructed" ) << ")" << endl << indent+1; ++indent; node->init->accept( *this ); --indent; os << endl; } // if if ( ! node->attributes.empty() ) { os << endl << indent << "... with attributes:" << endl; ++indent; printAll( node->attributes ); --indent; } if ( node->bitfieldWidth ) { os << indent << " with bitfield width "; node->bitfieldWidth->accept( *this ); } // if return node; } virtual const ast::DeclWithType * visit( const ast::FunctionDecl * node ) { if ( !node->name.empty() ) { os << node->name << ": "; } // if if ( node->linkage != Linkage::Cforall ) { os << Linkage::name( node->linkage ) << " "; } // if printAll( node->attributes ); print( node->storage ); print( node->funcSpec ); if ( node->type ) { node->type->accept( *this ); } else { os << "untyped entity "; } // if if ( node->stmts ) { os << indent << "... with body" << endl << indent+1; ++indent; node->stmts->accept( *this ); --indent; } // if return node; } virtual const ast::Decl * visit( const ast::StructDecl * node ) { print(node); return node; } virtual const ast::Decl * visit( const ast::UnionDecl * node ) { print(node); return node; } virtual const ast::Decl * visit( const ast::EnumDecl * node ) { print(node); return node; } virtual const ast::Decl * visit( const ast::TraitDecl * node ) { print(node); return node; } virtual const ast::Decl * visit( const ast::TypeDecl * node ) { print( node ); if ( node->init ) { os << endl << indent << "with type initializer: "; ++indent; node->init->accept( *this ); --indent; } return node; } virtual const ast::Decl * visit( const ast::TypedefDecl * node ) { print( node ); return node; } virtual const ast::AsmDecl * visit( const ast::AsmDecl * node ) { node->stmt->accept( *this ); return node; } virtual const ast::StaticAssertDecl * visit( const ast::StaticAssertDecl * node ) { os << "Static Assert with condition: "; ++indent; node->cond->accept( *this ); --indent; os << endl << indent << "and message: "; ++indent; node->msg->accept( *this ); --indent; os << endl; return node; } virtual const ast::CompoundStmt * visit( const ast::CompoundStmt * node ) { os << "CompoundStmt" << endl; ++indent; printAll( node->kids ); --indent; return node; } virtual const ast::Stmt * visit( const ast::ExprStmt * node ) { ++indent; os << "Expression Statement:" << endl << indent; node->expr->accept( *this ); --indent; return node; } virtual const ast::Stmt * visit( const ast::AsmStmt * node ) { os << "Assembler Statement:" << endl; ++indent; os << indent << "instruction: " << endl << indent; node->instruction->accept( *this ); if ( ! node->output.empty() ) { os << endl << indent+1 << "output: " << endl; printAll( node->output ); } // if if ( ! node->input.empty() ) { os << indent+1 << "input: " << endl; printAll( node->input ); } // if if ( ! node->clobber.empty() ) { os << indent+1 << "clobber: " << endl; printAll( node->clobber ); } // if --indent; return node; } virtual const ast::Stmt * visit( const ast::DirectiveStmt * node ) { os << "GCC Directive:" << node->directive << endl; return node; } virtual const ast::Stmt * visit( const ast::IfStmt * node ) { os << "If on condition: " << endl; os << indent+1; ++indent; node->cond->accept( *this ); --indent; if ( !node->inits.empty() ) { os << indent << "... with initialization: \n"; ++indent; for ( const Stmt * stmt : node->inits ) { os << indent; stmt->accept( *this ); } --indent; os << endl; } os << indent << "... then: " << endl; ++indent; os << indent; node->thenPart->accept( *this ); --indent; if ( node->elsePart != 0 ) { os << indent << "... else: " << endl; ++indent; os << indent; node->elsePart->accept( *this ); --indent; } // if return node; } virtual const ast::Stmt * visit( const ast::WhileStmt * node ) { return node; } virtual const ast::Stmt * visit( const ast::ForStmt * node ) { return node; } virtual const ast::Stmt * visit( const ast::SwitchStmt * node ) { return node; } virtual const ast::Stmt * visit( const ast::CaseStmt * node ) { return node; } virtual const ast::Stmt * visit( const ast::BranchStmt * node ) { return node; } virtual const ast::Stmt * visit( const ast::ReturnStmt * node ) { return node; } virtual const ast::Stmt * visit( const ast::ThrowStmt * node ) { return node; } virtual const ast::Stmt * visit( const ast::TryStmt * node ) { return node; } virtual const ast::Stmt * visit( const ast::CatchStmt * node ) { return node; } virtual const ast::Stmt * visit( const ast::FinallyStmt * node ) { return node; } virtual const ast::Stmt * visit( const ast::WaitForStmt * node ) { return node; } virtual const ast::Stmt * visit( const ast::WithStmt * node ) { return node; } virtual const ast::NullStmt * visit( const ast::NullStmt * node ) { return node; } virtual const ast::Stmt * visit( const ast::DeclStmt * node ) { return node; } virtual const ast::Stmt * visit( const ast::ImplicitCtorDtorStmt * node ) { return node; } virtual const ast::Expr * visit( const ast::ApplicationExpr * node ) { return node; } virtual const ast::Expr * visit( const ast::UntypedExpr * node ) { return node; } virtual const ast::Expr * visit( const ast::NameExpr * node ) { return node; } virtual const ast::Expr * visit( const ast::AddressExpr * node ) { return node; } virtual const ast::Expr * visit( const ast::LabelAddressExpr * node ) { return node; } virtual const ast::Expr * visit( const ast::CastExpr * node ) { return node; } virtual const ast::Expr * visit( const ast::KeywordCastExpr * node ) { return node; } virtual const ast::Expr * visit( const ast::VirtualCastExpr * node ) { return node; } virtual const ast::Expr * visit( const ast::UntypedMemberExpr * node ) { return node; } virtual const ast::Expr * visit( const ast::MemberExpr * node ) { return node; } virtual const ast::Expr * visit( const ast::VariableExpr * node ) { return node; } virtual const ast::Expr * visit( const ast::ConstantExpr * node ) { return node; } virtual const ast::Expr * visit( const ast::SizeofExpr * node ) { return node; } virtual const ast::Expr * visit( const ast::AlignofExpr * node ) { return node; } virtual const ast::Expr * visit( const ast::UntypedOffsetofExpr * node ) { return node; } virtual const ast::Expr * visit( const ast::OffsetofExpr * node ) { return node; } virtual const ast::Expr * visit( const ast::OffsetPackExpr * node ) { return node; } virtual const ast::Expr * visit( const ast::LogicalExpr * node ) { return node; } virtual const ast::Expr * visit( const ast::ConditionalExpr * node ) { return node; } virtual const ast::Expr * visit( const ast::CommaExpr * node ) { return node; } virtual const ast::Expr * visit( const ast::TypeExpr * node ) { return node; } virtual const ast::Expr * visit( const ast::AsmExpr * node ) { return node; } virtual const ast::Expr * visit( const ast::ImplicitCopyCtorExpr * node ) { return node; } virtual const ast::Expr * visit( const ast::ConstructorExpr * node ) { return node; } virtual const ast::Expr * visit( const ast::CompoundLiteralExpr * node ) { return node; } virtual const ast::Expr * visit( const ast::RangeExpr * node ) { return node; } virtual const ast::Expr * visit( const ast::UntypedTupleExpr * node ) { return node; } virtual const ast::Expr * visit( const ast::TupleExpr * node ) { return node; } virtual const ast::Expr * visit( const ast::TupleIndexExpr * node ) { return node; } virtual const ast::Expr * visit( const ast::TupleAssignExpr * node ) { return node; } virtual const ast::Expr * visit( const ast::StmtExpr * node ) { return node; } virtual const ast::Expr * visit( const ast::UniqueExpr * node ) { return node; } virtual const ast::Expr * visit( const ast::UntypedInitExpr * node ) { return node; } virtual const ast::Expr * visit( const ast::InitExpr * node ) { return node; } virtual const ast::Expr * visit( const ast::DeletedExpr * node ) { return node; } virtual const ast::Expr * visit( const ast::DefaultArgExpr * node ) { return node; } virtual const ast::Expr * visit( const ast::GenericExpr * node ) { return node; } virtual const ast::Type * visit( const ast::VoidType * node ) { preprint( node ); os << "void"; return node; } virtual const ast::Type * visit( const ast::BasicType * node ) { preprint( node ); os << ast::BasicType::typeNames[ node->kind ]; return node; } virtual const ast::Type * visit( const ast::PointerType * node ) { preprint( node ); if ( ! node->isArray() ) { os << "pointer to "; } else { os << "decayed "; if ( node->isStatic ) { os << "static "; } if ( node->isVarLen ) { os << "variable length array of "; } else if ( node->dimension ) { os << "array of "; node->dimension->accept( *this ); os << " "; } } if ( node->base ) { node->base->accept( *this ); } else { os << "UNDEFINED"; } return node; } virtual const ast::Type * visit( const ast::ArrayType * node ) { preprint( node ); if ( node->isStatic ) { os << "static "; } if ( node->isVarLen ) { os << "variable length array of "; } else if ( node->dimension ) { os << "array of "; } else { os << "open array of "; } if ( node->base ) { node->base->accept( *this ); } else { os << "UNDEFINED"; } if ( node->dimension ) { os << " with dimension of "; node->dimension->accept( *this ); } return node; } virtual const ast::Type * visit( const ast::ReferenceType * node ) { preprint( node ); os << "reference to "; if ( node->base ) { node->base->accept( *this ); } else { os << "UNDEFINED"; } return node; } virtual const ast::Type * visit( const ast::QualifiedType * node ) { preprint( node ); ++indent; os << "Qualified Type:" << std::endl << indent; node->parent->accept( *this ); os << std::endl << indent; node->child->accept( *this ); os << std::endl; --indent; return node; } virtual const ast::Type * visit( const ast::FunctionType * node ) { preprint( node ); os << "function" << std::endl; if ( ! node->params.empty() ) { os << indent << "... with parameters" << std::endl; ++indent; printAll( node->params ); if ( node->isVarArgs ) { os << indent << "and a variable number of other arguments" << std::endl; } --indent; } else if ( node->isVarArgs ) { os << indent+1 << "accepting unspecified arguments" << std::endl; } os << indent << "... returning"; if ( node->returns.empty() ) { os << " nothing" << std::endl; } else { os << std::endl; ++indent; printAll( node->returns ); --indent; } return node; } virtual const ast::Type * visit( const ast::StructInstType * node ) { preprint( node ); os << "instance of struct " << node->name; if ( node->base ) { os << " " << ( node->base->body ? "with" : "without" ) << " body"; } print( node->params ); return node; } virtual const ast::Type * visit( const ast::UnionInstType * node ) { preprint( node ); os << "instance of union " << node->name; if ( node->base ) { os << " " << ( node->base->body ? "with" : "without" ) << " body"; } print( node->params ); return node; } virtual const ast::Type * visit( const ast::EnumInstType * node ) { preprint( node ); os << "instance of enum " << node->name; if ( node->base ) { os << " " << ( node->base->body ? "with" : "without" ) << " body"; } print( node->params ); return node; } virtual const ast::Type * visit( const ast::TraitInstType * node ) { preprint( node ); os << "instance of trait " << node->name; print( node->params ); return node; } virtual const ast::Type * visit( const ast::TypeInstType * node ) { preprint( node ); os << "instance of type " << node->name << " (" << (node->kind == ast::TypeVar::Ftype ? "" : "not ") << "function type)"; print( node->params ); return node; } virtual const ast::Type * visit( const ast::TupleType * node ) { preprint( node ); os << "tuple of types" << std::endl; ++indent; printAll( node->types ); --indent; return node; } virtual const ast::Type * visit( const ast::TypeofType * node ) { preprint( node ); if ( node->kind == ast::TypeofType::Basetypeof ) { os << "base-"; } os << "type-of expression "; if ( node->expr ) { node->expr->accept( *this ); } else { os << "UNDEFINED"; } return node; } virtual const ast::Type * visit( const ast::VarArgsType * node ) { preprint( node ); os << "builtin var args pack"; return node; } virtual const ast::Type * visit( const ast::ZeroType * node ) { preprint( node ); os << "zero_t"; return node; } virtual const ast::Type * visit( const ast::OneType * node ) { preprint( node ); os << "one_t"; return node; } virtual const ast::Type * visit( const ast::GlobalScopeType * node ) { preprint( node ); os << "Global Scope Type"; return node; } virtual const ast::Designation * visit( const ast::Designation * node ) { if ( node->designators.empty() ) return node; os << "... designated by: " << std::endl; ++indent; for ( const ast::Expr * d : node->designators ) { os << indent; d->accept( *this ); os << std::endl; } --indent; return node; } virtual const ast::Init * visit( const ast::SingleInit * node ) { os << "Simple Initializer: "; node->value->accept( *this ); return node; } virtual const ast::Init * visit( const ast::ListInit * node ) { os << "Compound initializer: " << std::endl; ++indent; for ( auto p : group_iterate( node->designations, node->initializers ) ) { const ast::Designation * d = std::get<0>(p); const ast::Init * init = std::get<1>(p); os << indent; init->accept( *this ); os << std::endl; if ( ! d->designators.empty() ) { os << indent; d->accept( *this ); } } --indent; return node; } virtual const ast::Init * visit( const ast::ConstructorInit * node ) { os << "Constructor initializer: " << std::endl; if ( node->ctor ) { os << indent << "... initially constructed with "; ++indent; node->ctor->accept( *this ); --indent; } if ( node->dtor ) { os << indent << "... destructed with "; ++indent; node->dtor->accept( *this ); --indent; } if ( node->init ) { os << indent << "... with fallback C-style initializer: "; ++indent; node->init->accept( *this ); --indent; } return node; } virtual const ast::Attribute * visit( const ast::Attribute * node ) { if ( node->empty() ) return node; os << "Attribute with name: " << node->name; if ( node->params.empty() ) return node; os << " with parameters: " << std::endl; ++indent; printAll( node->params ); --indent; return node; } virtual const ast::TypeSubstitution * visit( const ast::TypeSubstitution * node ) { os << indent << "Types:" << std::endl; for ( const auto& i : *node ) { os << indent+1 << i.first << " -> "; indent += 2; i.second->accept( *this ); indent -= 2; os << std::endl; } os << indent << "Non-types:" << std::endl; for ( auto i = node->beginVar(); i != node->endVar(); ++i ) { os << indent+1 << i->first << " -> "; indent += 2; i->second->accept( *this ); indent -= 2; os << std::endl; } return node; } }; void print( ostream & os, const ast::Node * node, Indenter indent ) { Printer printer { os, indent, false }; node->accept(printer); } void printShort( ostream & os, const ast::Node * node, Indenter indent ) { Printer printer { os, indent, true }; node->accept(printer); } // Annoyingly these needed to be defined out of line to avoid undefined references. // The size here needs to be explicit but at least the compiler will produce an error // if the wrong size is specified constexpr array Printer::Names::FuncSpecifiers; constexpr array Printer::Names::StorageClasses; constexpr array Printer::Names::Qualifiers; }