Skip to content

Commit

Permalink
[fix #11475] expressions: add left and right associavity for dump of …
Browse files Browse the repository at this point in the history
…binary operators

complete test for left associativity
  • Loading branch information
3nids authored and m-kuhn committed Jun 16, 2015
1 parent 0bf1135 commit a518e9f
Show file tree
Hide file tree
Showing 4 changed files with 81 additions and 2 deletions.
2 changes: 2 additions & 0 deletions python/core/qgsexpression.sip
Expand Up @@ -378,6 +378,8 @@ class QgsExpression
virtual void accept( QgsExpression::Visitor& v ) const;

int precedence() const;
bool leftAssociative() const;
bool rightAssociative() const;
};

class NodeInOperator : QgsExpression::Node
Expand Down
76 changes: 74 additions & 2 deletions src/core/qgsexpression.cpp
Expand Up @@ -2540,15 +2540,87 @@ int QgsExpression::NodeBinaryOperator::precedence() const
return -1;
}

bool QgsExpression::NodeBinaryOperator::leftAssociative() const
{
// see left/right in qgsexpressionparser.yy
switch ( mOp )
{
case boOr:
case boAnd:
case boEQ:
case boNE:
case boLE:
case boGE:
case boLT:
case boGT:
case boRegexp:
case boLike:
case boILike:
case boNotLike:
case boNotILike:
case boIs:
case boIsNot:
case boPlus:
case boMinus:
case boMul:
case boDiv:
case boIntDiv:
case boMod:
case boConcat:
return true;

case boPow:
return false;
}
Q_ASSERT( 0 && "unexpected binary operator" );
return -1;
}

bool QgsExpression::NodeBinaryOperator::rightAssociative() const
{
// see left/right in qgsexpressionparser.yy
switch ( mOp )
{
case boOr:
case boAnd:
case boEQ:
case boNE:
case boLE:
case boGE:
case boLT:
case boGT:
case boRegexp:
case boLike:
case boILike:
case boNotLike:
case boNotILike:
case boIs:
case boIsNot:
case boPlus:
case boMul:
case boMod:
case boConcat:
case boPow:
return true;

case boMinus:
case boDiv:
case boIntDiv:
return false;
}
Q_ASSERT( 0 && "unexpected binary operator" );
return -1;
}

QString QgsExpression::NodeBinaryOperator::dump() const
{
QgsExpression::NodeBinaryOperator *lOp = dynamic_cast<QgsExpression::NodeBinaryOperator *>( mOpLeft );
QgsExpression::NodeBinaryOperator *rOp = dynamic_cast<QgsExpression::NodeBinaryOperator *>( mOpRight );

QString fmt;
fmt += lOp && lOp->precedence() < precedence() ? "(%1)" : "%1";
fmt += lOp && ( lOp->precedence() < precedence() || !lOp->leftAssociative() ) ? "(%1)" : "%1";
fmt += " %2 ";
fmt += rOp && rOp->precedence() <= precedence() ? "(%3)" : "%3";
fmt += rOp && ( rOp->precedence() < precedence() || !rOp->rightAssociative() ) ? "(%3)" : "%3";

return fmt.arg( mOpLeft->dump() ).arg( BinaryOperatorText[mOp] ).arg( mOpRight->dump() );
}
Expand Down
2 changes: 2 additions & 0 deletions src/core/qgsexpression.h
Expand Up @@ -513,6 +513,8 @@ class CORE_EXPORT QgsExpression
virtual void accept( Visitor& v ) const override { v.visit( *this ); }

int precedence() const;
bool leftAssociative() const;
bool rightAssociative() const;

protected:
bool compare( double diff );
Expand Down
3 changes: 3 additions & 0 deletions tests/src/core/testqgsexpression.cpp
Expand Up @@ -523,6 +523,9 @@ class TestQgsExpression: public QObject

QgsExpression e2( e1.dump() );
QCOMPARE( e2.evaluate().toInt(), 21 );

QgsExpression e3( "(2^3)^2" );
QCOMPARE( QgsExpression( e3.dump() ).evaluate().toInt(), 64 );
}

void eval_columns()
Expand Down

0 comments on commit a518e9f

Please sign in to comment.