double OptionRule::isArgumentValid( Argument &arg, bool once) const { RevPtr<RevVariable> theVar = arg.getVariable(); if ( theVar == NULL ) { return -1; } if ( evalType == BY_VALUE || theVar->isWorkspaceVariable() || ( theVar->getRevObject().isModelObject() && theVar->getRevObject().getDagNode()->getDagNodeType() == RevBayesCore::DagNode::CONSTANT) ) { once = true; } RlString *revObj = dynamic_cast<RlString *>( &theVar->getRevObject() ); if ( revObj != NULL ) { const std::string &argValue = revObj->getValue(); for ( std::vector<std::string>::const_iterator it = options.begin(); it != options.end(); ++it) { if ( argValue == *it ) { return 0.0; } } return -1; } else { return -1; } }
/** * 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() ); }
/** * Test if argument is valid. The boolean flag 'once' is used to signal whether the argument matching * is done in a static or a dynamic context. If the rule is constant, then the argument matching * is done in a static context (evaluate-once context) regardless of the setting of the once flag. * If the argument is constant, we try type promotion if permitted by the variable required type. * * @todo See the TODOs for fitArgument(...) */ double ArgumentRule::isArgumentValid( Argument &arg, bool once) const { RevPtr<RevVariable> theVar = arg.getVariable(); if ( theVar == NULL ) { return -1; } if ( evalType == BY_VALUE || theVar->isWorkspaceVariable() || ( theVar->getRevObject().isModelObject() && theVar->getRevObject().getDagNode()->getDagNodeType() == RevBayesCore::DagNode::CONSTANT) ) { once = true; } if ( nodeType == STOCHASTIC && theVar->getRevObject().getDagNode()->getDagNodeType() != RevBayesCore::DagNode::STOCHASTIC ) { return -1; } else if ( nodeType == DETERMINISTIC && theVar->getRevObject().getDagNode()->getDagNodeType() != RevBayesCore::DagNode::DETERMINISTIC ) { return -1; } for ( std::vector<TypeSpec>::const_iterator it = argTypeSpecs.begin(); it != argTypeSpecs.end(); ++it ) { if ( theVar->getRevObject().isType( *it ) ) { return 0.0; } else if ( theVar->getRevObject().isConvertibleTo( *it, once ) != -1 && (*it).isDerivedOf( theVar->getRequiredTypeSpec() ) ) { return theVar->getRevObject().isConvertibleTo( *it, once ); } else if ( theVar->getRevObject().isConvertibleTo( *it, once ) != -1 && evalType == BY_VALUE ) { return theVar->getRevObject().isConvertibleTo( *it, once ); } // else if ( once == true && //// !var->isAssignable() && // theVar->getRevObject().isConvertibleTo( *it, true ) != -1 && // (*it).isDerivedOf( theVar->getRequiredTypeSpec() ) // ) // { // return theVar->getRevObject().isConvertibleTo( *it, true ); // } else if ( nodeType != STOCHASTIC ) { 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 { // we just want to check if the function exists and can be found env.getFunction(functionName, args, once); return 0.1; } catch (RbException e) { // we do nothing here } } } return -1; }
/** * 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() ); }