#include // for NULL #include // for find, all_of #include // for assertf, assert, strict_dynamic_cast #include // for ostream, cerr, endl #include // for back_insert_iterator, back_inserter #include // for __shared_ptr #include "Common/SemanticError.h" // for SemanticError #include "Common/UniqueName.h" // for UniqueName #include "Common/utility.h" // for toString, deleteAll, maybeClone #include "GenPoly/GenPoly.h" // for getFunctionType #include "InitTweak.h" #include "Parser/LinkageSpec.h" // for Spec, isBuiltin, Intrinsic #include "ResolvExpr/typeops.h" // for typesCompatibleIgnoreQualifiers #include "SymTab/Indexer.h" // for Indexer #include "SynTree/Attribute.h" // for Attribute #include "SynTree/Constant.h" // for Constant #include "SynTree/Declaration.h" // for ObjectDecl, DeclarationWithType #include "SynTree/Expression.h" // for Expression, UntypedExpr, Applicati... #include "SynTree/Initializer.h" // for Initializer, ListInit, Designation #include "SynTree/Label.h" // for Label, noLabels #include "SynTree/Statement.h" // for CompoundStmt, ExprStmt, BranchStmt #include "SynTree/Type.h" // for FunctionType, ArrayType, PointerType #include "SynTree/Visitor.h" // for Visitor, maybeAccept class UntypedValofExpr; namespace InitTweak { namespace { class HasDesignations : public Visitor { public: bool hasDesignations = false; virtual void visit( Designation * des ) { if ( ! des->get_designators().empty() ) hasDesignations = true; else Visitor::visit( des ); } }; class InitDepthChecker : public Visitor { public: bool depthOkay = true; Type * type; int curDepth = 0, maxDepth = 0; InitDepthChecker( Type * type ) : type( type ) { Type * t = type; while ( ArrayType * at = dynamic_cast< ArrayType * >( t ) ) { maxDepth++; t = at->get_base(); } maxDepth++; } virtual void visit( ListInit * listInit ) { curDepth++; if ( curDepth > maxDepth ) depthOkay = false; Visitor::visit( listInit ); curDepth--; } }; class InitFlattener : public Visitor { public: virtual void visit( SingleInit * singleInit ); virtual void visit( ListInit * listInit ); std::list< Expression * > argList; }; void InitFlattener::visit( SingleInit * singleInit ) { argList.push_back( singleInit->get_value()->clone() ); } void InitFlattener::visit( ListInit * listInit ) { // flatten nested list inits std::list::iterator it = listInit->begin(); for ( ; it != listInit->end(); ++it ) { (*it)->accept( *this ); } } } std::list< Expression * > makeInitList( Initializer * init ) { InitFlattener flattener; maybeAccept( init, flattener ); return flattener.argList; } bool isDesignated( Initializer * init ) { HasDesignations finder; maybeAccept( init, finder ); return finder.hasDesignations; } bool checkInitDepth( ObjectDecl * objDecl ) { InitDepthChecker checker( objDecl->get_type() ); maybeAccept( objDecl->get_init(), checker ); return checker.depthOkay; } class InitExpander::ExpanderImpl { public: virtual std::list< Expression * > next( std::list< Expression * > & indices ) = 0; virtual Statement * buildListInit( UntypedExpr * callExpr, std::list< Expression * > & indices ) = 0; }; class InitImpl : public InitExpander::ExpanderImpl { public: InitImpl( Initializer * init ) : init( init ) {} virtual std::list< Expression * > next( __attribute((unused)) std::list< Expression * > & indices ) { // this is wrong, but just a placeholder for now // if ( ! flattened ) flatten( indices ); // return ! inits.empty() ? makeInitList( inits.front() ) : std::list< Expression * >(); return makeInitList( init ); } virtual Statement * buildListInit( UntypedExpr * callExpr, std::list< Expression * > & indices ); private: Initializer * init; }; class ExprImpl : public InitExpander::ExpanderImpl { public: ExprImpl( Expression * expr ) : arg( expr ) {} ~ExprImpl() { delete arg; } virtual std::list< Expression * > next( std::list< Expression * > & indices ) { std::list< Expression * > ret; Expression * expr = maybeClone( arg ); if ( expr ) { for ( std::list< Expression * >::reverse_iterator it = indices.rbegin(); it != indices.rend(); ++it ) { // go through indices and layer on subscript exprs ?[?] ++it; UntypedExpr * subscriptExpr = new UntypedExpr( new NameExpr( "?[?]") ); subscriptExpr->get_args().push_back( expr ); subscriptExpr->get_args().push_back( (*it)->clone() ); expr = subscriptExpr; } ret.push_back( expr ); } return ret; } virtual Statement * buildListInit( UntypedExpr * callExpr, std::list< Expression * > & indices ); private: Expression * arg; }; InitExpander::InitExpander( Initializer * init ) : expander( new InitImpl( init ) ) {} InitExpander::InitExpander( Expression * expr ) : expander( new ExprImpl( expr ) ) {} std::list< Expression * > InitExpander::operator*() { return cur; } InitExpander & InitExpander::operator++() { cur = expander->next( indices ); return *this; } // use array indices list to build switch statement void InitExpander::addArrayIndex( Expression * index, Expression * dimension ) { indices.push_back( index ); indices.push_back( dimension ); } void InitExpander::clearArrayIndices() { deleteAll( indices ); indices.clear(); } namespace { /// given index i, dimension d, initializer init, and callExpr f, generates /// if (i < d) f(..., init) /// ++i; /// so that only elements within the range of the array are constructed template< typename OutIterator > void buildCallExpr( UntypedExpr * callExpr, Expression * index, Expression * dimension, Initializer * init, OutIterator out ) { UntypedExpr * cond = new UntypedExpr( new NameExpr( "?get_args().push_back( index->clone() ); cond->get_args().push_back( dimension->clone() ); std::list< Expression * > args = makeInitList( init ); callExpr->get_args().splice( callExpr->get_args().end(), args ); *out++ = new IfStmt( noLabels, cond, new ExprStmt( noLabels, callExpr ), NULL ); UntypedExpr * increment = new UntypedExpr( new NameExpr( "++?" ) ); increment->get_args().push_back( index->clone() ); *out++ = new ExprStmt( noLabels, increment ); } template< typename OutIterator > void build( UntypedExpr * callExpr, InitExpander::IndexList::iterator idx, InitExpander::IndexList::iterator idxEnd, Initializer * init, OutIterator out ) { if ( idx == idxEnd ) return; Expression * index = *idx++; assert( idx != idxEnd ); Expression * dimension = *idx++; // xxx - may want to eventually issue a warning here if we can detect // that the number of elements exceeds to dimension of the array if ( idx == idxEnd ) { if ( ListInit * listInit = dynamic_cast< ListInit * >( init ) ) { for ( Initializer * init : *listInit ) { buildCallExpr( callExpr->clone(), index, dimension, init, out ); } } else { buildCallExpr( callExpr->clone(), index, dimension, init, out ); } } else { std::list< Statement * > branches; unsigned long cond = 0; ListInit * listInit = dynamic_cast< ListInit * >( init ); if ( ! listInit ) { // xxx - this shouldn't be an error, but need a way to // terminate without creating output, so should catch this error throw SemanticError( "unbalanced list initializers" ); } static UniqueName targetLabel( "L__autogen__" ); Label switchLabel( targetLabel.newName(), 0, std::list< Attribute * >{ new Attribute("unused") } ); for ( Initializer * init : *listInit ) { Expression * condition; // check for designations // if ( init-> ) { condition = new ConstantExpr( Constant::from_ulong( cond ) ); ++cond; // } else { // condition = // ... take designation // cond = // ... take designation+1 // } std::list< Statement * > stmts; build( callExpr, idx, idxEnd, init, back_inserter( stmts ) ); stmts.push_back( new BranchStmt( noLabels, switchLabel, BranchStmt::Break ) ); CaseStmt * caseStmt = new CaseStmt( noLabels, condition, stmts ); branches.push_back( caseStmt ); } *out++ = new SwitchStmt( noLabels, index->clone(), branches ); *out++ = new NullStmt( std::list