/** * Fit a variable into an argument according to the argument rule. If necessary and * appropriate, we do type conversion or type promotion. * * * * @todo To conform to the old code we change the required type of the incoming * variable wrapper here. We need to change this so that we do not change * the wrapper here, but make sure that if the argument variable is inserted * in a member variable or container element slot, that the slot variable * wrapper, which should be unique (not the same as the incoming variable * wrapper), has the right required type. */ Argument ArgumentRule::fitArgument( Argument& arg, bool once ) const { RevPtr<RevVariable> theVar = arg.getVariable(); if ( evalType == BY_VALUE || theVar->isWorkspaceVariable() || theVar->getRevObject().isConstant() ) { once = true; } for ( std::vector<TypeSpec>::const_iterator it = argTypeSpecs.begin(); it != argTypeSpecs.end(); ++it ) { if ( evalType == BY_VALUE ) { if ( theVar->getRevObject().isType( *it ) ) { RevPtr<RevVariable> valueVar = RevPtr<RevVariable>( new RevVariable(theVar->getRevObject().clone(),arg.getLabel()) ); return Argument( valueVar, getArgumentLabel(), false ); } else if ( theVar->getRevObject().isConvertibleTo( *it, once ) != -1) { // Fit by type conversion. For now, we also modify the type of the incoming variable wrapper. RevObject* convertedObject = theVar->getRevObject().convertTo( *it ); RevPtr<RevVariable> valueVar = RevPtr<RevVariable>( new RevVariable(convertedObject,arg.getLabel()) ); return Argument( valueVar, getArgumentLabel(), false ); } } // if (by-value) else { if ( theVar->getRevObject().isType( *it ) ) { // For now, change the required type of the incoming variable wrapper theVar->setRequiredTypeSpec( *it ); if ( !isEllipsis() ) { return Argument( theVar, getArgumentLabel(), evalType == BY_CONSTANT_REFERENCE ); } else { return Argument( theVar, arg.getLabel(), true ); } } else if ( theVar->getRevObject().isConvertibleTo( *it, once ) != -1 && (*it).isDerivedOf( theVar->getRequiredTypeSpec() )) { // Fit by type conversion. For now, we also modify the type of the incoming variable wrapper. RevObject* convertedObject = theVar->getRevObject().convertTo( *it ); theVar->replaceRevObject( convertedObject ); theVar->setRequiredTypeSpec( *it ); if ( !isEllipsis() ) { return Argument( theVar, getArgumentLabel(), false ); } else { return Argument( theVar, arg.getLabel(), false ); } } else { // Fit by type conversion function const TypeSpec& typeFrom = theVar->getRevObject().getTypeSpec(); const TypeSpec& typeTo = *it; // create the function name std::string functionName = "_" + typeFrom.getType() + "2" + typeTo.getType(); // Package arguments std::vector<Argument> args; Argument theArg = Argument( theVar, "arg" ); args.push_back( theVar ); Environment& env = Workspace::globalWorkspace(); try { Function* func = env.getFunction(functionName, args, once).clone(); // Allow the function to process the arguments func->processArguments( args, once ); // Set the execution environment of the function func->setExecutionEnviroment( &env ); // Evaluate the function RevPtr<RevVariable> conversionVar = func->execute(); // free the memory delete func; conversionVar->setHiddenVariableState( true ); conversionVar->setRequiredTypeSpec( *it ); return Argument( conversionVar, getArgumentLabel(), evalType == BY_CONSTANT_REFERENCE ); } catch (RbException e) { // we do nothing here } } // else (type conversion function) } // else (not by-value) } std::cerr << "Once = " << (once ? "TRUE" : "FALSE") << std::endl; throw RbException( "Argument type mismatch fitting a " + theVar->getRevObject().getType() + " argument to formal " + getArgumentTypeSpec()[0].getType() + " " + getArgumentLabel() ); }
/** * Fit a variable into an argument according to the argument rule. If necessary and * appropriate, we do type conversion or type promotion. * * @todo The constant flag is currently not used correctly in ArgumentRule. Therefore, * we ignore it here for now. This needs to be changed. * * @todo We need to check whether workspace objects with member variables are * modifiable by the user. * * @todo To conform to the old code we change the required type of the incoming * variable wrapper here. We need to change this so that we do not change * the wrapper here, but make sure that if the argument variable is inserted * in a member variable or container element slot, that the slot variable * wrapper, which should be unique (not the same as the incoming variable * wrapper), has the right required type. */ Argument ArgumentRule::fitArgument( Argument& arg, bool once ) const { // TODO: Use this code when the constant flag in ArgumentRule is used correctly // if ( isConstant() || !theVar->isAssignable() ) if ( evalType == BY_VALUE ) { once = true; } RevPtr<Variable> theVar = arg.getVariable(); for ( std::vector<TypeSpec>::const_iterator it = argTypeSpecs.begin(); it != argTypeSpecs.end(); ++it ) { if ( theVar->getRevObject().isTypeSpec( *it ) ) { // For now, change the required type of the incoming variable wrapper theVar->setRevObjectTypeSpec( *it ); if ( !isEllipsis() ) return Argument( theVar, getArgumentLabel(), evalType == BY_CONSTANT_REFERENCE ); else return Argument( theVar, arg.getLabel(), true ); } else if ( once == false && !theVar->isAssignable() && theVar->getRevObject().isConvertibleTo( *it, true ) && (*it).isDerivedOf( theVar->getRevObjectTypeSpec() ) ) { // Fit by type promotion. For now, we also modify the type of the incoming variable wrapper. RevObject* convertedObject = theVar->getRevObject().convertTo( *it ); theVar->setRevObject( convertedObject ); theVar->setRevObjectTypeSpec( *it ); if ( !isEllipsis() ) return Argument( theVar, getArgumentLabel(), evalType == BY_CONSTANT_REFERENCE ); else return Argument( theVar, arg.getLabel(), true ); } else if ( theVar->getRevObject().isConvertibleTo( *it, once ) ) { // Fit by type conversion if ( once || !theVar->getRevObject().hasDagNode() ) { RevObject* convertedObject = theVar->getRevObject().convertTo( *it ); Variable* convertedVar = new Variable( convertedObject ); convertedVar->setRevObjectTypeSpec( *it ); if ( !isEllipsis() ) return Argument( convertedVar, getArgumentLabel(), evalType == BY_CONSTANT_REFERENCE ); else return Argument( convertedVar, arg.getLabel(), true ); } else { RevObject* conversionObject = theVar->getRevObject().convertTo( *it ); conversionObject->makeConversionValue( theVar ); Variable* conversionVar = new Variable( conversionObject ); conversionVar->setRevObjectTypeSpec( *it ); if ( !isEllipsis() ) return Argument( conversionVar, getArgumentLabel(), evalType == BY_CONSTANT_REFERENCE ); else return Argument( conversionVar, arg.getLabel(), true ); } } } throw RbException( "Argument type mismatch fitting a " + theVar->getRevObject().getType() + " argument to formal " + getArgumentTypeSpec()[0].getType() + " " + getArgumentLabel() ); }