// // 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. // // Autogen.cc -- // // Author : Rob Schluntz // Created On : Thu Mar 03 15:45:56 2016 // Last Modified By : Rob Schluntz // Last Modified On : Thu May 26 14:14:09 2016 // Update Count : 1 // #include #include #include "SynTree/Visitor.h" #include "SynTree/Type.h" #include "SynTree/Statement.h" #include "SynTree/TypeSubstitution.h" #include "Common/utility.h" #include "AddVisit.h" #include "MakeLibCfa.h" #include "Autogen.h" namespace SymTab { class AutogenerateRoutines : public Visitor { public: std::list< Declaration * > &get_declsToAdd() { return declsToAdd; } virtual void visit( EnumDecl *enumDecl ); virtual void visit( StructDecl *structDecl ); virtual void visit( UnionDecl *structDecl ); virtual void visit( TypeDecl *typeDecl ); virtual void visit( TraitDecl *ctxDecl ); virtual void visit( FunctionDecl *functionDecl ); virtual void visit( FunctionType *ftype ); virtual void visit( PointerType *ftype ); virtual void visit( CompoundStmt *compoundStmt ); virtual void visit( SwitchStmt *switchStmt ); virtual void visit( ChooseStmt *chooseStmt ); // virtual void visit( CaseStmt *caseStmt ); AutogenerateRoutines() : functionNesting( 0 ) {} private: template< typename StmtClass > void visitStatement( StmtClass *stmt ); std::list< Declaration * > declsToAdd; std::set< std::string > structsDone; unsigned int functionNesting; // current level of nested functions }; void autogenerateRoutines( std::list< Declaration * > &translationUnit ) { AutogenerateRoutines visitor; acceptAndAdd( translationUnit, visitor, false ); } bool isUnnamedBitfield( ObjectDecl * obj ) { return obj != NULL && obj->get_name() == "" && obj->get_bitfieldWidth() != NULL; } template< typename OutputIterator > void makeScalarFunction( Expression *src, ObjectDecl *dstParam, DeclarationWithType *member, std::string fname, OutputIterator out ) { ObjectDecl *obj = dynamic_cast( member ); // unnamed bit fields are not copied as they cannot be accessed if ( isUnnamedBitfield( obj ) ) return; // want to be able to generate assignment, ctor, and dtor generically, // so fname is either ?=?, ?{}, or ^?{} UntypedExpr *fExpr = new UntypedExpr( new NameExpr( fname ) ); UntypedExpr *derefExpr = new UntypedExpr( new NameExpr( "*?" ) ); derefExpr->get_args().push_back( new VariableExpr( dstParam ) ); // do something special for unnamed members Expression *dstselect = new AddressExpr( new MemberExpr( member, derefExpr ) ); fExpr->get_args().push_back( dstselect ); if ( src ) { fExpr->get_args().push_back( src ); } *out++ = new ExprStmt( noLabels, fExpr ); } template< typename OutputIterator > void makeUnionFieldsAssignment( ObjectDecl *srcParam, ObjectDecl *dstParam, UnionInstType *unionType, OutputIterator out ) { UntypedExpr *copy = new UntypedExpr( new NameExpr( "__builtin_memcpy" ) ); copy->get_args().push_back( new VariableExpr( dstParam ) ); copy->get_args().push_back( new AddressExpr( new VariableExpr( srcParam ) ) ); copy->get_args().push_back( new SizeofExpr( unionType ) ); *out++ = new ExprStmt( noLabels, copy ); } //E ?=?(E volatile*, int), // ?=?(E _Atomic volatile*, int); void makeEnumFunctions( EnumDecl *enumDecl, EnumInstType *refType, unsigned int functionNesting, std::list< Declaration * > &declsToAdd ) { FunctionType *assignType = new FunctionType( Type::Qualifiers(), false ); ObjectDecl *dstParam = new ObjectDecl( "_dst", DeclarationNode::NoStorageClass, LinkageSpec::Cforall, 0, new PointerType( Type::Qualifiers(), refType ), 0 ); assignType->get_parameters().push_back( dstParam ); // void ?{}(E *); void ^?{}(E *); FunctionType * ctorType = assignType->clone(); FunctionType * dtorType = assignType->clone(); ObjectDecl *srcParam = new ObjectDecl( "_src", DeclarationNode::NoStorageClass, LinkageSpec::Cforall, 0, refType->clone(), 0 ); assignType->get_parameters().push_back( srcParam ); // void ?{}(E *, E); FunctionType *copyCtorType = assignType->clone(); // T ?=?(E *, E); ObjectDecl *returnVal = new ObjectDecl( "", DeclarationNode::NoStorageClass, LinkageSpec::Cforall, 0, refType->clone(), 0 ); assignType->get_returnVals().push_back( returnVal ); // xxx - should we also generate void ?{}(E *, int) and E ?{}(E *, E)? // right now these cases work, but that might change. // Routines at global scope marked "static" to prevent multiple definitions is separate translation units // because each unit generates copies of the default routines for each aggregate. // xxx - Temporary: make these functions intrinsic so they codegen as C assignment. // Really they're something of a cross between instrinsic and autogen, so should // probably make a new linkage type FunctionDecl *assignDecl = new FunctionDecl( "?=?", functionNesting > 0 ? DeclarationNode::NoStorageClass : DeclarationNode::Static, LinkageSpec::Intrinsic, assignType, new CompoundStmt( noLabels ), true, false ); FunctionDecl *ctorDecl = new FunctionDecl( "?{}", functionNesting > 0 ? DeclarationNode::NoStorageClass : DeclarationNode::Static, LinkageSpec::Intrinsic, ctorType, new CompoundStmt( noLabels ), true, false ); FunctionDecl *copyCtorDecl = new FunctionDecl( "?{}", functionNesting > 0 ? DeclarationNode::NoStorageClass : DeclarationNode::Static, LinkageSpec::Intrinsic, copyCtorType, new CompoundStmt( noLabels ), true, false ); FunctionDecl *dtorDecl = new FunctionDecl( "^?{}", functionNesting > 0 ? DeclarationNode::NoStorageClass : DeclarationNode::Static, LinkageSpec::Intrinsic, dtorType, new CompoundStmt( noLabels ), true, false ); assignDecl->fixUniqueId(); ctorDecl->fixUniqueId(); copyCtorDecl->fixUniqueId(); dtorDecl->fixUniqueId(); // enum copy construct and assignment is just C-style assignment. // this looks like a bad recursive call, but code gen will turn it into // a C-style assignment. // This happens before function pointer type conversion, so need to do it manually here VariableExpr * assignVarExpr = new VariableExpr( assignDecl ); Type *& assignVarExprType = assignVarExpr->get_results().front(); assignVarExprType = new PointerType( Type::Qualifiers(), assignVarExprType ); ApplicationExpr * assignExpr = new ApplicationExpr( assignVarExpr ); assignExpr->get_args().push_back( new VariableExpr( dstParam ) ); assignExpr->get_args().push_back( new VariableExpr( srcParam ) ); // body is either return stmt or expr stmt assignDecl->get_statements()->get_kids().push_back( new ReturnStmt( noLabels, assignExpr ) ); copyCtorDecl->get_statements()->get_kids().push_back( new ExprStmt( noLabels, assignExpr->clone() ) ); declsToAdd.push_back( assignDecl ); declsToAdd.push_back( ctorDecl ); declsToAdd.push_back( copyCtorDecl ); declsToAdd.push_back( dtorDecl ); } /// Clones a reference type, replacing any parameters it may have with a clone of the provided list template< typename GenericInstType > GenericInstType *cloneWithParams( GenericInstType *refType, const std::list< Expression* >& params ) { GenericInstType *clone = refType->clone(); clone->get_parameters().clear(); cloneAll( params, clone->get_parameters() ); return clone; } /// Creates a new type decl that's the same as src, but renamed and with only the ?=?, ?{} (default and copy), and ^?{} assertions (for complete types only) TypeDecl *cloneAndRename( TypeDecl *src, const std::string &name ) { // TypeDecl *dst = new TypeDecl( name, src->get_storageClass(), 0, src->get_kind() ); // if ( src->get_kind() == TypeDecl::Any ) { // TypeInstType *opParamType = new TypeInstType( Type::Qualifiers(), name, dst ); // FunctionType *opFunctionType = new FunctionType( Type::Qualifiers(), false ); // opFunctionType->get_parameters().push_back( // new ObjectDecl( "", DeclarationNode::NoStorageClass, LinkageSpec::Cforall, 0, new PointerType( Type::Qualifiers(), opParamType->clone() ), 0 ) ); // FunctionDecl *ctorAssert = new FunctionDecl( "?{}", DeclarationNode::NoStorageClass, LinkageSpec::Cforall, opFunctionType->clone(), 0, false, false ); // FunctionDecl *dtorAssert = new FunctionDecl( "^?{}", DeclarationNode::NoStorageClass, LinkageSpec::Cforall, opFunctionType->clone(), 0, false, false ); // opFunctionType->get_parameters().push_back( // new ObjectDecl( "", DeclarationNode::NoStorageClass, LinkageSpec::Cforall, 0, opParamType, 0 ) ); // FunctionDecl *copyCtorAssert = new FunctionDecl( "?{}", DeclarationNode::NoStorageClass, LinkageSpec::Cforall, opFunctionType->clone(), 0, false, false ); // opFunctionType->get_returnVals().push_back( // new ObjectDecl( "", DeclarationNode::NoStorageClass, LinkageSpec::Cforall, 0, opParamType->clone(), 0 ) ); // FunctionDecl *assignAssert = new FunctionDecl( "?=?", DeclarationNode::NoStorageClass, LinkageSpec::Cforall, opFunctionType, 0, false, false ); // dst->get_assertions().push_back( assignAssert ); // dst->get_assertions().push_back( ctorAssert ); // dst->get_assertions().push_back( dtorAssert ); // dst->get_assertions().push_back( copyCtorAssert ); // } TypeDecl *dst = new TypeDecl( src->get_name(), src->get_storageClass(), 0, src->get_kind() ); cloneAll(src->get_assertions(), dst->get_assertions()); return dst; } void makeStructMemberOp( ObjectDecl * dstParam, Expression * src, DeclarationWithType * field, FunctionDecl * func, TypeSubstitution & genericSubs, bool isGeneric, bool forward = true ) { if ( isGeneric ) { // rewrite member type in terms of the type variables on this operator field = field->clone(); genericSubs.apply( field ); if ( src ) { genericSubs.apply( src ); } } ObjectDecl * returnVal = NULL; if ( ! func->get_functionType()->get_returnVals().empty() ) { returnVal = dynamic_cast( func->get_functionType()->get_returnVals().front() ); } // assign to destination (and return value if generic) if ( ArrayType *array = dynamic_cast< ArrayType * >( field->get_type() ) ) { UntypedExpr *derefExpr = new UntypedExpr( new NameExpr( "*?" ) ); derefExpr->get_args().push_back( new VariableExpr( dstParam ) ); Expression *dstselect = new MemberExpr( field, derefExpr ); makeArrayFunction( src, dstselect, array, func->get_name(), back_inserter( func->get_statements()->get_kids() ), forward ); if ( isGeneric && returnVal ) { UntypedExpr *derefRet = new UntypedExpr( new NameExpr( "*?" ) ); derefRet->get_args().push_back( new VariableExpr( returnVal ) ); Expression *retselect = new MemberExpr( field, derefRet ); makeArrayFunction( src, retselect, array, func->get_name(), back_inserter( func->get_statements()->get_kids() ), forward ); } } else { makeScalarFunction( src, dstParam, field, func->get_name(), back_inserter( func->get_statements()->get_kids() ) ); if ( isGeneric && returnVal ) makeScalarFunction( src, returnVal, field, func->get_name(), back_inserter( func->get_statements()->get_kids() ) ); } // if } template void makeStructFunctionBody( Iterator member, Iterator end, FunctionDecl * func, TypeSubstitution & genericSubs, bool isGeneric, bool forward = true ) { for ( ; member != end; ++member ) { if ( DeclarationWithType *field = dynamic_cast< DeclarationWithType * >( *member ) ) { // otherwise some form of type declaration, e.g. Aggregate // query the type qualifiers of this field and skip assigning it if it is marked const. // If it is an array type, we need to strip off the array layers to find its qualifiers. Type * type = field->get_type(); while ( ArrayType * at = dynamic_cast< ArrayType * >( type ) ) { type = at->get_base(); } if ( type->get_qualifiers().isConst ) { // don't assign const members continue; } if ( field->get_name() == "" ) { // don't assign to anonymous members // xxx - this is a temporary fix. Anonymous members tie into // our inheritance model. I think the correct way to handle this is to // cast the structure to the type of the member and let the resolver // figure out whether it's valid and have a pass afterwards that fixes // the assignment to use pointer arithmetic with the offset of the // member, much like how generic type members are handled. continue; } assert( ! func->get_functionType()->get_parameters().empty() ); ObjectDecl * dstParam = dynamic_cast( func->get_functionType()->get_parameters().front() ); ObjectDecl * srcParam = NULL; if ( func->get_functionType()->get_parameters().size() == 2 ) { srcParam = dynamic_cast( func->get_functionType()->get_parameters().back() ); } // srcParam may be NULL, in which case we have default ctor/dtor assert( dstParam ); Expression *srcselect = srcParam ? new MemberExpr( field, new VariableExpr( srcParam ) ) : NULL; makeStructMemberOp( dstParam, srcselect, field, func, genericSubs, isGeneric, forward ); } // if } // for } // makeStructFunctionBody /// generate the body of a constructor which takes parameters that match fields, e.g. /// void ?{}(A *, int) and void?{}(A *, int, int) for a struct A which has two int fields. template void makeStructFieldCtorBody( Iterator member, Iterator end, FunctionDecl * func, TypeSubstitution & genericSubs, bool isGeneric ) { FunctionType * ftype = func->get_functionType(); std::list & params = ftype->get_parameters(); assert( params.size() >= 2 ); // should not call this function for default ctor, etc. // skip 'this' parameter ObjectDecl * dstParam = dynamic_cast( params.front() ); assert( dstParam ); std::list::iterator parameter = params.begin()+1; for ( ; member != end; ++member ) { if ( DeclarationWithType * field = dynamic_cast( *member ) ) { if ( parameter != params.end() ) { // matching parameter, initialize field with copy ctor Expression *srcselect = new VariableExpr(*parameter); makeStructMemberOp( dstParam, srcselect, field, func, genericSubs, isGeneric ); ++parameter; } else { // no matching parameter, initialize field with default ctor makeStructMemberOp( dstParam, NULL, field, func, genericSubs, isGeneric ); } } } } void makeStructFunctions( StructDecl *aggregateDecl, StructInstType *refType, unsigned int functionNesting, std::list< Declaration * > & declsToAdd ) { FunctionType *assignType = new FunctionType( Type::Qualifiers(), false ); // Make function polymorphic in same parameters as generic struct, if applicable bool isGeneric = false; // NOTE this flag is an incredibly ugly kludge; we should fix the assignment signature instead (ditto for union) std::list< TypeDecl* >& genericParams = aggregateDecl->get_parameters(); std::list< Expression* > structParams; // List of matching parameters to put on types TypeSubstitution genericSubs; // Substitutions to make to member types of struct for ( std::list< TypeDecl* >::const_iterator param = genericParams.begin(); param != genericParams.end(); ++param ) { isGeneric = true; TypeDecl *typeParam = cloneAndRename( *param, "_autoassign_" + aggregateDecl->get_name() + "_" + (*param)->get_name() ); assignType->get_forall().push_back( typeParam ); TypeInstType *newParamType = new TypeInstType( Type::Qualifiers(), typeParam->get_name(), typeParam ); genericSubs.add( (*param)->get_name(), newParamType ); structParams.push_back( new TypeExpr( newParamType ) ); } ObjectDecl *dstParam = new ObjectDecl( "_dst", DeclarationNode::NoStorageClass, LinkageSpec::Cforall, 0, new PointerType( Type::Qualifiers(), cloneWithParams( refType, structParams ) ), 0 ); assignType->get_parameters().push_back( dstParam ); // void ?{}(T *); void ^?{}(T *); FunctionType *ctorType = assignType->clone(); FunctionType *dtorType = assignType->clone(); ObjectDecl *srcParam = new ObjectDecl( "_src", DeclarationNode::NoStorageClass, LinkageSpec::Cforall, 0, cloneWithParams( refType, structParams ), 0 ); assignType->get_parameters().push_back( srcParam ); // void ?{}(T *, T); FunctionType *copyCtorType = assignType->clone(); // T ?=?(T *, T); ObjectDecl *returnVal = new ObjectDecl( "_ret", DeclarationNode::NoStorageClass, LinkageSpec::Cforall, 0, cloneWithParams( refType, structParams ), 0 ); assignType->get_returnVals().push_back( returnVal ); // Routines at global scope marked "static" to prevent multiple definitions is separate translation units // because each unit generates copies of the default routines for each aggregate. FunctionDecl *assignDecl = new FunctionDecl( "?=?", functionNesting > 0 ? DeclarationNode::NoStorageClass : DeclarationNode::Static, LinkageSpec::AutoGen, assignType, new CompoundStmt( noLabels ), true, false ); FunctionDecl *ctorDecl = new FunctionDecl( "?{}", functionNesting > 0 ? DeclarationNode::NoStorageClass : DeclarationNode::Static, LinkageSpec::AutoGen, ctorType, new CompoundStmt( noLabels ), true, false ); FunctionDecl *copyCtorDecl = new FunctionDecl( "?{}", functionNesting > 0 ? DeclarationNode::NoStorageClass : DeclarationNode::Static, LinkageSpec::AutoGen, copyCtorType, new CompoundStmt( noLabels ), true, false ); FunctionDecl *dtorDecl = new FunctionDecl( "^?{}", functionNesting > 0 ? DeclarationNode::NoStorageClass : DeclarationNode::Static, LinkageSpec::AutoGen, dtorType, new CompoundStmt( noLabels ), true, false ); assignDecl->fixUniqueId(); ctorDecl->fixUniqueId(); copyCtorDecl->fixUniqueId(); dtorDecl->fixUniqueId(); // create constructors which take each member type as a parameter. // for example, for struct A { int x, y; }; generate // void ?{}(A *, int) and void ?{}(A *, int, int) std::list memCtors; FunctionType * memCtorType = ctorType->clone(); for ( std::list::iterator i = aggregateDecl->get_members().begin(); i != aggregateDecl->get_members().end(); ++i ) { DeclarationWithType * member = dynamic_cast( *i ); assert( member ); if ( isUnnamedBitfield( dynamic_cast< ObjectDecl * > ( member ) ) ) { // don't make a function whose parameter is an unnamed bitfield continue; } else if ( member->get_name() == "" ) { // don't assign to anonymous members // xxx - this is a temporary fix. Anonymous members tie into // our inheritance model. I think the correct way to handle this is to // cast the structure to the type of the member and let the resolver // figure out whether it's valid and have a pass afterwards that fixes // the assignment to use pointer arithmetic with the offset of the // member, much like how generic type members are handled. continue; } memCtorType->get_parameters().push_back( new ObjectDecl( member->get_name(), DeclarationNode::NoStorageClass, LinkageSpec::Cforall, 0, member->get_type()->clone(), 0 ) ); FunctionDecl * ctor = new FunctionDecl( "?{}", functionNesting > 0 ? DeclarationNode::NoStorageClass : DeclarationNode::Static, LinkageSpec::AutoGen, memCtorType->clone(), new CompoundStmt( noLabels ), true, false ); ctor->fixUniqueId(); makeStructFieldCtorBody( aggregateDecl->get_members().begin(), aggregateDecl->get_members().end(), ctor, genericSubs, isGeneric ); memCtors.push_back( ctor ); } delete memCtorType; // generate appropriate calls to member ctor, assignment makeStructFunctionBody( aggregateDecl->get_members().begin(), aggregateDecl->get_members().end(), assignDecl, genericSubs, isGeneric ); makeStructFunctionBody( aggregateDecl->get_members().begin(), aggregateDecl->get_members().end(), ctorDecl, genericSubs, isGeneric ); makeStructFunctionBody( aggregateDecl->get_members().begin(), aggregateDecl->get_members().end(), copyCtorDecl, genericSubs, isGeneric ); // needs to do everything in reverse, so pass "forward" as false makeStructFunctionBody( aggregateDecl->get_members().rbegin(), aggregateDecl->get_members().rend(), dtorDecl, genericSubs, isGeneric, false ); if ( ! isGeneric ) assignDecl->get_statements()->get_kids().push_back( new ReturnStmt( noLabels, new VariableExpr( srcParam ) ) ); declsToAdd.push_back( assignDecl ); declsToAdd.push_back( ctorDecl ); declsToAdd.push_back( copyCtorDecl ); declsToAdd.push_back( dtorDecl ); declsToAdd.splice( declsToAdd.end(), memCtors ); } void makeUnionFunctions( UnionDecl *aggregateDecl, UnionInstType *refType, unsigned int functionNesting, std::list< Declaration * > & declsToAdd ) { FunctionType *assignType = new FunctionType( Type::Qualifiers(), false ); // Make function polymorphic in same parameters as generic union, if applicable bool isGeneric = false; // NOTE this flag is an incredibly ugly kludge; we should fix the assignment signature instead (ditto for struct) std::list< TypeDecl* >& genericParams = aggregateDecl->get_parameters(); std::list< Expression* > unionParams; // List of matching parameters to put on types for ( std::list< TypeDecl* >::const_iterator param = genericParams.begin(); param != genericParams.end(); ++param ) { isGeneric = true; TypeDecl *typeParam = cloneAndRename( *param, "_autoassign_" + aggregateDecl->get_name() + "_" + (*param)->get_name() ); assignType->get_forall().push_back( typeParam ); unionParams.push_back( new TypeExpr( new TypeInstType( Type::Qualifiers(), typeParam->get_name(), typeParam ) ) ); } ObjectDecl *dstParam = new ObjectDecl( "_dst", DeclarationNode::NoStorageClass, LinkageSpec::Cforall, 0, new PointerType( Type::Qualifiers(), cloneWithParams( refType, unionParams ) ), 0 ); assignType->get_parameters().push_back( dstParam ); // default ctor/dtor need only first parameter FunctionType * ctorType = assignType->clone(); FunctionType * dtorType = assignType->clone(); ObjectDecl *srcParam = new ObjectDecl( "_src", DeclarationNode::NoStorageClass, LinkageSpec::Cforall, 0, cloneWithParams( refType, unionParams ), 0 ); assignType->get_parameters().push_back( srcParam ); // copy ctor needs both parameters FunctionType * copyCtorType = assignType->clone(); // assignment needs both and return value ObjectDecl *returnVal = new ObjectDecl( "_ret", DeclarationNode::NoStorageClass, LinkageSpec::Cforall, 0, cloneWithParams( refType, unionParams ), 0 ); assignType->get_returnVals().push_back( returnVal ); // Routines at global scope marked "static" to prevent multiple definitions is separate translation units // because each unit generates copies of the default routines for each aggregate. FunctionDecl *assignDecl = new FunctionDecl( "?=?", functionNesting > 0 ? DeclarationNode::NoStorageClass : DeclarationNode::Static, LinkageSpec::AutoGen, assignType, new CompoundStmt( noLabels ), true, false ); FunctionDecl *ctorDecl = new FunctionDecl( "?{}", functionNesting > 0 ? DeclarationNode::NoStorageClass : DeclarationNode::Static, LinkageSpec::AutoGen, ctorType, new CompoundStmt( noLabels ), true, false ); FunctionDecl *copyCtorDecl = new FunctionDecl( "?{}", functionNesting > 0 ? DeclarationNode::NoStorageClass : DeclarationNode::Static, LinkageSpec::AutoGen, copyCtorType, NULL, true, false ); FunctionDecl *dtorDecl = new FunctionDecl( "^?{}", functionNesting > 0 ? DeclarationNode::NoStorageClass : DeclarationNode::Static, LinkageSpec::AutoGen, dtorType, new CompoundStmt( noLabels ), true, false ); assignDecl->fixUniqueId(); ctorDecl->fixUniqueId(); copyCtorDecl->fixUniqueId(); dtorDecl->fixUniqueId(); makeUnionFieldsAssignment( srcParam, dstParam, cloneWithParams( refType, unionParams ), back_inserter( assignDecl->get_statements()->get_kids() ) ); if ( isGeneric ) makeUnionFieldsAssignment( srcParam, returnVal, cloneWithParams( refType, unionParams ), back_inserter( assignDecl->get_statements()->get_kids() ) ); if ( ! isGeneric ) assignDecl->get_statements()->get_kids().push_back( new ReturnStmt( noLabels, new VariableExpr( srcParam ) ) ); // body of assignment and copy ctor is the same copyCtorDecl->set_statements( assignDecl->get_statements()->clone() ); declsToAdd.push_back( assignDecl ); declsToAdd.push_back( ctorDecl ); declsToAdd.push_back( copyCtorDecl ); declsToAdd.push_back( dtorDecl ); } void AutogenerateRoutines::visit( EnumDecl *enumDecl ) { if ( ! enumDecl->get_members().empty() ) { EnumInstType *enumInst = new EnumInstType( Type::Qualifiers(), enumDecl->get_name() ); // enumInst->set_baseEnum( enumDecl ); // declsToAdd.push_back( makeEnumFunctions( enumDecl, enumInst, functionNesting, declsToAdd ); } } void AutogenerateRoutines::visit( StructDecl *structDecl ) { if ( ! structDecl->get_members().empty() && structsDone.find( structDecl->get_name() ) == structsDone.end() ) { StructInstType structInst( Type::Qualifiers(), structDecl->get_name() ); structInst.set_baseStruct( structDecl ); makeStructFunctions( structDecl, &structInst, functionNesting, declsToAdd ); structsDone.insert( structDecl->get_name() ); } // if } void AutogenerateRoutines::visit( UnionDecl *unionDecl ) { if ( ! unionDecl->get_members().empty() ) { UnionInstType unionInst( Type::Qualifiers(), unionDecl->get_name() ); unionInst.set_baseUnion( unionDecl ); makeUnionFunctions( unionDecl, &unionInst, functionNesting, declsToAdd ); } // if } void AutogenerateRoutines::visit( TypeDecl *typeDecl ) { CompoundStmt *stmts = 0; TypeInstType *typeInst = new TypeInstType( Type::Qualifiers(), typeDecl->get_name(), false ); typeInst->set_baseType( typeDecl ); ObjectDecl *src = new ObjectDecl( "_src", DeclarationNode::NoStorageClass, LinkageSpec::Cforall, 0, typeInst->clone(), 0 ); ObjectDecl *dst = new ObjectDecl( "_dst", DeclarationNode::NoStorageClass, LinkageSpec::Cforall, 0, new PointerType( Type::Qualifiers(), typeInst->clone() ), 0 ); if ( typeDecl->get_base() ) { // xxx - generate ctor/dtors for typedecls, e.g. // otype T = int *; stmts = new CompoundStmt( std::list< Label >() ); UntypedExpr *assign = new UntypedExpr( new NameExpr( "?=?" ) ); assign->get_args().push_back( new CastExpr( new VariableExpr( dst ), new PointerType( Type::Qualifiers(), typeDecl->get_base()->clone() ) ) ); assign->get_args().push_back( new CastExpr( new VariableExpr( src ), typeDecl->get_base()->clone() ) ); stmts->get_kids().push_back( new ReturnStmt( std::list< Label >(), assign ) ); } // if FunctionType *type = new FunctionType( Type::Qualifiers(), false ); type->get_returnVals().push_back( new ObjectDecl( "", DeclarationNode::NoStorageClass, LinkageSpec::Cforall, 0, typeInst, 0 ) ); type->get_parameters().push_back( dst ); type->get_parameters().push_back( src ); FunctionDecl *func = new FunctionDecl( "?=?", DeclarationNode::NoStorageClass, LinkageSpec::AutoGen, type, stmts, true, false ); declsToAdd.push_back( func ); } void addDecls( std::list< Declaration * > &declsToAdd, std::list< Statement * > &statements, std::list< Statement * >::iterator i ) { for ( std::list< Declaration * >::iterator decl = declsToAdd.begin(); decl != declsToAdd.end(); ++decl ) { statements.insert( i, new DeclStmt( noLabels, *decl ) ); } // for declsToAdd.clear(); } void AutogenerateRoutines::visit( FunctionType *) { // ensure that we don't add assignment ops for types defined as part of the function } void AutogenerateRoutines::visit( PointerType *) { // ensure that we don't add assignment ops for types defined as part of the pointer } void AutogenerateRoutines::visit( TraitDecl *) { // ensure that we don't add assignment ops for types defined as part of the trait } template< typename StmtClass > inline void AutogenerateRoutines::visitStatement( StmtClass *stmt ) { std::set< std::string > oldStructs = structsDone; addVisit( stmt, *this ); structsDone = oldStructs; } void AutogenerateRoutines::visit( FunctionDecl *functionDecl ) { maybeAccept( functionDecl->get_functionType(), *this ); acceptAll( functionDecl->get_oldDecls(), *this ); functionNesting += 1; maybeAccept( functionDecl->get_statements(), *this ); functionNesting -= 1; } void AutogenerateRoutines::visit( CompoundStmt *compoundStmt ) { visitStatement( compoundStmt ); } void AutogenerateRoutines::visit( SwitchStmt *switchStmt ) { visitStatement( switchStmt ); } void AutogenerateRoutines::visit( ChooseStmt *switchStmt ) { visitStatement( switchStmt ); } // void AutogenerateRoutines::visit( CaseStmt *caseStmt ) { // visitStatement( caseStmt ); // } } // SymTab