Implement the "." operator.

Refs #5876
This commit is contained in:
Gunnar Beutner 2014-03-28 12:17:22 +01:00
parent de81baf515
commit b289987500
3 changed files with 54 additions and 20 deletions

View File

@ -27,6 +27,7 @@
#include "base/scriptvariable.h" #include "base/scriptvariable.h"
#include "base/utility.h" #include "base/utility.h"
#include "base/objectlock.h" #include "base/objectlock.h"
#include "base/object.h"
#include <boost/foreach.hpp> #include <boost/foreach.hpp>
#include <boost/exception_ptr.hpp> #include <boost/exception_ptr.hpp>
#include <boost/exception/errinfo_nested_exception.hpp> #include <boost/exception/errinfo_nested_exception.hpp>
@ -194,7 +195,9 @@ Value AExpression::OpIn(const AExpression *expr, const Dictionary::Ptr& locals)
{ {
Value right = expr->EvaluateOperand2(locals); Value right = expr->EvaluateOperand2(locals);
if (!right.IsObjectType<Array>()) if (right.IsEmpty())
return false;
else if (!right.IsObjectType<Array>())
BOOST_THROW_EXCEPTION(ConfigError("Invalid right side argument for 'in' operator: " + JsonSerialize(right))); BOOST_THROW_EXCEPTION(ConfigError("Invalid right side argument for 'in' operator: " + JsonSerialize(right)));
Value left = expr->EvaluateOperand1(locals); Value left = expr->EvaluateOperand1(locals);
@ -393,12 +396,28 @@ Value AExpression::OpSetDivide(const AExpression *expr, const Dictionary::Ptr& l
Value AExpression::OpIndexer(const AExpression *expr, const Dictionary::Ptr& locals) Value AExpression::OpIndexer(const AExpression *expr, const Dictionary::Ptr& locals)
{ {
Dictionary::Ptr dict = OpVariable(expr, locals); Value value = expr->EvaluateOperand1(locals);
Value index = expr->EvaluateOperand2(locals);
if (!dict) if (value.IsObjectType<Dictionary>()) {
BOOST_THROW_EXCEPTION(ConfigError("Script variable '" + expr->m_Operand1 + "' not set in this scope.")); Dictionary::Ptr dict = value;
return dict->Get(index);
} else if (value.IsObjectType<Object>()) {
Object::Ptr object = value;
const Type *type = object->GetReflectionType();
return dict->Get(expr->m_Operand2); if (!type)
BOOST_THROW_EXCEPTION(ConfigError("Dot operator applied to object which does not support reflection"));
int field = type->GetFieldId(index);
if (field == -1)
BOOST_THROW_EXCEPTION(ConfigError("Tried to access invalid property '" + index + "'"));
return object->GetField(field);
} else {
BOOST_THROW_EXCEPTION(ConfigError("Dot operator cannot be applied to type '" + value.GetTypeName() + "'"));
}
} }
Value AExpression::OpImport(const AExpression *expr, const Dictionary::Ptr& locals) Value AExpression::OpImport(const AExpression *expr, const Dictionary::Ptr& locals)

View File

@ -165,10 +165,11 @@ using namespace icinga;
%left T_NOT_IN %left T_NOT_IN
%nonassoc T_EQUAL %nonassoc T_EQUAL
%nonassoc T_NOT_EQUAL %nonassoc T_NOT_EQUAL
%left '+' '-' %left T_PLUS T_MINUS
%left '*' '/' %left T_MULTIPLY T_DIVIDE_OP
%left '&' %left T_BINARY_AND
%left '|' %left T_BINARY_OR
%left '.'
%right '~' %right '~'
%right '!' %right '!'
%{ %{
@ -528,6 +529,19 @@ lterm: identifier lbinary_op rterm
$$ = new Value(make_shared<AExpression>(&AExpression::OpSetPlus, $1, expr, DebugInfoRange(@1, @6))); $$ = new Value(make_shared<AExpression>(&AExpression::OpSetPlus, $1, expr, DebugInfoRange(@1, @6)));
free($1); free($1);
} }
| identifier '.' T_IDENTIFIER lbinary_op rterm
{
AExpression::Ptr subexpr = make_shared<AExpression>($4, $3, static_cast<AExpression::Ptr>(*$5), DebugInfoRange(@1, @5));
free($3);
delete $5;
Array::Ptr subexprl = make_shared<Array>();
subexprl->Add(subexpr);
AExpression::Ptr expr = make_shared<AExpression>(&AExpression::OpDict, subexprl, DebugInfoRange(@1, @5));
$$ = new Value(make_shared<AExpression>(&AExpression::OpSetPlus, $1, expr, DebugInfoRange(@1, @5)));
free($1);
}
| rterm | rterm
{ {
$$ = $1; $$ = $1;
@ -614,6 +628,12 @@ rterm: T_STRING
{ {
$$ = new Value(make_shared<AExpression>(&AExpression::OpLiteral, Empty, @1)); $$ = new Value(make_shared<AExpression>(&AExpression::OpLiteral, Empty, @1));
} }
| rterm '.' T_IDENTIFIER
{
$$ = new Value(make_shared<AExpression>(&AExpression::OpIndexer, static_cast<AExpression::Ptr>(*$1), make_shared<AExpression>(&AExpression::OpLiteral, $3, @3), DebugInfoRange(@1, @3)));
delete $1;
free($3);
}
| T_IDENTIFIER '(' rterm_items ')' | T_IDENTIFIER '(' rterm_items ')'
{ {
Array::Ptr arguments = Array::Ptr($3); Array::Ptr arguments = Array::Ptr($3);
@ -642,10 +662,10 @@ rterm: T_STRING
$$ = new Value(make_shared<AExpression>(&AExpression::OpNegate, static_cast<AExpression::Ptr>(*$2), DebugInfoRange(@1, @2))); $$ = new Value(make_shared<AExpression>(&AExpression::OpNegate, static_cast<AExpression::Ptr>(*$2), DebugInfoRange(@1, @2)));
delete $2; delete $2;
} }
| identifier '[' T_STRING ']' | rterm '[' rterm ']'
{ {
$$ = new Value(make_shared<AExpression>(&AExpression::OpIndexer, $1, $3, DebugInfoRange(@1, @4))); $$ = new Value(make_shared<AExpression>(&AExpression::OpIndexer, static_cast<AExpression::Ptr>(*$1), static_cast<AExpression::Ptr>(*$3), DebugInfoRange(@1, @4)));
free($1); delete $1;
free($3); free($3);
} }
| '[' rterm_items ']' | '[' rterm_items ']'

View File

@ -41,12 +41,7 @@ void Host::EvaluateApplyRules(const std::vector<ApplyRule>& rules)
CONTEXT("Evaluating 'apply' rules for Host '" + host->GetName() + "'"); CONTEXT("Evaluating 'apply' rules for Host '" + host->GetName() + "'");
Dictionary::Ptr locals = make_shared<Dictionary>(); Dictionary::Ptr locals = make_shared<Dictionary>();
locals->Set("host", host->GetName()); locals->Set("host", host);
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) {
DebugInfo di = rule.GetDebugInfo(); DebugInfo di = rule.GetDebugInfo();