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 "config/aexpression.h"
#include "base/array.h"
#include "base/serializer.h"
#include "base/context.h"
#include <boost/foreach.hpp>
using namespace icinga; using namespace icinga;
AExpression::AExpression(AOperator op, const AValue& operand1) AExpression::AExpression(AOperator op, const AValue& operand1, const DebugInfo& di)
: m_Operator(op), m_Operand1(operand1) : m_Operator(op), m_Operand1(operand1), m_DebugInfo(di)
{ {
ASSERT(op == AEReturn); ASSERT(op == AEReturn);
} }
AExpression::AExpression(AOperator op, const AValue& operand1, const AValue& operand2) AExpression::AExpression(AOperator op, const AValue& operand1, const AValue& operand2, const DebugInfo& di)
: m_Operator(op), m_Operand1(operand1), m_Operand2(operand2) : m_Operator(op), m_Operand1(operand1), m_Operand2(operand2), m_DebugInfo(di)
{ {
ASSERT(op == AEAdd || op == AENegate || op == AESubtract || op == AEMultiply || op == AEDivide || ASSERT(op == AEAdd || op == AENegate || op == AESubtract || op == AEMultiply || op == AEDivide ||
op == AEBinaryAnd || op == AEBinaryOr || op == AEShiftLeft || op == AEShiftRight); 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 AExpression::Evaluate(const Dictionary::Ptr& locals) const
{ {
Value left, right; Value left, right;
Array::Ptr arr;
bool found;
left = m_Operand1.Evaluate(locals); left = m_Operand1.Evaluate(locals);
right = m_Operand2.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) { switch (m_Operator) {
case AEReturn: case AEReturn:
return left; return left;
@ -69,6 +79,26 @@ Value AExpression::Evaluate(const Dictionary::Ptr& locals) const
return left == right; return left == right;
case AENotEqual: case AENotEqual:
return left != right; 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: default:
ASSERT(!"Invalid operator."); ASSERT(!"Invalid operator.");
} }

View File

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

View File

@ -227,6 +227,12 @@ to return T_TO;
where return T_WHERE; where return T_WHERE;
\<\< return T_SHIFT_LEFT; \<\< return T_SHIFT_LEFT;
\>\> return T_SHIFT_RIGHT; \>\> 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; } [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; } \<[^\>]*\> { 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; } -?[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]+)?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]+)?s { yylval->num = strtod(yytext, NULL); return T_NUMBER; }
-?[0-9]+(\.[0-9]+)? { 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 = OperatorSet; return T_SET; }
\+= { yylval->op = OperatorPlus; return T_PLUS_EQUAL; } \+= { yylval->op = OperatorPlus; return T_PLUS_EQUAL; }
-= { yylval->op = OperatorMinus; return T_MINUS_EQUAL; } -= { yylval->op = OperatorMinus; return T_MINUS_EQUAL; }

View File

@ -71,8 +71,6 @@ using namespace icinga;
%token <num> T_NUMBER %token <num> T_NUMBER
%token T_NULL %token T_NULL
%token <text> T_IDENTIFIER %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_SET "= (T_SET)"
%token <op> T_PLUS_EQUAL "+= (T_PLUS_EQUAL)" %token <op> T_PLUS_EQUAL "+= (T_PLUS_EQUAL)"
%token <op> T_MINUS_EQUAL "-= (T_MINUS_EQUAL)" %token <op> T_MINUS_EQUAL "-= (T_MINUS_EQUAL)"
@ -82,6 +80,12 @@ using namespace icinga;
%token T_CONST "const (T_CONST)" %token T_CONST "const (T_CONST)"
%token T_SHIFT_LEFT "<< (T_SHIFT_LEFT)" %token T_SHIFT_LEFT "<< (T_SHIFT_LEFT)"
%token T_SHIFT_RIGHT ">> (T_SHIFT_RIGHT)" %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_DICTIONARY "dictionary (T_TYPE_DICTIONARY)"
%token <type> T_TYPE_ARRAY "array (T_TYPE_ARRAY)" %token <type> T_TYPE_ARRAY "array (T_TYPE_ARRAY)"
%token <type> T_TYPE_NUMBER "number (T_TYPE_NUMBER)" %token <type> T_TYPE_NUMBER "number (T_TYPE_NUMBER)"
@ -122,6 +126,12 @@ using namespace icinga;
%type <aexpr> aterm %type <aexpr> aterm
%type <aexpr> aexpression %type <aexpr> aexpression
%type <num> variable_decl %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 '*' '/' %left '*' '/'
%left '&' %left '&'
@ -581,82 +591,106 @@ aterm: '(' aexpression ')'
aexpression: simplevalue aexpression: simplevalue
{ {
$$ = new Value(make_shared<AExpression>(AEReturn, AValue(ATSimple, *$1))); $$ = new Value(make_shared<AExpression>(AEReturn, AValue(ATSimple, *$1), yylloc));
delete $1; delete $1;
} }
| T_IDENTIFIER | T_IDENTIFIER
{ {
$$ = new Value(make_shared<AExpression>(AEReturn, AValue(ATVariable, $1))); $$ = new Value(make_shared<AExpression>(AEReturn, AValue(ATVariable, $1), yylloc));
free($1); free($1);
} }
| '~' aexpression | '~' 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; delete $2;
} }
| aexpression T_EQUAL aexpression | '(' aexpression ')'
{ {
$$ = new Value(make_shared<AExpression>(AEEqual, static_cast<AExpression::Ptr>(*$1), static_cast<AExpression::Ptr>(*$3))); $$ = $2;
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;
} }
| aexpression '+' aexpression | 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 $1;
delete $3; delete $3;
} }
| aexpression '-' aexpression | 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 $1;
delete $3; delete $3;
} }
| aexpression '*' aexpression | 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 $1;
delete $3; delete $3;
} }
| aexpression '/' aexpression | 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 $1;
delete $3; delete $3;
} }
| aexpression '&' aexpression | 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 $1;
delete $3; delete $3;
} }
| aexpression '|' aexpression | 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 $1;
delete $3; delete $3;
} }
| aexpression T_SHIFT_LEFT aexpression | 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 $1;
delete $3; delete $3;
} }
| aexpression T_SHIFT_RIGHT aexpression | 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 $1;
delete $3; 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, OperatorPlus,
OperatorMinus, OperatorMinus,
OperatorMultiply, OperatorMultiply,
OperatorDivide, OperatorDivide
OperatorEqual, /* Not used for Expressions */
OperatorNotEqual, /* Not used for Expressions */
}; };
class ExpressionList; class ExpressionList;

View File

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