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/utility.h"
#include "base/objectlock.h"
#include "base/object.h"
#include <boost/foreach.hpp>
#include <boost/exception_ptr.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);
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)));
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)
{
Dictionary::Ptr dict = OpVariable(expr, locals);
if (!dict)
BOOST_THROW_EXCEPTION(ConfigError("Script variable '" + expr->m_Operand1 + "' not set in this scope."));
return dict->Get(expr->m_Operand2);
Value value = expr->EvaluateOperand1(locals);
Value index = expr->EvaluateOperand2(locals);
if (value.IsObjectType<Dictionary>()) {
Dictionary::Ptr dict = value;
return dict->Get(index);
} else if (value.IsObjectType<Object>()) {
Object::Ptr object = value;
const Type *type = object->GetReflectionType();
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)

View File

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

View File

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