/** Get semantic value: insert symbol and return the rhs value of the assignment */
void SyntaxStochasticAssignment::assign(RevPtr<RevVariable> &lhs, RevPtr<RevVariable> &rhs)
{
#ifdef DEBUG_PARSER
    printf( "Evaluating tilde assignment\n" );
#endif
    
    // Get distribution, which should be the return value of the rhs function
    const RevObject& exprValue = rhs->getRevObject();
    if ( !exprValue.isType( Distribution::getClassTypeSpec() ) ) 
    {
        throw RbException( "Expression on the right-hand-side of '~' did not return a distribution object." );
    }
    const Distribution &dist = dynamic_cast<const Distribution &>( exprValue );
        
    // Create new stochastic variable
    RevObject* rv = dist.createRandomVariable();
    
    // Fill the slot with the new stochastic variable
    lhs->replaceRevObject( rv );
    
    // make sure all the implicitly created variables got a correct name
    RevBayesCore::DagNode* theNode = lhs->getRevObject().getDagNode();
    theNode->setParentNamePrefix( theNode->getName() );
    
#ifdef DEBUG_PARSER
    env.printValue(std::cerr);
#endif
}
/**
 * Get semantic value. When evaluating the semantic value of a reference assignment,
 * we first evaluate the rhs expression as if it were a constant expression. Among
 * other things, this makes it possible for us to create references to control
 * variables, which would be impossible if the rhs expression was evaluated as a
 * dynamic expression. We are interested in creating a reference to the variable
 * that results from evaluation of the rhs expression now.
 *
 * Note that the return variable is variable returned by the rhs expression.
 * We need not clone it.
 */
RevPtr<Variable> SyntaxReferenceAssignment::evaluateContent( Environment& env )
{
#ifdef DEBUG_PARSER
    printf( "Evaluating reference assignment\n" );
#endif
    
    // Declare variable storing the return value of the assignment expression
    RevPtr<Variable> theVariable;
    
    // Get the rhs expression wrapped and executed into a variable.
    theVariable = rhsExpression->evaluateContent( env );
    
    // Get variable slot from lhs
    RevPtr<Variable> theSlot;
    theSlot = lhsExpression->evaluateLHSContent( env, theVariable->getRevObject().getType() );
    
    // Make the slot a reference to the rhs expression variable
    theSlot->makeReference( theVariable );

#ifdef DEBUG_PARSER
    env.printValue(std::cerr);
#endif
    
    // Return variable
    return theVariable;
}
Beispiel #3
0
/** Add reference to variable to frame. */
void Environment::addReference( const std::string& name, const RevPtr<RevVariable>& theVar )
{
    
    /* Throw an error if the name string is empty. */
    if ( name == "" )
    {
        throw RbException("Invalid attempt to add unnamed reference variable to frame.");
    }
    
    /* Throw an error if the variable exists. Note that we cannot use the function
     existsVariable because that function looks recursively in parent frames, which
     would make it impossible to hide global variables. */
    if ( variableTable.find( name ) != variableTable.end() )
    {
        throw RbException( "Variable " + name + " already exists in frame" );
    }
    
    /* Insert new reference variable in variable table */
    RevPtr<RevVariable> theRef = new RevVariable( theVar );
    variableTable.insert( std::pair<std::string, RevPtr<RevVariable> >( name, theRef ) );
    theRef->setName( name );
    
#ifdef DEBUG_WORKSPACE
    printf("Inserted \"%s\" in frame\n", name.c_str());
#endif
    
}
/** Get an index from an index variable in a static context */
size_t SyntaxVariable::getIndex( const RevPtr<Variable>& indexVar, Environment& env ) const
{
    if ( indexVar->getRevObject().isTypeSpec( Natural::getClassTypeSpec() ) )
    {
        // Get a Natural one-offset index
        size_t oneOffsetIndex = static_cast<Natural &>( indexVar->getRevObject() ).getValue();
        
        // Check validity
        if ( oneOffsetIndex < 1 )
        {
            std::ostringstream msg;
            msg << "Index for ";
            if ( baseVariable != NULL )
                msg << baseVariable->getFullName( env ) << ".";
            msg << identifier;
            msg << " smaller than 1";
            throw RbException( msg );
        }
        
        // Return the index
        return oneOffsetIndex;
    }
    else if ( indexVar->getRevObject().isConvertibleTo( Natural::getClassTypeSpec(), true ) )
    {
        // Convert to Natural
        RevObject* theNaturalIndex = indexVar->getRevObject().convertTo( Natural::getClassTypeSpec() );
        size_t oneOffsetIndex = static_cast<Natural*>( theNaturalIndex )->getValue();
        delete theNaturalIndex;
        
        // Check validity
        if ( oneOffsetIndex < 1 )
        {
            std::ostringstream msg;
            msg << "Index for ";
            if ( baseVariable != NULL )
                msg << baseVariable->getFullName( env ) << ".";
            msg << identifier;
            msg << " smaller than 1";
            throw RbException( msg );
        }
        
        // Return the index
        return oneOffsetIndex;
    }
    else if ( indexVar->getRevObject().isTypeSpec( RlString::getClassTypeSpec() ) )
    {
        throw RbException( "String indexes not supported (yet)");
    }
    else
    {
        std::ostringstream msg;
        msg << "Index for ";
        if ( baseVariable != NULL )
            msg << baseVariable->getFullName( env ) << ".";
        msg << identifier;
        msg << " of wrong type (neither " << Natural::getClassType() << " nor " << RlString::getClassType() << ")";
        throw RbException( msg );
    }
}
Beispiel #5
0
/**
 * @brief Get semantic value
 * 
 * Here we evaluate the length specification (statically) and create the
 * requested variable.
 *
 */
RevPtr<RevVariable> SyntaxVariableDecl::evaluateContent( Environment& env, bool dynamic )
{
    
    // Check if variable exists
    if ( env.existsVariable( variableName ) )
        throw RbException( "Illegal attempt to redefine variable " + variableName );
    
    // Check if type exists
    if ( !Workspace::userWorkspace().existsType( elementTypeName ) )
        throw RbException( "Type '" + elementTypeName + "' does not exist" );

    // Evaluate length specification
    std::vector<size_t> lengths;
    for ( std::list<SyntaxElement*>::iterator it = lengthExpr->begin(); it != lengthExpr->end(); ++it )
    {
        if ( (*it) == NULL )
        {
            lengths.push_back( 1 );
        }
        else
        {
            RevPtr<RevVariable> temp    = (*it)->evaluateContent( env, dynamic );
            const RevObject& value   = temp->getRevObject();
            
            size_t theLength;
            if ( value.isType( Natural::getClassTypeSpec() ) )
                theLength = size_t( static_cast<const Natural&>( value ).getValue() );
            else if ( value.isConvertibleTo( Natural::getClassTypeSpec(), true ) )
            {
                RevObject* convObj = value.convertTo( Natural::getClassTypeSpec() );
                theLength = size_t( static_cast<Natural*>( convObj )->getValue() );
                delete convObj;
            }
            else
                throw RbException( "Length specification does not evaluate to an object of type 'Natural'" );
            
            if ( theLength == 0 )
                throw RbException( "Invalid length specification (0)" );
            
            lengths.push_back( theLength );
        }
    }
    
    // We ask the user workspace for the new objects
    RevObject* newObject;
    if ( lengths.size() == 0 )
        newObject = Workspace::userWorkspace().makeNewDefaultObject( elementTypeName );
    else
    {
        throw RbException("This needs replacements!!!");
//        newObject = Workspace::userWorkspace().makeNewEmptyContainer( elementTypeName, lengths.size() );
//        static_cast<Container*>( newObject )->resize( lengths );
    }

    // Add the new RevVariable
    env.addVariable( variableName, new RevVariable( newObject ) );
    
    return NULL;
}
/** Get semantic value: insert symbol and return the rhs value of the assignment */
RevPtr<Variable> SyntaxDeterministicAssignment::evaluateContent( Environment& env )
{
#ifdef DEBUG_PARSER
    printf( "Evaluating deterministic assignment\n" );
#endif
    
    // Get the rhs expression wrapped and executed into a variable.
    // We need to call evaluateDynamicContent to get some elements
    // to evaluate their semantic content properly
    RevPtr<Variable> theVariable = rhsExpression->evaluateDynamicContent(env);
    
    // Get variable slot from lhs using the evaluateLHSContent to get the
    // appropriate behavior in the variable syntax element class.
    RevPtr<Variable> theSlot = lhsExpression->evaluateLHSContent( env, theVariable->getRevObject().getType() );

    // Check if the variable returned from the rhs expression is a named
    // variable in the environment. If so, we want to create an indirect
    // reference to it; otherwise, we want to fill the slot with a clone
    // of the variable returned by the rhs expression.
    if ( theVariable->getName() != "" )
        theSlot->setRevObject( theVariable->getRevObject().makeIndirectReference() );
    else
        theSlot->setRevObject( theVariable->getRevObject().clone() );
    
#ifdef DEBUG_PARSER
    env.printValue(std::cerr);
#endif    
    
    // We return the rhs variable itself as the semantic value of the
    // assignment statement. It can be used in further assignments.
    return theVariable;
}
/**
 * Evaluate the dynamic content of the one-offset index variables.
 */
std::vector< RevPtr<Variable> > SyntaxVariable::computeDynamicIndex( Environment& env )
{
    std::vector< RevPtr<Variable> > indexVars;

    std::list<SyntaxElement*>::const_iterator it;
    for ( it = index->begin(); it != index->end(); ++it )
    {
        RevPtr<Variable> theIndex = ( *it )->evaluateDynamicContent( env );
    
        // We ensure that the variables are of type Natural or can be converted to Natural numbers.
        // No sense in checking indices against permissible range here; errors are thrown later by
        // the container or member object if we are out of range.
        if ( !theIndex->getRevObject().isTypeSpec( Natural::getClassTypeSpec() ) )
        {
            if( theIndex->getRevObject().isConstant() && theIndex->getRevObject().isConvertibleTo( Natural::getClassTypeSpec(), true ) &&
                Natural::getClassTypeSpec().isDerivedOf( theIndex->getRevObjectTypeSpec() ) )
            {
                // Type promotion
                theIndex->setRevObject( theIndex->getRevObject().convertTo( Natural::getClassTypeSpec() ) );
                theIndex->setRevObjectTypeSpec( Natural::getClassTypeSpec() );
            }
            else if ( theIndex->getRevObject().isConvertibleTo( Natural::getClassTypeSpec(), false ) )
            {
                // Dynamic type conversion
                ConverterNode<Natural>* converterNode = new ConverterNode<Natural>( "", theIndex, Natural::getClassTypeSpec() );
                theIndex = new Variable( new Natural( converterNode ) );
            }
            else
            {
                throw RbException( "No known conversion of type '" + theIndex->getRevObject().getType() + "' to 'Natural', required for index");
            }
            
        }
        
        indexVars.push_back( theIndex );
    }
    
    return indexVars;
}
Beispiel #8
0
/**
 * 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-x§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(...)
 */
bool ArgumentRule::isArgumentValid(const RevPtr<const Variable> &var, bool once) const
{
    
    if ( var == NULL )
    {
        return false;
    }
    
//    TODO: Use this code when the constant flag in ArgumentRule is used correctly
//    if ( isConstant() || !var->isAssignable() )
//    if ( isConstant() )
    if ( evalType == BY_VALUE )
    {
        once = true;
    }

    for ( std::vector<TypeSpec>::const_iterator it = argTypeSpecs.begin(); it != argTypeSpecs.end(); ++it )
    {
        if ( var->getRevObject().isTypeSpec( *it ) )
        {
            return true;
        }
        else if ( var->getRevObject().isConvertibleTo( *it, once ) )
        {
            return true;
        }
        else if ( once == false && !var->isAssignable() &&
                  var->getRevObject().isConvertibleTo( *it, true ) &&
                  (*it).isDerivedOf( var->getRevObjectTypeSpec() )
                )
        {
            return true;
        }
        
    }
    
    return false;
}
Beispiel #9
0
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;
    }

    
}
Beispiel #10
0
/**
 * This is a help function that evaluates the expression and then checks
 * whether the result is true or false, or can be interpreted as a RlBoolean
 * true or false value.
 */
bool SyntaxStatement::isTrue( SyntaxElement* expr, Environment& env ) const
{
    RevPtr<Variable> temp = expr->evaluateContent( env );
    
    if ( temp == NULL )
        return false;
    
    if ( temp->getRevObject().isTypeSpec( RlBoolean::getClassTypeSpec() ) )
    {
        bool retValue = static_cast<const RlBoolean&>( temp->getRevObject() ).getValue();
        
        return retValue;
    }
    else
    {
        RevObject *tempObject = temp->getRevObject().convertTo( RlBoolean::getClassTypeSpec() );
        RlBoolean* tempBool = static_cast<RlBoolean*>( tempObject );
        bool     retValue = tempBool->getValue();
        
        delete tempBool;
        
        return   retValue;
    }
}
/**
 * Evaluate the content of this syntax element. This will perform a
 * subtraction assignment operation.
 */
void SyntaxSubtractionAssignment::assign(RevPtr<RevVariable> &lhs, RevPtr<RevVariable> &rhs)
{
#ifdef DEBUG_PARSER
    printf( "Evaluating subtraction assignment\n" );
#endif
    
    // Get variable from lhs. We use standard evaluation because the variable is
    // implicitly on both sides (lhs and rhs) of this type of statement
    if ( lhs == NULL )
    {
        throw RbException( "Invalid NULL variable returned by lhs expression in subtraction assignment" );
    }
    
    // Make sure that the variable is constant
    if ( !lhs->getRevObject().isConstant() )
    {
        throw RbException( "Invalid subtraction assignment to dynamic variable" );
    }
    
    // Record whether it is a workspace (control) variable
    bool isWorkspaceVar = lhs->isWorkspaceVariable();
    
    // Get a reference to the lhs value object
    const RevObject& lhs_value = lhs->getRevObject();
    
    // Evaluate the rhs expression
    if ( rhs == NULL )
    {
        throw RbException( "Invalid NULL variable returned by rhs expression in subtraction assignment" );
    }
    
    // Get a reference to the rhs value object
    const RevObject& rhs_value = rhs->getRevObject();
    
    // Generate result of the multiplication
    RevObject *newValue = lhs_value.subtract( rhs_value );
    
    // Fill the slot with the new RevVariable
    lhs->replaceRevObject( newValue );
    
    // Reset it as workspace (control) variable, if it was a workspace (control) variable before the assignment.
    // When we fill the slot, the workspace (control) variable property is reset to false by default.
    if ( isWorkspaceVar )
    {
        lhs->setWorkspaceVariableState( true );
    }
    
#ifdef DEBUG_PARSER
    env.printValue(std::cerr);
#endif
}
/**
 * Evaluate the content of this syntax element. This will perform
 * a multiplication assignment operation.
 */
RevPtr<Variable> SyntaxMultiplicationAssignment::evaluateContent( Environment& env )
{
#ifdef DEBUG_PARSER
    printf( "Evaluating multiplication assignment\n" );
#endif
    
    // Get variable from lhs. We use standard evaluation because the variable is
    // implicitly on both sides (lhs and rhs) of this type of statement
    RevPtr<Variable> theVariable = lhsExpression->evaluateContent( env );
    if ( theVariable == NULL )
        throw RbException( "Invalid NULL variable returned by lhs expression in multiplication assignment" );
    
    // Make sure that the variable is constant
    if ( !theVariable->getRevObject().isConstant() )
        throw RbException( "Invalid multiplication assignment to dynamic variable" );
    
    // Record whether it is a control variable
    bool isControlVar = theVariable->isControlVar();
    
    // Get a reference to the lhs value object
    const RevObject& lhs_value = theVariable->getRevObject();
    
    // Evaluate the rhs expression
    const RevPtr<Variable>& rhs = rhsExpression->evaluateContent( env );
    if ( rhs == NULL )
        throw RbException( "Invalid NULL variable returned by rhs expression in multiplication assignment" );
    
    // Get a reference to the rhs value object
    const RevObject& rhs_value = rhs->getRevObject();
    
    // Generate result of the multiplication
    RevObject *newValue = lhs_value.multiply( rhs_value );
    
    // Fill the slot with the new variable
    theVariable->setRevObject( newValue );
    
    // Reset it as control variable, if it was a control variable before the assignment.
    // When we fill the slot, the control variable property is reset to false by default.
    if ( isControlVar )
        theVariable->setControlVarState( true );
    
#ifdef DEBUG_PARSER
    env.printValue(std::cerr);
#endif
    
    // Return the variable for further assignment
    return theVariable;
}
Beispiel #13
0
/**
 * This function causes recursive execution of a syntax tree by calling the root to get its value.
 * As long as we return to the bison code, bison takes care of deleting the syntax tree. However,
 * if we encounter a quit() call, we delete the syntax tree ourselves and exit immediately.
 */
int RevLanguage::Parser::execute(SyntaxElement* root, Environment &env) const {

    // don't execute command if we are in checking mode
    if (RevLanguage::Parser::getParser().isChecking()) {
#ifdef DEBUG_PARSER
        std::cerr << "Command is not executed since parser is set checking mode.";
#endif
        return 0;
    }

#ifdef DEBUG_PARSER
    // Print syntax tree
    std::cerr << std::endl;
    std::cerr << "Syntax tree root before execution:\n";
    root->printValue(std::cerr);
    std::cerr << std::endl;
#endif

    // Declare a variable for the result
    RevPtr<RevVariable> result = NULL;

    //! Execute syntax tree
    try
    {
#ifdef DEBUG_PARSER
        printf("Parser getting the semantic value of the syntax tree...\n");
#endif
        result = root->evaluateContent(env);
    }
    catch (RbException& rbException)
    {

        std::ostringstream msg;

        // Catch a quit request
        if (rbException.getExceptionType() == RbException::QUIT)
        {
            delete( root);
            
#ifdef RB_MPI
            MPI::Finalize();
#endif
            
            exit(0);
        }

        // Catch a missing variable exception that might be interpreted as a request for
        // usage help on a function
        SyntaxVariable* rootPtr = dynamic_cast<SyntaxVariable*> ((SyntaxElement*) root);
        SyntaxVariable* theVariable = rootPtr;
        if (rbException.getExceptionType() == RbException::MISSING_VARIABLE && theVariable != NULL)
        {

            const std::string& fxnName = theVariable->getIdentifier();
            const std::vector<Function*>& functions = Workspace::userWorkspace().getFunctionTable().findFunctions(fxnName);
            if (functions.size() != 0) {
                for (std::vector<Function*>::const_iterator i = functions.begin(); i != functions.end(); i++) {
                    std::ostringstream s;
                    (*i)->printValue(s);
                    RBOUT(s.str());

                    // Uncommenting this as the function callSignature() does not produce the call signature despite its name
                    // -- Fredrik
                    // RBOUT( (*i)->callSignature() );
                }
                return 0;
            }
        }

        // All other exceptions
#ifdef DEBUG_PARSER
        printf("Caught an exception\n");
#endif
        rbException.print(msg);
        RBOUT(msg.str());

        // Return signal indicating problem
        return 2;
    }

    // Print result if the root is not an assign expression
    if (!root->isAssignment() && result != NULL && result->getRevObject() != RevNullObject::getInstance())
    {
        std::ostringstream msg;
        result->getRevObject().printValue(msg,true);
        RBOUT(msg.str());
    }

    // Warn if a return signal has been encountered
    // @todo Find out why the following lines do not work; they should
    //    if ( Signals::getSignals().isSet( Signals::RETURN ) )
    //        RBOUT( "WARNING: No function to return from" );
    Signals::getSignals().clearFlags();

    // Return success
    return 0;
}
Beispiel #14
0
/**
 * @brief Evaluate left-hand-side content
 *
 * This function is similar to evaluateContent(). However, we
 * do not throw an error if the variable does not exist in the
 * frame; instead, we create and return a new null variable.
 */
RevPtr<Variable> SyntaxVariable::evaluateLHSContent( Environment& env, const std::string& elemType )
{
    // Get static index. No dynamic evaluation here
    std::vector<size_t> oneOffsetIndices = computeStaticIndex( env );
    
    RevPtr<Variable> theVar;
    
    if ( baseVariable == NULL )
    {
        if ( functionCall != NULL )
        {
            // Get the return variable of the function call
            theVar = functionCall->evaluateContent( env );
        }
        else if ( expression != NULL )
        {
            // Get the return variable of the expression
            theVar = expression->evaluateContent( env );
        }
        else
        {
            // Find or create the variable
            if ( env.existsVariableInFrame( identifier ) )
                theVar = env.getVariable( identifier );
            else    // add it
            {
                if ( oneOffsetIndices.size() == 0 )
                    theVar = new Variable( NULL, identifier );
                else
                    theVar = new Variable( Workspace::userWorkspace().makeNewEmptyContainer( elemType, oneOffsetIndices.size() ), identifier );
                env.addVariable( identifier, theVar );
            }
        }
    }
    else
    {
        // Note that the function call is always NULL if there is
        // a base variable, because any variables that are base to
        // the function call are handled by the function call. Note
        // also that generic expressions can only occur in base
        // variables, so we need not worry about any expression if
        // we are not a base variable.
        
        // Get the base variable. Note that we do not create the variable in this case.
        theVar = baseVariable->evaluateContent( env );

        // Find member variable based on its name
        theVar = theVar->getRevObject().getMember( identifier );
    }
    
    // Get element if indices are provided.
    while ( !oneOffsetIndices.empty() )
    {
        // Get the element...
        if ( theVar->getRevObject().isTypeSpec( Container::RevObject::getClassTypeSpec() ) )
        {
            // ... from a container
            
            // Get the container indices
            std::vector<size_t> containerOneOffsetIndices;
            for ( size_t i = 0; i < theVar->getRevObject().getDim(); ++i )
            {
                if ( !oneOffsetIndices.empty() )
                {
                    containerOneOffsetIndices.push_back( oneOffsetIndices[0] );
                    oneOffsetIndices.erase( oneOffsetIndices.begin() );
                }
                else
                    containerOneOffsetIndices.push_back( 0 );
            }
            
            // Get the element using the findOrCreateElement function
            theVar = theVar->getRevObject().findOrCreateElement( containerOneOffsetIndices );
        }
        else
        {
            // ... or from a subscript operator
            
            // Note that we do not name the element here; either the member object gives out
            // a variable it names itself, or it gives out a temporary variable copy, which
            // should not be named. A subscript operator cannot be used to assign to a non-
            // existing variable.
            
            // Create the single argument for the index operator
            std::vector<Argument> args;
            RevPtr<Variable> indexVar = new Variable( new Natural( oneOffsetIndices[0] ) );
            args.push_back( Argument( indexVar ) );
            
            // Get the variable using the subscript operator function
            // TODO: This needs to be made generic for user-defined member objects
            theVar = theVar->getRevObject().executeMethod( "[]", args );
            
            // Erase the index
            oneOffsetIndices.erase( oneOffsetIndices.begin() );
        }
    }

    // Return the variable for assignment
    return theVar;
}
Beispiel #15
0
/**
 * Erase a variable by its address. We just delegate the call to erase by name.
 */
void Environment::eraseVariable(const RevPtr<RevVariable>& var)
{
    
    // Delegate call
    eraseVariable( var->getName() );
}
Beispiel #16
0
/**
 * 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;
}
Beispiel #17
0
/**
 * 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() );
}
Beispiel #18
0
/**
 * 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() );
}
Beispiel #19
0
/**
 * @brief Evaluate dynamic rhs content
 *
 * This function returns the semantic value of the variable expression
 * when it is part of a dynamic expression, that is, the right-hand side
 * of an equation (deterministic) or tilde (stochastic) assignment.
 *
 * It differs from the standard evaluateContent() in several ways. First,
 * control variables need to return clones of themselves (temporary
 * variables) rather than themselves, so that they are not included in
 * the DAG. Second, we cannot compute a static index for indexed variables.
 * Instead, we need to deliver an index conisting of variables resulting
 * from dynamic evaluation of the index variables. These need to be put
 * in a dynamic lookup variable.
 */
RevPtr<Variable> SyntaxVariable::evaluateDynamicContent( Environment& env)
{
    RevPtr<Variable> theVar;
    
    if ( baseVariable == NULL )
    {
        if ( functionCall != NULL )
        {
            // Get the dynamic return variable of the function call
            theVar = functionCall->evaluateDynamicContent( env );
        }
        else if ( expression  != NULL )
        {
            // Get the dynamic return variable of the expression
            theVar = expression->evaluateDynamicContent( env );
        }
        else
        {
            // Get variable from the environment (no dynamic version of identifier)
            theVar = env.getVariable( identifier );
        }
    }
    else
    {
        // Note that the function call is always NULL if there is
        // a base variable, because any variables that are base to
        // the function call are handled by the function call. Note
        // also that generic expressions can only occur in base
        // variables, so we need not worry about any expression if
        // we are not a base variable.
        
        // Get the base variable
        theVar = baseVariable->evaluateDynamicContent( env );
        
        // Find member variable (no dynamic version of identifier)
        theVar = theVar->getRevObject().getMember( identifier );
    }

    // Get dynamic index
    std::vector< RevPtr<Variable> > oneOffsetIndexVars = computeDynamicIndex( env );
    
    // Check if we need a dynamic lookup
    bool dynamicLookup = false;
    for ( std::vector< RevPtr<Variable> >::iterator it = oneOffsetIndexVars.begin(); it != oneOffsetIndexVars.end(); ++it )
    {
        if ( (*it)->getRevObject().hasDagNode() && (*it)->isAssignable() )
        {
            dynamicLookup = true;
            break;
        }
    }
    
    // If the variable we are looking up things in does not have a DAG node, we do not need a dynamic lookup regardless
    // If it does have a DAG node, we need a dynamic lookup if it is named, regardless of whether we have constant indices
    if ( theVar->getRevObject().hasDagNode() == false )
        dynamicLookup = false;
    else if ( theVar->isAssignable() )
        dynamicLookup = true;

    // Get dynamic element from container or subscript operator
    while ( !oneOffsetIndexVars.empty() )
    {
        // Get the element...
        if ( theVar->getRevObject().isTypeSpec( Container::RevObject::getClassTypeSpec() ) )
        {
            // ... from a container
            
            // Get the container index variables
            std::vector< RevPtr<Variable> > containerOneOffsetIndexVars;
            for ( size_t i = 0; i < theVar->getRevObject().getDim(); ++i )
            {
                if ( !oneOffsetIndexVars.empty() )
                {
                    containerOneOffsetIndexVars.push_back( oneOffsetIndexVars[0] );
                    oneOffsetIndexVars.erase( oneOffsetIndexVars.begin() );
                }
                else
                    containerOneOffsetIndexVars.push_back( new Variable( new Natural( 0 ) ) );
            }
            
            if ( dynamicLookup )
            {
                // Make a dynamic element lookup
                theVar = new Variable( theVar->getRevObject().makeElementLookup( theVar, containerOneOffsetIndexVars ) );
            }
            else
            {
                // We want a static element lookup

                // Get the container indices statically
                std::vector<size_t> containerOneOffsetIndices;
                for ( size_t i = 0; i < containerOneOffsetIndexVars.size(); ++i )
                {
                    containerOneOffsetIndices.push_back( getIndex( containerOneOffsetIndexVars[i], env ) );
                }
                
                // Get the element using the getElement function
                theVar = theVar->getRevObject().getElement( containerOneOffsetIndices );
            }
        }
        else
        {
            // ... or from a subscript operator
            
            // Note that we do not name the element here; either the member object gives out
            // a variable it names itself, or it gives out a temporary variable copy, which
            // should not be named
            
            // Create the single argument for the index operator (statically always for now)
            std::vector<Argument> args;
            args.push_back( Argument( new Variable( new Natural( getIndex( oneOffsetIndexVars[0], env ) ) ) ) );

           // Get the variable using the subscript operator function
            // TODO: This needs to be made generic for user-defined member objects
            // TODO: This needs to check that there is a subscript operator function and not procedure,
            // and then return a dynamic element lookup
            theVar = theVar->getRevObject().executeMethod( "[]", args );
            
            // Erase the index
            oneOffsetIndexVars.erase( oneOffsetIndexVars.begin() );
        }
    }
    
    // Check whether we have a control variable and make a clone in that case
    if ( theVar->isControlVar() )
        theVar = new Variable( theVar->getRevObject().clone() );
    
    // Return the variable for assignment
    return theVar;
}
Beispiel #20
0
/**
 * @brief Process arguments
 *
 * This function processes arguments based on argument rules. First it deletes
 * any previously stored arguments. If the matching of the new arguments
 * succeeds, the processedArguments will be set to the new vector of processed
 * arguments and the function returns true. Any subsequent calls to execute()
 * will then use the processed arguments. You can also call the function with
 * the arguments directly, in which case processArguments will be called first
 * before the operation is actually performed.
 *
 * In matching arguments to argument rules, we use the same rules as in R with
 * the addition that types are also used in the matching process, after arguments
 * have been reordered as in R. The FunctionTable ensure that all argument rules
 * are distinct. However, several functions can nevertheless match the same
 * arguments because of the inheritance hierarchy. In these clases, the closest
 * match is chosen based on the first argument, then on the second, etc.
 *
 * The function returns a match score based on how closely the arguments match the
 * rules, with 0 being perfect match, 1 being a match to an immediate base class type,
 * 2 a match to a grandparent class, etc. A large number is used for arguments that
 * need type conversion.
 *
 * The evaluateOnce parameter MemberObject whether the function is to be evaluated once,
 * immediately after the call to processArguments, or whether the processed arguments
 * will be used in repeated function calls in a function node. Argument matching is
 * based on current values in the first case, but on the wrapper type in the second.
 *
 * @todo Labels need to be stored for ellipsis arguments.
 *
 * These are the argument matching rules:
 *
 *  1. If the last argument rule is an ellipsis, and it is the kth argument passed
 *     in, then all arguments passed in, from position k to the end, are wrapped
 *     in a single ContainerNode object. These arguments are not matched to any
 *     rules.
 *  2. The remaining arguments are matched to labels using exact matching. If the
 *     type does not match the type of the rule, it is an error.
 *  3. The remaining arguments are matched to any remaining slots using partial
 *     matching. If there is ambiguity or the types do not match, it is an error.
 *  4. The remaining arguments are used for the empty slots in the order they were
 *     passed in. If the types do not match, it is an error.
 *  5. Any remaining empty slots are filled with default values stored in the argument
 *     rules (we use copies of the values, of course).
 *  6. If there are still empty slots, the arguments do not match the rules.
 *
 * @todo Fredrik: The code and the logic has been changed without changing the comments, so these
 *       are out of date. Also note that the argument matching is problematic for unlabeled
 *       arguments (order can be changed based on argument types, which may cause unintended
 *       consequences). Furthermore, there is redundant code left from the old implementation.
 *       Finally, the ellipsis arguments no longer have to be last among the rules, but they
 *       are still the last arguments after processing.
 *
 * @todo Fredrik: Static and dynamic type conversion added, but partly hack-ish, so the implementation
 *       needs to be revised
 */
void Function::processArguments( const std::vector<Argument>& passedArgs, bool once )
{

    /*********************  0. Initialization  **********************/
    /* Get my own copy of the argument vector */
    std::vector<Argument> pArgs = passedArgs;
    
    /* Get the argument rules */
    const ArgumentRules& theRules = getArgumentRules();

    /* Get the number of argument rules */
    size_t nRules = theRules.size();

    /* Clear previously processed arguments */
    args.clear();
    
    /* Keep track of which arguments we have used, and which argument slots we have filled, and with what passed arguments */
    std::vector<bool>   taken           = std::vector<bool>( passedArgs.size(), false );
    std::vector<bool>   filled          = std::vector<bool>( nRules, false );
    std::vector<size_t> passedArgIndex  = std::vector<size_t>( nRules, 1000 );
    std::vector<Argument> ellipsisArgs;

    /*********************  1. Do exact matching  **********************/

    /* Do exact matching of labels */
    for(size_t i=0; i<passedArgs.size(); i++)
    {

        /* Test if swallowed by ellipsis; if so, we can quit because the remaining passedArgs will also be swallowed */
        if ( taken[i] )
        {
            break;
        }
        
        /* Skip if no label */
        if ( passedArgs[i].getLabel().size() == 0 )
        {
            continue;
        }
        
        /* Check for matches in all regular rules (we assume that all labels are unique; this is checked by FunctionTable) */
        for (size_t j=0; j<nRules; j++)
        {
            std::vector<std::string> aliases = theRules[j].getArgumentAliases();

            for(size_t k=0; k < aliases.size(); k++)
            {
                if ( passedArgs[i].getLabel() == aliases[k] )
                {

                    if ( filled[j] )
                    {
                        throw RbException( "Duplicate argument labels '" + passedArgs[i].getLabel() );
                    }

                    pArgs[i]            = theRules[j].fitArgument( pArgs[i], once );
                    taken[i]            = true;
                    filled[j]           = true;
                    passedArgIndex[j]   = static_cast<int>( i );

                    // We got an exact match -> we can skip the other labels for checking
                    j = nRules;
                    break;
                }
            }
        }
    }

 
    /*********************  2. Do partial matching  **********************/

    /* Do partial matching of labels */
    for(size_t i=0; i<passedArgs.size(); i++) 
    {

        /* Skip if already matched */
        if ( taken[i] )
        {
            continue;
        }
        
        /* Skip if no label */
        if ( passedArgs[i].getLabel().size() == 0 )
        {
            continue;
        }
        
        /* Initialize match index and number of matches */
        int nMatches = 0;
        int matchRule = -1;
        std::string label;

        /* Try all rules */
        for (size_t j=0; j<nRules; j++) 
        {
            std::vector<std::string> aliases = theRules[j].getArgumentAliases();

            for(size_t k=0; k < aliases.size(); k++)
            {
                if ( !filled[j] && aliases[k].compare(0, passedArgs[i].getLabel().size(), passedArgs[i].getLabel()) == 0 )
                {
                    ++nMatches;
                    matchRule = static_cast<int>( j );
                    label = aliases[k];
                }
            }
        }

        if (nMatches > 1)
        {
            throw RbException( "Argument label '" + passedArgs[i].getLabel() + "' matches mutliple parameter labels." );
        }
        else if (nMatches < 1)
        {
            throw RbException( "Argument label '" + passedArgs[i].getLabel() + "' matches no untaken parameter labels." );
        }
        
        if ( nMatches == 1)
        {
            pArgs[i].setLabel(label);
            pArgs[i]                    = theRules[matchRule].fitArgument( pArgs[i], once );
            taken[i]                    = true;
            filled[matchRule]           = true;
            passedArgIndex[matchRule]   = static_cast<int>( i );
        }
        
    }


    /*********************  3. Fill with unused passedArgs  **********************/

    /* Fill in empty slots using the remaining args in order */
    for(size_t i=0; i<passedArgs.size(); i++) 
    {

        /* Skip if already matched */
        if ( taken[i] )
        {
            continue;
        }
        
        /* Find first empty slot and try to fit argument there */
        for (size_t j=0; j<nRules; j++) 
        {

            if ( filled[j] == false &&
                 ( (!theRules[j].isEllipsis() && passedArgs[i].getLabel().size() == 0) || (theRules[j].isEllipsis()) ) )
            {
                
                Argument &arg = const_cast<Argument&>(passedArgs[i]);
                double penalty = theRules[j].isArgumentValid( arg, once );
                if ( penalty != -1 )
                {
                    if(theRules[j].getArgumentAliases().size() > 1)
                    {
                        throw RbException("Could not determine argument label for parameter '" + theRules[j].getArgumentLabel() + "'.");
                    }
                    pArgs[i].setLabel( theRules[j].getArgumentLabel() );
                    pArgs[i]          = theRules[j].fitArgument( pArgs[i], once );
                    taken[i]          = true;
                    if ( !theRules[j].isEllipsis() ) 
                    {
                        filled[j]     = true;
                        passedArgIndex[j] = static_cast<int>( i );
                    }
                    else 
                    {
                        ellipsisArgs.push_back( pArgs[i] );
                    }
                    
                    break;
                }
            }
        }
        
        /* Final test if we found a match */
        if ( !taken[i] )
        {
            throw RbException("Superfluous argument of type '" + passedArgs[i].getVariable()->getRevObject().getType() + "' and name '" + passedArgs[i].getLabel() + "' passed to function '" + getType() + "'.");
        }
    }

    /*********************  4. Fill with default values  **********************/

    /* Fill in empty slots using default values */
    for(size_t i=0; i<nRules; i++) 
    {

        if ( filled[i] == true || theRules[i].isEllipsis())
        {
            continue;
        }
        
        // we just leave the optional arguments empty
        if ( !theRules[i].hasDefault() )
        {
            throw RbException("No argument found for parameter '" + theRules[i].getArgumentLabel() + "'.");
        }
        
        const ArgumentRule& theRule = theRules[i];
        RevPtr<RevVariable> theVar = theRule.getDefaultVariable().clone();
        theVar->setName( "." + theRule.getArgumentLabel() );
        theVar->setRequiredTypeSpec( theRule.getDefaultVariable().getRequiredTypeSpec() );
        size_t idx = pArgs.size();
        passedArgIndex[i] = idx;
        pArgs.push_back( Argument( theVar, theRule.getArgumentLabel(), theRule.getEvaluationType() != ArgumentRule::BY_CONSTANT_REFERENCE ) );
    }

    argsProcessed = true;
    
    /*********************  5. Insert arguments into argument list  **********************/
    for (size_t j=0; j<nRules; j++) 
    {
        if ( passedArgIndex[j] < 1000 )
        {
            args.push_back( pArgs[ passedArgIndex[j] ] );
        }
        
    }
    
    /*********************  6. Insert ellipsis arguments  **********************/
    for (std::vector<Argument>::iterator i = ellipsisArgs.begin(); i != ellipsisArgs.end(); i++) 
    {
        args.push_back( *i );
    }

}
/**
 * Evaluate semantic content.
 *
 * If dynamic == false, then we know that we only want to evaluate the function once,
 * and get a constant value back. For now, it does the same thing as
 * if dynamic == true, with two exceptions. First, it uses the evaluate function
 * with dynamic == false to evaluate its arguments. Second, it makes the return
 * value a constant value.
 *
 * If dynamic == true, then we know that we want
 * to evaluate the function repeatedly, as part of a deterministic variable.
 * Therefore, we need to make a deterministic variable with the function inside
 * it. Currently, this is the default implementation for the execute function
 * in RevLanguage::Function, but we may want to differentiate between the two
 * contexts later.
 *
 * @todo Support this function call context better
 */
RevPtr<RevVariable> SyntaxFunctionCall::evaluateContent( Environment& env, bool dynamic )
{
    
    // Package arguments
    std::vector<Argument> args;
    for ( std::list<SyntaxLabeledExpr*>::const_iterator it = arguments->begin(); it != arguments->end(); ++it )
    {
#ifdef DEBUG_PARSER
        printf( "Adding argument with label \"%s\".\n", (*i)->getLabel().c_str() );
#endif
        
        const RlString& theLabel = (*it)->getLabel();
        RevPtr<RevVariable> theVar = (*it)->getExpression().evaluateContent(env,dynamic);
        
        Argument theArg = Argument( theVar, theLabel.getValue() );
        args.push_back( theArg );
    }
    
    Function* func = NULL;
    if ( baseVariable == NULL )
    {
        // We are trying to find a function in the current environment
        
        // First we see if the function name corresponds to a user-defined variable
        // We can do this first because user-defined variables are not allowed to mask function names
        bool found = false;
        if ( env.existsVariable( functionName ) )
        {
            RevObject &theObject = env.getRevObject( functionName );
            
            if ( theObject.isType( Function::getClassTypeSpec() ) )
            {
                func = static_cast<Function*>( theObject.clone() );
                found = func->checkArguments(args, NULL, !dynamic);
            }
        }
        
        // If we cannot find the function name as a variable, it must be in the function table
        // This call will throw with a relevant message if the function is not found
        if ( !found )
        {
            func = env.getFunction(functionName, args, !dynamic).clone();
        }
        
        // Allow the function to process the arguments
        func->processArguments( args, !dynamic );
        
        // Set the execution environment of the function
        func->setExecutionEnviroment( &env );
    }
    else
    {
        // We are trying to find a member function
        
        // First we get the base variable
        RevPtr<RevVariable> theVar = baseVariable->evaluateContent( env, dynamic );
        
        // Now we get a reference to the member object inside
        RevObject &theMemberObject = theVar->getRevObject();
        
        const MethodTable& mt = theMemberObject.getMethods();
        
        Function* theFunction = mt.getFunction( functionName, args, !dynamic ).clone();
        theFunction->processArguments(args, !dynamic);
        
        MemberMethod* theMemberMethod = dynamic_cast<MemberMethod*>( theFunction );
        if ( theMemberMethod != NULL )
        {
            theMemberMethod->setMemberObject( theVar );
            func = theFunction;
        }
        else
        {
            delete theFunction;
            throw RbException("Error while trying to access member function/procedure.");
        }
        
    }
    
    // Evaluate the function
    RevPtr<RevVariable> funcReturnValue = func->execute();
    
    // free the memory of our copy
    delete func;
    
    if ( dynamic == false )
    {
        // Return the value, which is typically a deterministic variable with the function
        // inside it, although many functions return constant values or NULL (void).
        // To make sure the value is a constant and not a deterministic variable in this
        // context, we convert the return value here to a constant value before returning it.
        if ( funcReturnValue != NULL )
        {
            funcReturnValue->getRevObject().makeConstantValue();
        }
    }
    
    return funcReturnValue;
}
Beispiel #22
0
/**
 * Get semantic value: it is here that we execute the statement.
 *
 * @todo Return statements do not appear to be correctly handled in
 *       for loops. The return variable is discarded and the loop
 *       just continues.
 */
RevPtr<Variable> SyntaxStatement::evaluateContent(Environment& env) {

    RevPtr<Variable> result = NULL;
    
    if (statementType == For)
    {
        // Convert expression to for condition
        SyntaxForLoop* forLoop = dynamic_cast<SyntaxForLoop*>( expression );
        assert ( forLoop != NULL );

        // Initialize for loop. We use current environment for the loop variables (as in R)
        Signals::getSignals().clearFlags();
        forLoop->initializeLoop( env );

        // Now loop over statements inside the for loop
        while ( !forLoop->isFinished() )
        {
            // Get next loop state. This will update the value of the loop variable
            forLoop->getNextLoopState();

            for ( std::list<SyntaxElement*>::iterator it = statements1->begin(); it != statements1->end(); ++it )
            {
                // Get a convenient pointer to the syntax element
                SyntaxElement* theSyntaxElement = *it;
                
                // Execute statement
                result = theSyntaxElement->evaluateContent( env );

                // We do not print the result (as in R). Uncomment the code below to change this behavior

#if 0
                // Print result if it is not an assign expression (== NULL)
                if ( !Signals::getSignals().isSet( Signals::RETURN ) && !theSyntaxElement->isAssignment() &&
                     result != NULL && result->getRevObject() != RevNullObject::getInstance())
                {
                    std::ostringstream msg;
                    result->getRevObject().printValue(msg);
                    RBOUT( msg.str() );
                }
#endif

                // Catch a return signal
                // TODO: This appears to inappropriately discard the return value of a return statement
				if ( !Signals::getSignals().isSet( Signals::RETURN ) && result != NULL)
                {
                    result = NULL;  // discard result
                }

                // Catch signal
                if ( !Signals::getSignals().isGood() )
                    break;
            }
            
            // Catch signals
            // TODO Return statement not handled correctly
            if ( Signals::getSignals().isSet(Signals::BREAK) )
            {
                Signals::getSignals().clearFlags();
                break;
            }
            else if ( Signals::getSignals().isSet(Signals::CONTINUE) )
            {
                Signals::getSignals().clearFlags();  // Just continue with next loop state
            }
        }
        
        // Finalize the loop (resets the forloop state for next execution round)
        forLoop->finalizeLoop();
        
    }
    else if ( statementType == Break )
    {
        // Set BREAK signal
        Signals::getSignals().set(Signals::BREAK);
    }
    else if (statementType == Next)
    {
        // Set CONTINUE signal
        Signals::getSignals().set(Signals::CONTINUE);
    }
    else if ( statementType == While )
    {
        // Loop over statements inside the while loop, first checking the expression
        while ( isTrue( expression, env ) ) {

            for ( std::list<SyntaxElement*>::iterator it = statements1->begin(); it != statements1->end(); ++it )
            {
                SyntaxElement* theSyntaxElement = *it;

                // Execute statement
	            result = theSyntaxElement->evaluateContent( env );
                
                // Print result if it is not an assign expression (==NULL)
                if ( !Signals::getSignals().isSet( Signals::RETURN ) && !theSyntaxElement->isAssignment()
                        && result != NULL && result->getRevObject() != RevNullObject::getInstance() )
                {
                    std::ostringstream msg;
                    result->getRevObject().printValue(msg);
                    RBOUT( msg.str() );
                }
	 
	            // Free memory
                if ( !Signals::getSignals().isSet( Signals::RETURN ) && result != NULL )
                {
                    result = NULL;  // discard result
                }
	 
	            // Catch signal
	            if ( !Signals::getSignals().isGood() )
                    break;
            }

            // Catch signals
            if ( Signals::getSignals().isSet(Signals::BREAK) )
            {
	                 Signals::getSignals().clearFlags();
	                 break;
            }
            else if ( Signals::getSignals().isSet(Signals::CONTINUE) )
            {
	                 Signals::getSignals().clearFlags();  // Just continue with next loop state
            }
        }
    }
    else if ( statementType == Return )
    {
        // Set RETURN signal and return expression value
        Signals::getSignals().set(Signals::RETURN);
        return expression->evaluateContent(env);
    }
    else if ( statementType == If )
    {
        // Process statements inside the if clause if expression is true
        if ( isTrue( expression, env ) )
        {
            for ( std::list<SyntaxElement*>::iterator it = statements1->begin(); it != statements1->end(); ++it )
            {
                // Execute statement
                result = (*it)->evaluateContent(env);
                
                // Print result if it is not an assign expression (==NULL)
                if ( !Signals::getSignals().isSet( Signals::RETURN ) && result != NULL )
                {
                    std::ostringstream msg;
                    result->getRevObject().printValue(msg);
                    RBOUT( msg.str() );
                }

                // Free memory
                if ( !Signals::getSignals().isSet( Signals::RETURN ) && result != NULL )
                {
                    result = NULL;  // discard result
                }
            }
        }
    }
    else if ( statementType == IfElse )
    {
        // Process statements inside the if clause if expression is true,
        // otherwise process statements in else clause
        if ( isTrue( expression, env ) )
        {
            for ( std::list<SyntaxElement*>::iterator it = statements1->begin(); it != statements1->end(); ++it )
            {
                // Execute statement
                result = (*it)->evaluateContent( env );
                
                // Print result if it is not an assign expression (==NULL)
                if ( !Signals::getSignals().isSet( Signals::RETURN ) && result != NULL )
                {
                    std::ostringstream msg;
                    result->getRevObject().printValue(msg);
                    RBOUT( msg.str() );
                }
                
                // Free memory
                if ( !Signals::getSignals().isSet( Signals::RETURN ) && result != NULL )
                {
                    result = NULL;  // discard result
                }
            }
        }
        else
        {
            for ( std::list<SyntaxElement*>::iterator it = statements2->begin(); it != statements2->end(); ++it )
            {
                // Execute statement
                result = (*it)->evaluateContent( env );
                
                // Print result if it is not an assign expression (==NULL)
                if ( !Signals::getSignals().isSet( Signals::RETURN ) && result != NULL )
                {
                    std::ostringstream msg;
                    result->getRevObject().printValue(msg);
                    RBOUT( msg.str() );
                }
                    
                // Free memory
                if ( !Signals::getSignals().isSet( Signals::RETURN ) && result != NULL )
                {
                    result = NULL;  // discard result
                }
            }
        }
    }

    return result;
}