#7316 Curve Calculator: Add support for single line if-statement

This commit is contained in:
Magne Sjaastad 2021-02-01 18:38:52 +01:00
parent 1a8f36373c
commit a060ba349e
6 changed files with 158 additions and 1 deletions

View File

@ -308,7 +308,7 @@ bool RimSummaryCalculation::calculate()
parser.assignVector( leftHandSideVariableName, resultValues );
QString errorText;
bool evaluatedOk = parser.evaluate( m_expression, &errorText );
bool evaluatedOk = parser.expandIfStatementsAndEvaluate( m_expression, &errorText );
if ( evaluatedOk )
{

View File

@ -2,6 +2,7 @@
#include "RimSummaryCalculation.h"
#include "ExpressionParserImpl.h"
#include "expressionparser/ExpressionParser.h"
#include <numeric>
@ -75,3 +76,87 @@ TEST( RicExpressionParserTest, FindLeftHandSide )
EXPECT_STREQ( s.toStdString().data(), "c" );
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
TEST( RicExpressionParserTest, ForLoopWithIfStatement )
{
std::vector<double> a( 10 );
std::iota( a.begin(), a.end(), 10 );
std::vector<double> b( 10 );
std::iota( b.begin(), b.end(), 100 );
std::vector<double> c( 10 );
ExpressionParser parser;
parser.assignVector( "a", a );
parser.assignVector( "b", b );
parser.assignVector( "c", c );
QString expr = "for (var i := 0; i < min(a[],b[],c[]); i += 1)\n"
"{ \n"
" c[i] := if((a[i] > 13), a[i], b[i]); \n"
"} \n";
EXPECT_TRUE( parser.evaluate( expr ) );
EXPECT_DOUBLE_EQ( c[0], 100.0 );
EXPECT_DOUBLE_EQ( c[9], 19.0 );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
TEST( RicExpressionParserTest, ExpandedIfStatement )
{
std::vector<double> a( 10 );
std::iota( a.begin(), a.end(), 10 );
std::vector<double> b( 10 );
std::iota( b.begin(), b.end(), 100 );
std::vector<double> c( 10 );
ExpressionParser parser;
parser.assignVector( "a", a );
parser.assignVector( "b", b );
parser.assignVector( "c", c );
QString expr = "c := if((a > 13), a, b)";
auto expandedText = ExpressionParserImpl::expandIfStatements( expr );
// std::cout << expandedText.toStdString();
EXPECT_TRUE( parser.evaluate( expandedText ) );
EXPECT_DOUBLE_EQ( c[0], 100.0 );
EXPECT_DOUBLE_EQ( c[9], 19.0 );
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
TEST( RicExpressionParserTest, ExpandIfStatementsAndEvaluate )
{
std::vector<double> a( 10 );
std::iota( a.begin(), a.end(), 10 );
std::vector<double> b( 10 );
std::iota( b.begin(), b.end(), 100 );
std::vector<double> c( 10 );
ExpressionParser parser;
parser.assignVector( "a", a );
parser.assignVector( "b", b );
parser.assignVector( "c", c );
QString expr = "c := if((a > 13), a, b)";
EXPECT_TRUE( parser.expandIfStatementsAndEvaluate( expr ) );
EXPECT_DOUBLE_EQ( c[0], 100.0 );
EXPECT_DOUBLE_EQ( c[9], 19.0 );
}

View File

@ -59,3 +59,21 @@ bool ExpressionParser::evaluate(const QString& expressionText, QString* errorTex
{
return m_expressionParserImpl->evaluate(expressionText, errorText);
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
bool ExpressionParser::expandIfStatementsAndEvaluate(const QString& expressionText, QString* errorText /*= nullptr*/)
{
if (expressionText.contains("if"))
{
QString expandedExpressionText = ExpressionParserImpl::expandIfStatements(expressionText);
return m_expressionParserImpl->evaluate(expandedExpressionText, errorText);
}
else
{
return m_expressionParserImpl->evaluate(expressionText, errorText);
}
}

View File

@ -38,6 +38,7 @@ public:
void assignVector(const QString& variableName, std::vector<double>& vector);
bool evaluate(const QString& expressionText, QString* errorText = nullptr);
bool expandIfStatementsAndEvaluate(const QString& expressionText, QString* errorText = nullptr);
private:
std::unique_ptr<ExpressionParserImpl> m_expressionParserImpl;

View File

@ -18,6 +18,8 @@
#include "ExpressionParserImpl.h"
#include <QRegularExpression>
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
@ -123,3 +125,52 @@ QString ExpressionParserImpl::parserErrorText(parser_t& parser)
return txt;
}
//--------------------------------------------------------------------------------------------------
//
// The parser do not support single-line if statements on a vector.
// Expand a single line if-statement to a for loop over all items in the referenced
// vectors. The script will add '[i]' as postfix to all variables, assuming all variables
// to be vectors. This statement will be put in a for loop over all elements counting
// up to size of the vector with minimum items.
//
// Single line statement :
// c := if((a > 13), a, b)
//
// Intended parser script text
//
// for (var i : = 0; i < min(c[], a[], b[]); i += 1)
// {
// c[i] : = if ((a[i] > 13), a[i], b[i]);
// }
//
//--------------------------------------------------------------------------------------------------
QString ExpressionParserImpl::expandIfStatements(const QString& expressionText)
{
QString expandedText;
{
QString textWithVectorBrackets = expressionText;
QString listOfVars;
auto allVectorVariables = detectReferencedVariables(expressionText);
for (const QString& var : allVectorVariables)
{
listOfVars += QString("%1[],").arg(var);
QString regexpText = QString("\\b%1\\b").arg(var);
QRegularExpression regexp(regexpText);
QString varWithBrackets = var + "[i]";
textWithVectorBrackets = textWithVectorBrackets.replace(regexp, varWithBrackets);
}
listOfVars = listOfVars.left(listOfVars.size() - 1);
expandedText = QString("for (var i := 0; i < min(%1); i += 1)\n").arg(listOfVars);
expandedText += "{\n";
expandedText += QString(" %1;\n").arg(textWithVectorBrackets);
expandedText += "}\n";
}
return expandedText;
}

View File

@ -39,6 +39,8 @@ public:
void assignVector(const QString& variableName, std::vector<double>& vector);
bool evaluate(const QString& expressionText, QString* errorText = nullptr);
static QString expandIfStatements(const QString& expressionText);
private:
QString parserErrorText(parser_t& parser);