// // 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 namespace ast { template constexpr auto make_array(T&&... values) -> std::array { return std::array{ std::forward(values)... }; } class Printer : public Visitor { public: std::ostream & os; Indenter indent; Printer(std::ostream & os, Indenter indent) : os( os ), indent( indent ) {} 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 << std::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 std::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 ); } public: virtual const ast::DeclWithType * visit( const ast::ObjectDecl * node ) { if ( node->name != "" ) 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" ) << ")" << std::endl << indent+1; ++indent; node->init->accept( *this ); --indent; os << std::endl; } // if if ( ! node->attributes.empty() ) { os << std::endl << indent << "... with attributes:" << std::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 ) { return node; } virtual const ast::Decl * visit( const ast::StructDecl * node ) { return node; } virtual const ast::Decl * visit( const ast::UnionDecl * node ) { return node; } virtual const ast::Decl * visit( const ast::EnumDecl * node ) { return node; } virtual const ast::Decl * visit( const ast::TraitDecl * node ) { return node; } virtual const ast::Decl * visit( const ast::TypeDecl * node ) { return node; } virtual const ast::Decl * visit( const ast::TypedefDecl * node ) { return node; } virtual const ast::AsmDecl * visit( const ast::AsmDecl * node ) { return node; } virtual const ast::StaticAssertDecl * visit( const ast::StaticAssertDecl * node ) { return node; } virtual const ast::CompoundStmt * visit( const ast::CompoundStmt * node ) { return node; } virtual const ast::Stmt * visit( const ast::ExprStmt * node ) { return node; } virtual const ast::Stmt * visit( const ast::AsmStmt * node ) { return node; } virtual const ast::Stmt * visit( const ast::DirectiveStmt * node ) { return node; } virtual const ast::Stmt * visit( const ast::IfStmt * node ) { 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( std::ostream & os, const ast::Node * node, Indenter indent ) { Printer printer { os, indent }; 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 std::array Printer::Names::FuncSpecifiers; constexpr std::array Printer::Names::StorageClasses; constexpr std::array Printer::Names::Qualifiers; }