diff --git a/doc/4.1-configuration-syntax.md b/doc/4.1-configuration-syntax.md index f602b5cd8..56b6b5ff6 100644 --- a/doc/4.1-configuration-syntax.md +++ b/doc/4.1-configuration-syntax.md @@ -24,8 +24,8 @@ define objects the `object` keyword is used: Each object is uniquely identified by its type (`Host`) and name (`host1.example.org`). Objects can contain a comma-separated list of -property declarations. The following data types are available for -property values: +property declarations. Instead of commas semi-colons may also be used. +The following data types are available for property values: ### Expressions @@ -52,6 +52,9 @@ Example: Supported suffixes include ms (milliseconds), s (seconds), m (minutes), h (hours) and d (days). +Duration literals are converted to seconds by the config parser and +are treated like numeric literals. + #### String Literals A string. @@ -170,7 +173,7 @@ in | "foo" in [ "foo", "bar" ] (true) | Element contained in !in | "foo" !in [ "bar", "baz" ] (true) | Element not contained in array () | (3 + 3) * 5 | Groups sub-expressions -Constants may be used in constant expressions: +Constants may be used in expressions: const MyCheckInterval = 10m @@ -200,6 +203,7 @@ intersection(array, array, ...) | Returns an array containing all unique element string(value) | Converts the value to a string. number(value) | Converts the value to a number. bool(value) | Converts to value to a bool. +log(value) | Writes a message to the log. Non-string values are converted to a JSON string. ### Dictionary Operators @@ -222,65 +226,67 @@ In this example a has the value 7 after both instructions are executed. #### Operator += -Modifies a dictionary or array by adding new elements to it. - -Example: +The += operator is a shortcut. The following expression: { a = [ "hello" ], a += [ "world" ] } -In this example a contains both `"hello"` and `"world"`. This currently -only works for dictionaries and arrays. +is equivalent to: - + { + a = 300, + a = a / 5 + } ### Indexer @@ -350,13 +356,11 @@ override its value by setting it explicitely to `null`. custom = null } - The same method applies for disabling services defined in the inline `services` dictionary by explicitly overriding their value with `null`. services["ping6"] = null - ### Constants Global constants can be set using the `const` keyword: 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/base/array.cpp b/lib/base/array.cpp index 102d679e4..9d236954b 100644 --- a/lib/base/array.cpp +++ b/lib/base/array.cpp @@ -157,6 +157,14 @@ void Array::Resize(size_t new_size) m_Data.resize(new_size); } +void Array::Clear(void) +{ + ASSERT(!OwnsLock()); + ObjectLock olock(this); + + m_Data.clear(); +} + void Array::CopyTo(const Array::Ptr& dest) const { ASSERT(!OwnsLock()); diff --git a/lib/base/array.h b/lib/base/array.h index 744c790ca..0e53fbf78 100644 --- a/lib/base/array.h +++ b/lib/base/array.h @@ -56,6 +56,7 @@ public: void Remove(Iterator it); void Resize(size_t new_size); + void Clear(void); void CopyTo(const Array::Ptr& dest) const; Array::Ptr ShallowClone(void) const; diff --git a/lib/base/exception.cpp b/lib/base/exception.cpp index 79f082cf5..fd142d734 100644 --- a/lib/base/exception.cpp +++ b/lib/base/exception.cpp @@ -38,28 +38,31 @@ void __cxa_throw(void *obj, void *pvtinfo, void (*dest)(void *)) void *thrown_ptr = obj; const std::type_info *tinfo = static_cast(pvtinfo); const std::type_info *boost_exc = &typeid(boost::exception); + const std::type_info *user_exc = &typeid(user_error); /* Check if the exception is a pointer type. */ if (tinfo->__is_pointer_p()) thrown_ptr = *(void **)thrown_ptr; + + if (!user_exc->__do_catch(tinfo, &thrown_ptr, 1)) { #endif /* __APPLE__ */ + StackTrace stack; + SetLastExceptionStack(stack); - StackTrace stack; - SetLastExceptionStack(stack); - - ContextTrace context; - SetLastExceptionContext(context); + ContextTrace context; + SetLastExceptionContext(context); #ifndef __APPLE__ - /* Check if thrown_ptr inherits from boost::exception. */ - if (boost_exc->__do_catch(tinfo, &thrown_ptr, 1)) { - boost::exception *ex = (boost::exception *)thrown_ptr; + /* Check if thrown_ptr inherits from boost::exception. */ + if (boost_exc->__do_catch(tinfo, &thrown_ptr, 1)) { + boost::exception *ex = (boost::exception *)thrown_ptr; - if (boost::get_error_info(*ex) == NULL) - *ex << StackTraceErrorInfo(stack); + if (boost::get_error_info(*ex) == NULL) + *ex << StackTraceErrorInfo(stack); - if (boost::get_error_info(*ex) == NULL) - *ex << ContextTraceErrorInfo(context); + if (boost::get_error_info(*ex) == NULL) + *ex << ContextTraceErrorInfo(context); + } } #endif /* __APPLE__ */ diff --git a/lib/base/exception.h b/lib/base/exception.h index 3cec78b18..872f69fd4 100644 --- a/lib/base/exception.h +++ b/lib/base/exception.h @@ -39,6 +39,8 @@ namespace icinga { +class I2_BASE_API user_error : virtual public std::exception, virtual public boost::exception { }; + I2_BASE_API StackTrace *GetLastExceptionStack(void); I2_BASE_API void SetLastExceptionStack(const StackTrace& trace); @@ -55,22 +57,24 @@ String DiagnosticInformation(const T& ex, StackTrace *stack = NULL, ContextTrace result << boost::diagnostic_information(ex); - if (boost::get_error_info(ex) == NULL) { - result << std::endl; + if (dynamic_cast(&ex) == NULL) { + if (boost::get_error_info(ex) == NULL) { + result << std::endl; - if (stack) - result << *stack; - else - result << *GetLastExceptionStack(); - } + if (stack) + result << *stack; + else + result << *GetLastExceptionStack(); + } - if (boost::get_error_info(ex) == NULL) { - result << std::endl; + if (boost::get_error_info(ex) == NULL) { + result << std::endl; - if (context) - result << *context; - else - result << *GetLastExceptionContext(); + if (context) + result << *context; + else + result << *GetLastExceptionContext(); + } } return result.str(); diff --git a/lib/methods/utilityfuncs.cpp b/lib/base/scriptutils.cpp similarity index 76% rename from lib/methods/utilityfuncs.cpp rename to lib/base/scriptutils.cpp index 4a5ae82e5..0828f75ee 100644 --- a/lib/methods/utilityfuncs.cpp +++ b/lib/base/scriptutils.cpp @@ -17,32 +17,37 @@ * 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 "base/application.h" #include #include #include 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(len, &ScriptUtils::Len); +REGISTER_SCRIPTFUNCTION(union, &ScriptUtils::Union); +REGISTER_SCRIPTFUNCTION(intersection, &ScriptUtils::Intersection); +REGISTER_SCRIPTFUNCTION(log, &ScriptUtils::Log); +REGISTER_SCRIPTFUNCTION(exit, &ScriptUtils::Exit); -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; @@ -55,7 +60,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; @@ -75,7 +80,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(); @@ -98,3 +103,16 @@ Array::Ptr UtilityFuncs::Intersection(const std::vector& arguments) return result; } + +void ScriptUtils::Log(const Value& message) +{ + if (message.IsString()) + ::Log(LogInformation, "config", message); + else + ::Log(LogInformation, "config", JsonSerialize(message)); +} + +void ScriptUtils::Exit(int code) +{ + exit(code); +} 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 4dbbb57f4..043b12cbb 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,20 +28,22 @@ 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 Value& message); + static void Exit(int code); private: - UtilityFuncs(void); + ScriptUtils(void); }; } -#endif /* UTILITYFUNCS_H */ +#endif /* SCRIPTUTILS_H */ diff --git a/lib/base/stacktrace.cpp b/lib/base/stacktrace.cpp index 71ab6772c..182774ea3 100644 --- a/lib/base/stacktrace.cpp +++ b/lib/base/stacktrace.cpp @@ -22,7 +22,6 @@ #include "base/utility.h" #include "base/convert.h" #include "base/application.h" -#include #ifdef HAVE_BACKTRACE_SYMBOLS # include @@ -100,43 +99,6 @@ void StackTrace::Initialize(void) #endif /* _WIN32 */ } -/** - * Looks up source file name and line number information for the specified - * ELF executable and RVA. - * - * @param exe The ELF file. - * @param rva The RVA. - * @returns Source file and line number. - */ -String StackTrace::Addr2Line(const String& exe, uintptr_t rva) -{ -#ifndef _WIN32 - std::ostringstream msgbuf; - msgbuf << "addr2line -s -e " << Application::GetExePath(exe) << " " << std::hex << rva << " 2>/dev/null"; - - String args = msgbuf.str(); - - FILE *fp = popen(args.CStr(), "r"); - - if (!fp) - return "RVA: " + Convert::ToString(rva); - - char buffer[512] = {}; - fgets(buffer, sizeof(buffer), fp); - fclose(fp); - - String line = buffer; - boost::algorithm::trim_right(line); - - if (line.GetLength() == 0) - return "RVA: " + Convert::ToString(rva); - - return line; -#else /* _WIN32 */ - return String(); -#endif /* _WIN32 */ -} - /** * Prints a stacktrace to the specified stream. * @@ -176,15 +138,7 @@ void StackTrace::Print(std::ostream& fp, int ignoreFrames) const path = path.SubStr(slashp + 1); message = path + ": " + sym_demangled + " (" + String(sym_end); - -#ifdef HAVE_DLADDR - Dl_info dli; - - if (dladdr(m_Frames[i], &dli) > 0) { - uintptr_t rva = reinterpret_cast(m_Frames[i]) - reinterpret_cast(dli.dli_fbase); - message += " (" + Addr2Line(dli.dli_fname, rva) + ")"; - } -#endif /* HAVE_DLADDR */ + message += " (" + Utility::GetSymbolSource(m_Frames[i]) + ")"; } } diff --git a/lib/base/stacktrace.h b/lib/base/stacktrace.h index a26228383..cd6828ff8 100644 --- a/lib/base/stacktrace.h +++ b/lib/base/stacktrace.h @@ -50,7 +50,6 @@ private: static boost::once_flag m_OnceFlag; static void Initialize(void); - static String Addr2Line(const String& exe, uintptr_t rva); }; I2_BASE_API std::ostream& operator<<(std::ostream& stream, const StackTrace& trace); diff --git a/lib/base/utility.cpp b/lib/base/utility.cpp index 44c5c1f4b..189f77333 100644 --- a/lib/base/utility.cpp +++ b/lib/base/utility.cpp @@ -28,6 +28,7 @@ #include #include #include +#include #ifdef __FreeBSD__ # include @@ -81,6 +82,69 @@ String Utility::GetTypeName(const std::type_info& ti) return DemangleSymbolName(ti.name()); } +/** + * Looks up source file name and line number information for the specified + * ELF executable and RVA. + * + * @param exe The ELF file. + * @param rva The RVA. + * @returns Source file and line number. + */ +String Utility::Addr2Line(const String& exe, uintptr_t rva) +{ +#ifndef _WIN32 + std::ostringstream msgbuf; + msgbuf << "addr2line -s -e " << Application::GetExePath(exe) << " " << std::hex << rva << " 2>/dev/null"; + + String args = msgbuf.str(); + + FILE *fp = popen(args.CStr(), "r"); + + if (!fp) + return "RVA: " + Convert::ToString(rva); + + char buffer[512] = {}; + fgets(buffer, sizeof(buffer), fp); + fclose(fp); + + String line = buffer; + boost::algorithm::trim_right(line); + + if (line.GetLength() == 0) + return "RVA: " + Convert::ToString(rva); + + return line; +#else /* _WIN32 */ + return String(); +#endif /* _WIN32 */ +} + +String Utility::GetSymbolName(const void *addr) +{ +#ifdef HAVE_DLADDR + Dl_info dli; + + if (dladdr(addr, &dli) > 0) + return dli.dli_sname; +#endif /* HAVE_DLADDR */ + + return ""; +} + +String Utility::GetSymbolSource(const void *addr) +{ +#ifdef HAVE_DLADDR + Dl_info dli; + + if (dladdr(addr, &dli) > 0) { + uintptr_t rva = reinterpret_cast(addr) - reinterpret_cast(dli.dli_fbase); + return Addr2Line(dli.dli_fname, rva); + } +#endif /* HAVE_DLADDR */ + + return ""; +} + /** * Performs wildcard pattern matching. * diff --git a/lib/base/utility.h b/lib/base/utility.h index 4a384acde..dbea5a6f2 100644 --- a/lib/base/utility.h +++ b/lib/base/utility.h @@ -59,6 +59,9 @@ class I2_BASE_API Utility public: static String DemangleSymbolName(const String& sym); static String GetTypeName(const std::type_info& ti); + static String Addr2Line(const String& exe, uintptr_t rva); + static String GetSymbolName(const void *addr); + static String GetSymbolSource(const void *addr); static bool Match(const String& pattern, const String& text); diff --git a/lib/base/value-operators.cpp b/lib/base/value-operators.cpp index e5bccd933..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() + "'")); @@ -440,6 +449,8 @@ 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.GetTypeName() != rhs.GetTypeName()) + return lhs.GetTypeName() < rhs.GetTypeName(); else BOOST_THROW_EXCEPTION(std::invalid_argument("Operator < cannot be applied to values of type '" + lhs.GetTypeName() + "' and '" + rhs.GetTypeName() + "'")); } @@ -470,6 +481,8 @@ 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.GetTypeName() != rhs.GetTypeName()) + return lhs.GetTypeName() > rhs.GetTypeName(); else BOOST_THROW_EXCEPTION(std::invalid_argument("Operator > cannot be applied to values of type '" + lhs.GetTypeName() + "' and '" + rhs.GetTypeName() + "'")); } @@ -500,6 +513,8 @@ 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.GetTypeName() != rhs.GetTypeName()) + return lhs.GetTypeName() <= rhs.GetTypeName(); else BOOST_THROW_EXCEPTION(std::invalid_argument("Operator <= cannot be applied to values of type '" + lhs.GetTypeName() + "' and '" + rhs.GetTypeName() + "'")); } @@ -530,6 +545,8 @@ 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.GetTypeName() != rhs.GetTypeName()) + return lhs.GetTypeName() >= rhs.GetTypeName(); 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 deb99ac26..05f9990b0 100644 --- a/lib/config/CMakeLists.txt +++ b/lib/config/CMakeLists.txt @@ -27,10 +27,10 @@ mkembedconfig_target(base-type.conf base-type.cpp) include_directories(${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}) add_library(config SHARED - aexpression.cpp applyrule.cpp avalue.cpp base-type.conf base-type.cpp + 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 e96cd8c53..3933efd92 100644 --- a/lib/config/aexpression.cpp +++ b/lib/config/aexpression.cpp @@ -18,135 +18,449 @@ ******************************************************************************/ #include "config/aexpression.h" +#include "config/configerror.h" #include "base/array.h" #include "base/serializer.h" #include "base/context.h" #include "base/scriptfunction.h" +#include "base/scriptvariable.h" +#include "base/utility.h" +#include "base/objectlock.h" #include +#include +#include using namespace icinga; -AExpression::AExpression(AOperator op, const AValue& operand1, const DebugInfo& di) - : m_Operator(op), m_Operand1(operand1), m_DebugInfo(di) -{ - ASSERT(op == AEReturn); -} +AExpression::AExpression(OpCallback op, const Value& operand1, const DebugInfo& di) + : m_Operator(op), m_Operand1(operand1), m_Operand2(), m_DebugInfo(di) +{ } -AExpression::AExpression(AOperator op, const AValue& operand1, const AValue& operand2, const DebugInfo& di) +AExpression::AExpression(OpCallback op, const Value& operand1, const Value& 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 || - op == AEEqual || op == AENotEqual || op == AEIn || op == AENotIn || - op == AELogicalAnd || op == AELogicalOr || op == AEFunctionCall); -} +{ } Value AExpression::Evaluate(const Dictionary::Ptr& locals) const { - Value left, right; - Array::Ptr arr, arr2; - bool found; - String funcName; - ScriptFunction::Ptr func; - std::vector arguments; - - 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; - case AENegate: - return ~(long)left; - case AEAdd: - return left + right; - case AESubtract: - return left - right; - case AEMultiply: - return left * right; - case AEDivide: - return left / right; - case AEBinaryAnd: - return left & right; - case AEBinaryOr: - return left | right; - case AEShiftLeft: - return left << right; - case AEShiftRight: - return left >> right; - case AEEqual: - return left == right; - case AENotEqual: - return left != right; - case AELessThan: - return left < right; - case AEGreaterThan: - return left > right; - case AELessThanOrEqual: - return left <= right; - case AEGreaterThanOrEqual: - return left >= right; - case AEIn: - if (!right.IsObjectType()) - 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: - if (!right.IsObjectType()) - 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 AELogicalAnd: - return left.ToBool() && right.ToBool(); - case AELogicalOr: - return left.ToBool() || right.ToBool(); - case AEFunctionCall: - funcName = left; - func = ScriptFunctionRegistry::GetInstance()->GetItem(funcName); - - if (!func) - BOOST_THROW_EXCEPTION(std::invalid_argument("Function '" + funcName + "' does not exist.")); - - arr = right; - BOOST_FOREACH(const AExpression::Ptr& aexpr, arr) { - arguments.push_back(aexpr->Evaluate(locals)); - } - - return func->Invoke(arguments); - case AEArray: - arr = left; - arr2 = make_shared(); - - if (arr) { - BOOST_FOREACH(const AExpression::Ptr& aexpr, arr) { - arr2->Add(aexpr->Evaluate(locals)); - } - } - - return arr2; - default: - ASSERT(!"Invalid operator."); + try { + return m_Operator(this, locals); + } catch (const std::exception& ex) { + if (boost::get_error_info(ex)) + throw; + else + 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; + ObjectLock olock(exprl); + BOOST_FOREACH(const AExpression::Ptr& expr, exprl) { + expr->ExtractPath(path, result); + } + } else if ((m_Operator == &AExpression::OpSet || m_Operator == &AExpression::OpSetPlus || + m_Operator == &AExpression::OpSetMinus || m_Operator == &AExpression::OpSetMultiply || + m_Operator == &AExpression::OpSetDivide) && path[0] == m_Operand1) { + AExpression::Ptr exprl = m_Operand2; + + if (path.size() == 1) { + if (m_Operator == &AExpression::OpSet) + result->Clear(); + + if (exprl->m_Operator != &AExpression::OpDict) + BOOST_THROW_EXCEPTION(ConfigError("The '" + path[0] + "' attribute must be a dictionary.") << errinfo_debuginfo(m_DebugInfo)); + + Array::Ptr subexprl = exprl->m_Operand1; + ObjectLock olock(subexprl); + BOOST_FOREACH(const AExpression::Ptr& expr, subexprl) { + result->Add(expr); + } + + return; + } + + std::vector sub_path(path.begin() + 1, path.end()); + exprl->ExtractPath(sub_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; + ObjectLock olock(exprl); + BOOST_FOREACH(const AExpression::Ptr& expr, exprl) { + expr->FindDebugInfoPath(path, result); + } + } else if ((m_Operator == &AExpression::OpSet || m_Operator == &AExpression::OpSetPlus || + m_Operator == &AExpression::OpSetMinus || m_Operator == &AExpression::OpSetMultiply || + m_Operator == &AExpression::OpSetDivide) && 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); + } + } +} + +void AExpression::MakeInline(void) +{ + if (m_Operator == &AExpression::OpDict) + m_Operand2 = true; +} + +void AExpression::DumpOperand(std::ostream& stream, const Value& operand, int indent) { + if (operand.IsObjectType()) { + Array::Ptr arr = operand; + stream << String(indent, ' ') << "Array:\n"; + ObjectLock olock(arr); + BOOST_FOREACH(const Value& elem, arr) { + DumpOperand(stream, elem, indent + 1); + } + } else if (operand.IsObjectType()) { + AExpression::Ptr left = operand; + left->Dump(stream, indent); + } else { + stream << String(indent, ' ') << JsonSerialize(operand) << "\n"; + } +} + +void AExpression::Dump(std::ostream& stream, int indent) const +{ + String sym = Utility::GetSymbolName(reinterpret_cast(m_Operator)); + stream << String(indent, ' ') << "op: " << Utility::DemangleSymbolName(sym) << "\n"; + stream << String(indent, ' ') << "left:\n"; + DumpOperand(stream, m_Operand1, indent + 1); + + stream << String(indent, ' ') << "right:\n"; + DumpOperand(stream, m_Operand2, indent + 1); +} + +void AExpression::Dump(void) const +{ + Dump(std::cerr); +} + +Value AExpression::EvaluateOperand1(const Dictionary::Ptr& locals) const +{ + return static_cast(m_Operand1)->Evaluate(locals); +} + +Value AExpression::EvaluateOperand2(const Dictionary::Ptr& locals) const +{ + return static_cast(m_Operand2)->Evaluate(locals); +} + +Value AExpression::OpLiteral(const AExpression *expr, const Dictionary::Ptr& locals) +{ + return expr->m_Operand1; +} + +Value AExpression::OpVariable(const AExpression *expr, const Dictionary::Ptr& locals) +{ + Dictionary::Ptr scope = locals; + + while (scope) { + if (scope->Contains(expr->m_Operand1)) + return scope->Get(expr->m_Operand1); + + scope = scope->Get("__parent"); + } + + return ScriptVariable::Get(expr->m_Operand1); +} + +Value AExpression::OpNegate(const AExpression *expr, const Dictionary::Ptr& locals) +{ + return ~(long)expr->EvaluateOperand1(locals); +} + +Value AExpression::OpAdd(const AExpression *expr, const Dictionary::Ptr& locals) +{ + return expr->EvaluateOperand1(locals) + expr->EvaluateOperand2(locals); +} + +Value AExpression::OpSubtract(const AExpression *expr, const Dictionary::Ptr& locals) +{ + return expr->EvaluateOperand1(locals) - expr->EvaluateOperand2(locals); +} + +Value AExpression::OpMultiply(const AExpression *expr, const Dictionary::Ptr& locals) +{ + return expr->EvaluateOperand1(locals) * expr->EvaluateOperand2(locals); +} + +Value AExpression::OpDivide(const AExpression *expr, const Dictionary::Ptr& locals) +{ + return expr->EvaluateOperand1(locals) / expr->EvaluateOperand2(locals); +} + +Value AExpression::OpBinaryAnd(const AExpression *expr, const Dictionary::Ptr& locals) +{ + return expr->EvaluateOperand1(locals) & expr->EvaluateOperand2(locals); +} + +Value AExpression::OpBinaryOr(const AExpression *expr, const Dictionary::Ptr& locals) +{ + return expr->EvaluateOperand1(locals) | expr->EvaluateOperand2(locals); +} + +Value AExpression::OpShiftLeft(const AExpression *expr, const Dictionary::Ptr& locals) +{ + return expr->EvaluateOperand1(locals) << expr->EvaluateOperand2(locals); +} + +Value AExpression::OpShiftRight(const AExpression *expr, const Dictionary::Ptr& locals) +{ + return expr->EvaluateOperand1(locals) >> expr->EvaluateOperand2(locals); +} + +Value AExpression::OpEqual(const AExpression *expr, const Dictionary::Ptr& locals) +{ + return expr->EvaluateOperand1(locals) == expr->EvaluateOperand2(locals); +} + +Value AExpression::OpNotEqual(const AExpression *expr, const Dictionary::Ptr& locals) +{ + return expr->EvaluateOperand1(locals) != expr->EvaluateOperand2(locals); +} + +Value AExpression::OpLessThan(const AExpression *expr, const Dictionary::Ptr& locals) +{ + return expr->EvaluateOperand1(locals) < expr->EvaluateOperand2(locals); +} + +Value AExpression::OpGreaterThan(const AExpression *expr, const Dictionary::Ptr& locals) +{ + return expr->EvaluateOperand1(locals) > expr->EvaluateOperand2(locals); +} + +Value AExpression::OpLessThanOrEqual(const AExpression *expr, const Dictionary::Ptr& locals) +{ + return expr->EvaluateOperand1(locals) <= expr->EvaluateOperand2(locals); +} + +Value AExpression::OpGreaterThanOrEqual(const AExpression *expr, const Dictionary::Ptr& locals) +{ + return expr->EvaluateOperand1(locals) >= expr->EvaluateOperand2(locals); +} + +Value AExpression::OpIn(const AExpression *expr, const Dictionary::Ptr& locals) +{ + Value right = expr->EvaluateOperand2(locals); + + if (!right.IsObjectType()) + BOOST_THROW_EXCEPTION(ConfigError("Invalid right side argument for 'in' operator: " + JsonSerialize(right))); + + Value left = expr->EvaluateOperand1(locals); + + Array::Ptr arr = right; + bool found = false; + ObjectLock olock(arr); + BOOST_FOREACH(const Value& value, arr) { + if (value == left) { + found = true; + break; + } + } + + return found; +} + +Value AExpression::OpNotIn(const AExpression *expr, const Dictionary::Ptr& locals) +{ + return !OpIn(expr, locals); +} + +Value AExpression::OpLogicalAnd(const AExpression *expr, const Dictionary::Ptr& locals) +{ + return expr->EvaluateOperand1(locals).ToBool() && expr->EvaluateOperand2(locals).ToBool(); +} + +Value AExpression::OpLogicalOr(const AExpression *expr, const Dictionary::Ptr& locals) +{ + return expr->EvaluateOperand1(locals).ToBool() || expr->EvaluateOperand2(locals).ToBool(); +} + +Value AExpression::OpFunctionCall(const AExpression *expr, const Dictionary::Ptr& locals) +{ + String funcName = expr->m_Operand1; + ScriptFunction::Ptr func = ScriptFunctionRegistry::GetInstance()->GetItem(funcName); + + if (!func) + BOOST_THROW_EXCEPTION(ConfigError("Function '" + funcName + "' does not exist.")); + + Array::Ptr arr = expr->EvaluateOperand2(locals); + std::vector arguments; + ObjectLock olock(arr); + BOOST_FOREACH(const AExpression::Ptr& aexpr, arr) { + arguments.push_back(aexpr->Evaluate(locals)); + } + + return func->Invoke(arguments); +} + +Value AExpression::OpArray(const AExpression *expr, const Dictionary::Ptr& locals) +{ + Array::Ptr arr = expr->m_Operand1; + Array::Ptr result = make_shared(); + + if (arr) { + ObjectLock olock(arr); + BOOST_FOREACH(const AExpression::Ptr& aexpr, arr) { + result->Add(aexpr->Evaluate(locals)); + } + } + + return result; +} + +Value AExpression::OpDict(const AExpression *expr, const Dictionary::Ptr& locals) +{ + Array::Ptr arr = expr->m_Operand1; + bool in_place = expr->m_Operand2; + Dictionary::Ptr result = make_shared(); + + result->Set("__parent", locals); + + if (arr) { + ObjectLock olock(arr); + BOOST_FOREACH(const AExpression::Ptr& aexpr, arr) { + aexpr->Evaluate(in_place ? locals : result); + } + } + + result->Remove("__parent"); + + return result; +} + +Value AExpression::OpSet(const AExpression *expr, const Dictionary::Ptr& locals) +{ + Value right = expr->EvaluateOperand2(locals); + locals->Set(expr->m_Operand1, right); + return right; +} + +Value AExpression::OpSetPlus(const AExpression *expr, const Dictionary::Ptr& locals) +{ + Value left = locals->Get(expr->m_Operand1); + AExpression::Ptr exp_right = expr->m_Operand2; + Dictionary::Ptr xlocals = locals; + + if (exp_right->m_Operator == &AExpression::OpDict) { + xlocals = left; + + if (!xlocals) + xlocals = make_shared(); + + xlocals->Set("__parent", locals); + } + + Value result = left + expr->EvaluateOperand2(xlocals); + + if (exp_right->m_Operator == &AExpression::OpDict) { + Dictionary::Ptr dict = result; + dict->Remove("__parent"); + } + + locals->Set(expr->m_Operand1, result); + return result; +} + +Value AExpression::OpSetMinus(const AExpression *expr, const Dictionary::Ptr& locals) +{ + Value left = locals->Get(expr->m_Operand1); + AExpression::Ptr exp_right = expr->m_Operand2; + Dictionary::Ptr xlocals = locals; + + if (exp_right->m_Operator == &AExpression::OpDict) { + xlocals = left; + + if (!xlocals) + xlocals = make_shared(); + + xlocals->Set("__parent", locals); + } + + Value result = left - expr->EvaluateOperand2(xlocals); + + if (exp_right->m_Operator == &AExpression::OpDict) { + Dictionary::Ptr dict = result; + dict->Remove("__parent"); + } + + locals->Set(expr->m_Operand1, result); + return result; +} + +Value AExpression::OpSetMultiply(const AExpression *expr, const Dictionary::Ptr& locals) +{ + Value left = locals->Get(expr->m_Operand1); + AExpression::Ptr exp_right = expr->m_Operand2; + Dictionary::Ptr xlocals = locals; + + if (exp_right->m_Operator == &AExpression::OpDict) { + xlocals = left; + + if (!xlocals) + xlocals = make_shared(); + + xlocals->Set("__parent", locals); + } + + Value result = left * expr->EvaluateOperand2(xlocals); + + if (exp_right->m_Operator == &AExpression::OpDict) { + Dictionary::Ptr dict = result; + dict->Remove("__parent"); + } + + locals->Set(expr->m_Operand1, result); + return result; +} + +Value AExpression::OpSetDivide(const AExpression *expr, const Dictionary::Ptr& locals) +{ + Value left = locals->Get(expr->m_Operand1); + AExpression::Ptr exp_right = expr->m_Operand2; + Dictionary::Ptr xlocals = locals; + + if (exp_right->m_Operator == &AExpression::OpDict) { + xlocals = left; + + if (!xlocals) + xlocals = make_shared(); + + xlocals->Set("__parent", locals); + } + + Value result = left / expr->EvaluateOperand2(xlocals); + + if (exp_right->m_Operator == &AExpression::OpDict) { + Dictionary::Ptr dict = result; + dict->Remove("__parent"); + } + + locals->Set(expr->m_Operand1, result); + return result; +} + +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); +} diff --git a/lib/config/aexpression.h b/lib/config/aexpression.h index 56c16c33d..181ba5740 100644 --- a/lib/config/aexpression.h +++ b/lib/config/aexpression.h @@ -21,42 +21,13 @@ #define AEXPRESSION_H #include "config/i2-config.h" -#include "config/avalue.h" #include "config/debuginfo.h" +#include "base/array.h" #include "base/dictionary.h" namespace icinga { -/** - * @ingroup config - */ -enum AOperator -{ - AEReturn, - AENegate, - AEAdd, - AESubtract, - AEMultiply, - AEDivide, - AEBinaryAnd, - AEBinaryOr, - AEShiftLeft, - AEShiftRight, - AEEqual, - AENotEqual, - AEIn, - AENotIn, - AELogicalAnd, - AELogicalOr, - AEFunctionCall, - AEArray, - AELessThan, - AEGreaterThan, - AELessThanOrEqual, - AEGreaterThanOrEqual -}; - /** * @ingroup config */ @@ -64,17 +35,62 @@ class I2_CONFIG_API AExpression : public Object { public: DECLARE_PTR_TYPEDEFS(AExpression); + + typedef Value (*OpCallback)(const AExpression *, const Dictionary::Ptr&); - AExpression(AOperator op, const AValue& operand1, const DebugInfo& di); - AExpression(AOperator op, const AValue& operand1, const AValue& operand2, const DebugInfo& di); + AExpression(OpCallback op, const Value& operand1, const DebugInfo& di); + 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); + + void Dump(std::ostream& stream, int indent = 0) const; + void Dump(void) const; + + static Value OpLiteral(const AExpression *expr, const Dictionary::Ptr& locals); + static Value OpVariable(const AExpression *expr, const Dictionary::Ptr& locals); + static Value OpNegate(const AExpression *expr, const Dictionary::Ptr& locals); + static Value OpAdd(const AExpression *expr, const Dictionary::Ptr& locals); + static Value OpSubtract(const AExpression *expr, const Dictionary::Ptr& locals); + static Value OpMultiply(const AExpression *expr, const Dictionary::Ptr& locals); + static Value OpDivide(const AExpression *expr, const Dictionary::Ptr& locals); + static Value OpBinaryAnd(const AExpression *expr, const Dictionary::Ptr& locals); + static Value OpBinaryOr(const AExpression *expr, const Dictionary::Ptr& locals); + static Value OpShiftLeft(const AExpression *expr, const Dictionary::Ptr& locals); + static Value OpShiftRight(const AExpression *expr, const Dictionary::Ptr& locals); + static Value OpEqual(const AExpression *expr, const Dictionary::Ptr& locals); + static Value OpNotEqual(const AExpression *expr, const Dictionary::Ptr& locals); + static Value OpLessThan(const AExpression *expr, const Dictionary::Ptr& locals); + static Value OpGreaterThan(const AExpression *expr, const Dictionary::Ptr& locals); + static Value OpLessThanOrEqual(const AExpression *expr, const Dictionary::Ptr& locals); + static Value OpGreaterThanOrEqual(const AExpression *expr, const Dictionary::Ptr& locals); + static Value OpIn(const AExpression *expr, const Dictionary::Ptr& locals); + static Value OpNotIn(const AExpression *expr, const Dictionary::Ptr& locals); + static Value OpLogicalAnd(const AExpression *expr, const Dictionary::Ptr& locals); + static Value OpLogicalOr(const AExpression *expr, const Dictionary::Ptr& locals); + static Value OpFunctionCall(const AExpression *expr, const Dictionary::Ptr& locals); + static Value OpArray(const AExpression *expr, const Dictionary::Ptr& locals); + static Value OpDict(const AExpression *expr, const Dictionary::Ptr& locals); + static Value OpSet(const AExpression *expr, const Dictionary::Ptr& locals); + static Value OpSetPlus(const AExpression *expr, const Dictionary::Ptr& locals); + static Value OpSetMinus(const AExpression *expr, const Dictionary::Ptr& locals); + static Value OpSetMultiply(const AExpression *expr, const Dictionary::Ptr& locals); + static Value OpSetDivide(const AExpression *expr, const Dictionary::Ptr& locals); + static Value OpIndexer(const AExpression *expr, const Dictionary::Ptr& locals); private: - AOperator m_Operator; - AValue m_Operand1; - AValue m_Operand2; + OpCallback m_Operator; + Value m_Operand1; + Value m_Operand2; DebugInfo m_DebugInfo; + + Value EvaluateOperand1(const Dictionary::Ptr& locals) const; + Value EvaluateOperand2(const Dictionary::Ptr& locals) const; + + static void DumpOperand(std::ostream& stream, const Value& operand, int indent); }; } diff --git a/lib/config/applyrule.cpp b/lib/config/applyrule.cpp index 23247db27..c31fd2b07 100644 --- a/lib/config/applyrule.cpp +++ b/lib/config/applyrule.cpp @@ -24,8 +24,8 @@ using namespace icinga; ApplyRule::RuleMap ApplyRule::m_Rules; ApplyRule::CallbackMap ApplyRule::m_Callbacks; -ApplyRule::ApplyRule(const String& tmpl, const AExpression::Ptr& expression, const DebugInfo& di) - : m_Template(tmpl), m_Expression(expression), m_DebugInfo(di) +ApplyRule::ApplyRule(const String& tmpl, const AExpression::Ptr& expression, const DebugInfo& di, const Dictionary::Ptr& scope) + : m_Template(tmpl), m_Expression(expression), m_DebugInfo(di), m_Scope(scope) { } String ApplyRule::GetTemplate(void) const @@ -43,9 +43,14 @@ DebugInfo ApplyRule::GetDebugInfo(void) const return m_DebugInfo; } -void ApplyRule::AddRule(const String& sourceType, const String& tmpl, const String& targetType, const AExpression::Ptr& expression, const DebugInfo& di) +Dictionary::Ptr ApplyRule::GetScope(void) const { - m_Rules[std::make_pair(sourceType, targetType)].push_back(ApplyRule(tmpl, expression, di)); + return m_Scope; +} + +void ApplyRule::AddRule(const String& sourceType, const String& tmpl, const String& targetType, const AExpression::Ptr& expression, const DebugInfo& di, const Dictionary::Ptr& scope) +{ + m_Rules[std::make_pair(sourceType, targetType)].push_back(ApplyRule(tmpl, expression, di, scope)); } void ApplyRule::EvaluateRules(void) diff --git a/lib/config/applyrule.h b/lib/config/applyrule.h index e08ad98fb..3fba61006 100644 --- a/lib/config/applyrule.h +++ b/lib/config/applyrule.h @@ -42,8 +42,9 @@ public: String GetTemplate(void) const; AExpression::Ptr GetExpression(void) const; DebugInfo GetDebugInfo(void) const; + Dictionary::Ptr GetScope(void) const; - static void AddRule(const String& sourceType, const String& tmpl, const String& targetType, const AExpression::Ptr& expression, const DebugInfo& di); + static void AddRule(const String& sourceType, const String& tmpl, const String& targetType, const AExpression::Ptr& expression, const DebugInfo& di, const Dictionary::Ptr& scope); static void EvaluateRules(void); static void RegisterCombination(const String& sourceType, const String& targetType, const ApplyRule::Callback& callback); @@ -53,11 +54,12 @@ private: String m_Template; AExpression::Ptr m_Expression; DebugInfo m_DebugInfo; + Dictionary::Ptr m_Scope; static CallbackMap m_Callbacks; static RuleMap m_Rules; - ApplyRule(const String& tmpl, const AExpression::Ptr& expression, const DebugInfo& di); + ApplyRule(const String& tmpl, const AExpression::Ptr& expression, const DebugInfo& di, const Dictionary::Ptr& scope); }; } diff --git a/lib/config/avalue.cpp b/lib/config/avalue.cpp deleted file mode 100644 index 742bbca22..000000000 --- a/lib/config/avalue.cpp +++ /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. * - ******************************************************************************/ - -#include "config/avalue.h" -#include "config/aexpression.h" -#include "base/scriptvariable.h" - -using namespace icinga; - -AValue::AValue(void) - : m_Type(ATSimple) -{ } - -AValue::AValue(const AExpression::Ptr& expr) - : m_Type(ATExpression), m_Expression(expr) -{ } - -AValue::AValue(AValueType type, const Value& value) - : m_Type(type), m_Value(value) -{ } - -Value AValue::Evaluate(const Dictionary::Ptr& locals) const -{ - switch (m_Type) { - case ATSimple: - return m_Value; - case ATVariable: - if (locals && locals->Contains(m_Value)) - return locals->Get(m_Value); - else - return ScriptVariable::Get(m_Value); - case ATThisRef: - VERIFY(!"Not implemented."); - case ATExpression: - return m_Expression->Evaluate(locals); - default: - ASSERT(!"Invalid type."); - } -} diff --git a/lib/config/avalue.h b/lib/config/avalue.h deleted file mode 100644 index 37969ca3f..000000000 --- a/lib/config/avalue.h +++ /dev/null @@ -1,64 +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 AVALUE_H -#define AVALUE_H - -#include "config/i2-config.h" -#include "base/value.h" -#include "base/dictionary.h" - -namespace icinga -{ - -/** - * @ingroup config - */ -enum AValueType -{ - ATSimple, - ATVariable, - ATThisRef, - ATExpression -}; - -class AExpression; - -/** - * @ingroup config - */ -class I2_CONFIG_API AValue -{ -public: - AValue(void); - AValue(const shared_ptr& expr); - AValue(AValueType type, const Value& value); - - Value Evaluate(const Dictionary::Ptr& locals) const; - -private: - AValueType m_Type; - Value m_Value; - shared_ptr m_Expression; -}; - -} - -#endif /* AVALUE_H */ - 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 976f0d4b7..8be7318b5 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,20 @@ 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 rterm_scope +%type lterm %type variable_decl %left T_LOGICAL_OR %left T_LOGICAL_AND @@ -179,18 +185,22 @@ 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) { - ConfigCompilerContext::GetInstance()->AddMessage(true, ex.what(), ex.GetDebugInfo()); + const DebugInfo *di = boost::get_error_info(ex); + ConfigCompilerContext::GetInstance()->AddMessage(true, ex.what(), di ? *di : DebugInfo()); } catch (const std::exception& ex) { ConfigCompilerContext::GetInstance()->AddMessage(true, DiagnosticInformation(ex)); } @@ -206,12 +216,21 @@ statements: /* empty */ ; statement: object | type | include | include_recursive | library | variable | apply + { } + | 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 { @@ -220,16 +239,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)); } ; @@ -240,22 +265,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; } ; @@ -285,7 +303,7 @@ type: partial_specifier T_TYPE identifier if (!m_Type) { if ($1) - BOOST_THROW_EXCEPTION(ConfigError("Partial type definition for unknown type '" + name + "'", DebugInfoRange(@1, @3))); + BOOST_THROW_EXCEPTION(ConfigError("Partial type definition for unknown type '" + name + "'") << errinfo_debuginfo(DebugInfoRange(@1, @3))); m_Type = make_shared(name, DebugInfoRange(@1, @3)); m_Type->Register(); @@ -393,35 +411,38 @@ object: { m_Abstract = false; } - object_declaration identifier T_STRING object_inherits_specifier expressionlist + object_declaration identifier rterm object_inherits_specifier rterm_scope { DebugInfo di = DebugInfoRange(@2, @6); ConfigItemBuilder::Ptr item = make_shared(di); - ConfigItem::Ptr oldItem = ConfigItem::GetObject($3, $4); + AExpression::Ptr aexpr = static_cast(*$4); + delete $4; + + String name = aexpr->Evaluate(m_ModuleScope); + + ConfigItem::Ptr oldItem = ConfigItem::GetObject($3, name); if (oldItem) { std::ostringstream msgbuf; - msgbuf << "Object '" << $4 << "' of type '" << $3 << "' re-defined: " << di << "; previous definition: " << oldItem->GetDebugInfo(); + msgbuf << "Object '" << name << "' of type '" << $3 << "' re-defined: " << di << "; previous definition: " << oldItem->GetDebugInfo(); free($3); - free($4); delete $5; - BOOST_THROW_EXCEPTION(ConfigError(msgbuf.str(), di)); + BOOST_THROW_EXCEPTION(ConfigError(msgbuf.str()) << errinfo_debuginfo(di)); } item->SetType($3); - if (strchr($4, '!') != NULL) { + if (name.FindFirstOf("!") != String::NPos) { std::ostringstream msgbuf; - msgbuf << "Name for object '" << $4 << "' of type '" << $3 << "' is invalid: Object names may not contain '!'"; + msgbuf << "Name for object '" << name << "' of type '" << $3 << "' is invalid: Object names may not contain '!'"; free($3); - BOOST_THROW_EXCEPTION(ConfigError(msgbuf.str(), @4)); + BOOST_THROW_EXCEPTION(ConfigError(msgbuf.str()) << errinfo_debuginfo(@4)); } free($3); - item->SetName($4); - free($4); + item->SetName(name); if ($5) { BOOST_FOREACH(const String& parent, *$5) { @@ -431,13 +452,16 @@ 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); + item->SetScope(m_ModuleScope); + item->Compile()->Register(); item.reset(); } @@ -481,96 +505,39 @@ object_inherits_specifier: } ; -expressionlist: '{' expressions '}' - { - if ($2) - $$ = $2; - else - $$ = new ExpressionList(); - } - ; - -expressions: expressions_inner - { - $$ = $1; - } - | expressions_inner ',' - { - $$ = $1; - } - -expressions_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 +lbinary_op: T_SET + | T_SET_PLUS + | T_SET_MINUS + | T_SET_MULTIPLY + | T_SET_DIVIDE { $$ = $1; } ; -array_items: array_items_inner +comma_or_semicolon: ',' | ';' + ; + +lterm_items: lterm_items_inner { $$ = $1; } - | array_items_inner ',' + | lterm_items_inner comma_or_semicolon { $$ = $1; } -array_items_inner: /* empty */ +lterm_items_inner: /* empty */ { - $$ = NULL; + $$ = new Array(); } - | aexpression + | lterm { $$ = new Array(); $$->Add(*$1); delete $1; } - | array_items_inner ',' aexpression + | lterm_items_inner comma_or_semicolon lterm { if ($1) $$ = $1; @@ -582,168 +549,156 @@ array_items_inner: /* empty */ } ; -aexpression: T_STRING +lterm: identifier lbinary_op rterm { - $$ = new Value(make_shared(AEReturn, AValue(ATSimple, $1), @1)); + AExpression::Ptr aexpr = static_cast(*$3); + $$ = new Value(make_shared($2, $1, aexpr, DebugInfoRange(@1, @3))); + free($1); + 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); } - | T_NUMBER + | rterm { - $$ = new Value(make_shared(AEReturn, AValue(ATSimple, $1), @1)); + $$ = $1; } - | T_NULL + ; + +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 { - $$ = new Value(make_shared(AEReturn, AValue(ATSimple, Empty), @1)); + $$ = $1; } - | T_IDENTIFIER '(' array_items ')' + ; + +rterm_items: rterm_items_inner { - Array::Ptr arguments = Array::Ptr($3); - $$ = new Value(make_shared(AEFunctionCall, AValue(ATSimple, $1), AValue(ATSimple, arguments), DebugInfoRange(@1, @4))); - free($1); + $$ = $1; } - | T_IDENTIFIER + | rterm_items_inner ',' { - $$ = new Value(make_shared(AEReturn, AValue(ATVariable, $1), @1)); - free($1); + $$ = $1; } - | '!' aexpression + ; + +rterm_items_inner: /* empty */ { - $$ = new Value(make_shared(AENegate, static_cast(*$2), DebugInfoRange(@1, @2))); - delete $2; + $$ = new Array(); } - | '~' aexpression + | rterm { - $$ = new Value(make_shared(AENegate, static_cast(*$2), DebugInfoRange(@1, @2))); - delete $2; - } - | '[' array_items ']' - { - $$ = new Value(make_shared(AEArray, AValue(ATSimple, Array::Ptr($2)), DebugInfoRange(@1, @3))); - } - | '(' aexpression ')' - { - $$ = $2; - } - | aexpression '+' aexpression - { - $$ = new Value(make_shared(AEAdd, static_cast(*$1), static_cast(*$3), DebugInfoRange(@1, @3))); + $$ = new Array(); + $$->Add(*$1); delete $1; - delete $3; } - | aexpression '-' aexpression + | rterm_items_inner ',' rterm { - $$ = new Value(make_shared(AESubtract, static_cast(*$1), static_cast(*$3), DebugInfoRange(@1, @3))); - delete $1; - delete $3; - } - | aexpression '*' aexpression - { - $$ = new Value(make_shared(AEMultiply, static_cast(*$1), static_cast(*$3), DebugInfoRange(@1, @3))); - delete $1; - delete $3; - } - | aexpression '/' aexpression - { - $$ = new Value(make_shared(AEDivide, static_cast(*$1), static_cast(*$3), DebugInfoRange(@1, @3))); - delete $1; - delete $3; - } - | aexpression '&' aexpression - { - $$ = new Value(make_shared(AEBinaryAnd, static_cast(*$1), static_cast(*$3), DebugInfoRange(@1, @3))); - delete $1; - delete $3; - } - | aexpression '|' aexpression - { - $$ = new Value(make_shared(AEBinaryOr, static_cast(*$1), static_cast(*$3), DebugInfoRange(@1, @2))); - delete $1; - delete $3; - } - | aexpression T_IN aexpression - { - $$ = new Value(make_shared(AEIn, static_cast(*$1), static_cast(*$3), DebugInfoRange(@1, @3))); - delete $1; - delete $3; - } - | aexpression T_NOT_IN aexpression - { - $$ = new Value(make_shared(AENotIn, static_cast(*$1), static_cast(*$3), DebugInfoRange(@1, @3))); - delete $1; - delete $3; - } - | aexpression T_LESS_THAN_OR_EQUAL aexpression - { - $$ = new Value(make_shared(AELessThanOrEqual, static_cast(*$1), static_cast(*$3), DebugInfoRange(@1, @3))); - delete $1; - delete $3; - } - | aexpression T_GREATER_THAN_OR_EQUAL aexpression - { - $$ = new Value(make_shared(AEGreaterThanOrEqual, static_cast(*$1), static_cast(*$3), DebugInfoRange(@1, @3))); - delete $1; - delete $3; - } - | aexpression '<' aexpression - { - $$ = new Value(make_shared(AELessThan, static_cast(*$1), static_cast(*$3), DebugInfoRange(@1, @3))); - delete $1; - delete $3; - } - | aexpression '>' aexpression - { - $$ = new Value(make_shared(AEGreaterThan, static_cast(*$1), static_cast(*$3), DebugInfoRange(@1, @3))); - delete $1; - delete $3; - } - | aexpression T_EQUAL aexpression - { - $$ = new Value(make_shared(AEEqual, static_cast(*$1), static_cast(*$3), DebugInfoRange(@1, @3))); - delete $1; - delete $3; - } - | aexpression T_NOT_EQUAL aexpression - { - $$ = new Value(make_shared(AENotEqual, static_cast(*$1), static_cast(*$3), DebugInfoRange(@1, @3))); - delete $1; - delete $3; - } - | aexpression T_SHIFT_LEFT aexpression - { - $$ = new Value(make_shared(AEShiftLeft, static_cast(*$1), static_cast(*$3), DebugInfoRange(@1, @3))); - delete $1; - delete $3; - } - | aexpression T_SHIFT_RIGHT aexpression - { - $$ = new Value(make_shared(AEShiftRight, static_cast(*$1), static_cast(*$3), DebugInfoRange(@1, @3))); - delete $1; - delete $3; - } - | aexpression T_LOGICAL_AND aexpression - { - $$ = new Value(make_shared(AELogicalAnd, static_cast(*$1), static_cast(*$3), DebugInfoRange(@1, @3))); - delete $1; - delete $3; - } - | aexpression T_LOGICAL_OR aexpression - { - $$ = new Value(make_shared(AELogicalOr, static_cast(*$1), static_cast(*$3), DebugInfoRange(@1, @3))); - delete $1; + if ($1) + $$ = $1; + else + $$ = new Array(); + + $$->Add(*$3); delete $3; } ; -value: expressionlist +rbinary_op: '+' { - ExpressionList::Ptr exprl = ExpressionList::Ptr($1); - $$ = new Value(exprl); + $$ = &AExpression::OpAdd; } - | aexpression + ; + +rterm_scope: '{' lterm_items '}' { - AExpression::Ptr aexpr = *$1; - $$ = new Value(aexpr->Evaluate(Dictionary::Ptr())); + $$ = new Value(make_shared(&AExpression::OpDict, Array::Ptr($2), DebugInfoRange(@1, @3))); + } + ; + +rterm: T_STRING + { + $$ = new Value(make_shared(&AExpression::OpLiteral, $1, @1)); + free($1); + } + | T_NUMBER + { + $$ = new Value(make_shared(&AExpression::OpLiteral, $1, @1)); + } + | T_NULL + { + $$ = new Value(make_shared(&AExpression::OpLiteral, Empty, @1)); + } + | 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))); + free($1); + } + | T_IDENTIFIER + { + $$ = new Value(make_shared(&AExpression::OpVariable, $1, @1)); + free($1); + } + | '!' rterm + { + $$ = new Value(make_shared(&AExpression::OpNegate, static_cast(*$2), DebugInfoRange(@1, @2))); + delete $2; + } + | '~' rterm + { + $$ = new Value(make_shared(&AExpression::OpNegate, static_cast(*$2), DebugInfoRange(@1, @2))); + delete $2; + } + | identifier '[' T_STRING ']' + { + $$ = new Value(make_shared(&AExpression::OpIndexer, $1, $3, DebugInfoRange(@1, @4))); + free($1); + free($3); + } + | '[' rterm_items ']' + { + $$ = new Value(make_shared(&AExpression::OpArray, Array::Ptr($2), DebugInfoRange(@1, @3))); + } + | rterm_scope + { + $$ = $1; + } + | '(' rterm ')' + { + $$ = $2; + } + | rterm rbinary_op rterm + { + $$ = new Value(make_shared($2, static_cast(*$1), static_cast(*$3), DebugInfoRange(@1, @3))); delete $1; + delete $3; } ; @@ -751,18 +706,18 @@ 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) + "'.", @1)); + BOOST_THROW_EXCEPTION(ConfigError("'apply' cannot be used with types '" + String($3) + "' and '" + String($6) + "'.") << errinfo_debuginfo(@1)); } Array::Ptr arguments = make_shared(); arguments->Add(*$8); delete $8; - AExpression::Ptr aexpr = make_shared(AEFunctionCall, AValue(ATSimple, "bool"), AValue(ATSimple, arguments), @8); + AExpression::Ptr aexpr = make_shared(&AExpression::OpFunctionCall, "bool", make_shared(&AExpression::OpLiteral, arguments, @8), @8); - ApplyRule::AddRule($3, $4, $6, aexpr, DebugInfoRange(@1, @8)); + ApplyRule::AddRule($3, $4, $6, aexpr, DebugInfoRange(@1, @8), m_ModuleScope); } %% diff --git a/lib/config/configerror.cpp b/lib/config/configerror.cpp index a4b232c35..1f3c092f7 100644 --- a/lib/config/configerror.cpp +++ b/lib/config/configerror.cpp @@ -18,11 +18,12 @@ ******************************************************************************/ #include "config/configerror.h" +#include using namespace icinga; -ConfigError::ConfigError(const String& message, const DebugInfo& di) - : m_Message(message), m_DebugInfo(di) +ConfigError::ConfigError(const String& message) + : m_Message(message) { } ConfigError::~ConfigError(void) throw() @@ -33,7 +34,10 @@ const char *ConfigError::what(void) const throw() return m_Message.CStr(); } -DebugInfo ConfigError::GetDebugInfo(void) const +std::string icinga::to_string(const errinfo_debuginfo& e) { - return m_DebugInfo; -} \ No newline at end of file + std::ostringstream msgbuf; + msgbuf << "Config location: " << e.value() << "\n"; + ShowCodeFragment(msgbuf, e.value()); + return msgbuf.str(); +} diff --git a/lib/config/configerror.h b/lib/config/configerror.h index 10bccfe4e..c60725b99 100644 --- a/lib/config/configerror.h +++ b/lib/config/configerror.h @@ -22,6 +22,7 @@ #include "config/i2-config.h" #include "config/debuginfo.h" +#include "base/exception.h" namespace icinga { @@ -29,20 +30,23 @@ namespace icinga /* * @ingroup config */ -class I2_CONFIG_API ConfigError : public std::exception +class I2_CONFIG_API ConfigError : virtual public user_error { public: - ConfigError(const String& message, const DebugInfo& di); + ConfigError(const String& message); ~ConfigError(void) throw(); const char *what(void) const throw(); - DebugInfo GetDebugInfo(void) const; private: String m_Message; - DebugInfo m_DebugInfo; }; +struct errinfo_debuginfo_; +typedef boost::error_info errinfo_debuginfo; + +std::string to_string(const errinfo_debuginfo& e); + } #endif /* CONFIGERROR_H */ diff --git a/lib/config/configitem.cpp b/lib/config/configitem.cpp index 95ca34f5a..8668dbf3c 100644 --- a/lib/config/configitem.cpp +++ b/lib/config/configitem.cpp @@ -48,10 +48,12 @@ ConfigItem::ItemMap ConfigItem::m_Items; * @param debuginfo Debug information. */ ConfigItem::ConfigItem(const String& type, const String& name, - bool abstract, const ExpressionList::Ptr& exprl, - const std::vector& parents, const DebugInfo& debuginfo) + bool abstract, const AExpression::Ptr& exprl, + const std::vector& parents, const DebugInfo& debuginfo, + const Dictionary::Ptr& scope) : m_Type(type), m_Name(name), m_Abstract(abstract), m_Validated(false), - m_ExpressionList(exprl), m_ParentNames(parents), m_DebugInfo(debuginfo) + m_ExpressionList(exprl), m_ParentNames(parents), m_DebugInfo(debuginfo), + m_Scope(scope) { } @@ -95,25 +97,30 @@ DebugInfo ConfigItem::GetDebugInfo(void) const return m_DebugInfo; } +Dictionary::Ptr ConfigItem::GetScope(void) const +{ + return m_Scope; +} + /** * Retrieves the expression list for the configuration item. * * @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 +130,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; } @@ -143,9 +152,16 @@ Dictionary::Ptr ConfigItem::GetProperties(void) { ASSERT(OwnsLock()); - Dictionary::Ptr properties = make_shared(); - GetLinkedExpressionList()->Execute(properties); - return properties; + if (!m_Properties) { + m_Properties = make_shared(); + m_Properties->Set("__parent", m_Scope); + GetLinkedExpressionList()->Evaluate(m_Properties); + m_Properties->Remove("__parent"); + + VERIFY(m_Properties->Get("__type") == GetType() && m_Properties->Get("__name") == GetName()); + } + + return m_Properties; } /** diff --git a/lib/config/configitem.h b/lib/config/configitem.h index 415879a87..7af2918dc 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,8 +45,8 @@ public: DECLARE_PTR_TYPEDEFS(ConfigItem); ConfigItem(const String& type, const String& name, bool abstract, - const ExpressionList::Ptr& exprl, const std::vector& parents, - const DebugInfo& debuginfo); + const AExpression::Ptr& exprl, const std::vector& parents, + const DebugInfo& debuginfo, const Dictionary::Ptr& scope); String GetType(void) const; String GetName(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); @@ -62,6 +62,8 @@ public: DebugInfo GetDebugInfo(void) const; + Dictionary::Ptr GetScope(void) const; + static ConfigItem::Ptr GetObject(const String& type, const String& name); static bool HasObject(const String& type, const String& name); @@ -72,21 +74,23 @@ 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; + Dictionary::Ptr m_Properties; std::vector m_ParentNames; /**< The names of parent configuration items. */ DebugInfo m_DebugInfo; /**< Debug information. */ + Dictionary::Ptr m_Scope; /**< variable scope. */ - 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..dbae3768e 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; } @@ -55,26 +55,19 @@ void ConfigItemBuilder::SetAbstract(bool abstract) m_Abstract = abstract; } +void ConfigItemBuilder::SetScope(const Dictionary::Ptr& scope) +{ + m_Scope = scope; +} + 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,17 +95,13 @@ 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::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)); + exprs->Add(make_shared(&AExpression::OpDict, m_Expressions, true, 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); + m_Parents, m_DebugInfo, m_Scope); } diff --git a/lib/config/configitembuilder.h b/lib/config/configitembuilder.h index a18da56be..74fa75df6 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" @@ -46,13 +45,11 @@ public: void SetType(const String& type); void SetName(const String& name); void SetAbstract(bool abstract); + void SetScope(const Dictionary::Ptr& scope); 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,8 +59,9 @@ 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. */ + Dictionary::Ptr m_Scope; /**< variable scope. */ }; } diff --git a/lib/config/expression.cpp b/lib/config/expression.cpp deleted file mode 100644 index 911e298d4..000000000 --- a/lib/config/expression.cpp +++ /dev/null @@ -1,238 +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 OperatorNop: - /* Nothing to do here. */ - - return; - - 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::ExtractFiltered(const std::set& keys, const shared_ptr& result) const -{ - if (keys.find(m_Key) != keys.end()) { - result->AddExpression(*this); - } else if (m_Operator == OperatorExecute) { - ExpressionList::Ptr exprl = m_Value; - exprl->ExtractFiltered(keys, result); - } -} - -void Expression::ErasePath(const std::vector& path) -{ - ASSERT(!path.empty()); - - if (path[0] == m_Key) { - if (path.size() == 1) { - m_Operator = OperatorNop; - } else if (m_Value.IsObjectType()) { - ExpressionList::Ptr exprl = m_Value; - - std::vector sub_path(path.begin() + 1, path.end()); - exprl->ErasePath(sub_path); - } - } else if (m_Operator == OperatorExecute) { - ExpressionList::Ptr exprl = m_Value; - exprl->ErasePath(path); - } -} - -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 1c0881019..000000000 --- a/lib/config/expression.h +++ /dev/null @@ -1,82 +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 -{ - OperatorNop, - 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 ExtractFiltered(const std::set& keys, const shared_ptr& result) const; - - void ErasePath(const std::vector& path); - - 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 d61eb32e6..000000000 --- a/lib/config/expressionlist.cpp +++ /dev/null @@ -1,84 +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); -} - -/** - * Returns the number of items currently contained in the expression list. - * - * @returns The length of the list. - */ -size_t ExpressionList::GetLength(void) const -{ - return m_Expressions.size(); -} - -/** - * 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::ExtractFiltered(const std::set& keys, const ExpressionList::Ptr& result) const -{ - BOOST_FOREACH(const Expression& expression, m_Expressions) { - expression.ExtractFiltered(keys, result); - } -} - -void ExpressionList::ErasePath(const std::vector& path) -{ - BOOST_FOREACH(Expression& expression, m_Expressions) { - expression.ErasePath(path); - } -} - -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 71758a9d7..000000000 --- a/lib/config/expressionlist.h +++ /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. * - ******************************************************************************/ - -#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; - - size_t GetLength(void) const; - - void ExtractPath(const std::vector& path, const ExpressionList::Ptr& result) const; - void ExtractFiltered(const std::set& keys, const ExpressionList::Ptr& result) const; - - void ErasePath(const std::vector& path); - - 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..010987ba4 100644 --- a/lib/icinga/host-apply.cpp +++ b/lib/icinga/host-apply.cpp @@ -77,7 +77,8 @@ 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->SetScope(rule.GetScope()); + 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..386605473 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,12 @@ 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)); + + builder->SetScope(item->GetScope()); ConfigItem::Ptr serviceItem = builder->Compile(); serviceItem->Register(); diff --git a/lib/icinga/service-dependency.cpp b/lib/icinga/service-dependency.cpp index be202002c..36b455bee 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,12 @@ 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)); + + builder->SetScope(item->GetScope()); ConfigItem::Ptr dependencyItem = builder->Compile(); dependencyItem->Register(); diff --git a/lib/icinga/service-downtime.cpp b/lib/icinga/service-downtime.cpp index 0913ee9a9..d914284a4 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,12 @@ 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)); + + builder->SetScope(item->GetScope()); ConfigItem::Ptr scheduledDowntimeItem = builder->Compile(); scheduledDowntimeItem->Register(); diff --git a/lib/icinga/service-notification.cpp b/lib/icinga/service-notification.cpp index 5b5964b4e..5fb711aa4 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,12 @@ 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)); + + builder->SetScope(item->GetScope()); 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)