/** 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: 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; }
/** 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 ); } }
/** * 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; }
/** * 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; }
/** * @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; }
/** * 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; }
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; } }
/** * 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 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; }
/** * 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; }
/** * 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; }
/** * Fit a variable into an argument according to the argument rule. If necessary and * appropriate, we do type conversion or type promotion. * * * * @todo To conform to the old code we change the required type of the incoming * variable wrapper here. We need to change this so that we do not change * the wrapper here, but make sure that if the argument variable is inserted * in a member variable or container element slot, that the slot variable * wrapper, which should be unique (not the same as the incoming variable * wrapper), has the right required type. */ Argument ArgumentRule::fitArgument( Argument& arg, bool once ) const { RevPtr<RevVariable> theVar = arg.getVariable(); if ( evalType == BY_VALUE || theVar->isWorkspaceVariable() || theVar->getRevObject().isConstant() ) { once = true; } for ( std::vector<TypeSpec>::const_iterator it = argTypeSpecs.begin(); it != argTypeSpecs.end(); ++it ) { if ( evalType == BY_VALUE ) { if ( theVar->getRevObject().isType( *it ) ) { RevPtr<RevVariable> valueVar = RevPtr<RevVariable>( new RevVariable(theVar->getRevObject().clone(),arg.getLabel()) ); return Argument( valueVar, getArgumentLabel(), false ); } else if ( theVar->getRevObject().isConvertibleTo( *it, once ) != -1) { // Fit by type conversion. For now, we also modify the type of the incoming variable wrapper. RevObject* convertedObject = theVar->getRevObject().convertTo( *it ); RevPtr<RevVariable> valueVar = RevPtr<RevVariable>( new RevVariable(convertedObject,arg.getLabel()) ); return Argument( valueVar, getArgumentLabel(), false ); } } // if (by-value) else { if ( theVar->getRevObject().isType( *it ) ) { // For now, change the required type of the incoming variable wrapper theVar->setRequiredTypeSpec( *it ); if ( !isEllipsis() ) { return Argument( theVar, getArgumentLabel(), evalType == BY_CONSTANT_REFERENCE ); } else { return Argument( theVar, arg.getLabel(), true ); } } else if ( theVar->getRevObject().isConvertibleTo( *it, once ) != -1 && (*it).isDerivedOf( theVar->getRequiredTypeSpec() )) { // Fit by type conversion. For now, we also modify the type of the incoming variable wrapper. RevObject* convertedObject = theVar->getRevObject().convertTo( *it ); theVar->replaceRevObject( convertedObject ); theVar->setRequiredTypeSpec( *it ); if ( !isEllipsis() ) { return Argument( theVar, getArgumentLabel(), false ); } else { return Argument( theVar, arg.getLabel(), false ); } } else { // Fit by type conversion function const TypeSpec& typeFrom = theVar->getRevObject().getTypeSpec(); const TypeSpec& typeTo = *it; // create the function name std::string functionName = "_" + typeFrom.getType() + "2" + typeTo.getType(); // Package arguments std::vector<Argument> args; Argument theArg = Argument( theVar, "arg" ); args.push_back( theVar ); Environment& env = Workspace::globalWorkspace(); try { Function* func = env.getFunction(functionName, args, once).clone(); // Allow the function to process the arguments func->processArguments( args, once ); // Set the execution environment of the function func->setExecutionEnviroment( &env ); // Evaluate the function RevPtr<RevVariable> conversionVar = func->execute(); // free the memory delete func; conversionVar->setHiddenVariableState( true ); conversionVar->setRequiredTypeSpec( *it ); return Argument( conversionVar, getArgumentLabel(), evalType == BY_CONSTANT_REFERENCE ); } catch (RbException e) { // we do nothing here } } // else (type conversion function) } // else (not by-value) } std::cerr << "Once = " << (once ? "TRUE" : "FALSE") << std::endl; throw RbException( "Argument type mismatch fitting a " + theVar->getRevObject().getType() + " argument to formal " + getArgumentTypeSpec()[0].getType() + " " + getArgumentLabel() ); }
/** * Test if argument is valid. The boolean flag 'once' is used to signal whether the argument matching * is done in a static or a dynamic context. If the rule is constant, then the argument matching * is done in a static context (evaluate-once context) regardless of the setting of the once flag. * If the argument is constant, we try type promotion if permitted by the variable required type. * * @todo See the TODOs for fitArgument(...) */ double ArgumentRule::isArgumentValid( Argument &arg, bool once) const { RevPtr<RevVariable> theVar = arg.getVariable(); if ( theVar == NULL ) { return -1; } if ( evalType == BY_VALUE || theVar->isWorkspaceVariable() || ( theVar->getRevObject().isModelObject() && theVar->getRevObject().getDagNode()->getDagNodeType() == RevBayesCore::DagNode::CONSTANT) ) { once = true; } if ( nodeType == STOCHASTIC && theVar->getRevObject().getDagNode()->getDagNodeType() != RevBayesCore::DagNode::STOCHASTIC ) { return -1; } else if ( nodeType == DETERMINISTIC && theVar->getRevObject().getDagNode()->getDagNodeType() != RevBayesCore::DagNode::DETERMINISTIC ) { return -1; } for ( std::vector<TypeSpec>::const_iterator it = argTypeSpecs.begin(); it != argTypeSpecs.end(); ++it ) { if ( theVar->getRevObject().isType( *it ) ) { return 0.0; } else if ( theVar->getRevObject().isConvertibleTo( *it, once ) != -1 && (*it).isDerivedOf( theVar->getRequiredTypeSpec() ) ) { return theVar->getRevObject().isConvertibleTo( *it, once ); } else if ( theVar->getRevObject().isConvertibleTo( *it, once ) != -1 && evalType == BY_VALUE ) { return theVar->getRevObject().isConvertibleTo( *it, once ); } // else if ( once == true && //// !var->isAssignable() && // theVar->getRevObject().isConvertibleTo( *it, true ) != -1 && // (*it).isDerivedOf( theVar->getRequiredTypeSpec() ) // ) // { // return theVar->getRevObject().isConvertibleTo( *it, true ); // } else if ( nodeType != STOCHASTIC ) { const TypeSpec& typeFrom = theVar->getRevObject().getTypeSpec(); const TypeSpec& typeTo = *it; // create the function name std::string functionName = "_" + typeFrom.getType() + "2" + typeTo.getType(); // Package arguments std::vector<Argument> args; Argument theArg = Argument( theVar, "arg" ); args.push_back( theVar ); Environment& env = Workspace::globalWorkspace(); try { // we just want to check if the function exists and can be found env.getFunction(functionName, args, once); return 0.1; } catch (RbException e) { // we do nothing here } } } return -1; }
/** * Fit a variable into an argument according to the argument rule. If necessary and * appropriate, we do type conversion or type promotion. * * @todo The constant flag is currently not used correctly in ArgumentRule. Therefore, * we ignore it here for now. This needs to be changed. * * @todo We need to check whether workspace objects with member variables are * modifiable by the user. * * @todo To conform to the old code we change the required type of the incoming * variable wrapper here. We need to change this so that we do not change * the wrapper here, but make sure that if the argument variable is inserted * in a member variable or container element slot, that the slot variable * wrapper, which should be unique (not the same as the incoming variable * wrapper), has the right required type. */ Argument ArgumentRule::fitArgument( Argument& arg, bool once ) const { // TODO: Use this code when the constant flag in ArgumentRule is used correctly // if ( isConstant() || !theVar->isAssignable() ) if ( evalType == BY_VALUE ) { once = true; } RevPtr<Variable> theVar = arg.getVariable(); for ( std::vector<TypeSpec>::const_iterator it = argTypeSpecs.begin(); it != argTypeSpecs.end(); ++it ) { if ( theVar->getRevObject().isTypeSpec( *it ) ) { // For now, change the required type of the incoming variable wrapper theVar->setRevObjectTypeSpec( *it ); if ( !isEllipsis() ) return Argument( theVar, getArgumentLabel(), evalType == BY_CONSTANT_REFERENCE ); else return Argument( theVar, arg.getLabel(), true ); } else if ( once == false && !theVar->isAssignable() && theVar->getRevObject().isConvertibleTo( *it, true ) && (*it).isDerivedOf( theVar->getRevObjectTypeSpec() ) ) { // Fit by type promotion. For now, we also modify the type of the incoming variable wrapper. RevObject* convertedObject = theVar->getRevObject().convertTo( *it ); theVar->setRevObject( convertedObject ); theVar->setRevObjectTypeSpec( *it ); if ( !isEllipsis() ) return Argument( theVar, getArgumentLabel(), evalType == BY_CONSTANT_REFERENCE ); else return Argument( theVar, arg.getLabel(), true ); } else if ( theVar->getRevObject().isConvertibleTo( *it, once ) ) { // Fit by type conversion if ( once || !theVar->getRevObject().hasDagNode() ) { RevObject* convertedObject = theVar->getRevObject().convertTo( *it ); Variable* convertedVar = new Variable( convertedObject ); convertedVar->setRevObjectTypeSpec( *it ); if ( !isEllipsis() ) return Argument( convertedVar, getArgumentLabel(), evalType == BY_CONSTANT_REFERENCE ); else return Argument( convertedVar, arg.getLabel(), true ); } else { RevObject* conversionObject = theVar->getRevObject().convertTo( *it ); conversionObject->makeConversionValue( theVar ); Variable* conversionVar = new Variable( conversionObject ); conversionVar->setRevObjectTypeSpec( *it ); if ( !isEllipsis() ) return Argument( conversionVar, getArgumentLabel(), evalType == BY_CONSTANT_REFERENCE ); else return Argument( conversionVar, arg.getLabel(), true ); } } } throw RbException( "Argument type mismatch fitting a " + theVar->getRevObject().getType() + " argument to formal " + getArgumentTypeSpec()[0].getType() + " " + getArgumentLabel() ); }
/** * 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; }
/** * @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; }
/** * @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; }