Merge branch 'feature/config-parser-5846' into next

Fixes #5846
This commit is contained in:
Gunnar Beutner 2014-03-24 12:02:57 +01:00
commit dc415a620a
38 changed files with 1062 additions and 1245 deletions

View File

@ -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.
#### <a id="string-literals"></a> 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.
### <a id="operators"></a> Dictionary Operators
@ -222,65 +226,67 @@ In this example a has the value 7 after both instructions are executed.
#### <a id="operator-additive-assignment"></a> 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 = [ "hello" ],
a = a + [ "world" ]
}
#### <a id="operator-substractive-assignment"></a> Operator -=
Removes elements from a dictionary.
Example:
The -= operator is a shortcut. The following expression:
{
a = { "hello", "world" },
a -= [ "world" ]
a = 10,
a -= 5
}
In this example a contains `"hello"`. Trying to remove an item that does
not exist is not an error. Not implemented yet.
is equivalent to:
{
a = 10,
a = a - 5
}
#### <a id="operator-multiply-assignment"></a> Operator \*=
Multiplies an existing dictionary element with the specified number. If
the dictionary element does not already exist 0 is used as its value.
Example:
The *= operator is a shortcut. The following expression:
{
a = 60,
a *= 5
}
In this example a is 300. This only works for numbers. Not implemented
yet.
is equivalent to:
{
a = 60,
a = a * 5
}
#### <a id="operator-dividing-assignment"></a> Operator /=
Divides an existing dictionary element by the specified number. If the
dictionary element does not already exist 0 is used as its value.
Example:
The /= operator is a shortcut. The following expression:
{
a = 300,
a /= 5
}
In this example a is 60. This only works for numbers. Not implemented
yet.
is equivalent to:
-->
{
a = 300,
a = a / 5
}
### <a id="indexer"></a> 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
### <a id="constants"></a> Constants
Global constants can be set using the `const` keyword:

View File

@ -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

View File

@ -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());

View File

@ -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;

View File

@ -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<std::type_info *>(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<StackTraceErrorInfo>(*ex) == NULL)
*ex << StackTraceErrorInfo(stack);
if (boost::get_error_info<StackTraceErrorInfo>(*ex) == NULL)
*ex << StackTraceErrorInfo(stack);
if (boost::get_error_info<ContextTraceErrorInfo>(*ex) == NULL)
*ex << ContextTraceErrorInfo(context);
if (boost::get_error_info<ContextTraceErrorInfo>(*ex) == NULL)
*ex << ContextTraceErrorInfo(context);
}
}
#endif /* __APPLE__ */

View File

@ -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<StackTraceErrorInfo>(ex) == NULL) {
result << std::endl;
if (dynamic_cast<const user_error *>(&ex) == NULL) {
if (boost::get_error_info<StackTraceErrorInfo>(ex) == NULL) {
result << std::endl;
if (stack)
result << *stack;
else
result << *GetLastExceptionStack();
}
if (stack)
result << *stack;
else
result << *GetLastExceptionStack();
}
if (boost::get_error_info<ContextTraceErrorInfo>(ex) == NULL) {
result << std::endl;
if (boost::get_error_info<ContextTraceErrorInfo>(ex) == NULL) {
result << std::endl;
if (context)
result << *context;
else
result << *GetLastExceptionContext();
if (context)
result << *context;
else
result << *GetLastExceptionContext();
}
}
return result.str();

View File

@ -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 <boost/regex.hpp>
#include <algorithm>
#include <set>
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>()) {
Dictionary::Ptr dict = value;
@ -55,7 +60,7 @@ int UtilityFuncs::Len(const Value& value)
}
}
Array::Ptr UtilityFuncs::Union(const std::vector<Value>& arguments)
Array::Ptr ScriptUtils::Union(const std::vector<Value>& arguments)
{
std::set<Value> values;
@ -75,7 +80,7 @@ Array::Ptr UtilityFuncs::Union(const std::vector<Value>& arguments)
return result;
}
Array::Ptr UtilityFuncs::Intersection(const std::vector<Value>& arguments)
Array::Ptr ScriptUtils::Intersection(const std::vector<Value>& arguments)
{
if (arguments.size() == 0)
return make_shared<Array>();
@ -98,3 +103,16 @@ Array::Ptr UtilityFuncs::Intersection(const std::vector<Value>& 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);
}

View File

@ -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<Value>& arguments);
static Array::Ptr Intersection(const std::vector<Value>& arguments);
static void Log(const Value& message);
static void Exit(int code);
private:
UtilityFuncs(void);
ScriptUtils(void);
};
}
#endif /* UTILITYFUNCS_H */
#endif /* SCRIPTUTILS_H */

View File

@ -22,7 +22,6 @@
#include "base/utility.h"
#include "base/convert.h"
#include "base/application.h"
#include <boost/algorithm/string/trim.hpp>
#ifdef HAVE_BACKTRACE_SYMBOLS
# include <execinfo.h>
@ -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<uintptr_t>(m_Frames[i]) - reinterpret_cast<uintptr_t>(dli.dli_fbase);
message += " (" + Addr2Line(dli.dli_fname, rva) + ")";
}
#endif /* HAVE_DLADDR */
message += " (" + Utility::GetSymbolSource(m_Frames[i]) + ")";
}
}

View File

@ -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);

View File

@ -28,6 +28,7 @@
#include <boost/foreach.hpp>
#include <boost/algorithm/string/split.hpp>
#include <boost/algorithm/string/classification.hpp>
#include <boost/algorithm/string/trim.hpp>
#ifdef __FreeBSD__
# include <pthread_np.h>
@ -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<uintptr_t>(addr) - reinterpret_cast<uintptr_t>(dli.dli_fbase);
return Addr2Line(dli.dli_fname, rva);
}
#endif /* HAVE_DLADDR */
return "";
}
/**
* Performs wildcard pattern matching.
*

View File

@ -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);

View File

@ -201,10 +201,19 @@ Value icinga::operator+(const Value& lhs, const Value& rhs)
return static_cast<String>(lhs) + static_cast<String>(rhs);
else if ((lhs.IsNumber() || lhs.IsEmpty()) && (rhs.IsNumber() || rhs.IsEmpty()) && !(lhs.IsEmpty() && rhs.IsEmpty()))
return static_cast<double>(lhs) + static_cast<double>(rhs);
else if (lhs.IsObjectType<Array>() && rhs.IsObjectType<Array>()) {
else if ((lhs.IsObjectType<Array>() || lhs.IsEmpty()) && (rhs.IsObjectType<Array>() || rhs.IsEmpty()) && !(lhs.IsEmpty() && rhs.IsEmpty())) {
Array::Ptr result = make_shared<Array>();
static_cast<Array::Ptr>(lhs)->CopyTo(result);
static_cast<Array::Ptr>(rhs)->CopyTo(result);
if (!lhs.IsEmpty())
static_cast<Array::Ptr>(lhs)->CopyTo(result);
if (!rhs.IsEmpty())
static_cast<Array::Ptr>(rhs)->CopyTo(result);
return result;
} else if ((lhs.IsObjectType<Dictionary>() || lhs.IsEmpty()) && (rhs.IsObjectType<Dictionary>() || rhs.IsEmpty()) && !(lhs.IsEmpty() && rhs.IsEmpty())) {
Dictionary::Ptr result = make_shared<Dictionary>();
if (!lhs.IsEmpty())
static_cast<Dictionary::Ptr>(lhs)->CopyTo(result);
if (!rhs.IsEmpty())
static_cast<Dictionary::Ptr>(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<String>(lhs) < static_cast<String>(rhs);
else if ((lhs.IsNumber() || lhs.IsEmpty()) && (rhs.IsNumber() || rhs.IsEmpty()) && !(lhs.IsEmpty() && rhs.IsEmpty()))
return static_cast<int>(lhs) < static_cast<int>(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<String>(lhs) > static_cast<String>(rhs);
else if ((lhs.IsNumber() || lhs.IsEmpty()) && (rhs.IsNumber() || rhs.IsEmpty()) && !(lhs.IsEmpty() && rhs.IsEmpty()))
return static_cast<int>(lhs) > static_cast<int>(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<String>(lhs) <= static_cast<String>(rhs);
else if ((lhs.IsNumber() || lhs.IsEmpty()) && (rhs.IsNumber() || rhs.IsEmpty()) && !(lhs.IsEmpty() && rhs.IsEmpty()))
return static_cast<int>(lhs) <= static_cast<int>(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<String>(lhs) >= static_cast<String>(rhs);
else if ((lhs.IsNumber() || lhs.IsEmpty()) && (rhs.IsNumber() || rhs.IsEmpty()) && !(lhs.IsEmpty() && rhs.IsEmpty()))
return static_cast<int>(lhs) >= static_cast<int>(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() + "'"));
}

View File

@ -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)

View File

@ -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 <boost/foreach.hpp>
#include <boost/exception_ptr.hpp>
#include <boost/exception/errinfo_nested_exception.hpp>
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<Value> 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<Array>())
BOOST_THROW_EXCEPTION(std::invalid_argument("Invalid right side argument for 'in' operator: " + JsonSerialize(right)));
arr = right;
found = false;
BOOST_FOREACH(const Value& value, arr) {
if (value == left) {
found = true;
break;
}
}
return found;
case AENotIn:
if (!right.IsObjectType<Array>())
BOOST_THROW_EXCEPTION(std::invalid_argument("Invalid right side argument for 'in' operator: " + JsonSerialize(right)));
arr = right;
found = false;
BOOST_FOREACH(const Value& value, arr) {
if (value == left) {
found = true;
break;
}
}
return !found;
case 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<Array>();
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<boost::errinfo_nested_exception>(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<String>& 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<String> sub_path(path.begin() + 1, path.end());
exprl->ExtractPath(sub_path, result);
}
}
void AExpression::FindDebugInfoPath(const std::vector<String>& 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<String> 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>()) {
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>()) {
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<const void *>(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<AExpression::Ptr>(m_Operand1)->Evaluate(locals);
}
Value AExpression::EvaluateOperand2(const Dictionary::Ptr& locals) const
{
return static_cast<AExpression::Ptr>(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<Array>())
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<Value> 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<Array>();
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<Dictionary>();
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<Dictionary>();
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<Dictionary>();
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<Dictionary>();
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<Dictionary>();
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);
}

View File

@ -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<String>& path, const Array::Ptr& result) const;
void FindDebugInfoPath(const std::vector<String>& 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);
};
}

View File

@ -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)

View File

@ -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);
};
}

View File

@ -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.");
}
}

View File

@ -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<AExpression>& expr);
AValue(AValueType type, const Value& value);
Value Evaluate(const Dictionary::Ptr& locals) const;
private:
AValueType m_Type;
Value m_Value;
shared_ptr<AExpression> m_Expression;
};
}
#endif /* AVALUE_H */

View File

@ -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];

View File

@ -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<String> *slist;
Expression *expr;
ExpressionList *exprl;
Array *array;
Value *aexpr;
}
%token <text> T_STRING
@ -100,23 +95,34 @@ using namespace icinga;
%token <num> T_NUMBER
%token T_NULL
%token <text> T_IDENTIFIER
%token <op> T_SET "= (T_SET)"
%token <op> T_PLUS_EQUAL "+= (T_PLUS_EQUAL)"
%token <op> T_MINUS_EQUAL "-= (T_MINUS_EQUAL)"
%token <op> T_MULTIPLY_EQUAL "*= (T_MULTIPLY_EQUAL)"
%token <op> T_DIVIDE_EQUAL "/= (T_DIVIDE_EQUAL)"
%token <op> T_SET_PLUS "+= (T_SET_PLUS)"
%token <op> T_SET_MINUS "-= (T_SET_MINUS)"
%token <op> T_SET_MULTIPLY "*= (T_SET_MULTIPLY)"
%token <op> T_SET_DIVIDE "/= (T_SET_DIVIDE)"
%token <op> T_SHIFT_LEFT "<< (T_SHIFT_LEFT)"
%token <op> T_SHIFT_RIGHT ">> (T_SHIFT_RIGHT)"
%token <op> T_EQUAL "== (T_EQUAL)"
%token <op> T_NOT_EQUAL "!= (T_NOT_EQUAL)"
%token <op> T_IN "in (T_IN)"
%token <op> T_NOT_IN "!in (T_NOT_IN)"
%token <op> T_LOGICAL_AND "&& (T_LOGICAL_AND)"
%token <op> T_LOGICAL_OR "|| (T_LOGICAL_OR)"
%token <op> T_LESS_THAN_OR_EQUAL "<= (T_LESS_THAN_OR_EQUAL)"
%token <op> T_GREATER_THAN_OR_EQUAL ">= (T_GREATER_THAN_OR_EQUAL)"
%token <op> T_PLUS "+ (T_PLUS)"
%token <op> T_MINUS "- (T_MINUS)"
%token <op> T_MULTIPLY "* (T_MULTIPLY)"
%token <op> T_DIVIDE "/ (T_DIVIDE)"
%token <op> T_BINARY_AND "& (T_BINARY_AND)"
%token <op> T_BINARY_OR "| (T_BINARY_OR)"
%token <op> T_LESS_THAN "< (T_LESS_THAN)"
%token <op> 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 <type> T_TYPE_DICTIONARY "dictionary (T_TYPE_DICTIONARY)"
%token <type> T_TYPE_ARRAY "array (T_TYPE_ARRAY)"
%token <type> 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 <text> identifier
%type <array> array_items
%type <array> array_items_inner
%type <variant> value
%type <expr> expression
%type <exprl> expressions
%type <exprl> expressions_inner
%type <exprl> expressionlist
%type <array> rterm_items
%type <array> rterm_items_inner
%type <array> lterm_items
%type <array> lterm_items_inner
%type <variant> typerulelist
%type <op> operator
%type <op> lbinary_op
%type <op> rbinary_op
%type <type> type
%type <num> partial_specifier
%type <slist> object_inherits_list
%type <slist> object_inherits_specifier
%type <aexpr> aexpression
%type <variant> rterm
%type <variant> rterm_scope
%type <variant> lterm
%type <num> 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<Array::Ptr> m_Arrays;
static bool m_Abstract;
static std::stack<TypeRuleList::Ptr> m_RuleLists;
static ConfigType::Ptr m_Type;
static Dictionary::Ptr m_ModuleScope;
void ConfigCompiler::Compile(void)
{
m_ModuleScope = make_shared<Dictionary>();
try {
yyparse(this);
} catch (const ConfigError& ex) {
ConfigCompilerContext::GetInstance()->AddMessage(true, ex.what(), ex.GetDebugInfo());
const DebugInfo *di = boost::get_error_info<errinfo_debuginfo>(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<AExpression::Ptr>(*$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<AExpression::Ptr>(*$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<AExpression::Ptr>(*$2);
delete $2;
AExpression::Ptr aexpr2 = static_cast<AExpression::Ptr>(*$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<ExpressionList>()) {
Dictionary::Ptr dict = make_shared<Dictionary>();
ExpressionList::Ptr exprl = *value;
exprl->Execute(dict);
delete value;
value = new Value(dict);
}
AExpression::Ptr aexpr = static_cast<AExpression::Ptr>(*$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<ConfigType>(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<ConfigItemBuilder>(di);
ConfigItem::Ptr oldItem = ConfigItem::GetObject($3, $4);
AExpression::Ptr aexpr = static_cast<AExpression::Ptr>(*$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<AExpression::Ptr>(*$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<ExpressionList>();
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<AExpression>(AEReturn, AValue(ATSimple, $1), @1));
AExpression::Ptr aexpr = static_cast<AExpression::Ptr>(*$3);
$$ = new Value(make_shared<AExpression>($2, $1, aexpr, DebugInfoRange(@1, @3)));
free($1);
delete $3;
}
| identifier '[' T_STRING ']' lbinary_op rterm
{
AExpression::Ptr subexpr = make_shared<AExpression>($5, $3, static_cast<AExpression::Ptr>(*$6), DebugInfoRange(@1, @6));
free($3);
delete $6;
Array::Ptr subexprl = make_shared<Array>();
subexprl->Add(subexpr);
AExpression::Ptr expr = make_shared<AExpression>(&AExpression::OpDict, subexprl, DebugInfoRange(@1, @6));
$$ = new Value(make_shared<AExpression>(&AExpression::OpSetPlus, $1, expr, DebugInfoRange(@1, @6)));
free($1);
}
| T_NUMBER
| rterm
{
$$ = new Value(make_shared<AExpression>(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<AExpression>(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<AExpression>(AEFunctionCall, AValue(ATSimple, $1), AValue(ATSimple, arguments), DebugInfoRange(@1, @4)));
free($1);
$$ = $1;
}
| T_IDENTIFIER
| rterm_items_inner ','
{
$$ = new Value(make_shared<AExpression>(AEReturn, AValue(ATVariable, $1), @1));
free($1);
$$ = $1;
}
| '!' aexpression
;
rterm_items_inner: /* empty */
{
$$ = new Value(make_shared<AExpression>(AENegate, static_cast<AExpression::Ptr>(*$2), DebugInfoRange(@1, @2)));
delete $2;
$$ = new Array();
}
| '~' aexpression
| rterm
{
$$ = new Value(make_shared<AExpression>(AENegate, static_cast<AExpression::Ptr>(*$2), DebugInfoRange(@1, @2)));
delete $2;
}
| '[' array_items ']'
{
$$ = new Value(make_shared<AExpression>(AEArray, AValue(ATSimple, Array::Ptr($2)), DebugInfoRange(@1, @3)));
}
| '(' aexpression ')'
{
$$ = $2;
}
| aexpression '+' aexpression
{
$$ = new Value(make_shared<AExpression>(AEAdd, static_cast<AExpression::Ptr>(*$1), static_cast<AExpression::Ptr>(*$3), DebugInfoRange(@1, @3)));
$$ = new Array();
$$->Add(*$1);
delete $1;
delete $3;
}
| aexpression '-' aexpression
| rterm_items_inner ',' rterm
{
$$ = new Value(make_shared<AExpression>(AESubtract, static_cast<AExpression::Ptr>(*$1), static_cast<AExpression::Ptr>(*$3), DebugInfoRange(@1, @3)));
delete $1;
delete $3;
}
| aexpression '*' aexpression
{
$$ = new Value(make_shared<AExpression>(AEMultiply, static_cast<AExpression::Ptr>(*$1), static_cast<AExpression::Ptr>(*$3), DebugInfoRange(@1, @3)));
delete $1;
delete $3;
}
| aexpression '/' aexpression
{
$$ = new Value(make_shared<AExpression>(AEDivide, static_cast<AExpression::Ptr>(*$1), static_cast<AExpression::Ptr>(*$3), DebugInfoRange(@1, @3)));
delete $1;
delete $3;
}
| aexpression '&' aexpression
{
$$ = new Value(make_shared<AExpression>(AEBinaryAnd, static_cast<AExpression::Ptr>(*$1), static_cast<AExpression::Ptr>(*$3), DebugInfoRange(@1, @3)));
delete $1;
delete $3;
}
| aexpression '|' aexpression
{
$$ = new Value(make_shared<AExpression>(AEBinaryOr, static_cast<AExpression::Ptr>(*$1), static_cast<AExpression::Ptr>(*$3), DebugInfoRange(@1, @2)));
delete $1;
delete $3;
}
| aexpression T_IN aexpression
{
$$ = new Value(make_shared<AExpression>(AEIn, static_cast<AExpression::Ptr>(*$1), static_cast<AExpression::Ptr>(*$3), DebugInfoRange(@1, @3)));
delete $1;
delete $3;
}
| aexpression T_NOT_IN aexpression
{
$$ = new Value(make_shared<AExpression>(AENotIn, static_cast<AExpression::Ptr>(*$1), static_cast<AExpression::Ptr>(*$3), DebugInfoRange(@1, @3)));
delete $1;
delete $3;
}
| aexpression T_LESS_THAN_OR_EQUAL aexpression
{
$$ = new Value(make_shared<AExpression>(AELessThanOrEqual, static_cast<AExpression::Ptr>(*$1), static_cast<AExpression::Ptr>(*$3), DebugInfoRange(@1, @3)));
delete $1;
delete $3;
}
| aexpression T_GREATER_THAN_OR_EQUAL aexpression
{
$$ = new Value(make_shared<AExpression>(AEGreaterThanOrEqual, static_cast<AExpression::Ptr>(*$1), static_cast<AExpression::Ptr>(*$3), DebugInfoRange(@1, @3)));
delete $1;
delete $3;
}
| aexpression '<' aexpression
{
$$ = new Value(make_shared<AExpression>(AELessThan, static_cast<AExpression::Ptr>(*$1), static_cast<AExpression::Ptr>(*$3), DebugInfoRange(@1, @3)));
delete $1;
delete $3;
}
| aexpression '>' aexpression
{
$$ = new Value(make_shared<AExpression>(AEGreaterThan, static_cast<AExpression::Ptr>(*$1), static_cast<AExpression::Ptr>(*$3), DebugInfoRange(@1, @3)));
delete $1;
delete $3;
}
| aexpression T_EQUAL aexpression
{
$$ = new Value(make_shared<AExpression>(AEEqual, static_cast<AExpression::Ptr>(*$1), static_cast<AExpression::Ptr>(*$3), DebugInfoRange(@1, @3)));
delete $1;
delete $3;
}
| aexpression T_NOT_EQUAL aexpression
{
$$ = new Value(make_shared<AExpression>(AENotEqual, static_cast<AExpression::Ptr>(*$1), static_cast<AExpression::Ptr>(*$3), DebugInfoRange(@1, @3)));
delete $1;
delete $3;
}
| aexpression T_SHIFT_LEFT aexpression
{
$$ = new Value(make_shared<AExpression>(AEShiftLeft, static_cast<AExpression::Ptr>(*$1), static_cast<AExpression::Ptr>(*$3), DebugInfoRange(@1, @3)));
delete $1;
delete $3;
}
| aexpression T_SHIFT_RIGHT aexpression
{
$$ = new Value(make_shared<AExpression>(AEShiftRight, static_cast<AExpression::Ptr>(*$1), static_cast<AExpression::Ptr>(*$3), DebugInfoRange(@1, @3)));
delete $1;
delete $3;
}
| aexpression T_LOGICAL_AND aexpression
{
$$ = new Value(make_shared<AExpression>(AELogicalAnd, static_cast<AExpression::Ptr>(*$1), static_cast<AExpression::Ptr>(*$3), DebugInfoRange(@1, @3)));
delete $1;
delete $3;
}
| aexpression T_LOGICAL_OR aexpression
{
$$ = new Value(make_shared<AExpression>(AELogicalOr, static_cast<AExpression::Ptr>(*$1), static_cast<AExpression::Ptr>(*$3), 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>(&AExpression::OpDict, Array::Ptr($2), DebugInfoRange(@1, @3)));
}
;
rterm: T_STRING
{
$$ = new Value(make_shared<AExpression>(&AExpression::OpLiteral, $1, @1));
free($1);
}
| T_NUMBER
{
$$ = new Value(make_shared<AExpression>(&AExpression::OpLiteral, $1, @1));
}
| T_NULL
{
$$ = new Value(make_shared<AExpression>(&AExpression::OpLiteral, Empty, @1));
}
| T_IDENTIFIER '(' rterm_items ')'
{
Array::Ptr arguments = Array::Ptr($3);
$$ = new Value(make_shared<AExpression>(&AExpression::OpFunctionCall, $1, make_shared<AExpression>(&AExpression::OpLiteral, arguments, @3), DebugInfoRange(@1, @4)));
free($1);
}
| T_IDENTIFIER
{
$$ = new Value(make_shared<AExpression>(&AExpression::OpVariable, $1, @1));
free($1);
}
| '!' rterm
{
$$ = new Value(make_shared<AExpression>(&AExpression::OpNegate, static_cast<AExpression::Ptr>(*$2), DebugInfoRange(@1, @2)));
delete $2;
}
| '~' rterm
{
$$ = new Value(make_shared<AExpression>(&AExpression::OpNegate, static_cast<AExpression::Ptr>(*$2), DebugInfoRange(@1, @2)));
delete $2;
}
| identifier '[' T_STRING ']'
{
$$ = new Value(make_shared<AExpression>(&AExpression::OpIndexer, $1, $3, DebugInfoRange(@1, @4)));
free($1);
free($3);
}
| '[' rterm_items ']'
{
$$ = new Value(make_shared<AExpression>(&AExpression::OpArray, Array::Ptr($2), DebugInfoRange(@1, @3)));
}
| rterm_scope
{
$$ = $1;
}
| '(' rterm ')'
{
$$ = $2;
}
| rterm rbinary_op rterm
{
$$ = new Value(make_shared<AExpression>($2, static_cast<AExpression::Ptr>(*$1), static_cast<AExpression::Ptr>(*$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<Array>();
arguments->Add(*$8);
delete $8;
AExpression::Ptr aexpr = make_shared<AExpression>(AEFunctionCall, AValue(ATSimple, "bool"), AValue(ATSimple, arguments), @8);
AExpression::Ptr aexpr = make_shared<AExpression>(&AExpression::OpFunctionCall, "bool", make_shared<AExpression>(&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);
}
%%

View File

@ -18,11 +18,12 @@
******************************************************************************/
#include "config/configerror.h"
#include <sstream>
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;
}
std::ostringstream msgbuf;
msgbuf << "Config location: " << e.value() << "\n";
ShowCodeFragment(msgbuf, e.value());
return msgbuf.str();
}

View File

@ -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<struct errinfo_debuginfo_, DebugInfo> errinfo_debuginfo;
std::string to_string(const errinfo_debuginfo& e);
}
#endif /* CONFIGERROR_H */

View File

@ -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<String>& parents, const DebugInfo& debuginfo)
bool abstract, const AExpression::Ptr& exprl,
const std::vector<String>& 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<ExpressionList>();
Array::Ptr subexprs = make_shared<Array>();
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>(&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<Dictionary>();
GetLinkedExpressionList()->Execute(properties);
return properties;
if (!m_Properties) {
m_Properties = make_shared<Dictionary>();
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;
}
/**

View File

@ -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<String>& parents,
const DebugInfo& debuginfo);
const AExpression::Ptr& exprl, const std::vector<String>& parents,
const DebugInfo& debuginfo, const Dictionary::Ptr& scope);
String GetType(void) const;
String GetName(void) const;
@ -54,7 +54,7 @@ public:
std::vector<ConfigItem::Ptr> 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<String> 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;

View File

@ -26,7 +26,7 @@
using namespace icinga;
ConfigItemBuilder::ConfigItemBuilder(void)
: m_Abstract(false), m_ExpressionList(make_shared<ExpressionList>())
: m_Abstract(false), m_Expressions(make_shared<Array>())
{
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<ExpressionList>())
: m_Abstract(false), m_Expressions(make_shared<Array>())
{
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<ExpressionList>();
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<Array>();
exprs->Add(make_shared<AExpression>(&AExpression::OpSet, "__type", make_shared<AExpression>(&AExpression::OpLiteral, m_Type, m_DebugInfo), m_DebugInfo));
exprs->Add(make_shared<AExpression>(&AExpression::OpSet, "__name", make_shared<AExpression>(&AExpression::OpLiteral, m_Name, m_DebugInfo), m_DebugInfo));
exprs->Add(make_shared<AExpression>(&AExpression::OpDict, m_Expressions, true, m_DebugInfo));
AExpression::Ptr exprl = make_shared<AExpression>(&AExpression::OpDict, exprs, true, m_DebugInfo);
return make_shared<ConfigItem>(m_Type, m_Name, m_Abstract, exprl,
m_Parents, m_DebugInfo);
m_Parents, m_DebugInfo, m_Scope);
}

View File

@ -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<String> 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. */
};
}

View File

@ -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 <sstream>
#include <boost/foreach.hpp>
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<ExpressionList>());
}
Value Expression::DeepClone(const Value& value)
{
if (value.IsObjectType<Array>()) {
Array::Ptr array = value;
Array::Ptr result = make_shared<Array>();
ObjectLock olock(array);
BOOST_FOREACH(const Value& item, array) {
result->Add(DeepClone(item));
}
return result;
} else if (value.IsObjectType<Dictionary>()) {
Dictionary::Ptr dict = value;
Dictionary::Ptr result = make_shared<Dictionary>();
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<ExpressionList>())
valueExprl = m_Value;
if (m_Value.IsObjectType<Dictionary>())
valueDict = m_Value;
if (m_Value.IsObjectType<Array>())
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<Dictionary>();
valueExprl->Execute(dict);
newValue = dict;
} else {
newValue = DeepClone(newValue);
}
break;
case OperatorPlus:
oldValue = dictionary->Get(m_Key);
if (oldValue.IsObjectType<Dictionary>())
dict = oldValue;
if (oldValue.IsObjectType<Array>())
array = oldValue;
if (valueExprl) {
if (!dict)
dict = make_shared<Dictionary>();
valueExprl->Execute(dict);
newValue = dict;
} else if (valueDict) {
if (!dict)
dict = make_shared<Dictionary>();
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<Array>();
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<String>& path, const ExpressionList::Ptr& result) const
{
ASSERT(!path.empty());
if (path[0] == m_Key) {
if (!m_Value.IsObjectType<ExpressionList>())
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<String> 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<String>& keys, const shared_ptr<ExpressionList>& 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<String>& path)
{
ASSERT(!path.empty());
if (path[0] == m_Key) {
if (path.size() == 1) {
m_Operator = OperatorNop;
} else if (m_Value.IsObjectType<ExpressionList>()) {
ExpressionList::Ptr exprl = m_Value;
std::vector<String> 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<String>& 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>()) {
ExpressionList::Ptr exprl = m_Value;
std::vector<String> 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);
}
}

View File

@ -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 <iostream>
#include <vector>
#include <set>
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<String>& path, const shared_ptr<ExpressionList>& result) const;
void ExtractFiltered(const std::set<String>& keys, const shared_ptr<ExpressionList>& result) const;
void ErasePath(const std::vector<String>& path);
void FindDebugInfoPath(const std::vector<String>& 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 */

View File

@ -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 <boost/foreach.hpp>
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<String>& path, const ExpressionList::Ptr& result) const
{
BOOST_FOREACH(const Expression& expression, m_Expressions) {
expression.ExtractPath(path, result);
}
}
void ExpressionList::ExtractFiltered(const std::set<String>& keys, const ExpressionList::Ptr& result) const
{
BOOST_FOREACH(const Expression& expression, m_Expressions) {
expression.ExtractFiltered(keys, result);
}
}
void ExpressionList::ErasePath(const std::vector<String>& path)
{
BOOST_FOREACH(Expression& expression, m_Expressions) {
expression.ErasePath(path);
}
}
void ExpressionList::FindDebugInfoPath(const std::vector<String>& path, DebugInfo& result) const
{
BOOST_FOREACH(const Expression& expression, m_Expressions) {
expression.FindDebugInfoPath(path, result);
}
}

View File

@ -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 <vector>
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<String>& path, const ExpressionList::Ptr& result) const;
void ExtractFiltered(const std::set<String>& keys, const ExpressionList::Ptr& result) const;
void ErasePath(const std::vector<String>& path);
void FindDebugInfoPath(const std::vector<String>& path, DebugInfo& result) const;
private:
std::vector<Expression> m_Expressions;
};
}
#endif /* EXPRESSIONLIST_H */

View File

@ -77,7 +77,8 @@ void Host::EvaluateApplyRules(const std::vector<ApplyRule>& rules)
ConfigItemBuilder::Ptr builder = make_shared<ConfigItemBuilder>(rule.GetDebugInfo());
builder->SetType("Service");
builder->SetName(name);
builder->AddExpression("host", OperatorSet, host->GetName());
builder->SetScope(rule.GetScope());
builder->AddExpression(make_shared<AExpression>(&AExpression::OpSet, "host", make_shared<AExpression>(&AExpression::OpLiteral, host->GetName(), rule.GetDebugInfo()), rule.GetDebugInfo()));
builder->AddParent(rule.GetTemplate());

View File

@ -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<ConfigItemBuilder>(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>(&AExpression::OpSet, "host", make_shared<AExpression>(&AExpression::OpLiteral, GetName(), di), di));
builder->AddExpression(make_shared<AExpression>(&AExpression::OpSet, "display_name", make_shared<AExpression>(&AExpression::OpLiteral, kv.first, di), di));
builder->AddExpression(make_shared<AExpression>(&AExpression::OpSet, "short_name", make_shared<AExpression>(&AExpression::OpLiteral, kv.first, di), di));
if (!kv.second.IsObjectType<Dictionary>())
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<ExpressionList>();
Array::Ptr svc_exprl = make_shared<Array>();
exprl->ExtractPath(path, svc_exprl);
builder->AddExpressionList(svc_exprl);
builder->AddExpression(make_shared<AExpression>(&AExpression::OpDict, svc_exprl, true, di));
builder->SetScope(item->GetScope());
ConfigItem::Ptr serviceItem = builder->Compile();
serviceItem->Register();

View File

@ -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<ConfigItemBuilder>(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>(&AExpression::OpSet, "child_host", make_shared<AExpression>(&AExpression::OpLiteral, GetHost()->GetName(), di), di));
builder->AddExpression(make_shared<AExpression>(&AExpression::OpSet, "child_service", make_shared<AExpression>(&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<ExpressionList>();
Array::Ptr sd_exprl = make_shared<Array>();
exprl->ExtractPath(path, sd_exprl);
builder->AddExpressionList(sd_exprl);
builder->AddExpression(make_shared<AExpression>(&AExpression::OpDict, sd_exprl, true, di));
builder->SetScope(item->GetScope());
ConfigItem::Ptr dependencyItem = builder->Compile();
dependencyItem->Register();

View File

@ -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<ConfigItemBuilder>(di);
builder->SetType("ScheduledDowntime");
builder->SetName(name);
builder->AddExpression("host", OperatorSet, GetHost()->GetName());
builder->AddExpression("service", OperatorSet, GetShortName());
builder->AddExpression(make_shared<AExpression>(&AExpression::OpSet, "host", make_shared<AExpression>(&AExpression::OpLiteral, GetHost()->GetName(), di), di));
builder->AddExpression(make_shared<AExpression>(&AExpression::OpSet, "service", make_shared<AExpression>(&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<ExpressionList>();
Array::Ptr sd_exprl = make_shared<Array>();
exprl->ExtractPath(path, sd_exprl);
builder->AddExpressionList(sd_exprl);
builder->AddExpression(make_shared<AExpression>(&AExpression::OpDict, sd_exprl, true, di));
builder->SetScope(item->GetScope());
ConfigItem::Ptr scheduledDowntimeItem = builder->Compile();
scheduledDowntimeItem->Register();

View File

@ -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<ConfigItemBuilder>(di);
builder->SetType("Notification");
builder->SetName(name);
builder->AddExpression("host", OperatorSet, GetHost()->GetName());
builder->AddExpression("service", OperatorSet, GetShortName());
builder->AddExpression(make_shared<AExpression>(&AExpression::OpSet, "host", make_shared<AExpression>(&AExpression::OpLiteral, GetHost()->GetName(), di), di));
builder->AddExpression(make_shared<AExpression>(&AExpression::OpSet, "service", make_shared<AExpression>(&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<ExpressionList>();
Array::Ptr nfc_exprl = make_shared<Array>();
exprl->ExtractPath(path, nfc_exprl);
builder->AddExpressionList(nfc_exprl);
builder->AddExpression(make_shared<AExpression>(&AExpression::OpDict, nfc_exprl, true, di));
builder->SetScope(item->GetScope());
ConfigItem::Ptr notificationItem = builder->Compile();
notificationItem->Register();

View File

@ -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)