/** 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; }
/** * 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; }
/** * 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() ); }