From aacc699dd4f22d4289a1df46c19e17b4c6f5871f Mon Sep 17 00:00:00 2001 From: Gunnar Beutner Date: Sun, 23 Mar 2014 11:27:40 +0100 Subject: [PATCH] Refactor the config parser's AST. Refs #5846 --- lib/base/CMakeLists.txt | 2 +- .../utilityfuncs.cpp => base/scriptutils.cpp} | 28 +- .../utilityfuncs.h => base/scriptutils.h} | 16 +- lib/base/value-operators.cpp | 15 +- lib/config/CMakeLists.txt | 2 +- lib/config/aexpression.cpp | 114 ++++- lib/config/aexpression.h | 11 + lib/config/config_lexer.ll | 39 +- lib/config/config_parser.yy | 423 ++++++++---------- lib/config/configitem.cpp | 20 +- lib/config/configitem.h | 14 +- lib/config/configitembuilder.cpp | 36 +- lib/config/configitembuilder.h | 10 +- lib/config/expression.cpp | 204 --------- lib/config/expression.h | 78 ---- lib/config/expressionlist.cpp | 60 --- lib/config/expressionlist.h | 55 --- lib/icinga/host-apply.cpp | 2 +- lib/icinga/host.cpp | 12 +- lib/icinga/service-dependency.cpp | 10 +- lib/icinga/service-downtime.cpp | 10 +- lib/icinga/service-notification.cpp | 10 +- lib/methods/CMakeLists.txt | 2 +- 23 files changed, 411 insertions(+), 762 deletions(-) rename lib/{methods/utilityfuncs.cpp => base/scriptutils.cpp} (80%) rename lib/{methods/utilityfuncs.h => base/scriptutils.h} (88%) delete mode 100644 lib/config/expression.cpp delete mode 100644 lib/config/expression.h delete mode 100644 lib/config/expressionlist.cpp delete mode 100644 lib/config/expressionlist.h diff --git a/lib/base/CMakeLists.txt b/lib/base/CMakeLists.txt index 0fc7a9aa4..d230c402c 100644 --- a/lib/base/CMakeLists.txt +++ b/lib/base/CMakeLists.txt @@ -30,7 +30,7 @@ add_library(base SHARED netstring.cpp networkstream.cpp object.cpp objectlock.cpp process.cpp process-unix.cpp process-windows.cpp qstring.cpp ringbuffer.cpp script.cpp script.th scriptfunction.cpp scriptfunctionwrapper.cpp scriptinterpreter.cpp - scriptlanguage.cpp scriptvariable.cpp serializer.cpp socket.cpp stacktrace.cpp + scriptlanguage.cpp scriptutils.cpp scriptvariable.cpp serializer.cpp socket.cpp stacktrace.cpp statsfunction.cpp stdiostream.cpp stream_bio.cpp stream.cpp streamlogger.cpp streamlogger.th sysloglogger.cpp sysloglogger.th tcpsocket.cpp threadpool.cpp timer.cpp tlsstream.cpp tlsutility.cpp type.cpp unixsocket.cpp utility.cpp value.cpp diff --git a/lib/methods/utilityfuncs.cpp b/lib/base/scriptutils.cpp similarity index 80% rename from lib/methods/utilityfuncs.cpp rename to lib/base/scriptutils.cpp index 8b305c7ba..2b07408d3 100644 --- a/lib/methods/utilityfuncs.cpp +++ b/lib/base/scriptutils.cpp @@ -17,12 +17,13 @@ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ -#include "methods/utilityfuncs.h" +#include "base/scriptutils.h" #include "base/scriptfunction.h" #include "base/utility.h" #include "base/convert.h" #include "base/array.h" #include "base/dictionary.h" +#include "base/serializer.h" #include "base/logger_fwd.h" #include #include @@ -30,21 +31,21 @@ using namespace icinga; -REGISTER_SCRIPTFUNCTION(regex, &UtilityFuncs::Regex); +REGISTER_SCRIPTFUNCTION(regex, &ScriptUtils::Regex); REGISTER_SCRIPTFUNCTION(match, &Utility::Match); -REGISTER_SCRIPTFUNCTION(len, &UtilityFuncs::Len); -REGISTER_SCRIPTFUNCTION(union, &UtilityFuncs::Union); -REGISTER_SCRIPTFUNCTION(intersection, &UtilityFuncs::Intersection); -REGISTER_SCRIPTFUNCTION(log, &UtilityFuncs::Log); +REGISTER_SCRIPTFUNCTION(len, &ScriptUtils::Len); +REGISTER_SCRIPTFUNCTION(union, &ScriptUtils::Union); +REGISTER_SCRIPTFUNCTION(intersection, &ScriptUtils::Intersection); +REGISTER_SCRIPTFUNCTION(log, &ScriptUtils::Log); -bool UtilityFuncs::Regex(const String& pattern, const String& text) +bool ScriptUtils::Regex(const String& pattern, const String& text) { boost::regex expr(pattern.GetData()); boost::smatch what; return boost::regex_search(text.GetData(), what, expr); } -int UtilityFuncs::Len(const Value& value) +int ScriptUtils::Len(const Value& value) { if (value.IsObjectType()) { Dictionary::Ptr dict = value; @@ -57,7 +58,7 @@ int UtilityFuncs::Len(const Value& value) } } -Array::Ptr UtilityFuncs::Union(const std::vector& arguments) +Array::Ptr ScriptUtils::Union(const std::vector& arguments) { std::set values; @@ -77,7 +78,7 @@ Array::Ptr UtilityFuncs::Union(const std::vector& arguments) return result; } -Array::Ptr UtilityFuncs::Intersection(const std::vector& arguments) +Array::Ptr ScriptUtils::Intersection(const std::vector& arguments) { if (arguments.size() == 0) return make_shared(); @@ -101,7 +102,10 @@ Array::Ptr UtilityFuncs::Intersection(const std::vector& arguments) return result; } -void UtilityFuncs::Log(const String& message) +void ScriptUtils::Log(const Value& message) { - ::Log(LogInformation, "config", message); + if (message.IsString()) + ::Log(LogInformation, "config", message); + else + ::Log(LogInformation, "config", JsonSerialize(message)); } diff --git a/lib/methods/utilityfuncs.h b/lib/base/scriptutils.h similarity index 88% rename from lib/methods/utilityfuncs.h rename to lib/base/scriptutils.h index 4bf55920d..a23fd3317 100644 --- a/lib/methods/utilityfuncs.h +++ b/lib/base/scriptutils.h @@ -17,10 +17,10 @@ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * ******************************************************************************/ -#ifndef UTILITYFUNCS_H -#define UTILITYFUNCS_H +#ifndef SCRIPTUTILS_H +#define SCRIPTUTILS_H -#include "methods/i2-methods.h" +#include "base/i2-base.h" #include "base/qstring.h" #include "base/array.h" @@ -28,21 +28,21 @@ namespace icinga { /** - * @ingroup methods + * @ingroup base */ -class I2_METHODS_API UtilityFuncs +class I2_BASE_API ScriptUtils { public: static bool Regex(const String& pattern, const String& text); static int Len(const Value& value); static Array::Ptr Union(const std::vector& arguments); static Array::Ptr Intersection(const std::vector& arguments); - static void Log(const String& message); + static void Log(const Value& message); private: - UtilityFuncs(void); + ScriptUtils(void); }; } -#endif /* UTILITYFUNCS_H */ +#endif /* SCRIPTUTILS_H */ diff --git a/lib/base/value-operators.cpp b/lib/base/value-operators.cpp index 234b27b77..afd4d8a16 100644 --- a/lib/base/value-operators.cpp +++ b/lib/base/value-operators.cpp @@ -201,10 +201,19 @@ Value icinga::operator+(const Value& lhs, const Value& rhs) return static_cast(lhs) + static_cast(rhs); else if ((lhs.IsNumber() || lhs.IsEmpty()) && (rhs.IsNumber() || rhs.IsEmpty()) && !(lhs.IsEmpty() && rhs.IsEmpty())) return static_cast(lhs) + static_cast(rhs); - else if (lhs.IsObjectType() && rhs.IsObjectType()) { + else if ((lhs.IsObjectType() || lhs.IsEmpty()) && (rhs.IsObjectType() || rhs.IsEmpty()) && !(lhs.IsEmpty() && rhs.IsEmpty())) { Array::Ptr result = make_shared(); - static_cast(lhs)->CopyTo(result); - static_cast(rhs)->CopyTo(result); + if (!lhs.IsEmpty()) + static_cast(lhs)->CopyTo(result); + if (!rhs.IsEmpty()) + static_cast(rhs)->CopyTo(result); + return result; + } else if ((lhs.IsObjectType() || lhs.IsEmpty()) && (rhs.IsObjectType() || rhs.IsEmpty()) && !(lhs.IsEmpty() && rhs.IsEmpty())) { + Dictionary::Ptr result = make_shared(); + if (!lhs.IsEmpty()) + static_cast(lhs)->CopyTo(result); + if (!rhs.IsEmpty()) + static_cast(rhs)->CopyTo(result); return result; } else { BOOST_THROW_EXCEPTION(std::invalid_argument("Operator + cannot be applied to values of type '" + lhs.GetTypeName() + "' and '" + rhs.GetTypeName() + "'")); diff --git a/lib/config/CMakeLists.txt b/lib/config/CMakeLists.txt index 4a846d719..05f9990b0 100644 --- a/lib/config/CMakeLists.txt +++ b/lib/config/CMakeLists.txt @@ -30,7 +30,7 @@ add_library(config SHARED aexpression.cpp applyrule.cpp base-type.conf base-type.cpp configcompilercontext.cpp configcompiler.cpp configerror.cpp configitembuilder.cpp configitem.cpp ${FLEX_config_lexer_OUTPUTS} ${BISON_config_parser_OUTPUTS} - configtype.cpp debuginfo.cpp expression.cpp expressionlist.cpp typerule.cpp typerulelist.cpp + configtype.cpp debuginfo.cpp typerule.cpp typerulelist.cpp ) target_link_libraries(config ${Boost_LIBRARIES} base) diff --git a/lib/config/aexpression.cpp b/lib/config/aexpression.cpp index 797b23672..e7d977d23 100644 --- a/lib/config/aexpression.cpp +++ b/lib/config/aexpression.cpp @@ -31,7 +31,7 @@ using namespace icinga; AExpression::AExpression(OpCallback op, const Value& operand1, const DebugInfo& di) - : m_Operator(op), m_Operand1(operand1), m_DebugInfo(di) + : m_Operator(op), m_Operand1(operand1), m_Operand2(), m_DebugInfo(di) { } AExpression::AExpression(OpCallback op, const Value& operand1, const Value& operand2, const DebugInfo& di) @@ -46,10 +46,66 @@ Value AExpression::Evaluate(const Dictionary::Ptr& locals) const if (boost::get_error_info(ex)) throw; else - BOOST_THROW_EXCEPTION(ConfigError("Error while evaluating expression.") << boost::errinfo_nested_exception(boost::current_exception()) << errinfo_debuginfo(m_DebugInfo)); + BOOST_THROW_EXCEPTION(ConfigError("Error while evaluating expression: " + String(ex.what())) << boost::errinfo_nested_exception(boost::current_exception()) << errinfo_debuginfo(m_DebugInfo)); } } +void AExpression::ExtractPath(const std::vector& path, const Array::Ptr& result) const +{ + ASSERT(!path.empty()); + + if (m_Operator == &AExpression::OpDict) { + Array::Ptr exprl = m_Operand1; + BOOST_FOREACH(const AExpression::Ptr& expr, exprl) { + expr->ExtractPath(path, result); + } + } else if (m_Operator == &AExpression::OpSet && path[0] == m_Operand1) { + AExpression::Ptr exprl = m_Operand2; + + if (path.size() == 1) { + result->Add(m_Operand1); + + return; + } + + std::vector sub_path(path.begin() + 1, path.end()); + exprl->ExtractPath(sub_path, result); + } else if (m_Operator == &AExpression::OpDict && static_cast(m_Operand2)) { + AExpression::Ptr exprl = m_Operand1; + exprl->ExtractPath(path, result); + } +} + +void AExpression::FindDebugInfoPath(const std::vector& path, DebugInfo& result) const +{ + ASSERT(!path.empty()); + + if (m_Operator == &AExpression::OpDict) { + Array::Ptr exprl = m_Operand1; + BOOST_FOREACH(const AExpression::Ptr& expr, exprl) { + expr->FindDebugInfoPath(path, result); + } + } else if (m_Operator == &AExpression::OpSet && path[0] == m_Operand1) { + AExpression::Ptr exprl = m_Operand2; + + if (path.size() == 1) { + result = m_DebugInfo; + } else { + std::vector sub_path(path.begin() + 1, path.end()); + exprl->FindDebugInfoPath(sub_path, result); + } + } else if (m_Operator == &AExpression::OpDict && static_cast(m_Operand2)) { + AExpression::Ptr exprl = m_Operand1; + exprl->FindDebugInfoPath(path, result); + } +} + +void AExpression::MakeInline(void) +{ + ASSERT(m_Operator == &AExpression::OpDict); + m_Operand2 = true; +} + Value AExpression::EvaluateOperand1(const Dictionary::Ptr& locals) const { return static_cast(m_Operand1)->Evaluate(locals); @@ -150,12 +206,12 @@ Value AExpression::OpGreaterThanOrEqual(const Dictionary::Ptr& locals) const Value AExpression::OpIn(const Dictionary::Ptr& locals) const { - Value right = EvaluateOperand1(locals); + Value right = EvaluateOperand2(locals); if (!right.IsObjectType()) BOOST_THROW_EXCEPTION(ConfigError("Invalid right side argument for 'in' operator: " + JsonSerialize(right))); - Value left = EvaluateOperand2(locals); + Value left = EvaluateOperand1(locals); Array::Ptr arr = right; bool found = false; @@ -214,3 +270,53 @@ Value AExpression::OpArray(const Dictionary::Ptr& locals) const return result; } + +Value AExpression::OpDict(const Dictionary::Ptr& locals) const +{ + Array::Ptr arr = m_Operand1; + bool in_place = m_Operand2; + Dictionary::Ptr result = make_shared(); + + if (arr) { + BOOST_FOREACH(const AExpression::Ptr& aexpr, arr) { + aexpr->Evaluate(in_place ? locals : result); + } + } + + return result; +} + +Value AExpression::OpSet(const Dictionary::Ptr& locals) const +{ + Value right = EvaluateOperand2(locals); + locals->Set(m_Operand1, right); + return right; +} + +Value AExpression::OpSetPlus(const Dictionary::Ptr& locals) const +{ + Value result = locals->Get(m_Operand1) + EvaluateOperand2(locals); + locals->Set(m_Operand1, result); + return result; +} + +Value AExpression::OpSetMinus(const Dictionary::Ptr& locals) const +{ + Value result = locals->Get(m_Operand1) - EvaluateOperand2(locals); + locals->Set(m_Operand1, result); + return result; +} + +Value AExpression::OpSetMultiply(const Dictionary::Ptr& locals) const +{ + Value result = locals->Get(m_Operand1) * EvaluateOperand2(locals); + locals->Set(m_Operand1, result); + return result; +} + +Value AExpression::OpSetDivide(const Dictionary::Ptr& locals) const +{ + Value result = locals->Get(m_Operand1) / EvaluateOperand2(locals); + locals->Set(m_Operand1, result); + return result; +} diff --git a/lib/config/aexpression.h b/lib/config/aexpression.h index 182626167..36c77a20e 100644 --- a/lib/config/aexpression.h +++ b/lib/config/aexpression.h @@ -22,6 +22,7 @@ #include "config/i2-config.h" #include "config/debuginfo.h" +#include "base/array.h" #include "base/dictionary.h" namespace icinga @@ -41,7 +42,11 @@ public: AExpression(OpCallback op, const Value& operand1, const Value& operand2, const DebugInfo& di); Value Evaluate(const Dictionary::Ptr& locals) const; + void ExtractPath(const std::vector& path, const Array::Ptr& result) const; + void FindDebugInfoPath(const std::vector& path, DebugInfo& result) const; + void MakeInline(void); + Value OpLiteral(const Dictionary::Ptr& locals) const; Value OpVariable(const Dictionary::Ptr& locals) const; Value OpNegate(const Dictionary::Ptr& locals) const; @@ -65,6 +70,12 @@ public: Value OpLogicalOr(const Dictionary::Ptr& locals) const; Value OpFunctionCall(const Dictionary::Ptr& locals) const; Value OpArray(const Dictionary::Ptr& locals) const; + Value OpDict(const Dictionary::Ptr& locals) const; + Value OpSet(const Dictionary::Ptr& locals) const; + Value OpSetPlus(const Dictionary::Ptr& locals) const; + Value OpSetMinus(const Dictionary::Ptr& locals) const; + Value OpSetMultiply(const Dictionary::Ptr& locals) const; + Value OpSetDivide(const Dictionary::Ptr& locals) const; private: OpCallback m_Operator; diff --git a/lib/config/config_lexer.ll b/lib/config/config_lexer.ll index 54cb1f561..d6e9331ea 100644 --- a/lib/config/config_lexer.ll +++ b/lib/config/config_lexer.ll @@ -19,7 +19,6 @@ ******************************************************************************/ #include "config/configcompiler.h" -#include "config/expression.h" #include "config/typerule.h" #include "config/configcompilercontext.h" @@ -225,16 +224,16 @@ const return T_CONST; apply return T_APPLY; to return T_TO; where return T_WHERE; -\<\< return T_SHIFT_LEFT; -\>\> return T_SHIFT_RIGHT; -\<= return T_LESS_THAN_OR_EQUAL; -\>= return T_GREATER_THAN_OR_EQUAL; -== return T_EQUAL; -!= return T_NOT_EQUAL; -!in return T_NOT_IN; -in return T_IN; -&& return T_LOGICAL_AND; -\|\| return T_LOGICAL_OR; +\<\< { yylval->op = &AExpression::OpShiftLeft; return T_SHIFT_LEFT; } +\>\> { yylval->op = &AExpression::OpShiftRight; return T_SHIFT_RIGHT; } +\<= { yylval->op = &AExpression::OpLessThanOrEqual; return T_LESS_THAN_OR_EQUAL; } +\>= { yylval->op = &AExpression::OpGreaterThanOrEqual; return T_GREATER_THAN_OR_EQUAL; } +== { yylval->op = &AExpression::OpEqual; return T_EQUAL; } +!= { yylval->op = &AExpression::OpNotEqual; return T_NOT_EQUAL; } +!in { yylval->op = &AExpression::OpNotIn; return T_NOT_IN; } +in { yylval->op = &AExpression::OpIn; return T_IN; } +&& { yylval->op = &AExpression::OpLogicalAnd; return T_LOGICAL_AND; } +\|\| { yylval->op = &AExpression::OpLogicalOr; 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; } @@ -243,11 +242,19 @@ in return T_IN; -?[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 = OperatorSet; return T_SET; } -\+= { yylval->op = OperatorPlus; return T_PLUS_EQUAL; } --= { yylval->op = OperatorMinus; return T_MINUS_EQUAL; } -\*= { yylval->op = OperatorMultiply; return T_MULTIPLY_EQUAL; } -\/= { yylval->op = OperatorDivide; return T_DIVIDE_EQUAL; } += { yylval->op = &AExpression::OpSet; return T_SET; } +\+= { yylval->op = &AExpression::OpSetPlus; return T_SET_PLUS; } +-= { yylval->op = &AExpression::OpSetMinus; return T_SET_MINUS; } +\*= { yylval->op = &AExpression::OpSetMultiply; return T_SET_MULTIPLY; } +\/= { yylval->op = &AExpression::OpSetDivide; return T_SET_DIVIDE; } +\+ { yylval->op = &AExpression::OpAdd; return T_PLUS; } +\- { yylval->op = &AExpression::OpSubtract; return T_MINUS; } +\* { yylval->op = &AExpression::OpMultiply; return T_MULTIPLY; } +\/ { yylval->op = &AExpression::OpMultiply; return T_DIVIDE; } +\& { yylval->op = &AExpression::OpBinaryAnd; return T_BINARY_AND; } +\| { yylval->op = &AExpression::OpBinaryOr; return T_BINARY_OR; } +\< { yylval->op = &AExpression::OpLessThan; return T_LESS_THAN; } +\> { yylval->op = &AExpression::OpLessThan; return T_GREATER_THAN; } } . return yytext[0]; diff --git a/lib/config/config_parser.yy b/lib/config/config_parser.yy index d4427ff57..4381b8fb4 100644 --- a/lib/config/config_parser.yy +++ b/lib/config/config_parser.yy @@ -21,8 +21,6 @@ ******************************************************************************/ #include "i2-config.h" -#include "config/expression.h" -#include "config/expressionlist.h" #include "config/configitembuilder.h" #include "config/configcompiler.h" #include "config/configcompilercontext.h" @@ -86,13 +84,10 @@ using namespace icinga; char *text; double num; icinga::Value *variant; - icinga::ExpressionOperator op; + icinga::AExpression::OpCallback op; icinga::TypeSpecifier type; std::vector *slist; - Expression *expr; - ExpressionList *exprl; Array *array; - Value *aexpr; } %token T_STRING @@ -100,23 +95,34 @@ using namespace icinga; %token T_NUMBER %token T_NULL %token T_IDENTIFIER + %token T_SET "= (T_SET)" -%token T_PLUS_EQUAL "+= (T_PLUS_EQUAL)" -%token T_MINUS_EQUAL "-= (T_MINUS_EQUAL)" -%token T_MULTIPLY_EQUAL "*= (T_MULTIPLY_EQUAL)" -%token T_DIVIDE_EQUAL "/= (T_DIVIDE_EQUAL)" +%token T_SET_PLUS "+= (T_SET_PLUS)" +%token T_SET_MINUS "-= (T_SET_MINUS)" +%token T_SET_MULTIPLY "*= (T_SET_MULTIPLY)" +%token T_SET_DIVIDE "/= (T_SET_DIVIDE)" + +%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 T_LESS_THAN_OR_EQUAL "<= (T_LESS_THAN_OR_EQUAL)" +%token T_GREATER_THAN_OR_EQUAL ">= (T_GREATER_THAN_OR_EQUAL)" +%token T_PLUS "+ (T_PLUS)" +%token T_MINUS "- (T_MINUS)" +%token T_MULTIPLY "* (T_MULTIPLY)" +%token T_DIVIDE "/ (T_DIVIDE)" +%token T_BINARY_AND "& (T_BINARY_AND)" +%token T_BINARY_OR "| (T_BINARY_OR)" +%token T_LESS_THAN "< (T_LESS_THAN)" +%token T_GREATER_THAN "> (T_GREATER_THAN)" + %token T_VAR "var (T_VAR)" %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 T_LESS_THAN_OR_EQUAL "<= (T_LESS_THAN_OR_EQUAL)" -%token T_GREATER_THAN_OR_EQUAL ">= (T_GREATER_THAN_OR_EQUAL)" %token T_TYPE_DICTIONARY "dictionary (T_TYPE_DICTIONARY)" %token T_TYPE_ARRAY "array (T_TYPE_ARRAY)" %token T_TYPE_NUMBER "number (T_TYPE_NUMBER)" @@ -139,20 +145,19 @@ using namespace icinga; %token T_TO "to (T_TO)" %token T_WHERE "where (T_WHERE)" %type identifier -%type array_items -%type array_items_inner -%type value -%type expression -%type expressions -%type expressions_inner -%type expressionlist +%type rterm_items +%type rterm_items_inner +%type lterm_items +%type lterm_items_inner %type typerulelist -%type operator +%type lbinary_op +%type rbinary_op %type type %type partial_specifier %type object_inherits_list %type object_inherits_specifier -%type aexpression +%type rterm +%type lterm %type variable_decl %left T_LOGICAL_OR %left T_LOGICAL_AND @@ -179,14 +184,17 @@ void yyerror(YYLTYPE *locp, ConfigCompiler *, const char *err) int yyparse(ConfigCompiler *context); -static std::stack m_Arrays; static bool m_Abstract; static std::stack m_RuleLists; static ConfigType::Ptr m_Type; +static Dictionary::Ptr m_ModuleScope; + void ConfigCompiler::Compile(void) { + m_ModuleScope = make_shared(); + try { yyparse(this); } catch (const ConfigError& ex) { @@ -208,16 +216,20 @@ statements: /* empty */ statement: object | type | include | include_recursive | library | variable | apply { } - | value + | lterm { + AExpression::Ptr aexpr = *$1; + aexpr->Evaluate(m_ModuleScope); delete $1; } ; -include: T_INCLUDE value +include: T_INCLUDE rterm { - context->HandleInclude(*$2, false, DebugInfoRange(@1, @2)); + AExpression::Ptr aexpr = static_cast(*$2); delete $2; + + context->HandleInclude(aexpr->Evaluate(m_ModuleScope), false, DebugInfoRange(@1, @2)); } | T_INCLUDE T_STRING_ANGLE { @@ -226,16 +238,22 @@ include: T_INCLUDE value } ; -include_recursive: T_INCLUDE_RECURSIVE value +include_recursive: T_INCLUDE_RECURSIVE rterm { - context->HandleIncludeRecursive(*$2, "*.conf", DebugInfoRange(@1, @2)); + AExpression::Ptr aexpr = static_cast(*$2); delete $2; + + context->HandleIncludeRecursive(aexpr->Evaluate(m_ModuleScope), "*.conf", DebugInfoRange(@1, @2)); } - | T_INCLUDE_RECURSIVE value value + | T_INCLUDE_RECURSIVE rterm rterm { - context->HandleIncludeRecursive(*$2, *$3, DebugInfoRange(@1, @3)); + AExpression::Ptr aexpr1 = static_cast(*$2); delete $2; + + AExpression::Ptr aexpr2 = static_cast(*$3); delete $3; + + context->HandleIncludeRecursive(aexpr1->Evaluate(m_ModuleScope), aexpr2->Evaluate(m_ModuleScope), DebugInfoRange(@1, @3)); } ; @@ -246,22 +264,15 @@ library: T_LIBRARY T_STRING } ; -variable: variable_decl identifier T_SET value +variable: variable_decl identifier T_SET rterm { - Value *value = $4; - if (value->IsObjectType()) { - Dictionary::Ptr dict = make_shared(); - ExpressionList::Ptr exprl = *value; - exprl->Execute(dict); - delete value; - value = new Value(dict); - } + AExpression::Ptr aexpr = static_cast(*$4); + delete $4; - ScriptVariable::Ptr sv = ScriptVariable::Set($2, *value); + ScriptVariable::Ptr sv = ScriptVariable::Set($2, aexpr->Evaluate(m_ModuleScope)); sv->SetConstant(true); free($2); - delete value; } ; @@ -399,7 +410,7 @@ object: { m_Abstract = false; } - object_declaration identifier T_STRING object_inherits_specifier expressionlist + object_declaration identifier T_STRING object_inherits_specifier rterm { DebugInfo di = DebugInfoRange(@2, @6); ConfigItemBuilder::Ptr item = make_shared(di); @@ -437,10 +448,11 @@ object: delete $5; } - if ($6) { - ExpressionList::Ptr exprl = ExpressionList::Ptr($6); - item->AddExpressionList(exprl); - } + AExpression::Ptr exprl = static_cast(*$6); + delete $6; + + exprl->MakeInline(); + item->AddExpression(exprl); item->SetAbstract(m_Abstract); @@ -487,96 +499,36 @@ object_inherits_specifier: } ; -expressionlist: '{' expressions '}' +lbinary_op: T_SET + | T_SET_PLUS + | T_SET_MINUS + | T_SET_MULTIPLY + | T_SET_DIVIDE { - if ($2) - $$ = $2; - else - $$ = new ExpressionList(); + $$ = $1; } ; -expressions: expressions_inner +lterm_items: lterm_items_inner { $$ = $1; } - | expressions_inner ',' + | lterm_items_inner ',' { $$ = $1; } -expressions_inner: /* empty */ +lterm_items_inner: /* empty */ { $$ = NULL; } - | expression - { - $$ = new ExpressionList(); - $$->AddExpression(*$1); - delete $1; - } - | expressions_inner ',' expression - { - if ($1) - $$ = $1; - else - $$ = new ExpressionList(); - - $$->AddExpression(*$3); - delete $3; - } - ; - -expression: identifier operator value - { - $$ = new Expression($1, $2, *$3, DebugInfoRange(@1, @3)); - free($1); - delete $3; - } - | identifier '[' T_STRING ']' operator value - { - Expression subexpr($3, $5, *$6, DebugInfoRange(@1, @6)); - free($3); - delete $6; - - ExpressionList::Ptr subexprl = make_shared(); - subexprl->AddExpression(subexpr); - - $$ = new Expression($1, OperatorPlus, subexprl, DebugInfoRange(@1, @6)); - free($1); - } - ; - -operator: T_SET - | T_PLUS_EQUAL - | T_MINUS_EQUAL - | T_MULTIPLY_EQUAL - | T_DIVIDE_EQUAL - { - $$ = $1; - } - ; - -array_items: array_items_inner - { - $$ = $1; - } - | array_items_inner ',' - { - $$ = $1; - } - -array_items_inner: /* empty */ - { - $$ = NULL; - } - | aexpression + | lterm { $$ = new Array(); $$->Add(*$1); delete $1; } - | array_items_inner ',' aexpression + | lterm_items_inner ',' lterm { if ($1) $$ = $1; @@ -588,7 +540,93 @@ array_items_inner: /* empty */ } ; -aexpression: T_STRING +lterm: T_IDENTIFIER lbinary_op rterm + { + $$ = new Value(make_shared($2, $1, static_cast(*$3), DebugInfoRange(@1, @3))); + delete $3; + } + | identifier '[' T_STRING ']' lbinary_op rterm + { + AExpression::Ptr subexpr = make_shared($5, $3, static_cast(*$6), DebugInfoRange(@1, @6)); + free($3); + delete $6; + + Array::Ptr subexprl = make_shared(); + subexprl->Add(subexpr); + + AExpression::Ptr expr = make_shared(&AExpression::OpDict, subexprl, DebugInfoRange(@1, @6)); + + $$ = new Value(make_shared(&AExpression::OpSetPlus, $1, expr, DebugInfoRange(@1, @6))); + free($1); + } + | rterm + { + $$ = $1; + } + ; + +rbinary_op: T_PLUS + | T_MINUS + | T_MULTIPLY + | T_DIVIDE + | T_BINARY_AND + | T_BINARY_OR + | T_LESS_THAN + | T_GREATER_THAN + | T_LESS_THAN_OR_EQUAL + | T_GREATER_THAN_OR_EQUAL + | T_EQUAL + | T_NOT_EQUAL + | T_IN + | T_NOT_IN + | T_LOGICAL_AND + | T_LOGICAL_OR + | T_SHIFT_LEFT + | T_SHIFT_RIGHT + { + $$ = $1; + } + ; + +rterm_items: rterm_items_inner + { + $$ = $1; + } + | rterm_items_inner ',' + { + $$ = $1; + } + ; + +rterm_items_inner: /* empty */ + { + $$ = NULL; + } + | rterm + { + $$ = new Array(); + $$->Add(*$1); + delete $1; + } + | rterm_items_inner ',' rterm + { + if ($1) + $$ = $1; + else + $$ = new Array(); + + $$->Add(*$3); + delete $3; + } + ; + +rbinary_op: '+' + { + $$ = &AExpression::OpAdd; + } + ; + +rterm: T_STRING { $$ = new Value(make_shared(&AExpression::OpLiteral, $1, @1)); free($1); @@ -601,7 +639,7 @@ aexpression: T_STRING { $$ = new Value(make_shared(&AExpression::OpLiteral, Empty, @1)); } - | T_IDENTIFIER '(' array_items ')' + | T_IDENTIFIER '(' rterm_items ')' { Array::Ptr arguments = Array::Ptr($3); $$ = new Value(make_shared(&AExpression::OpFunctionCall, $1, make_shared(&AExpression::OpLiteral, arguments, @3), DebugInfoRange(@1, @4))); @@ -612,152 +650,41 @@ aexpression: T_STRING $$ = new Value(make_shared(&AExpression::OpVariable, $1, @1)); free($1); } - | '!' aexpression + | '!' rterm { $$ = new Value(make_shared(&AExpression::OpNegate, static_cast(*$2), DebugInfoRange(@1, @2))); delete $2; } - | '~' aexpression + | '~' rterm { $$ = new Value(make_shared(&AExpression::OpNegate, static_cast(*$2), DebugInfoRange(@1, @2))); delete $2; } - | '[' array_items ']' + | '[' rterm_items ']' { $$ = new Value(make_shared(&AExpression::OpArray, Array::Ptr($2), DebugInfoRange(@1, @3))); } - | '(' aexpression ')' + | '{' lterm_items '}' + { + $$ = new Value(make_shared(&AExpression::OpDict, Array::Ptr($2), DebugInfoRange(@1, @3))); + } + | '(' rterm ')' { $$ = $2; } - | aexpression '+' aexpression + | rterm rbinary_op rterm { - $$ = new Value(make_shared(&AExpression::OpAdd, static_cast(*$1), static_cast(*$3), DebugInfoRange(@1, @3))); + $$ = new Value(make_shared($2, static_cast(*$1), static_cast(*$3), DebugInfoRange(@1, @3))); delete $1; delete $3; } - | aexpression '-' aexpression - { - $$ = new Value(make_shared(&AExpression::OpSubtract, static_cast(*$1), static_cast(*$3), DebugInfoRange(@1, @3))); - delete $1; - delete $3; - } - | aexpression '*' aexpression - { - $$ = new Value(make_shared(&AExpression::OpMultiply, static_cast(*$1), static_cast(*$3), DebugInfoRange(@1, @3))); - delete $1; - delete $3; - } - | aexpression '/' aexpression - { - $$ = new Value(make_shared(&AExpression::OpDivide, static_cast(*$1), static_cast(*$3), DebugInfoRange(@1, @3))); - delete $1; - delete $3; - } - | aexpression '&' aexpression - { - $$ = new Value(make_shared(&AExpression::OpBinaryAnd, static_cast(*$1), static_cast(*$3), DebugInfoRange(@1, @3))); - delete $1; - delete $3; - } - | aexpression '|' aexpression - { - $$ = new Value(make_shared(&AExpression::OpBinaryOr, static_cast(*$1), static_cast(*$3), DebugInfoRange(@1, @2))); - delete $1; - delete $3; - } - | aexpression T_IN aexpression - { - $$ = new Value(make_shared(&AExpression::OpIn, static_cast(*$1), static_cast(*$3), DebugInfoRange(@1, @3))); - delete $1; - delete $3; - } - | aexpression T_NOT_IN aexpression - { - $$ = new Value(make_shared(&AExpression::OpNotIn, static_cast(*$1), static_cast(*$3), DebugInfoRange(@1, @3))); - delete $1; - delete $3; - } - | aexpression T_LESS_THAN_OR_EQUAL aexpression - { - $$ = new Value(make_shared(&AExpression::OpLessThanOrEqual, static_cast(*$1), static_cast(*$3), DebugInfoRange(@1, @3))); - delete $1; - delete $3; - } - | aexpression T_GREATER_THAN_OR_EQUAL aexpression - { - $$ = new Value(make_shared(&AExpression::OpGreaterThanOrEqual, static_cast(*$1), static_cast(*$3), DebugInfoRange(@1, @3))); - delete $1; - delete $3; - } - | aexpression '<' aexpression - { - $$ = new Value(make_shared(&AExpression::OpLessThan, static_cast(*$1), static_cast(*$3), DebugInfoRange(@1, @3))); - delete $1; - delete $3; - } - | aexpression '>' aexpression - { - $$ = new Value(make_shared(&AExpression::OpGreaterThan, static_cast(*$1), static_cast(*$3), DebugInfoRange(@1, @3))); - delete $1; - delete $3; - } - | aexpression T_EQUAL aexpression - { - $$ = new Value(make_shared(&AExpression::OpEqual, static_cast(*$1), static_cast(*$3), DebugInfoRange(@1, @3))); - delete $1; - delete $3; - } - | aexpression T_NOT_EQUAL aexpression - { - $$ = new Value(make_shared(&AExpression::OpNotEqual, static_cast(*$1), static_cast(*$3), DebugInfoRange(@1, @3))); - delete $1; - delete $3; - } - | aexpression T_SHIFT_LEFT aexpression - { - $$ = new Value(make_shared(&AExpression::OpShiftLeft, static_cast(*$1), static_cast(*$3), DebugInfoRange(@1, @3))); - delete $1; - delete $3; - } - | aexpression T_SHIFT_RIGHT aexpression - { - $$ = new Value(make_shared(&AExpression::OpShiftRight, static_cast(*$1), static_cast(*$3), DebugInfoRange(@1, @3))); - delete $1; - delete $3; - } - | aexpression T_LOGICAL_AND aexpression - { - $$ = new Value(make_shared(&AExpression::OpLogicalAnd, static_cast(*$1), static_cast(*$3), DebugInfoRange(@1, @3))); - delete $1; - delete $3; - } - | aexpression T_LOGICAL_OR aexpression - { - $$ = new Value(make_shared(&AExpression::OpLogicalOr, static_cast(*$1), static_cast(*$3), DebugInfoRange(@1, @3))); - delete $1; - delete $3; - } - ; - -value: expressionlist - { - ExpressionList::Ptr exprl = ExpressionList::Ptr($1); - $$ = new Value(exprl); - } - | aexpression - { - AExpression::Ptr aexpr = *$1; - $$ = new Value(aexpr->Evaluate(Dictionary::Ptr())); - delete $1; - } ; optional_template: /* empty */ | T_TEMPLATE ; -apply: T_APPLY optional_template identifier identifier T_TO identifier T_WHERE aexpression +apply: T_APPLY optional_template identifier identifier T_TO identifier T_WHERE rterm { if (!ApplyRule::IsValidCombination($3, $6)) { BOOST_THROW_EXCEPTION(ConfigError("'apply' cannot be used with types '" + String($3) + "' and '" + String($6) + "'.") << errinfo_debuginfo(@1)); diff --git a/lib/config/configitem.cpp b/lib/config/configitem.cpp index 95ca34f5a..609e7f3ff 100644 --- a/lib/config/configitem.cpp +++ b/lib/config/configitem.cpp @@ -48,7 +48,7 @@ ConfigItem::ItemMap ConfigItem::m_Items; * @param debuginfo Debug information. */ ConfigItem::ConfigItem(const String& type, const String& name, - bool abstract, const ExpressionList::Ptr& exprl, + bool abstract, const AExpression::Ptr& exprl, const std::vector& parents, const DebugInfo& debuginfo) : m_Type(type), m_Name(name), m_Abstract(abstract), m_Validated(false), m_ExpressionList(exprl), m_ParentNames(parents), m_DebugInfo(debuginfo) @@ -100,20 +100,20 @@ DebugInfo ConfigItem::GetDebugInfo(void) const * * @returns The expression list. */ -ExpressionList::Ptr ConfigItem::GetExpressionList(void) const +AExpression::Ptr ConfigItem::GetExpressionList(void) const { return m_ExpressionList; } -ExpressionList::Ptr ConfigItem::GetLinkedExpressionList(void) +AExpression::Ptr ConfigItem::GetLinkedExpressionList(void) { ASSERT(OwnsLock()); if (m_LinkedExpressionList) return m_LinkedExpressionList; - m_LinkedExpressionList = make_shared(); - + Array::Ptr subexprs = make_shared(); + BOOST_FOREACH(const String& name, m_ParentNames) { ConfigItem::Ptr parent = ConfigItem::GetObject(m_Type, name); @@ -123,19 +123,21 @@ ExpressionList::Ptr ConfigItem::GetLinkedExpressionList(void) " exist (" << m_DebugInfo << ")"; ConfigCompilerContext::GetInstance()->AddMessage(true, message.str(), m_DebugInfo); } else { - ExpressionList::Ptr pexprl; + AExpression::Ptr pexprl; { ObjectLock olock(parent); pexprl = parent->GetLinkedExpressionList(); } - m_LinkedExpressionList->AddExpression(Expression("", OperatorExecute, pexprl, m_DebugInfo)); + subexprs->Add(pexprl); } } - m_LinkedExpressionList->AddExpression(Expression("", OperatorExecute, m_ExpressionList, m_DebugInfo)); + subexprs->Add(m_ExpressionList); + m_LinkedExpressionList = make_shared(&AExpression::OpDict, subexprs, true, m_DebugInfo); + return m_LinkedExpressionList; } @@ -144,7 +146,7 @@ Dictionary::Ptr ConfigItem::GetProperties(void) ASSERT(OwnsLock()); Dictionary::Ptr properties = make_shared(); - GetLinkedExpressionList()->Execute(properties); + GetLinkedExpressionList()->Evaluate(properties); return properties; } diff --git a/lib/config/configitem.h b/lib/config/configitem.h index 415879a87..2435d9a7c 100644 --- a/lib/config/configitem.h +++ b/lib/config/configitem.h @@ -21,7 +21,7 @@ #define CONFIGITEM_H #include "config/i2-config.h" -#include "config/expressionlist.h" +#include "config/aexpression.h" #include "base/dynamicobject.h" namespace icinga @@ -45,7 +45,7 @@ public: DECLARE_PTR_TYPEDEFS(ConfigItem); ConfigItem(const String& type, const String& name, bool abstract, - const ExpressionList::Ptr& exprl, const std::vector& parents, + const AExpression::Ptr& exprl, const std::vector& parents, const DebugInfo& debuginfo); String GetType(void) const; @@ -54,7 +54,7 @@ public: std::vector GetParents(void) const; - ExpressionList::Ptr GetLinkedExpressionList(void); + AExpression::Ptr GetLinkedExpressionList(void); Dictionary::Ptr GetProperties(void); DynamicObject::Ptr Commit(void); @@ -72,21 +72,21 @@ public: static void DiscardItems(void); private: - ExpressionList::Ptr GetExpressionList(void) const; + AExpression::Ptr GetExpressionList(void) const; String m_Type; /**< The object type. */ String m_Name; /**< The name. */ bool m_Abstract; /**< Whether this is a template. */ bool m_Validated; /** Whether this object has been validated. */ - ExpressionList::Ptr m_ExpressionList; + AExpression::Ptr m_ExpressionList; std::vector m_ParentNames; /**< The names of parent configuration items. */ DebugInfo m_DebugInfo; /**< Debug information. */ - ExpressionList::Ptr m_LinkedExpressionList; + AExpression::Ptr m_LinkedExpressionList; - DynamicObject::Ptr m_Object; + DynamicObject::Ptr m_Object; static boost::mutex m_Mutex; diff --git a/lib/config/configitembuilder.cpp b/lib/config/configitembuilder.cpp index 10e229378..a9f6f77e7 100644 --- a/lib/config/configitembuilder.cpp +++ b/lib/config/configitembuilder.cpp @@ -26,7 +26,7 @@ using namespace icinga; ConfigItemBuilder::ConfigItemBuilder(void) - : m_Abstract(false), m_ExpressionList(make_shared()) + : m_Abstract(false), m_Expressions(make_shared()) { m_DebugInfo.FirstLine = 0; m_DebugInfo.FirstColumn = 0; @@ -35,7 +35,7 @@ ConfigItemBuilder::ConfigItemBuilder(void) } ConfigItemBuilder::ConfigItemBuilder(const DebugInfo& debugInfo) - : m_Abstract(false), m_ExpressionList(make_shared()) + : m_Abstract(false), m_Expressions(make_shared()) { m_DebugInfo = debugInfo; } @@ -60,21 +60,9 @@ void ConfigItemBuilder::AddParent(const String& parent) m_Parents.push_back(parent); } -void ConfigItemBuilder::AddExpression(const Expression& expr) +void ConfigItemBuilder::AddExpression(const AExpression::Ptr& expr) { - m_ExpressionList->AddExpression(expr); -} - -void ConfigItemBuilder::AddExpression(const String& key, ExpressionOperator op, - const Value& value) -{ - Expression expr(key, op, value, m_DebugInfo); - AddExpression(expr); -} - -void ConfigItemBuilder::AddExpressionList(const ExpressionList::Ptr& exprl) -{ - AddExpression("", OperatorExecute, exprl); + m_Expressions->Add(expr); } ConfigItem::Ptr ConfigItemBuilder::Compile(void) @@ -102,16 +90,12 @@ ConfigItem::Ptr ConfigItemBuilder::Compile(void) BOOST_THROW_EXCEPTION(std::invalid_argument("Configuration item '" + m_Name + "' of type '" + m_Type + "' must not inherit from itself.")); } - ExpressionList::Ptr exprl = make_shared(); - - Expression execExpr("", OperatorExecute, m_ExpressionList, m_DebugInfo); - exprl->AddExpression(execExpr); - - Expression typeExpr("__type", OperatorSet, m_Type, m_DebugInfo); - exprl->AddExpression(typeExpr); - - Expression nameExpr("__name", OperatorSet, m_Name, m_DebugInfo); - exprl->AddExpression(nameExpr); + Array::Ptr exprs = make_shared(); + exprs->Add(make_shared(&AExpression::OpDict, m_Expressions, true, m_DebugInfo)); + exprs->Add(make_shared(&AExpression::OpSet, "__type", make_shared(&AExpression::OpLiteral, m_Type, m_DebugInfo), m_DebugInfo)); + exprs->Add(make_shared(&AExpression::OpSet, "__name", make_shared(&AExpression::OpLiteral, m_Name, m_DebugInfo), m_DebugInfo)); + + AExpression::Ptr exprl = make_shared(&AExpression::OpDict, exprs, true, m_DebugInfo); return make_shared(m_Type, m_Name, m_Abstract, exprl, m_Parents, m_DebugInfo); diff --git a/lib/config/configitembuilder.h b/lib/config/configitembuilder.h index a18da56be..8a37359d4 100644 --- a/lib/config/configitembuilder.h +++ b/lib/config/configitembuilder.h @@ -21,8 +21,7 @@ #define CONFIGITEMBUILDER_H #include "config/debuginfo.h" -#include "config/expression.h" -#include "config/expressionlist.h" +#include "config/aexpression.h" #include "config/configitem.h" #include "base/object.h" @@ -49,10 +48,7 @@ public: void AddParent(const String& parent); - void AddExpression(const Expression& expr); - void AddExpression(const String& key, ExpressionOperator op, - const Value& value); - void AddExpressionList(const ExpressionList::Ptr& exprl); + void AddExpression(const AExpression::Ptr& expr); ConfigItem::Ptr Compile(void); @@ -62,7 +58,7 @@ private: bool m_Abstract; /**< Whether the item is abstract. */ std::vector m_Parents; /**< The names of parent configuration items. */ - ExpressionList::Ptr m_ExpressionList; /**< Expressions for this item. */ + Array::Ptr m_Expressions; /**< Expressions for this item. */ DebugInfo m_DebugInfo; /**< Debug information. */ }; diff --git a/lib/config/expression.cpp b/lib/config/expression.cpp deleted file mode 100644 index db501f4cb..000000000 --- a/lib/config/expression.cpp +++ /dev/null @@ -1,204 +0,0 @@ -/****************************************************************************** - * Icinga 2 * - * Copyright (C) 2012-2014 Icinga Development Team (http://www.icinga.org) * - * * - * This program is free software; you can redistribute it and/or * - * modify it under the terms of the GNU General Public License * - * as published by the Free Software Foundation; either version 2 * - * of the License, or (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the Free Software Foundation * - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * - ******************************************************************************/ - -#include "config/expression.h" -#include "config/expressionlist.h" -#include "base/objectlock.h" -#include "base/debug.h" -#include "base/array.h" -#include -#include - -using namespace icinga; - -Expression::Expression(const String& key, ExpressionOperator op, - const Value& value, const DebugInfo& debuginfo) - : m_Key(key), m_Operator(op), m_Value(value), m_DebugInfo(debuginfo) -{ - ASSERT(op != OperatorExecute || value.IsObjectType()); -} - -Value Expression::DeepClone(const Value& value) -{ - if (value.IsObjectType()) { - Array::Ptr array = value; - Array::Ptr result = make_shared(); - - ObjectLock olock(array); - - BOOST_FOREACH(const Value& item, array) { - result->Add(DeepClone(item)); - } - - return result; - } else if (value.IsObjectType()) { - Dictionary::Ptr dict = value; - Dictionary::Ptr result = make_shared(); - - ObjectLock olock(dict); - - BOOST_FOREACH(const Dictionary::Pair& kv, dict) { - result->Set(kv.first, DeepClone(kv.second)); - } - - return result; - } - - return value; -} - -void Expression::Execute(const Dictionary::Ptr& dictionary) const -{ - Value oldValue, newValue; - - ExpressionList::Ptr valueExprl; - Dictionary::Ptr valueDict; - Array::Ptr valueArray; - if (m_Value.IsObjectType()) - valueExprl = m_Value; - - if (m_Value.IsObjectType()) - valueDict = m_Value; - - if (m_Value.IsObjectType()) - valueArray = m_Value; - - newValue = m_Value; - - Dictionary::Ptr dict; - Array::Ptr array; - - switch (m_Operator) { - case OperatorExecute: - if (!valueExprl) - BOOST_THROW_EXCEPTION(std::invalid_argument("Operand for OperatorExecute must be an ExpressionList.")); - - valueExprl->Execute(dictionary); - - return; - - case OperatorSet: - if (valueExprl) { - dict = make_shared(); - valueExprl->Execute(dict); - newValue = dict; - } else { - newValue = DeepClone(newValue); - } - - break; - - case OperatorPlus: - oldValue = dictionary->Get(m_Key); - - if (oldValue.IsObjectType()) - dict = oldValue; - - if (oldValue.IsObjectType()) - array = oldValue; - - if (valueExprl) { - if (!dict) - dict = make_shared(); - - valueExprl->Execute(dict); - - newValue = dict; - } else if (valueDict) { - if (!dict) - dict = make_shared(); - - ObjectLock olock(valueDict); - - String key; - Value value; - BOOST_FOREACH(const Dictionary::Pair& kv, valueDict) { - dict->Set(kv.first, DeepClone(kv.second)); - } - - newValue = dict; - } else if (valueArray) { - if (!array) - array = make_shared(); - - ObjectLock olock(valueArray); - - BOOST_FOREACH(const Value& value, valueArray) { - array->Add(DeepClone(value)); - } - - newValue = array; - } else { - std::ostringstream message; - message << "+= only works for dictionaries and arrays (" - << m_DebugInfo << ")"; - BOOST_THROW_EXCEPTION(std::invalid_argument(message.str())); - } - - break; - - default: - BOOST_THROW_EXCEPTION(std::runtime_error("Not yet implemented.")); - } - - dictionary->Set(m_Key, newValue); -} - -void Expression::ExtractPath(const std::vector& path, const ExpressionList::Ptr& result) const -{ - ASSERT(!path.empty()); - - if (path[0] == m_Key) { - if (!m_Value.IsObjectType()) - BOOST_THROW_EXCEPTION(std::invalid_argument("Specified path does not exist.")); - - ExpressionList::Ptr exprl = m_Value; - - if (path.size() == 1) { - result->AddExpression(Expression("", OperatorExecute, exprl, m_DebugInfo)); - - return; - } - - std::vector sub_path(path.begin() + 1, path.end()); - exprl->ExtractPath(sub_path, result); - } else if (m_Operator == OperatorExecute) { - ExpressionList::Ptr exprl = m_Value; - exprl->ExtractPath(path, result); - } -} - -void Expression::FindDebugInfoPath(const std::vector& path, DebugInfo& result) const -{ - ASSERT(!path.empty()); - - if (path[0] == m_Key) { - if (path.size() == 1) { - result = m_DebugInfo; - } else if (m_Value.IsObjectType()) { - ExpressionList::Ptr exprl = m_Value; - - std::vector sub_path(path.begin() + 1, path.end()); - exprl->FindDebugInfoPath(sub_path, result); - } - } else if (m_Operator == OperatorExecute) { - ExpressionList::Ptr exprl = m_Value; - exprl->FindDebugInfoPath(path, result); - } -} diff --git a/lib/config/expression.h b/lib/config/expression.h deleted file mode 100644 index 7a0a04ce9..000000000 --- a/lib/config/expression.h +++ /dev/null @@ -1,78 +0,0 @@ -/****************************************************************************** - * Icinga 2 * - * Copyright (C) 2012-2014 Icinga Development Team (http://www.icinga.org) * - * * - * This program is free software; you can redistribute it and/or * - * modify it under the terms of the GNU General Public License * - * as published by the Free Software Foundation; either version 2 * - * of the License, or (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the Free Software Foundation * - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * - ******************************************************************************/ - -#ifndef EXPRESSION_H -#define EXPRESSION_H - -#include "config/i2-config.h" -#include "config/debuginfo.h" -#include "base/dictionary.h" -#include -#include -#include - -namespace icinga -{ - -/** - * The operator in a configuration expression. - * - * @ingroup config - */ -enum ExpressionOperator -{ - OperatorExecute, - OperatorSet, - OperatorPlus, - OperatorMinus, - OperatorMultiply, - OperatorDivide -}; - -class ExpressionList; - -/** - * A configuration expression. - * - * @ingroup config - */ -struct I2_CONFIG_API Expression -{ -public: - Expression(const String& key, ExpressionOperator op, const Value& value, - const DebugInfo& debuginfo); - - void Execute(const Dictionary::Ptr& dictionary) const; - - void ExtractPath(const std::vector& path, const shared_ptr& result) const; - - void FindDebugInfoPath(const std::vector& path, DebugInfo& result) const; - -private: - String m_Key; - ExpressionOperator m_Operator; - Value m_Value; - DebugInfo m_DebugInfo; - - static Value DeepClone(const Value& value); -}; - -} - -#endif /* EXPRESSION_H */ diff --git a/lib/config/expressionlist.cpp b/lib/config/expressionlist.cpp deleted file mode 100644 index 0ff844ef9..000000000 --- a/lib/config/expressionlist.cpp +++ /dev/null @@ -1,60 +0,0 @@ -/****************************************************************************** - * Icinga 2 * - * Copyright (C) 2012-2014 Icinga Development Team (http://www.icinga.org) * - * * - * This program is free software; you can redistribute it and/or * - * modify it under the terms of the GNU General Public License * - * as published by the Free Software Foundation; either version 2 * - * of the License, or (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the Free Software Foundation * - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * - ******************************************************************************/ - -#include "config/expressionlist.h" -#include - -using namespace icinga; - -/** - * Adds an expression to an expression list. - * - * @param expression The expression that should be added. - */ -void ExpressionList::AddExpression(const Expression& expression) -{ - m_Expressions.push_back(expression); -} - -/** - * Executes the expression list. - * - * @param dictionary The dictionary that should be manipulated by the - * expressions. - */ -void ExpressionList::Execute(const Dictionary::Ptr& dictionary) const -{ - BOOST_FOREACH(const Expression& expression, m_Expressions) { - expression.Execute(dictionary); - } -} - -void ExpressionList::ExtractPath(const std::vector& path, const ExpressionList::Ptr& result) const -{ - BOOST_FOREACH(const Expression& expression, m_Expressions) { - expression.ExtractPath(path, result); - } -} - -void ExpressionList::FindDebugInfoPath(const std::vector& path, DebugInfo& result) const -{ - BOOST_FOREACH(const Expression& expression, m_Expressions) { - expression.FindDebugInfoPath(path, result); - } -} diff --git a/lib/config/expressionlist.h b/lib/config/expressionlist.h deleted file mode 100644 index 55b1882e0..000000000 --- a/lib/config/expressionlist.h +++ /dev/null @@ -1,55 +0,0 @@ -/****************************************************************************** - * Icinga 2 * - * Copyright (C) 2012-2014 Icinga Development Team (http://www.icinga.org) * - * * - * This program is free software; you can redistribute it and/or * - * modify it under the terms of the GNU General Public License * - * as published by the Free Software Foundation; either version 2 * - * of the License, or (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the Free Software Foundation * - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. * - ******************************************************************************/ - -#ifndef EXPRESSIONLIST_H -#define EXPRESSIONLIST_H - -#include "config/i2-config.h" -#include "config/expression.h" -#include "base/dictionary.h" -#include - -namespace icinga -{ - -/** - * A list of configuration expressions. - * - * @ingroup config - */ -class I2_CONFIG_API ExpressionList : public Object -{ -public: - DECLARE_PTR_TYPEDEFS(ExpressionList); - - void AddExpression(const Expression& expression); - - void Execute(const Dictionary::Ptr& dictionary) const; - - void ExtractPath(const std::vector& path, const ExpressionList::Ptr& result) const; - - void FindDebugInfoPath(const std::vector& path, DebugInfo& result) const; - -private: - std::vector m_Expressions; -}; - -} - -#endif /* EXPRESSIONLIST_H */ diff --git a/lib/icinga/host-apply.cpp b/lib/icinga/host-apply.cpp index 46b1beb48..8ffe602ac 100644 --- a/lib/icinga/host-apply.cpp +++ b/lib/icinga/host-apply.cpp @@ -77,7 +77,7 @@ void Host::EvaluateApplyRules(const std::vector& rules) ConfigItemBuilder::Ptr builder = make_shared(rule.GetDebugInfo()); builder->SetType("Service"); builder->SetName(name); - builder->AddExpression("host", OperatorSet, host->GetName()); + builder->AddExpression(make_shared(&AExpression::OpSet, "host", make_shared(&AExpression::OpLiteral, host->GetName(), rule.GetDebugInfo()), rule.GetDebugInfo())); builder->AddParent(rule.GetTemplate()); diff --git a/lib/icinga/host.cpp b/lib/icinga/host.cpp index 23a5c3469..42d5d780d 100644 --- a/lib/icinga/host.cpp +++ b/lib/icinga/host.cpp @@ -113,7 +113,7 @@ void Host::UpdateSlaveServices(void) path.push_back("services"); path.push_back(kv.first); - ExpressionList::Ptr exprl; + AExpression::Ptr exprl; { ObjectLock ilock(item); @@ -130,9 +130,9 @@ void Host::UpdateSlaveServices(void) ConfigItemBuilder::Ptr builder = make_shared(di); builder->SetType("Service"); builder->SetName(name); - builder->AddExpression("host", OperatorSet, GetName()); - builder->AddExpression("display_name", OperatorSet, kv.first); - builder->AddExpression("short_name", OperatorSet, kv.first); + builder->AddExpression(make_shared(&AExpression::OpSet, "host", make_shared(&AExpression::OpLiteral, GetName(), di), di)); + builder->AddExpression(make_shared(&AExpression::OpSet, "display_name", make_shared(&AExpression::OpLiteral, kv.first, di), di)); + builder->AddExpression(make_shared(&AExpression::OpSet, "short_name", make_shared(&AExpression::OpLiteral, kv.first, di), di)); if (!kv.second.IsObjectType()) BOOST_THROW_EXCEPTION(std::invalid_argument("Service description must be either a string or a dictionary.")); @@ -150,10 +150,10 @@ void Host::UpdateSlaveServices(void) } /* Clone attributes from the service expression list. */ - ExpressionList::Ptr svc_exprl = make_shared(); + Array::Ptr svc_exprl = make_shared(); exprl->ExtractPath(path, svc_exprl); - builder->AddExpressionList(svc_exprl); + builder->AddExpression(make_shared(&AExpression::OpDict, svc_exprl, true, di)); ConfigItem::Ptr serviceItem = builder->Compile(); serviceItem->Register(); diff --git a/lib/icinga/service-dependency.cpp b/lib/icinga/service-dependency.cpp index be202002c..913950887 100644 --- a/lib/icinga/service-dependency.cpp +++ b/lib/icinga/service-dependency.cpp @@ -193,7 +193,7 @@ void Service::UpdateSlaveDependencies(void) path.push_back("dependencies"); path.push_back(kv.first); - ExpressionList::Ptr exprl; + AExpression::Ptr exprl; { ObjectLock ilock(item); @@ -210,8 +210,8 @@ void Service::UpdateSlaveDependencies(void) ConfigItemBuilder::Ptr builder = make_shared(di); builder->SetType("Dependency"); builder->SetName(name); - builder->AddExpression("child_host", OperatorSet, GetHost()->GetName()); - builder->AddExpression("child_service", OperatorSet, GetShortName()); + builder->AddExpression(make_shared(&AExpression::OpSet, "child_host", make_shared(&AExpression::OpLiteral, GetHost()->GetName(), di), di)); + builder->AddExpression(make_shared(&AExpression::OpSet, "child_service", make_shared(&AExpression::OpLiteral, GetShortName(), di), di)); Dictionary::Ptr dependency = kv.second; @@ -226,10 +226,10 @@ void Service::UpdateSlaveDependencies(void) } /* Clone attributes from the scheduled downtime expression list. */ - ExpressionList::Ptr sd_exprl = make_shared(); + Array::Ptr sd_exprl = make_shared(); exprl->ExtractPath(path, sd_exprl); - builder->AddExpressionList(sd_exprl); + builder->AddExpression(make_shared(&AExpression::OpDict, sd_exprl, true, di)); ConfigItem::Ptr dependencyItem = builder->Compile(); dependencyItem->Register(); diff --git a/lib/icinga/service-downtime.cpp b/lib/icinga/service-downtime.cpp index 0913ee9a9..748b61858 100644 --- a/lib/icinga/service-downtime.cpp +++ b/lib/icinga/service-downtime.cpp @@ -342,7 +342,7 @@ void Service::UpdateSlaveScheduledDowntimes(void) path.push_back("scheduled_downtimes"); path.push_back(kv.first); - ExpressionList::Ptr exprl; + AExpression::Ptr exprl; { ObjectLock ilock(item); @@ -359,8 +359,8 @@ void Service::UpdateSlaveScheduledDowntimes(void) ConfigItemBuilder::Ptr builder = make_shared(di); builder->SetType("ScheduledDowntime"); builder->SetName(name); - builder->AddExpression("host", OperatorSet, GetHost()->GetName()); - builder->AddExpression("service", OperatorSet, GetShortName()); + builder->AddExpression(make_shared(&AExpression::OpSet, "host", make_shared(&AExpression::OpLiteral, GetHost()->GetName(), di), di)); + builder->AddExpression(make_shared(&AExpression::OpSet, "service", make_shared(&AExpression::OpLiteral, GetShortName(), di), di)); Dictionary::Ptr scheduledDowntime = kv.second; @@ -375,10 +375,10 @@ void Service::UpdateSlaveScheduledDowntimes(void) } /* Clone attributes from the scheduled downtime expression list. */ - ExpressionList::Ptr sd_exprl = make_shared(); + Array::Ptr sd_exprl = make_shared(); exprl->ExtractPath(path, sd_exprl); - builder->AddExpressionList(sd_exprl); + builder->AddExpression(make_shared(&AExpression::OpDict, sd_exprl, true, di)); ConfigItem::Ptr scheduledDowntimeItem = builder->Compile(); scheduledDowntimeItem->Register(); diff --git a/lib/icinga/service-notification.cpp b/lib/icinga/service-notification.cpp index 5b5964b4e..344e33c0c 100644 --- a/lib/icinga/service-notification.cpp +++ b/lib/icinga/service-notification.cpp @@ -121,7 +121,7 @@ void Service::UpdateSlaveNotifications(void) path.push_back("notifications"); path.push_back(kv.first); - ExpressionList::Ptr exprl; + AExpression::Ptr exprl; { ObjectLock ilock(item); @@ -138,8 +138,8 @@ void Service::UpdateSlaveNotifications(void) ConfigItemBuilder::Ptr builder = make_shared(di); builder->SetType("Notification"); builder->SetName(name); - builder->AddExpression("host", OperatorSet, GetHost()->GetName()); - builder->AddExpression("service", OperatorSet, GetShortName()); + builder->AddExpression(make_shared(&AExpression::OpSet, "host", make_shared(&AExpression::OpLiteral, GetHost()->GetName(), di), di)); + builder->AddExpression(make_shared(&AExpression::OpSet, "service", make_shared(&AExpression::OpLiteral, GetShortName(), di), di)); Dictionary::Ptr notification = kv.second; @@ -154,10 +154,10 @@ void Service::UpdateSlaveNotifications(void) } /* Clone attributes from the notification expression list. */ - ExpressionList::Ptr nfc_exprl = make_shared(); + Array::Ptr nfc_exprl = make_shared(); exprl->ExtractPath(path, nfc_exprl); - builder->AddExpressionList(nfc_exprl); + builder->AddExpression(make_shared(&AExpression::OpDict, nfc_exprl, true, di)); ConfigItem::Ptr notificationItem = builder->Compile(); notificationItem->Register(); diff --git a/lib/methods/CMakeLists.txt b/lib/methods/CMakeLists.txt index 49f11fe80..6f271b292 100644 --- a/lib/methods/CMakeLists.txt +++ b/lib/methods/CMakeLists.txt @@ -18,7 +18,7 @@ add_library(methods SHARED castfuncs.cpp icingachecktask.cpp nullchecktask.cpp nulleventtask.cpp pluginchecktask.cpp plugineventtask.cpp pluginnotificationtask.cpp - randomchecktask.cpp timeperiodtask.cpp utilityfuncs.cpp + randomchecktask.cpp timeperiodtask.cpp ) target_link_libraries(methods ${Boost_LIBRARIES} base config icinga)