/** Find function (also processes arguments) */ const Function& FunctionTable::findFunction(const std::string& name, const std::vector<Argument>& args, bool once) const { std::pair<std::multimap<std::string, Function *>::const_iterator, std::multimap<std::string, Function *>::const_iterator> retVal; size_t hits = count(name); if (hits == 0) { if (parentTable != NULL) { // \TODO: We shouldn't allow const casts!!! FunctionTable* pt = const_cast<FunctionTable*>(parentTable); return pt->findFunction(name, args, once); } else { throw RbException("No function named '"+ name + "'"); } } retVal = equal_range(name); if (hits == 1) { if (retVal.first->second->checkArguments(args,NULL,once) == false) { std::ostringstream msg; msg << "Argument or label mismatch for function call '" << name << "' with arguments ("; // print the passed arguments for (std::vector<Argument>::const_iterator it = args.begin(); it != args.end(); it++) { // add a comma before the every argument except the first if (it != args.begin()) { msg << ","; } // create the default type of the passed-in argument std::string type = "NULL"; // get the type if the variable wasn't NULL if (it->getVariable() != NULL) { type = it->getVariable()->getRevObject().getType(); } msg << " " << type; // create the default DAG type of the passed-in argument std::string dagtype = ""; // get the type if the variable wasn't NULL if (it->getVariable() != NULL && it->getVariable()->getRevObject().getDagNode() != NULL ) { if ( it->getVariable()->getRevObject().getDagNode()->getDagNodeType() == RevBayesCore::DagNode::DETERMINISTIC ) { dagtype = "<deterministic>"; } else if ( it->getVariable()->getRevObject().getDagNode()->getDagNodeType() == RevBayesCore::DagNode::STOCHASTIC ) { dagtype = "<stochastic>"; } else if ( it->getVariable()->getRevObject().getDagNode()->getDagNodeType() == RevBayesCore::DagNode::CONSTANT ) { dagtype = "<constant>"; } else { dagtype = "<?>"; } } msg << dagtype; if ( it->getLabel() != "" ) { msg << " '" << it->getLabel() << "'"; } } msg << " )." << std::endl; msg << "Correct usage is:" << std::endl; retVal.first->second->printValue( msg ); msg << std::endl; throw RbException( msg ); } return *retVal.first->second; } else { std::vector<double>* matchScore = new std::vector<double>(); std::vector<double> bestScore; Function* bestMatch = NULL; bool ambiguous = false; std::multimap<std::string, Function *>::const_iterator it; for (it=retVal.first; it!=retVal.second; it++) { matchScore->clear(); if ( (*it).second->checkArguments(args, matchScore, once) == true ) { if ( bestMatch == NULL ) { bestScore = *matchScore; bestMatch = it->second; ambiguous = false; } else { size_t j; for (j=0; j<matchScore->size() && j<bestScore.size(); j++) { if ((*matchScore)[j] < bestScore[j]) { bestScore = *matchScore; bestMatch = it->second; ambiguous = false; break; } else if ((*matchScore)[j] > bestScore[j]) break; } if (j==matchScore->size() || j==bestScore.size()) { ambiguous = true; // Continue checking, there might be better matches ahead } } } } // free the memory delete matchScore; /* Delete all processed arguments except those of the best matching function, if it is ambiguous */ for ( it = retVal.first; it != retVal.second; it++ ) { if ( !( (*it).second == bestMatch && ambiguous == false ) ) (*it).second->clear(); } if ( bestMatch == NULL || ambiguous == true ) { std::ostringstream msg; if ( bestMatch == NULL ) msg << "No overloaded function '" << name << "' matches for arguments ("; else msg << "Ambiguous call to function '" << name << "' with arguments ("; // print the passed arguments for (std::vector<Argument>::const_iterator j = args.begin(); j != args.end(); j++) { if (j != args.begin()) { msg << ","; } const RevPtr<const RevVariable>& theVar = j->getVariable(); msg << " " << theVar->getRevObject().getTypeSpec().getType(); } msg << " )" << std::endl; msg << "Potentially matching functions are:" << std::endl; for ( it = retVal.first; it != retVal.second; it++ ) { (*it).second->printValue( msg ); msg << std::endl; } throw RbException( msg ); } else { return *bestMatch; } } }
/** Find function (also processes arguments) */ Function& FunctionTable::findFunction(const std::string& name, const std::vector<Argument>& args) { std::pair<std::multimap<std::string, Function *>::iterator, std::multimap<std::string, Function *>::iterator> retVal; size_t hits = count(name); if (hits == 0) { if (parentTable != NULL) { // \TODO: We shouldn't allow const casts!!! FunctionTable* pt = const_cast<FunctionTable*>(parentTable); return pt->findFunction(name, args); } else { throw RbException("No function named '"+ name + "'"); } } retVal = equal_range(name); if (hits == 1) { if (retVal.first->second->checkArguments(args,NULL) == false) { std::ostringstream msg; msg << "Argument mismatch for call to function '" << name << "'("; // print the passed arguments for (std::vector<Argument>::const_iterator it = args.begin(); it != args.end(); it++) { if (it != args.begin()) { msg << ","; } std::string type = "NULL"; if (it->getVariable() != NULL) type = it->getVariable()->getRevObject().getType(); msg << " " << type << " \"" << it->getLabel() << "\""; } msg << " ). Correct usage is:" << std::endl; retVal.first->second->printValue( msg ); msg << std::endl; throw RbException( msg ); } return *retVal.first->second; } else { std::vector<unsigned int>* matchScore = new std::vector<unsigned int>(); std::vector<unsigned int> bestScore; Function* bestMatch = NULL; bool ambiguous = false; std::multimap<std::string, Function *>::iterator it; for (it=retVal.first; it!=retVal.second; it++) { matchScore->clear(); if ( (*it).second->checkArguments(args, matchScore) == true ) { if ( bestMatch == NULL ) { bestScore = *matchScore; bestMatch = it->second; ambiguous = false; } else { size_t j; for (j=0; j<matchScore->size() && j<bestScore.size(); j++) { if ((*matchScore)[j] < bestScore[j]) { bestScore = *matchScore; bestMatch = it->second; ambiguous = false; break; } else if ((*matchScore)[j] > bestScore[j]) break; } if (j==matchScore->size() || j==bestScore.size()) { ambiguous = true; // Continue checking, there might be better matches ahead } } } } // free the memory delete matchScore; /* Delete all processed arguments except those of the best matching function, if it is ambiguous */ for ( it = retVal.first; it != retVal.second; it++ ) { if ( !( (*it).second == bestMatch && ambiguous == false ) ) (*it).second->clear(); } if ( bestMatch == NULL || ambiguous == true ) { std::ostringstream msg; if ( bestMatch == NULL ) msg << "No overloaded function '" << name << "' matches for arguments ("; else msg << "Ambiguous call to function '" << name << "' with arguments ("; // print the passed arguments for (std::vector<Argument>::const_iterator j = args.begin(); j != args.end(); j++) { if (j != args.begin()) { msg << ","; } // msg << " " << it->getVariable().getDagNode()->getValue().getTypeSpec(); const RevPtr<const Variable>& theVar = j->getVariable(); msg << " " << theVar->getRevObject().getTypeSpec().getType(); } msg << " )" << std::endl; msg << "Potentially matching functions are:" << std::endl; for ( it = retVal.first; it != retVal.second; it++ ) { (*it).second->printValue( msg ); msg << std::endl; } throw RbException( msg ); } else { return *bestMatch; } } }