/** 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 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;
}
示例#3
0
/**
 * 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;
}
示例#4
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() );
}