Implement additional operators: &&, ||, in and !in.

Refs #5789
This commit is contained in:
Gunnar Beutner 2014-03-18 15:29:04 +01:00
parent e21e2ef707
commit ec0557afea
6 changed files with 113 additions and 38 deletions

View File

@ -18,17 +18,21 @@
******************************************************************************/
#include "config/aexpression.h"
#include "base/array.h"
#include "base/serializer.h"
#include "base/context.h"
#include <boost/foreach.hpp>
using namespace icinga;
AExpression::AExpression(AOperator op, const AValue& operand1)
: m_Operator(op), m_Operand1(operand1)
AExpression::AExpression(AOperator op, const AValue& operand1, const DebugInfo& di)
: m_Operator(op), m_Operand1(operand1), m_DebugInfo(di)
{
ASSERT(op == AEReturn);
}
AExpression::AExpression(AOperator op, const AValue& operand1, const AValue& operand2)
: m_Operator(op), m_Operand1(operand1), m_Operand2(operand2)
AExpression::AExpression(AOperator op, const AValue& operand1, const AValue& operand2, const DebugInfo& di)
: m_Operator(op), m_Operand1(operand1), m_Operand2(operand2), m_DebugInfo(di)
{
ASSERT(op == AEAdd || op == AENegate || op == AESubtract || op == AEMultiply || op == AEDivide ||
op == AEBinaryAnd || op == AEBinaryOr || op == AEShiftLeft || op == AEShiftRight);
@ -37,10 +41,16 @@ AExpression::AExpression(AOperator op, const AValue& operand1, const AValue& ope
Value AExpression::Evaluate(const Dictionary::Ptr& locals) const
{
Value left, right;
Array::Ptr arr;
bool found;
left = m_Operand1.Evaluate(locals);
right = m_Operand2.Evaluate(locals);
std::ostringstream msgbuf;
msgbuf << "Evaluating AExpression " << m_DebugInfo << "; left=" << JsonSerialize(left) << "; right=" << JsonSerialize(right);
CONTEXT(msgbuf.str());
switch (m_Operator) {
case AEReturn:
return left;
@ -69,6 +79,26 @@ Value AExpression::Evaluate(const Dictionary::Ptr& locals) const
return left == right;
case AENotEqual:
return left != right;
case AEIn:
if (!right.IsObjectType<Array>())
BOOST_THROW_EXCEPTION(std::invalid_argument("Invalid right side argument for 'in' operator: " + JsonSerialize(right)));
arr = right;
found = false;
BOOST_FOREACH(const Value& value, arr) {
if (value == left) {
found = true;
break;
}
}
return found;
case AENotIn:
return left != right;
case AELogicalAnd:
return (long)left && (long)right;
case AELogicalOr:
return (long)left || (long)right;
default:
ASSERT(!"Invalid operator.");
}

View File

@ -22,6 +22,7 @@
#include "config/i2-config.h"
#include "config/avalue.h"
#include "config/debuginfo.h"
#include "base/dictionary.h"
namespace icinga
@ -44,6 +45,10 @@ enum AOperator
AEShiftRight,
AEEqual,
AENotEqual,
AEIn,
AENotIn,
AELogicalAnd,
AELogicalOr
};
/**
@ -54,8 +59,8 @@ class I2_CONFIG_API AExpression : public Object
public:
DECLARE_PTR_TYPEDEFS(AExpression);
AExpression(AOperator op, const AValue& operand1);
AExpression(AOperator op, const AValue& operand1, const AValue& operand2);
AExpression(AOperator op, const AValue& operand1, const DebugInfo& di);
AExpression(AOperator op, const AValue& operand1, const AValue& operand2, const DebugInfo& di);
Value Evaluate(const Dictionary::Ptr& locals) const;
@ -63,6 +68,7 @@ private:
AOperator m_Operator;
AValue m_Operand1;
AValue m_Operand2;
DebugInfo m_DebugInfo;
};
}

View File

@ -227,6 +227,12 @@ to return T_TO;
where return T_WHERE;
\<\< return T_SHIFT_LEFT;
\>\> return T_SHIFT_RIGHT;
== return T_EQUAL;
!= return T_NOT_EQUAL;
!in return T_NOT_IN;
in return T_IN;
&& return T_LOGICAL_AND;
\|\| return T_LOGICAL_OR;
[a-zA-Z_][:a-zA-Z0-9\-_]* { yylval->text = strdup(yytext); return T_IDENTIFIER; }
\<[^\>]*\> { yytext[yyleng-1] = '\0'; yylval->text = strdup(yytext + 1); return T_STRING_ANGLE; }
-?[0-9]+(\.[0-9]+)?ms { yylval->num = strtod(yytext, NULL) / 1000; return T_NUMBER; }
@ -235,8 +241,6 @@ where return T_WHERE;
-?[0-9]+(\.[0-9]+)?m { yylval->num = strtod(yytext, NULL) * 60; return T_NUMBER; }
-?[0-9]+(\.[0-9]+)?s { yylval->num = strtod(yytext, NULL); return T_NUMBER; }
-?[0-9]+(\.[0-9]+)? { yylval->num = strtod(yytext, NULL); return T_NUMBER; }
== { yylval->op = OperatorEqual; return T_EQUAL; }
!= { yylval->op = OperatorNotEqual; return T_NOT_EQUAL; }
= { yylval->op = OperatorSet; return T_SET; }
\+= { yylval->op = OperatorPlus; return T_PLUS_EQUAL; }
-= { yylval->op = OperatorMinus; return T_MINUS_EQUAL; }

View File

@ -71,8 +71,6 @@ using namespace icinga;
%token <num> T_NUMBER
%token T_NULL
%token <text> T_IDENTIFIER
%token <op> T_EQUAL "== (T_EQUAL)"
%token <op> T_NOT_EQUAL "!= (T_NOT_EQUAL)"
%token <op> T_SET "= (T_SET)"
%token <op> T_PLUS_EQUAL "+= (T_PLUS_EQUAL)"
%token <op> T_MINUS_EQUAL "-= (T_MINUS_EQUAL)"
@ -82,6 +80,12 @@ using namespace icinga;
%token T_CONST "const (T_CONST)"
%token T_SHIFT_LEFT "<< (T_SHIFT_LEFT)"
%token T_SHIFT_RIGHT ">> (T_SHIFT_RIGHT)"
%token T_EQUAL "== (T_EQUAL)"
%token T_NOT_EQUAL "!= (T_NOT_EQUAL)"
%token T_IN "in (T_IN)"
%token T_NOT_IN "!in (T_NOT_IN)"
%token T_LOGICAL_AND "&& (T_LOGICAL_AND)"
%token T_LOGICAL_OR "|| (T_LOGICAL_OR)"
%token <type> T_TYPE_DICTIONARY "dictionary (T_TYPE_DICTIONARY)"
%token <type> T_TYPE_ARRAY "array (T_TYPE_ARRAY)"
%token <type> T_TYPE_NUMBER "number (T_TYPE_NUMBER)"
@ -122,6 +126,12 @@ using namespace icinga;
%type <aexpr> aterm
%type <aexpr> aexpression
%type <num> variable_decl
%left T_LOGICAL_OR
%left T_LOGICAL_AND
%left T_IN
%left T_NOT_IN
%nonassoc T_EQUAL
%nonassoc T_NOT_EQUAL
%left '+' '-'
%left '*' '/'
%left '&'
@ -581,82 +591,106 @@ aterm: '(' aexpression ')'
aexpression: simplevalue
{
$$ = new Value(make_shared<AExpression>(AEReturn, AValue(ATSimple, *$1)));
$$ = new Value(make_shared<AExpression>(AEReturn, AValue(ATSimple, *$1), yylloc));
delete $1;
}
| T_IDENTIFIER
{
$$ = new Value(make_shared<AExpression>(AEReturn, AValue(ATVariable, $1)));
$$ = new Value(make_shared<AExpression>(AEReturn, AValue(ATVariable, $1), yylloc));
free($1);
}
| '~' aexpression
{
$$ = new Value(make_shared<AExpression>(AENegate, static_cast<AExpression::Ptr>(*$2)));
$$ = new Value(make_shared<AExpression>(AENegate, static_cast<AExpression::Ptr>(*$2), yylloc));
delete $2;
}
| aexpression T_EQUAL aexpression
| '(' aexpression ')'
{
$$ = new Value(make_shared<AExpression>(AEEqual, static_cast<AExpression::Ptr>(*$1), static_cast<AExpression::Ptr>(*$3)));
delete $1;
delete $3;
}
| aexpression T_NOT_EQUAL aexpression
{
$$ = new Value(make_shared<AExpression>(AENotEqual, static_cast<AExpression::Ptr>(*$1), static_cast<AExpression::Ptr>(*$3)));
delete $1;
delete $3;
$$ = $2;
}
| aexpression '+' aexpression
{
$$ = new Value(make_shared<AExpression>(AEAdd, static_cast<AExpression::Ptr>(*$1), static_cast<AExpression::Ptr>(*$3)));
$$ = new Value(make_shared<AExpression>(AEAdd, static_cast<AExpression::Ptr>(*$1), static_cast<AExpression::Ptr>(*$3), yylloc));
delete $1;
delete $3;
}
| aexpression '-' aexpression
{
$$ = new Value(make_shared<AExpression>(AESubtract, static_cast<AExpression::Ptr>(*$1), static_cast<AExpression::Ptr>(*$3)));
$$ = new Value(make_shared<AExpression>(AESubtract, static_cast<AExpression::Ptr>(*$1), static_cast<AExpression::Ptr>(*$3), yylloc));
delete $1;
delete $3;
}
| aexpression '*' aexpression
{
$$ = new Value(make_shared<AExpression>(AEMultiply, static_cast<AExpression::Ptr>(*$1), static_cast<AExpression::Ptr>(*$3)));
$$ = new Value(make_shared<AExpression>(AEMultiply, static_cast<AExpression::Ptr>(*$1), static_cast<AExpression::Ptr>(*$3), yylloc));
delete $1;
delete $3;
}
| aexpression '/' aexpression
{
$$ = new Value(make_shared<AExpression>(AEDivide, static_cast<AExpression::Ptr>(*$1), static_cast<AExpression::Ptr>(*$3)));
$$ = new Value(make_shared<AExpression>(AEDivide, static_cast<AExpression::Ptr>(*$1), static_cast<AExpression::Ptr>(*$3), yylloc));
delete $1;
delete $3;
}
| aexpression '&' aexpression
{
$$ = new Value(make_shared<AExpression>(AEBinaryAnd, static_cast<AExpression::Ptr>(*$1), static_cast<AExpression::Ptr>(*$3)));
$$ = new Value(make_shared<AExpression>(AEBinaryAnd, static_cast<AExpression::Ptr>(*$1), static_cast<AExpression::Ptr>(*$3), yylloc));
delete $1;
delete $3;
}
| aexpression '|' aexpression
{
$$ = new Value(make_shared<AExpression>(AEBinaryOr, static_cast<AExpression::Ptr>(*$1), static_cast<AExpression::Ptr>(*$3)));
$$ = new Value(make_shared<AExpression>(AEBinaryOr, static_cast<AExpression::Ptr>(*$1), static_cast<AExpression::Ptr>(*$3), yylloc));
delete $1;
delete $3;
}
| aexpression T_IN aexpression
{
$$ = new Value(make_shared<AExpression>(AEIn, static_cast<AExpression::Ptr>(*$1), static_cast<AExpression::Ptr>(*$3), yylloc));
delete $1;
delete $3;
}
| aexpression T_NOT_IN aexpression
{
$$ = new Value(make_shared<AExpression>(AENotIn, static_cast<AExpression::Ptr>(*$1), static_cast<AExpression::Ptr>(*$3), yylloc));
delete $1;
delete $3;
}
| aexpression T_EQUAL aexpression
{
$$ = new Value(make_shared<AExpression>(AEEqual, static_cast<AExpression::Ptr>(*$1), static_cast<AExpression::Ptr>(*$3), yylloc));
delete $1;
delete $3;
}
| aexpression T_NOT_EQUAL aexpression
{
$$ = new Value(make_shared<AExpression>(AENotEqual, static_cast<AExpression::Ptr>(*$1), static_cast<AExpression::Ptr>(*$3), yylloc));
delete $1;
delete $3;
}
| aexpression T_SHIFT_LEFT aexpression
{
$$ = new Value(make_shared<AExpression>(AEShiftLeft, static_cast<AExpression::Ptr>(*$1), static_cast<AExpression::Ptr>(*$3)));
$$ = new Value(make_shared<AExpression>(AEShiftLeft, static_cast<AExpression::Ptr>(*$1), static_cast<AExpression::Ptr>(*$3), yylloc));
delete $1;
delete $3;
}
| aexpression T_SHIFT_RIGHT aexpression
{
$$ = new Value(make_shared<AExpression>(AEShiftRight, static_cast<AExpression::Ptr>(*$1), static_cast<AExpression::Ptr>(*$3)));
$$ = new Value(make_shared<AExpression>(AEShiftRight, static_cast<AExpression::Ptr>(*$1), static_cast<AExpression::Ptr>(*$3), yylloc));
delete $1;
delete $3;
}
| '(' aexpression ')'
| aexpression T_LOGICAL_AND aexpression
{
$$ = $2;
$$ = new Value(make_shared<AExpression>(AELogicalAnd, static_cast<AExpression::Ptr>(*$1), static_cast<AExpression::Ptr>(*$3), yylloc));
delete $1;
delete $3;
}
| aexpression T_LOGICAL_OR aexpression
{
$$ = new Value(make_shared<AExpression>(AELogicalOr, static_cast<AExpression::Ptr>(*$1), static_cast<AExpression::Ptr>(*$3), yylloc));
delete $1;
delete $3;
}
;

View File

@ -43,9 +43,7 @@ enum ExpressionOperator
OperatorPlus,
OperatorMinus,
OperatorMultiply,
OperatorDivide,
OperatorEqual, /* Not used for Expressions */
OperatorNotEqual, /* Not used for Expressions */
OperatorDivide
};
class ExpressionList;

View File

@ -43,6 +43,11 @@ void Host::EvaluateApplyRules(const std::vector<ApplyRule>& rules)
Dictionary::Ptr locals = make_shared<Dictionary>();
locals->Set("host", host->GetName());
Array::Ptr groups = host->GetGroups();
if (!groups)
groups = make_shared<Array>();
locals->Set("hostgroups", groups);
BOOST_FOREACH(const ApplyRule& rule, rules) {
std::ostringstream msgbuf;
msgbuf << "Evaluating 'apply' rule (" << rule.GetDebugInfo() << ")";
@ -79,8 +84,6 @@ void Host::EvaluateApplyRules(const std::vector<ApplyRule>& rules)
serviceItem->Register();
DynamicObject::Ptr dobj = serviceItem->Commit();
dobj->OnConfigLoaded();
Log(LogInformation, "icinga", "Rule result: " + Convert::ToString(result));
}
}
}