struct EvaluateExprHelperParams { int _numValuesSet; // modified const bool _postingDiags; const bool _doCollectNotes; const RplExpression* _expr; Rpl::SlotSet* _sourceSlotSet; const QString _stdUnits; const double _usrScale; const QString _usrUnits; EvaluateExprHelperParams (const SeriesSlot* sslot) : _numValuesSet (0), // mutable, changed _postingDiags (false), // set below _doCollectNotes (false), // set below _expr (sslot->getExpr()), _sourceSlotSet(sslot->getExprSlotSet()), _stdUnits (sslot->getStdUnitRef()), _usrScale (sslot->getUsrScale()), _usrUnits (sslot-> getUsrUnits()) { _postingDiags = Diag::Instance()->getOptInfo() && Diag::Instance()->passFilterCheck(RULEID_EXPR_SLOT); _doCollectNotes = RplExprSlotMgr::Instance()->doCollectReferencedSlotNotes()); } }; // private helper method RplResult::Status SeriesSlot::evaluateExpr_TstepHelper( const Date_Time& currentDate, EvaluateExprHelperParams& parms) { //------------------------------------------------------------ // NOTE: This method is to be called from only evaluateExpr(). //------------------------------------------------------------ RplResult result (RplResult::SUCCESS); QString valString; QString unitsString; // So that diagnostics can be appropriately filtered by timestep. AutoTimestepContext innerContext(¤tDate); // Because the current date changes on each iteration, // clear the expression slot RPL set caches. RplExprSlotMgr::Instance()->getRplSet()->clearExecutionCache(); // Notify our RplApplication of the current date. RplApplication::Instance(RplApplication::SLOT_EXPR)-> setCurrentDate(currentDate); // Clear any values retained from the expression's last evaluation. expr->clearLastEvalValues(); expr->invalidateCachedData(); // Allow the debugger to pause and perhaps stop execution. rplDebugger->notifySlotEvaluation(this); if (!rplDebugger->notifyCanPauseExec(this, RplDebugger::BEFORE_EXEC)) { // Note: a diagnostic should already have been posted. rplDebugger->notifySlotEvaluationDone(this); return RplResult::FAILURE; } // Evaluate the expression. if (parms._doCollectNotes) { expr->evaluate(result, parms._sourceSlotSet); } else { expr->evaluate(result, NULL); } // Permit debugging of an error; rplDebugger->checkForError(this, result); // Allow the debugger to pause and perhaps stop execution. if (!rplDebugger->notifyCanPauseExec(this, RplDebugger::AFTER_EXEC)) { // Note: a diagnostic should already have been posted. rplDebugger->notifySlotEvaluationDone(this); return RplResult::FAILURE; } // Note: for performance reasons, we only clear certain // debugger flags when we leave this loop. rplDebugger->notifySlotEvaluationDone(this, false); // ... Encountered an invalid value. if (result == RplResult::INVALID_VALUE) { // Continue on invalid value. return RplResult::INVALID_VALUE; // continue iteration } // ... Evaluation was successful. else if (result == RplResult::SUCCESS) { // Get the value in our standard units with scale = 1.0. const RplValue* val(result.getValue()); rwAssert(val->getType() == RplValue::NUMERIC); double convertedVal; if (!convertRplValue(*static_cast(val), parms._stdUnits, convertedVal)) { rplDebugger->clearSlotEvaluationFlags(); return RplResult::FAILURE; } // Do the assignment at the appropriate date. // We just change the value, skip all checks, flag setting. p_fastGetDoubleRef(i) = convertedVal; ++parms._numValuesSet; // Post an informational diagnostic (which includes the result, // in user units). if (_usersIndexByInt) { // Don't use reference Date_Time for user unit conversions. if (unitMgr->convertWithinType( convertedVal, 1.0, parms._stdUnits, convertedVal, parms._usrScale, parms._usrUnits)) { rplDebugger->clearSlotEvaluationFlags(); return RplResult::FAILURE; } } else { if (unitMgr->convertWithinType( convertedVal, 1.0, parms._stdUnits, convertedVal, parms._usrScale, parms._usrUnits, currentDate)) { rplDebugger->clearSlotEvaluationFlags(); return RplResult::FAILURE; } } if (parms._postingDiags) { valString = SlotGUIUtils::formatValueUsrStr(this, 0, convertedVal); unitsString = SlotGUIUtils::getUnitsScaleStr(this, 0); Diag::Instance()-> diagnostic_nofilt(RULEID_EXPR_SLOT, MSG_EXPR_SLOT_EVAL, qPrintable(valString), qPrintable(unitsString)); } } // ... An IF with no ELSE sometimes does nothing. else if (result == RplResult::NO_CHANGE) { if (parms._postingDiags) { Diag::Instance()->diagnostic_nofilt(RULEID_EXPR_SLOT, MSG_EXPR_SLOT_NO_ELSE); } } // ... Some sort of problematic evaluation result. else { rwError(SLOTID, MSG_EXPR_EVAL_FAIL, qPrintable(result.getExplanation()), qPrintable( result.getLocation()->getText( RPL_EXPR_DEFAULT_INDENT, RPL_VALUE_DEFAULT_PRECISION, RplValue::USER_FRIENDLY))); rplDebugger->clearSlotEvaluationFlags(); return RplResult::FAILURE; } return RplResult::SUCCESS; }