diff --git a/doc/4.1-configuration-syntax.md b/doc/4.1-configuration-syntax.md
index f602b5cd8..56b6b5ff6 100644
--- a/doc/4.1-configuration-syntax.md
+++ b/doc/4.1-configuration-syntax.md
@@ -24,8 +24,8 @@ define objects the `object` keyword is used:
Each object is uniquely identified by its type (`Host`) and name
(`host1.example.org`). Objects can contain a comma-separated list of
-property declarations. The following data types are available for
-property values:
+property declarations. Instead of commas semi-colons may also be used.
+The following data types are available for property values:
### Expressions
@@ -52,6 +52,9 @@ Example:
Supported suffixes include ms (milliseconds), s (seconds), m (minutes),
h (hours) and d (days).
+Duration literals are converted to seconds by the config parser and
+are treated like numeric literals.
+
#### String Literals
A string.
@@ -170,7 +173,7 @@ in | "foo" in [ "foo", "bar" ] (true) | Element contained in
!in | "foo" !in [ "bar", "baz" ] (true) | Element not contained in array
() | (3 + 3) * 5 | Groups sub-expressions
-Constants may be used in constant expressions:
+Constants may be used in expressions:
const MyCheckInterval = 10m
@@ -200,6 +203,7 @@ intersection(array, array, ...) | Returns an array containing all unique element
string(value) | Converts the value to a string.
number(value) | Converts the value to a number.
bool(value) | Converts to value to a bool.
+log(value) | Writes a message to the log. Non-string values are converted to a JSON string.
### Dictionary Operators
@@ -222,65 +226,67 @@ In this example a has the value 7 after both instructions are executed.
#### Operator +=
-Modifies a dictionary or array by adding new elements to it.
-
-Example:
+The += operator is a shortcut. The following expression:
{
a = [ "hello" ],
a += [ "world" ]
}
-In this example a contains both `"hello"` and `"world"`. This currently
-only works for dictionaries and arrays.
+is equivalent to:
-
+ {
+ a = 300,
+ a = a / 5
+ }
### Indexer
@@ -350,13 +356,11 @@ override its value by setting it explicitely to `null`.
custom = null
}
-
The same method applies for disabling services defined in the inline `services`
dictionary by explicitly overriding their value with `null`.
services["ping6"] = null
-
### Constants
Global constants can be set using the `const` keyword:
diff --git a/lib/base/CMakeLists.txt b/lib/base/CMakeLists.txt
index 0fc7a9aa4..d230c402c 100644
--- a/lib/base/CMakeLists.txt
+++ b/lib/base/CMakeLists.txt
@@ -30,7 +30,7 @@ add_library(base SHARED
netstring.cpp networkstream.cpp object.cpp objectlock.cpp process.cpp
process-unix.cpp process-windows.cpp qstring.cpp ringbuffer.cpp script.cpp
script.th scriptfunction.cpp scriptfunctionwrapper.cpp scriptinterpreter.cpp
- scriptlanguage.cpp scriptvariable.cpp serializer.cpp socket.cpp stacktrace.cpp
+ scriptlanguage.cpp scriptutils.cpp scriptvariable.cpp serializer.cpp socket.cpp stacktrace.cpp
statsfunction.cpp stdiostream.cpp stream_bio.cpp stream.cpp streamlogger.cpp streamlogger.th
sysloglogger.cpp sysloglogger.th tcpsocket.cpp threadpool.cpp timer.cpp
tlsstream.cpp tlsutility.cpp type.cpp unixsocket.cpp utility.cpp value.cpp
diff --git a/lib/base/array.cpp b/lib/base/array.cpp
index 102d679e4..9d236954b 100644
--- a/lib/base/array.cpp
+++ b/lib/base/array.cpp
@@ -157,6 +157,14 @@ void Array::Resize(size_t new_size)
m_Data.resize(new_size);
}
+void Array::Clear(void)
+{
+ ASSERT(!OwnsLock());
+ ObjectLock olock(this);
+
+ m_Data.clear();
+}
+
void Array::CopyTo(const Array::Ptr& dest) const
{
ASSERT(!OwnsLock());
diff --git a/lib/base/array.h b/lib/base/array.h
index 744c790ca..0e53fbf78 100644
--- a/lib/base/array.h
+++ b/lib/base/array.h
@@ -56,6 +56,7 @@ public:
void Remove(Iterator it);
void Resize(size_t new_size);
+ void Clear(void);
void CopyTo(const Array::Ptr& dest) const;
Array::Ptr ShallowClone(void) const;
diff --git a/lib/base/exception.cpp b/lib/base/exception.cpp
index 79f082cf5..fd142d734 100644
--- a/lib/base/exception.cpp
+++ b/lib/base/exception.cpp
@@ -38,28 +38,31 @@ void __cxa_throw(void *obj, void *pvtinfo, void (*dest)(void *))
void *thrown_ptr = obj;
const std::type_info *tinfo = static_cast(pvtinfo);
const std::type_info *boost_exc = &typeid(boost::exception);
+ const std::type_info *user_exc = &typeid(user_error);
/* Check if the exception is a pointer type. */
if (tinfo->__is_pointer_p())
thrown_ptr = *(void **)thrown_ptr;
+
+ if (!user_exc->__do_catch(tinfo, &thrown_ptr, 1)) {
#endif /* __APPLE__ */
+ StackTrace stack;
+ SetLastExceptionStack(stack);
- StackTrace stack;
- SetLastExceptionStack(stack);
-
- ContextTrace context;
- SetLastExceptionContext(context);
+ ContextTrace context;
+ SetLastExceptionContext(context);
#ifndef __APPLE__
- /* Check if thrown_ptr inherits from boost::exception. */
- if (boost_exc->__do_catch(tinfo, &thrown_ptr, 1)) {
- boost::exception *ex = (boost::exception *)thrown_ptr;
+ /* Check if thrown_ptr inherits from boost::exception. */
+ if (boost_exc->__do_catch(tinfo, &thrown_ptr, 1)) {
+ boost::exception *ex = (boost::exception *)thrown_ptr;
- if (boost::get_error_info(*ex) == NULL)
- *ex << StackTraceErrorInfo(stack);
+ if (boost::get_error_info(*ex) == NULL)
+ *ex << StackTraceErrorInfo(stack);
- if (boost::get_error_info(*ex) == NULL)
- *ex << ContextTraceErrorInfo(context);
+ if (boost::get_error_info(*ex) == NULL)
+ *ex << ContextTraceErrorInfo(context);
+ }
}
#endif /* __APPLE__ */
diff --git a/lib/base/exception.h b/lib/base/exception.h
index 3cec78b18..872f69fd4 100644
--- a/lib/base/exception.h
+++ b/lib/base/exception.h
@@ -39,6 +39,8 @@
namespace icinga
{
+class I2_BASE_API user_error : virtual public std::exception, virtual public boost::exception { };
+
I2_BASE_API StackTrace *GetLastExceptionStack(void);
I2_BASE_API void SetLastExceptionStack(const StackTrace& trace);
@@ -55,22 +57,24 @@ String DiagnosticInformation(const T& ex, StackTrace *stack = NULL, ContextTrace
result << boost::diagnostic_information(ex);
- if (boost::get_error_info(ex) == NULL) {
- result << std::endl;
+ if (dynamic_cast(&ex) == NULL) {
+ if (boost::get_error_info(ex) == NULL) {
+ result << std::endl;
- if (stack)
- result << *stack;
- else
- result << *GetLastExceptionStack();
- }
+ if (stack)
+ result << *stack;
+ else
+ result << *GetLastExceptionStack();
+ }
- if (boost::get_error_info(ex) == NULL) {
- result << std::endl;
+ if (boost::get_error_info(ex) == NULL) {
+ result << std::endl;
- if (context)
- result << *context;
- else
- result << *GetLastExceptionContext();
+ if (context)
+ result << *context;
+ else
+ result << *GetLastExceptionContext();
+ }
}
return result.str();
diff --git a/lib/methods/utilityfuncs.cpp b/lib/base/scriptutils.cpp
similarity index 76%
rename from lib/methods/utilityfuncs.cpp
rename to lib/base/scriptutils.cpp
index 4a5ae82e5..0828f75ee 100644
--- a/lib/methods/utilityfuncs.cpp
+++ b/lib/base/scriptutils.cpp
@@ -17,32 +17,37 @@
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
******************************************************************************/
-#include "methods/utilityfuncs.h"
+#include "base/scriptutils.h"
#include "base/scriptfunction.h"
#include "base/utility.h"
#include "base/convert.h"
#include "base/array.h"
#include "base/dictionary.h"
+#include "base/serializer.h"
+#include "base/logger_fwd.h"
+#include "base/application.h"
#include
#include
#include
using namespace icinga;
-REGISTER_SCRIPTFUNCTION(regex, &UtilityFuncs::Regex);
+REGISTER_SCRIPTFUNCTION(regex, &ScriptUtils::Regex);
REGISTER_SCRIPTFUNCTION(match, &Utility::Match);
-REGISTER_SCRIPTFUNCTION(len, &UtilityFuncs::Len);
-REGISTER_SCRIPTFUNCTION(union, &UtilityFuncs::Union);
-REGISTER_SCRIPTFUNCTION(intersection, &UtilityFuncs::Intersection);
+REGISTER_SCRIPTFUNCTION(len, &ScriptUtils::Len);
+REGISTER_SCRIPTFUNCTION(union, &ScriptUtils::Union);
+REGISTER_SCRIPTFUNCTION(intersection, &ScriptUtils::Intersection);
+REGISTER_SCRIPTFUNCTION(log, &ScriptUtils::Log);
+REGISTER_SCRIPTFUNCTION(exit, &ScriptUtils::Exit);
-bool UtilityFuncs::Regex(const String& pattern, const String& text)
+bool ScriptUtils::Regex(const String& pattern, const String& text)
{
boost::regex expr(pattern.GetData());
boost::smatch what;
return boost::regex_search(text.GetData(), what, expr);
}
-int UtilityFuncs::Len(const Value& value)
+int ScriptUtils::Len(const Value& value)
{
if (value.IsObjectType()) {
Dictionary::Ptr dict = value;
@@ -55,7 +60,7 @@ int UtilityFuncs::Len(const Value& value)
}
}
-Array::Ptr UtilityFuncs::Union(const std::vector& arguments)
+Array::Ptr ScriptUtils::Union(const std::vector& arguments)
{
std::set values;
@@ -75,7 +80,7 @@ Array::Ptr UtilityFuncs::Union(const std::vector& arguments)
return result;
}
-Array::Ptr UtilityFuncs::Intersection(const std::vector& arguments)
+Array::Ptr ScriptUtils::Intersection(const std::vector& arguments)
{
if (arguments.size() == 0)
return make_shared();
@@ -98,3 +103,16 @@ Array::Ptr UtilityFuncs::Intersection(const std::vector& arguments)
return result;
}
+
+void ScriptUtils::Log(const Value& message)
+{
+ if (message.IsString())
+ ::Log(LogInformation, "config", message);
+ else
+ ::Log(LogInformation, "config", JsonSerialize(message));
+}
+
+void ScriptUtils::Exit(int code)
+{
+ exit(code);
+}
diff --git a/lib/methods/utilityfuncs.h b/lib/base/scriptutils.h
similarity index 88%
rename from lib/methods/utilityfuncs.h
rename to lib/base/scriptutils.h
index 4dbbb57f4..043b12cbb 100644
--- a/lib/methods/utilityfuncs.h
+++ b/lib/base/scriptutils.h
@@ -17,10 +17,10 @@
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
******************************************************************************/
-#ifndef UTILITYFUNCS_H
-#define UTILITYFUNCS_H
+#ifndef SCRIPTUTILS_H
+#define SCRIPTUTILS_H
-#include "methods/i2-methods.h"
+#include "base/i2-base.h"
#include "base/qstring.h"
#include "base/array.h"
@@ -28,20 +28,22 @@ namespace icinga
{
/**
- * @ingroup methods
+ * @ingroup base
*/
-class I2_METHODS_API UtilityFuncs
+class I2_BASE_API ScriptUtils
{
public:
static bool Regex(const String& pattern, const String& text);
static int Len(const Value& value);
static Array::Ptr Union(const std::vector& arguments);
static Array::Ptr Intersection(const std::vector& arguments);
+ static void Log(const Value& message);
+ static void Exit(int code);
private:
- UtilityFuncs(void);
+ ScriptUtils(void);
};
}
-#endif /* UTILITYFUNCS_H */
+#endif /* SCRIPTUTILS_H */
diff --git a/lib/base/stacktrace.cpp b/lib/base/stacktrace.cpp
index 71ab6772c..182774ea3 100644
--- a/lib/base/stacktrace.cpp
+++ b/lib/base/stacktrace.cpp
@@ -22,7 +22,6 @@
#include "base/utility.h"
#include "base/convert.h"
#include "base/application.h"
-#include
#ifdef HAVE_BACKTRACE_SYMBOLS
# include
@@ -100,43 +99,6 @@ void StackTrace::Initialize(void)
#endif /* _WIN32 */
}
-/**
- * Looks up source file name and line number information for the specified
- * ELF executable and RVA.
- *
- * @param exe The ELF file.
- * @param rva The RVA.
- * @returns Source file and line number.
- */
-String StackTrace::Addr2Line(const String& exe, uintptr_t rva)
-{
-#ifndef _WIN32
- std::ostringstream msgbuf;
- msgbuf << "addr2line -s -e " << Application::GetExePath(exe) << " " << std::hex << rva << " 2>/dev/null";
-
- String args = msgbuf.str();
-
- FILE *fp = popen(args.CStr(), "r");
-
- if (!fp)
- return "RVA: " + Convert::ToString(rva);
-
- char buffer[512] = {};
- fgets(buffer, sizeof(buffer), fp);
- fclose(fp);
-
- String line = buffer;
- boost::algorithm::trim_right(line);
-
- if (line.GetLength() == 0)
- return "RVA: " + Convert::ToString(rva);
-
- return line;
-#else /* _WIN32 */
- return String();
-#endif /* _WIN32 */
-}
-
/**
* Prints a stacktrace to the specified stream.
*
@@ -176,15 +138,7 @@ void StackTrace::Print(std::ostream& fp, int ignoreFrames) const
path = path.SubStr(slashp + 1);
message = path + ": " + sym_demangled + " (" + String(sym_end);
-
-#ifdef HAVE_DLADDR
- Dl_info dli;
-
- if (dladdr(m_Frames[i], &dli) > 0) {
- uintptr_t rva = reinterpret_cast(m_Frames[i]) - reinterpret_cast(dli.dli_fbase);
- message += " (" + Addr2Line(dli.dli_fname, rva) + ")";
- }
-#endif /* HAVE_DLADDR */
+ message += " (" + Utility::GetSymbolSource(m_Frames[i]) + ")";
}
}
diff --git a/lib/base/stacktrace.h b/lib/base/stacktrace.h
index a26228383..cd6828ff8 100644
--- a/lib/base/stacktrace.h
+++ b/lib/base/stacktrace.h
@@ -50,7 +50,6 @@ private:
static boost::once_flag m_OnceFlag;
static void Initialize(void);
- static String Addr2Line(const String& exe, uintptr_t rva);
};
I2_BASE_API std::ostream& operator<<(std::ostream& stream, const StackTrace& trace);
diff --git a/lib/base/utility.cpp b/lib/base/utility.cpp
index 44c5c1f4b..189f77333 100644
--- a/lib/base/utility.cpp
+++ b/lib/base/utility.cpp
@@ -28,6 +28,7 @@
#include
#include
#include
+#include
#ifdef __FreeBSD__
# include
@@ -81,6 +82,69 @@ String Utility::GetTypeName(const std::type_info& ti)
return DemangleSymbolName(ti.name());
}
+/**
+ * Looks up source file name and line number information for the specified
+ * ELF executable and RVA.
+ *
+ * @param exe The ELF file.
+ * @param rva The RVA.
+ * @returns Source file and line number.
+ */
+String Utility::Addr2Line(const String& exe, uintptr_t rva)
+{
+#ifndef _WIN32
+ std::ostringstream msgbuf;
+ msgbuf << "addr2line -s -e " << Application::GetExePath(exe) << " " << std::hex << rva << " 2>/dev/null";
+
+ String args = msgbuf.str();
+
+ FILE *fp = popen(args.CStr(), "r");
+
+ if (!fp)
+ return "RVA: " + Convert::ToString(rva);
+
+ char buffer[512] = {};
+ fgets(buffer, sizeof(buffer), fp);
+ fclose(fp);
+
+ String line = buffer;
+ boost::algorithm::trim_right(line);
+
+ if (line.GetLength() == 0)
+ return "RVA: " + Convert::ToString(rva);
+
+ return line;
+#else /* _WIN32 */
+ return String();
+#endif /* _WIN32 */
+}
+
+String Utility::GetSymbolName(const void *addr)
+{
+#ifdef HAVE_DLADDR
+ Dl_info dli;
+
+ if (dladdr(addr, &dli) > 0)
+ return dli.dli_sname;
+#endif /* HAVE_DLADDR */
+
+ return "";
+}
+
+String Utility::GetSymbolSource(const void *addr)
+{
+#ifdef HAVE_DLADDR
+ Dl_info dli;
+
+ if (dladdr(addr, &dli) > 0) {
+ uintptr_t rva = reinterpret_cast(addr) - reinterpret_cast(dli.dli_fbase);
+ return Addr2Line(dli.dli_fname, rva);
+ }
+#endif /* HAVE_DLADDR */
+
+ return "";
+}
+
/**
* Performs wildcard pattern matching.
*
diff --git a/lib/base/utility.h b/lib/base/utility.h
index 4a384acde..dbea5a6f2 100644
--- a/lib/base/utility.h
+++ b/lib/base/utility.h
@@ -59,6 +59,9 @@ class I2_BASE_API Utility
public:
static String DemangleSymbolName(const String& sym);
static String GetTypeName(const std::type_info& ti);
+ static String Addr2Line(const String& exe, uintptr_t rva);
+ static String GetSymbolName(const void *addr);
+ static String GetSymbolSource(const void *addr);
static bool Match(const String& pattern, const String& text);
diff --git a/lib/base/value-operators.cpp b/lib/base/value-operators.cpp
index e5bccd933..afd4d8a16 100644
--- a/lib/base/value-operators.cpp
+++ b/lib/base/value-operators.cpp
@@ -201,10 +201,19 @@ Value icinga::operator+(const Value& lhs, const Value& rhs)
return static_cast(lhs) + static_cast(rhs);
else if ((lhs.IsNumber() || lhs.IsEmpty()) && (rhs.IsNumber() || rhs.IsEmpty()) && !(lhs.IsEmpty() && rhs.IsEmpty()))
return static_cast(lhs) + static_cast(rhs);
- else if (lhs.IsObjectType() && rhs.IsObjectType()) {
+ else if ((lhs.IsObjectType() || lhs.IsEmpty()) && (rhs.IsObjectType() || rhs.IsEmpty()) && !(lhs.IsEmpty() && rhs.IsEmpty())) {
Array::Ptr result = make_shared();
- static_cast(lhs)->CopyTo(result);
- static_cast(rhs)->CopyTo(result);
+ if (!lhs.IsEmpty())
+ static_cast(lhs)->CopyTo(result);
+ if (!rhs.IsEmpty())
+ static_cast(rhs)->CopyTo(result);
+ return result;
+ } else if ((lhs.IsObjectType() || lhs.IsEmpty()) && (rhs.IsObjectType() || rhs.IsEmpty()) && !(lhs.IsEmpty() && rhs.IsEmpty())) {
+ Dictionary::Ptr result = make_shared();
+ if (!lhs.IsEmpty())
+ static_cast(lhs)->CopyTo(result);
+ if (!rhs.IsEmpty())
+ static_cast(rhs)->CopyTo(result);
return result;
} else {
BOOST_THROW_EXCEPTION(std::invalid_argument("Operator + cannot be applied to values of type '" + lhs.GetTypeName() + "' and '" + rhs.GetTypeName() + "'"));
@@ -440,6 +449,8 @@ Value icinga::operator<(const Value& lhs, const Value& rhs)
return static_cast(lhs) < static_cast(rhs);
else if ((lhs.IsNumber() || lhs.IsEmpty()) && (rhs.IsNumber() || rhs.IsEmpty()) && !(lhs.IsEmpty() && rhs.IsEmpty()))
return static_cast(lhs) < static_cast(rhs);
+ else if (lhs.GetTypeName() != rhs.GetTypeName())
+ return lhs.GetTypeName() < rhs.GetTypeName();
else
BOOST_THROW_EXCEPTION(std::invalid_argument("Operator < cannot be applied to values of type '" + lhs.GetTypeName() + "' and '" + rhs.GetTypeName() + "'"));
}
@@ -470,6 +481,8 @@ Value icinga::operator>(const Value& lhs, const Value& rhs)
return static_cast(lhs) > static_cast(rhs);
else if ((lhs.IsNumber() || lhs.IsEmpty()) && (rhs.IsNumber() || rhs.IsEmpty()) && !(lhs.IsEmpty() && rhs.IsEmpty()))
return static_cast(lhs) > static_cast(rhs);
+ else if (lhs.GetTypeName() != rhs.GetTypeName())
+ return lhs.GetTypeName() > rhs.GetTypeName();
else
BOOST_THROW_EXCEPTION(std::invalid_argument("Operator > cannot be applied to values of type '" + lhs.GetTypeName() + "' and '" + rhs.GetTypeName() + "'"));
}
@@ -500,6 +513,8 @@ Value icinga::operator<=(const Value& lhs, const Value& rhs)
return static_cast(lhs) <= static_cast(rhs);
else if ((lhs.IsNumber() || lhs.IsEmpty()) && (rhs.IsNumber() || rhs.IsEmpty()) && !(lhs.IsEmpty() && rhs.IsEmpty()))
return static_cast(lhs) <= static_cast(rhs);
+ else if (lhs.GetTypeName() != rhs.GetTypeName())
+ return lhs.GetTypeName() <= rhs.GetTypeName();
else
BOOST_THROW_EXCEPTION(std::invalid_argument("Operator <= cannot be applied to values of type '" + lhs.GetTypeName() + "' and '" + rhs.GetTypeName() + "'"));
}
@@ -530,6 +545,8 @@ Value icinga::operator>=(const Value& lhs, const Value& rhs)
return static_cast(lhs) >= static_cast(rhs);
else if ((lhs.IsNumber() || lhs.IsEmpty()) && (rhs.IsNumber() || rhs.IsEmpty()) && !(lhs.IsEmpty() && rhs.IsEmpty()))
return static_cast(lhs) >= static_cast(rhs);
+ else if (lhs.GetTypeName() != rhs.GetTypeName())
+ return lhs.GetTypeName() >= rhs.GetTypeName();
else
BOOST_THROW_EXCEPTION(std::invalid_argument("Operator >= cannot be applied to values of type '" + lhs.GetTypeName() + "' and '" + rhs.GetTypeName() + "'"));
}
diff --git a/lib/config/CMakeLists.txt b/lib/config/CMakeLists.txt
index deb99ac26..05f9990b0 100644
--- a/lib/config/CMakeLists.txt
+++ b/lib/config/CMakeLists.txt
@@ -27,10 +27,10 @@ mkembedconfig_target(base-type.conf base-type.cpp)
include_directories(${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR})
add_library(config SHARED
- aexpression.cpp applyrule.cpp avalue.cpp base-type.conf base-type.cpp
+ aexpression.cpp applyrule.cpp base-type.conf base-type.cpp
configcompilercontext.cpp configcompiler.cpp configerror.cpp configitembuilder.cpp
configitem.cpp ${FLEX_config_lexer_OUTPUTS} ${BISON_config_parser_OUTPUTS}
- configtype.cpp debuginfo.cpp expression.cpp expressionlist.cpp typerule.cpp typerulelist.cpp
+ configtype.cpp debuginfo.cpp typerule.cpp typerulelist.cpp
)
target_link_libraries(config ${Boost_LIBRARIES} base)
diff --git a/lib/config/aexpression.cpp b/lib/config/aexpression.cpp
index e96cd8c53..3933efd92 100644
--- a/lib/config/aexpression.cpp
+++ b/lib/config/aexpression.cpp
@@ -18,135 +18,449 @@
******************************************************************************/
#include "config/aexpression.h"
+#include "config/configerror.h"
#include "base/array.h"
#include "base/serializer.h"
#include "base/context.h"
#include "base/scriptfunction.h"
+#include "base/scriptvariable.h"
+#include "base/utility.h"
+#include "base/objectlock.h"
#include
+#include
+#include
using namespace icinga;
-AExpression::AExpression(AOperator op, const AValue& operand1, const DebugInfo& di)
- : m_Operator(op), m_Operand1(operand1), m_DebugInfo(di)
-{
- ASSERT(op == AEReturn);
-}
+AExpression::AExpression(OpCallback op, const Value& operand1, const DebugInfo& di)
+ : m_Operator(op), m_Operand1(operand1), m_Operand2(), m_DebugInfo(di)
+{ }
-AExpression::AExpression(AOperator op, const AValue& operand1, const AValue& operand2, const DebugInfo& di)
+AExpression::AExpression(OpCallback op, const Value& operand1, const Value& operand2, const DebugInfo& di)
: m_Operator(op), m_Operand1(operand1), m_Operand2(operand2), m_DebugInfo(di)
-{
- ASSERT(op == AEAdd || op == AENegate || op == AESubtract || op == AEMultiply || op == AEDivide ||
- op == AEBinaryAnd || op == AEBinaryOr || op == AEShiftLeft || op == AEShiftRight ||
- op == AEEqual || op == AENotEqual || op == AEIn || op == AENotIn ||
- op == AELogicalAnd || op == AELogicalOr || op == AEFunctionCall);
-}
+{ }
Value AExpression::Evaluate(const Dictionary::Ptr& locals) const
{
- Value left, right;
- Array::Ptr arr, arr2;
- bool found;
- String funcName;
- ScriptFunction::Ptr func;
- std::vector arguments;
-
- left = m_Operand1.Evaluate(locals);
- right = m_Operand2.Evaluate(locals);
-
- std::ostringstream msgbuf;
- msgbuf << "Evaluating AExpression " << m_DebugInfo << "; left=" << JsonSerialize(left) << "; right=" << JsonSerialize(right);
- CONTEXT(msgbuf.str());
-
- switch (m_Operator) {
- case AEReturn:
- return left;
- case AENegate:
- return ~(long)left;
- case AEAdd:
- return left + right;
- case AESubtract:
- return left - right;
- case AEMultiply:
- return left * right;
- case AEDivide:
- return left / right;
- case AEBinaryAnd:
- return left & right;
- case AEBinaryOr:
- return left | right;
- case AEShiftLeft:
- return left << right;
- case AEShiftRight:
- return left >> right;
- case AEEqual:
- return left == right;
- case AENotEqual:
- return left != right;
- case AELessThan:
- return left < right;
- case AEGreaterThan:
- return left > right;
- case AELessThanOrEqual:
- return left <= right;
- case AEGreaterThanOrEqual:
- return left >= right;
- case AEIn:
- if (!right.IsObjectType())
- BOOST_THROW_EXCEPTION(std::invalid_argument("Invalid right side argument for 'in' operator: " + JsonSerialize(right)));
-
- arr = right;
- found = false;
- BOOST_FOREACH(const Value& value, arr) {
- if (value == left) {
- found = true;
- break;
- }
- }
-
- return found;
- case AENotIn:
- if (!right.IsObjectType())
- BOOST_THROW_EXCEPTION(std::invalid_argument("Invalid right side argument for 'in' operator: " + JsonSerialize(right)));
-
- arr = right;
- found = false;
- BOOST_FOREACH(const Value& value, arr) {
- if (value == left) {
- found = true;
- break;
- }
- }
-
- return !found;
- case AELogicalAnd:
- return left.ToBool() && right.ToBool();
- case AELogicalOr:
- return left.ToBool() || right.ToBool();
- case AEFunctionCall:
- funcName = left;
- func = ScriptFunctionRegistry::GetInstance()->GetItem(funcName);
-
- if (!func)
- BOOST_THROW_EXCEPTION(std::invalid_argument("Function '" + funcName + "' does not exist."));
-
- arr = right;
- BOOST_FOREACH(const AExpression::Ptr& aexpr, arr) {
- arguments.push_back(aexpr->Evaluate(locals));
- }
-
- return func->Invoke(arguments);
- case AEArray:
- arr = left;
- arr2 = make_shared();
-
- if (arr) {
- BOOST_FOREACH(const AExpression::Ptr& aexpr, arr) {
- arr2->Add(aexpr->Evaluate(locals));
- }
- }
-
- return arr2;
- default:
- ASSERT(!"Invalid operator.");
+ try {
+ return m_Operator(this, locals);
+ } catch (const std::exception& ex) {
+ if (boost::get_error_info(ex))
+ throw;
+ else
+ BOOST_THROW_EXCEPTION(ConfigError("Error while evaluating expression: " + String(ex.what())) << boost::errinfo_nested_exception(boost::current_exception()) << errinfo_debuginfo(m_DebugInfo));
}
}
+
+void AExpression::ExtractPath(const std::vector& path, const Array::Ptr& result) const
+{
+ ASSERT(!path.empty());
+
+ if (m_Operator == &AExpression::OpDict) {
+ Array::Ptr exprl = m_Operand1;
+ ObjectLock olock(exprl);
+ BOOST_FOREACH(const AExpression::Ptr& expr, exprl) {
+ expr->ExtractPath(path, result);
+ }
+ } else if ((m_Operator == &AExpression::OpSet || m_Operator == &AExpression::OpSetPlus ||
+ m_Operator == &AExpression::OpSetMinus || m_Operator == &AExpression::OpSetMultiply ||
+ m_Operator == &AExpression::OpSetDivide) && path[0] == m_Operand1) {
+ AExpression::Ptr exprl = m_Operand2;
+
+ if (path.size() == 1) {
+ if (m_Operator == &AExpression::OpSet)
+ result->Clear();
+
+ if (exprl->m_Operator != &AExpression::OpDict)
+ BOOST_THROW_EXCEPTION(ConfigError("The '" + path[0] + "' attribute must be a dictionary.") << errinfo_debuginfo(m_DebugInfo));
+
+ Array::Ptr subexprl = exprl->m_Operand1;
+ ObjectLock olock(subexprl);
+ BOOST_FOREACH(const AExpression::Ptr& expr, subexprl) {
+ result->Add(expr);
+ }
+
+ return;
+ }
+
+ std::vector sub_path(path.begin() + 1, path.end());
+ exprl->ExtractPath(sub_path, result);
+ }
+}
+
+void AExpression::FindDebugInfoPath(const std::vector& path, DebugInfo& result) const
+{
+ ASSERT(!path.empty());
+
+ if (m_Operator == &AExpression::OpDict) {
+ Array::Ptr exprl = m_Operand1;
+ ObjectLock olock(exprl);
+ BOOST_FOREACH(const AExpression::Ptr& expr, exprl) {
+ expr->FindDebugInfoPath(path, result);
+ }
+ } else if ((m_Operator == &AExpression::OpSet || m_Operator == &AExpression::OpSetPlus ||
+ m_Operator == &AExpression::OpSetMinus || m_Operator == &AExpression::OpSetMultiply ||
+ m_Operator == &AExpression::OpSetDivide) && path[0] == m_Operand1) {
+ AExpression::Ptr exprl = m_Operand2;
+
+ if (path.size() == 1) {
+ result = m_DebugInfo;
+ } else {
+ std::vector sub_path(path.begin() + 1, path.end());
+ exprl->FindDebugInfoPath(sub_path, result);
+ }
+ }
+}
+
+void AExpression::MakeInline(void)
+{
+ if (m_Operator == &AExpression::OpDict)
+ m_Operand2 = true;
+}
+
+void AExpression::DumpOperand(std::ostream& stream, const Value& operand, int indent) {
+ if (operand.IsObjectType()) {
+ Array::Ptr arr = operand;
+ stream << String(indent, ' ') << "Array:\n";
+ ObjectLock olock(arr);
+ BOOST_FOREACH(const Value& elem, arr) {
+ DumpOperand(stream, elem, indent + 1);
+ }
+ } else if (operand.IsObjectType()) {
+ AExpression::Ptr left = operand;
+ left->Dump(stream, indent);
+ } else {
+ stream << String(indent, ' ') << JsonSerialize(operand) << "\n";
+ }
+}
+
+void AExpression::Dump(std::ostream& stream, int indent) const
+{
+ String sym = Utility::GetSymbolName(reinterpret_cast(m_Operator));
+ stream << String(indent, ' ') << "op: " << Utility::DemangleSymbolName(sym) << "\n";
+ stream << String(indent, ' ') << "left:\n";
+ DumpOperand(stream, m_Operand1, indent + 1);
+
+ stream << String(indent, ' ') << "right:\n";
+ DumpOperand(stream, m_Operand2, indent + 1);
+}
+
+void AExpression::Dump(void) const
+{
+ Dump(std::cerr);
+}
+
+Value AExpression::EvaluateOperand1(const Dictionary::Ptr& locals) const
+{
+ return static_cast(m_Operand1)->Evaluate(locals);
+}
+
+Value AExpression::EvaluateOperand2(const Dictionary::Ptr& locals) const
+{
+ return static_cast(m_Operand2)->Evaluate(locals);
+}
+
+Value AExpression::OpLiteral(const AExpression *expr, const Dictionary::Ptr& locals)
+{
+ return expr->m_Operand1;
+}
+
+Value AExpression::OpVariable(const AExpression *expr, const Dictionary::Ptr& locals)
+{
+ Dictionary::Ptr scope = locals;
+
+ while (scope) {
+ if (scope->Contains(expr->m_Operand1))
+ return scope->Get(expr->m_Operand1);
+
+ scope = scope->Get("__parent");
+ }
+
+ return ScriptVariable::Get(expr->m_Operand1);
+}
+
+Value AExpression::OpNegate(const AExpression *expr, const Dictionary::Ptr& locals)
+{
+ return ~(long)expr->EvaluateOperand1(locals);
+}
+
+Value AExpression::OpAdd(const AExpression *expr, const Dictionary::Ptr& locals)
+{
+ return expr->EvaluateOperand1(locals) + expr->EvaluateOperand2(locals);
+}
+
+Value AExpression::OpSubtract(const AExpression *expr, const Dictionary::Ptr& locals)
+{
+ return expr->EvaluateOperand1(locals) - expr->EvaluateOperand2(locals);
+}
+
+Value AExpression::OpMultiply(const AExpression *expr, const Dictionary::Ptr& locals)
+{
+ return expr->EvaluateOperand1(locals) * expr->EvaluateOperand2(locals);
+}
+
+Value AExpression::OpDivide(const AExpression *expr, const Dictionary::Ptr& locals)
+{
+ return expr->EvaluateOperand1(locals) / expr->EvaluateOperand2(locals);
+}
+
+Value AExpression::OpBinaryAnd(const AExpression *expr, const Dictionary::Ptr& locals)
+{
+ return expr->EvaluateOperand1(locals) & expr->EvaluateOperand2(locals);
+}
+
+Value AExpression::OpBinaryOr(const AExpression *expr, const Dictionary::Ptr& locals)
+{
+ return expr->EvaluateOperand1(locals) | expr->EvaluateOperand2(locals);
+}
+
+Value AExpression::OpShiftLeft(const AExpression *expr, const Dictionary::Ptr& locals)
+{
+ return expr->EvaluateOperand1(locals) << expr->EvaluateOperand2(locals);
+}
+
+Value AExpression::OpShiftRight(const AExpression *expr, const Dictionary::Ptr& locals)
+{
+ return expr->EvaluateOperand1(locals) >> expr->EvaluateOperand2(locals);
+}
+
+Value AExpression::OpEqual(const AExpression *expr, const Dictionary::Ptr& locals)
+{
+ return expr->EvaluateOperand1(locals) == expr->EvaluateOperand2(locals);
+}
+
+Value AExpression::OpNotEqual(const AExpression *expr, const Dictionary::Ptr& locals)
+{
+ return expr->EvaluateOperand1(locals) != expr->EvaluateOperand2(locals);
+}
+
+Value AExpression::OpLessThan(const AExpression *expr, const Dictionary::Ptr& locals)
+{
+ return expr->EvaluateOperand1(locals) < expr->EvaluateOperand2(locals);
+}
+
+Value AExpression::OpGreaterThan(const AExpression *expr, const Dictionary::Ptr& locals)
+{
+ return expr->EvaluateOperand1(locals) > expr->EvaluateOperand2(locals);
+}
+
+Value AExpression::OpLessThanOrEqual(const AExpression *expr, const Dictionary::Ptr& locals)
+{
+ return expr->EvaluateOperand1(locals) <= expr->EvaluateOperand2(locals);
+}
+
+Value AExpression::OpGreaterThanOrEqual(const AExpression *expr, const Dictionary::Ptr& locals)
+{
+ return expr->EvaluateOperand1(locals) >= expr->EvaluateOperand2(locals);
+}
+
+Value AExpression::OpIn(const AExpression *expr, const Dictionary::Ptr& locals)
+{
+ Value right = expr->EvaluateOperand2(locals);
+
+ if (!right.IsObjectType())
+ BOOST_THROW_EXCEPTION(ConfigError("Invalid right side argument for 'in' operator: " + JsonSerialize(right)));
+
+ Value left = expr->EvaluateOperand1(locals);
+
+ Array::Ptr arr = right;
+ bool found = false;
+ ObjectLock olock(arr);
+ BOOST_FOREACH(const Value& value, arr) {
+ if (value == left) {
+ found = true;
+ break;
+ }
+ }
+
+ return found;
+}
+
+Value AExpression::OpNotIn(const AExpression *expr, const Dictionary::Ptr& locals)
+{
+ return !OpIn(expr, locals);
+}
+
+Value AExpression::OpLogicalAnd(const AExpression *expr, const Dictionary::Ptr& locals)
+{
+ return expr->EvaluateOperand1(locals).ToBool() && expr->EvaluateOperand2(locals).ToBool();
+}
+
+Value AExpression::OpLogicalOr(const AExpression *expr, const Dictionary::Ptr& locals)
+{
+ return expr->EvaluateOperand1(locals).ToBool() || expr->EvaluateOperand2(locals).ToBool();
+}
+
+Value AExpression::OpFunctionCall(const AExpression *expr, const Dictionary::Ptr& locals)
+{
+ String funcName = expr->m_Operand1;
+ ScriptFunction::Ptr func = ScriptFunctionRegistry::GetInstance()->GetItem(funcName);
+
+ if (!func)
+ BOOST_THROW_EXCEPTION(ConfigError("Function '" + funcName + "' does not exist."));
+
+ Array::Ptr arr = expr->EvaluateOperand2(locals);
+ std::vector arguments;
+ ObjectLock olock(arr);
+ BOOST_FOREACH(const AExpression::Ptr& aexpr, arr) {
+ arguments.push_back(aexpr->Evaluate(locals));
+ }
+
+ return func->Invoke(arguments);
+}
+
+Value AExpression::OpArray(const AExpression *expr, const Dictionary::Ptr& locals)
+{
+ Array::Ptr arr = expr->m_Operand1;
+ Array::Ptr result = make_shared();
+
+ if (arr) {
+ ObjectLock olock(arr);
+ BOOST_FOREACH(const AExpression::Ptr& aexpr, arr) {
+ result->Add(aexpr->Evaluate(locals));
+ }
+ }
+
+ return result;
+}
+
+Value AExpression::OpDict(const AExpression *expr, const Dictionary::Ptr& locals)
+{
+ Array::Ptr arr = expr->m_Operand1;
+ bool in_place = expr->m_Operand2;
+ Dictionary::Ptr result = make_shared();
+
+ result->Set("__parent", locals);
+
+ if (arr) {
+ ObjectLock olock(arr);
+ BOOST_FOREACH(const AExpression::Ptr& aexpr, arr) {
+ aexpr->Evaluate(in_place ? locals : result);
+ }
+ }
+
+ result->Remove("__parent");
+
+ return result;
+}
+
+Value AExpression::OpSet(const AExpression *expr, const Dictionary::Ptr& locals)
+{
+ Value right = expr->EvaluateOperand2(locals);
+ locals->Set(expr->m_Operand1, right);
+ return right;
+}
+
+Value AExpression::OpSetPlus(const AExpression *expr, const Dictionary::Ptr& locals)
+{
+ Value left = locals->Get(expr->m_Operand1);
+ AExpression::Ptr exp_right = expr->m_Operand2;
+ Dictionary::Ptr xlocals = locals;
+
+ if (exp_right->m_Operator == &AExpression::OpDict) {
+ xlocals = left;
+
+ if (!xlocals)
+ xlocals = make_shared();
+
+ xlocals->Set("__parent", locals);
+ }
+
+ Value result = left + expr->EvaluateOperand2(xlocals);
+
+ if (exp_right->m_Operator == &AExpression::OpDict) {
+ Dictionary::Ptr dict = result;
+ dict->Remove("__parent");
+ }
+
+ locals->Set(expr->m_Operand1, result);
+ return result;
+}
+
+Value AExpression::OpSetMinus(const AExpression *expr, const Dictionary::Ptr& locals)
+{
+ Value left = locals->Get(expr->m_Operand1);
+ AExpression::Ptr exp_right = expr->m_Operand2;
+ Dictionary::Ptr xlocals = locals;
+
+ if (exp_right->m_Operator == &AExpression::OpDict) {
+ xlocals = left;
+
+ if (!xlocals)
+ xlocals = make_shared();
+
+ xlocals->Set("__parent", locals);
+ }
+
+ Value result = left - expr->EvaluateOperand2(xlocals);
+
+ if (exp_right->m_Operator == &AExpression::OpDict) {
+ Dictionary::Ptr dict = result;
+ dict->Remove("__parent");
+ }
+
+ locals->Set(expr->m_Operand1, result);
+ return result;
+}
+
+Value AExpression::OpSetMultiply(const AExpression *expr, const Dictionary::Ptr& locals)
+{
+ Value left = locals->Get(expr->m_Operand1);
+ AExpression::Ptr exp_right = expr->m_Operand2;
+ Dictionary::Ptr xlocals = locals;
+
+ if (exp_right->m_Operator == &AExpression::OpDict) {
+ xlocals = left;
+
+ if (!xlocals)
+ xlocals = make_shared();
+
+ xlocals->Set("__parent", locals);
+ }
+
+ Value result = left * expr->EvaluateOperand2(xlocals);
+
+ if (exp_right->m_Operator == &AExpression::OpDict) {
+ Dictionary::Ptr dict = result;
+ dict->Remove("__parent");
+ }
+
+ locals->Set(expr->m_Operand1, result);
+ return result;
+}
+
+Value AExpression::OpSetDivide(const AExpression *expr, const Dictionary::Ptr& locals)
+{
+ Value left = locals->Get(expr->m_Operand1);
+ AExpression::Ptr exp_right = expr->m_Operand2;
+ Dictionary::Ptr xlocals = locals;
+
+ if (exp_right->m_Operator == &AExpression::OpDict) {
+ xlocals = left;
+
+ if (!xlocals)
+ xlocals = make_shared();
+
+ xlocals->Set("__parent", locals);
+ }
+
+ Value result = left / expr->EvaluateOperand2(xlocals);
+
+ if (exp_right->m_Operator == &AExpression::OpDict) {
+ Dictionary::Ptr dict = result;
+ dict->Remove("__parent");
+ }
+
+ locals->Set(expr->m_Operand1, result);
+ return result;
+}
+
+Value AExpression::OpIndexer(const AExpression *expr, const Dictionary::Ptr& locals)
+{
+ Dictionary::Ptr dict = OpVariable(expr, locals);
+
+ if (!dict)
+ BOOST_THROW_EXCEPTION(ConfigError("Script variable '" + expr->m_Operand1 + "' not set in this scope."));
+
+ return dict->Get(expr->m_Operand2);
+}
diff --git a/lib/config/aexpression.h b/lib/config/aexpression.h
index 56c16c33d..181ba5740 100644
--- a/lib/config/aexpression.h
+++ b/lib/config/aexpression.h
@@ -21,42 +21,13 @@
#define AEXPRESSION_H
#include "config/i2-config.h"
-#include "config/avalue.h"
#include "config/debuginfo.h"
+#include "base/array.h"
#include "base/dictionary.h"
namespace icinga
{
-/**
- * @ingroup config
- */
-enum AOperator
-{
- AEReturn,
- AENegate,
- AEAdd,
- AESubtract,
- AEMultiply,
- AEDivide,
- AEBinaryAnd,
- AEBinaryOr,
- AEShiftLeft,
- AEShiftRight,
- AEEqual,
- AENotEqual,
- AEIn,
- AENotIn,
- AELogicalAnd,
- AELogicalOr,
- AEFunctionCall,
- AEArray,
- AELessThan,
- AEGreaterThan,
- AELessThanOrEqual,
- AEGreaterThanOrEqual
-};
-
/**
* @ingroup config
*/
@@ -64,17 +35,62 @@ class I2_CONFIG_API AExpression : public Object
{
public:
DECLARE_PTR_TYPEDEFS(AExpression);
+
+ typedef Value (*OpCallback)(const AExpression *, const Dictionary::Ptr&);
- AExpression(AOperator op, const AValue& operand1, const DebugInfo& di);
- AExpression(AOperator op, const AValue& operand1, const AValue& operand2, const DebugInfo& di);
+ AExpression(OpCallback op, const Value& operand1, const DebugInfo& di);
+ AExpression(OpCallback op, const Value& operand1, const Value& operand2, const DebugInfo& di);
Value Evaluate(const Dictionary::Ptr& locals) const;
+ void ExtractPath(const std::vector& path, const Array::Ptr& result) const;
+ void FindDebugInfoPath(const std::vector& path, DebugInfo& result) const;
+
+ void MakeInline(void);
+
+ void Dump(std::ostream& stream, int indent = 0) const;
+ void Dump(void) const;
+
+ static Value OpLiteral(const AExpression *expr, const Dictionary::Ptr& locals);
+ static Value OpVariable(const AExpression *expr, const Dictionary::Ptr& locals);
+ static Value OpNegate(const AExpression *expr, const Dictionary::Ptr& locals);
+ static Value OpAdd(const AExpression *expr, const Dictionary::Ptr& locals);
+ static Value OpSubtract(const AExpression *expr, const Dictionary::Ptr& locals);
+ static Value OpMultiply(const AExpression *expr, const Dictionary::Ptr& locals);
+ static Value OpDivide(const AExpression *expr, const Dictionary::Ptr& locals);
+ static Value OpBinaryAnd(const AExpression *expr, const Dictionary::Ptr& locals);
+ static Value OpBinaryOr(const AExpression *expr, const Dictionary::Ptr& locals);
+ static Value OpShiftLeft(const AExpression *expr, const Dictionary::Ptr& locals);
+ static Value OpShiftRight(const AExpression *expr, const Dictionary::Ptr& locals);
+ static Value OpEqual(const AExpression *expr, const Dictionary::Ptr& locals);
+ static Value OpNotEqual(const AExpression *expr, const Dictionary::Ptr& locals);
+ static Value OpLessThan(const AExpression *expr, const Dictionary::Ptr& locals);
+ static Value OpGreaterThan(const AExpression *expr, const Dictionary::Ptr& locals);
+ static Value OpLessThanOrEqual(const AExpression *expr, const Dictionary::Ptr& locals);
+ static Value OpGreaterThanOrEqual(const AExpression *expr, const Dictionary::Ptr& locals);
+ static Value OpIn(const AExpression *expr, const Dictionary::Ptr& locals);
+ static Value OpNotIn(const AExpression *expr, const Dictionary::Ptr& locals);
+ static Value OpLogicalAnd(const AExpression *expr, const Dictionary::Ptr& locals);
+ static Value OpLogicalOr(const AExpression *expr, const Dictionary::Ptr& locals);
+ static Value OpFunctionCall(const AExpression *expr, const Dictionary::Ptr& locals);
+ static Value OpArray(const AExpression *expr, const Dictionary::Ptr& locals);
+ static Value OpDict(const AExpression *expr, const Dictionary::Ptr& locals);
+ static Value OpSet(const AExpression *expr, const Dictionary::Ptr& locals);
+ static Value OpSetPlus(const AExpression *expr, const Dictionary::Ptr& locals);
+ static Value OpSetMinus(const AExpression *expr, const Dictionary::Ptr& locals);
+ static Value OpSetMultiply(const AExpression *expr, const Dictionary::Ptr& locals);
+ static Value OpSetDivide(const AExpression *expr, const Dictionary::Ptr& locals);
+ static Value OpIndexer(const AExpression *expr, const Dictionary::Ptr& locals);
private:
- AOperator m_Operator;
- AValue m_Operand1;
- AValue m_Operand2;
+ OpCallback m_Operator;
+ Value m_Operand1;
+ Value m_Operand2;
DebugInfo m_DebugInfo;
+
+ Value EvaluateOperand1(const Dictionary::Ptr& locals) const;
+ Value EvaluateOperand2(const Dictionary::Ptr& locals) const;
+
+ static void DumpOperand(std::ostream& stream, const Value& operand, int indent);
};
}
diff --git a/lib/config/applyrule.cpp b/lib/config/applyrule.cpp
index 23247db27..c31fd2b07 100644
--- a/lib/config/applyrule.cpp
+++ b/lib/config/applyrule.cpp
@@ -24,8 +24,8 @@ using namespace icinga;
ApplyRule::RuleMap ApplyRule::m_Rules;
ApplyRule::CallbackMap ApplyRule::m_Callbacks;
-ApplyRule::ApplyRule(const String& tmpl, const AExpression::Ptr& expression, const DebugInfo& di)
- : m_Template(tmpl), m_Expression(expression), m_DebugInfo(di)
+ApplyRule::ApplyRule(const String& tmpl, const AExpression::Ptr& expression, const DebugInfo& di, const Dictionary::Ptr& scope)
+ : m_Template(tmpl), m_Expression(expression), m_DebugInfo(di), m_Scope(scope)
{ }
String ApplyRule::GetTemplate(void) const
@@ -43,9 +43,14 @@ DebugInfo ApplyRule::GetDebugInfo(void) const
return m_DebugInfo;
}
-void ApplyRule::AddRule(const String& sourceType, const String& tmpl, const String& targetType, const AExpression::Ptr& expression, const DebugInfo& di)
+Dictionary::Ptr ApplyRule::GetScope(void) const
{
- m_Rules[std::make_pair(sourceType, targetType)].push_back(ApplyRule(tmpl, expression, di));
+ return m_Scope;
+}
+
+void ApplyRule::AddRule(const String& sourceType, const String& tmpl, const String& targetType, const AExpression::Ptr& expression, const DebugInfo& di, const Dictionary::Ptr& scope)
+{
+ m_Rules[std::make_pair(sourceType, targetType)].push_back(ApplyRule(tmpl, expression, di, scope));
}
void ApplyRule::EvaluateRules(void)
diff --git a/lib/config/applyrule.h b/lib/config/applyrule.h
index e08ad98fb..3fba61006 100644
--- a/lib/config/applyrule.h
+++ b/lib/config/applyrule.h
@@ -42,8 +42,9 @@ public:
String GetTemplate(void) const;
AExpression::Ptr GetExpression(void) const;
DebugInfo GetDebugInfo(void) const;
+ Dictionary::Ptr GetScope(void) const;
- static void AddRule(const String& sourceType, const String& tmpl, const String& targetType, const AExpression::Ptr& expression, const DebugInfo& di);
+ static void AddRule(const String& sourceType, const String& tmpl, const String& targetType, const AExpression::Ptr& expression, const DebugInfo& di, const Dictionary::Ptr& scope);
static void EvaluateRules(void);
static void RegisterCombination(const String& sourceType, const String& targetType, const ApplyRule::Callback& callback);
@@ -53,11 +54,12 @@ private:
String m_Template;
AExpression::Ptr m_Expression;
DebugInfo m_DebugInfo;
+ Dictionary::Ptr m_Scope;
static CallbackMap m_Callbacks;
static RuleMap m_Rules;
- ApplyRule(const String& tmpl, const AExpression::Ptr& expression, const DebugInfo& di);
+ ApplyRule(const String& tmpl, const AExpression::Ptr& expression, const DebugInfo& di, const Dictionary::Ptr& scope);
};
}
diff --git a/lib/config/avalue.cpp b/lib/config/avalue.cpp
deleted file mode 100644
index 742bbca22..000000000
--- a/lib/config/avalue.cpp
+++ /dev/null
@@ -1,55 +0,0 @@
-/******************************************************************************
- * Icinga 2 *
- * Copyright (C) 2012-2014 Icinga Development Team (http://www.icinga.org) *
- * *
- * This program is free software; you can redistribute it and/or *
- * modify it under the terms of the GNU General Public License *
- * as published by the Free Software Foundation; either version 2 *
- * of the License, or (at your option) any later version. *
- * *
- * This program is distributed in the hope that it will be useful, *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
- * GNU General Public License for more details. *
- * *
- * You should have received a copy of the GNU General Public License *
- * along with this program; if not, write to the Free Software Foundation *
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
- ******************************************************************************/
-
-#include "config/avalue.h"
-#include "config/aexpression.h"
-#include "base/scriptvariable.h"
-
-using namespace icinga;
-
-AValue::AValue(void)
- : m_Type(ATSimple)
-{ }
-
-AValue::AValue(const AExpression::Ptr& expr)
- : m_Type(ATExpression), m_Expression(expr)
-{ }
-
-AValue::AValue(AValueType type, const Value& value)
- : m_Type(type), m_Value(value)
-{ }
-
-Value AValue::Evaluate(const Dictionary::Ptr& locals) const
-{
- switch (m_Type) {
- case ATSimple:
- return m_Value;
- case ATVariable:
- if (locals && locals->Contains(m_Value))
- return locals->Get(m_Value);
- else
- return ScriptVariable::Get(m_Value);
- case ATThisRef:
- VERIFY(!"Not implemented.");
- case ATExpression:
- return m_Expression->Evaluate(locals);
- default:
- ASSERT(!"Invalid type.");
- }
-}
diff --git a/lib/config/avalue.h b/lib/config/avalue.h
deleted file mode 100644
index 37969ca3f..000000000
--- a/lib/config/avalue.h
+++ /dev/null
@@ -1,64 +0,0 @@
-/******************************************************************************
- * Icinga 2 *
- * Copyright (C) 2012-2014 Icinga Development Team (http://www.icinga.org) *
- * *
- * This program is free software; you can redistribute it and/or *
- * modify it under the terms of the GNU General Public License *
- * as published by the Free Software Foundation; either version 2 *
- * of the License, or (at your option) any later version. *
- * *
- * This program is distributed in the hope that it will be useful, *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
- * GNU General Public License for more details. *
- * *
- * You should have received a copy of the GNU General Public License *
- * along with this program; if not, write to the Free Software Foundation *
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
- ******************************************************************************/
-
-#ifndef AVALUE_H
-#define AVALUE_H
-
-#include "config/i2-config.h"
-#include "base/value.h"
-#include "base/dictionary.h"
-
-namespace icinga
-{
-
-/**
- * @ingroup config
- */
-enum AValueType
-{
- ATSimple,
- ATVariable,
- ATThisRef,
- ATExpression
-};
-
-class AExpression;
-
-/**
- * @ingroup config
- */
-class I2_CONFIG_API AValue
-{
-public:
- AValue(void);
- AValue(const shared_ptr& expr);
- AValue(AValueType type, const Value& value);
-
- Value Evaluate(const Dictionary::Ptr& locals) const;
-
-private:
- AValueType m_Type;
- Value m_Value;
- shared_ptr m_Expression;
-};
-
-}
-
-#endif /* AVALUE_H */
-
diff --git a/lib/config/config_lexer.ll b/lib/config/config_lexer.ll
index 54cb1f561..d6e9331ea 100644
--- a/lib/config/config_lexer.ll
+++ b/lib/config/config_lexer.ll
@@ -19,7 +19,6 @@
******************************************************************************/
#include "config/configcompiler.h"
-#include "config/expression.h"
#include "config/typerule.h"
#include "config/configcompilercontext.h"
@@ -225,16 +224,16 @@ const return T_CONST;
apply return T_APPLY;
to return T_TO;
where return T_WHERE;
-\<\< return T_SHIFT_LEFT;
-\>\> return T_SHIFT_RIGHT;
-\<= return T_LESS_THAN_OR_EQUAL;
-\>= return T_GREATER_THAN_OR_EQUAL;
-== return T_EQUAL;
-!= return T_NOT_EQUAL;
-!in return T_NOT_IN;
-in return T_IN;
-&& return T_LOGICAL_AND;
-\|\| return T_LOGICAL_OR;
+\<\< { yylval->op = &AExpression::OpShiftLeft; return T_SHIFT_LEFT; }
+\>\> { yylval->op = &AExpression::OpShiftRight; return T_SHIFT_RIGHT; }
+\<= { yylval->op = &AExpression::OpLessThanOrEqual; return T_LESS_THAN_OR_EQUAL; }
+\>= { yylval->op = &AExpression::OpGreaterThanOrEqual; return T_GREATER_THAN_OR_EQUAL; }
+== { yylval->op = &AExpression::OpEqual; return T_EQUAL; }
+!= { yylval->op = &AExpression::OpNotEqual; return T_NOT_EQUAL; }
+!in { yylval->op = &AExpression::OpNotIn; return T_NOT_IN; }
+in { yylval->op = &AExpression::OpIn; return T_IN; }
+&& { yylval->op = &AExpression::OpLogicalAnd; return T_LOGICAL_AND; }
+\|\| { yylval->op = &AExpression::OpLogicalOr; return T_LOGICAL_OR; }
[a-zA-Z_][:a-zA-Z0-9\-_]* { yylval->text = strdup(yytext); return T_IDENTIFIER; }
\<[^\>]*\> { yytext[yyleng-1] = '\0'; yylval->text = strdup(yytext + 1); return T_STRING_ANGLE; }
-?[0-9]+(\.[0-9]+)?ms { yylval->num = strtod(yytext, NULL) / 1000; return T_NUMBER; }
@@ -243,11 +242,19 @@ in return T_IN;
-?[0-9]+(\.[0-9]+)?m { yylval->num = strtod(yytext, NULL) * 60; return T_NUMBER; }
-?[0-9]+(\.[0-9]+)?s { yylval->num = strtod(yytext, NULL); return T_NUMBER; }
-?[0-9]+(\.[0-9]+)? { yylval->num = strtod(yytext, NULL); return T_NUMBER; }
-= { yylval->op = OperatorSet; return T_SET; }
-\+= { yylval->op = OperatorPlus; return T_PLUS_EQUAL; }
--= { yylval->op = OperatorMinus; return T_MINUS_EQUAL; }
-\*= { yylval->op = OperatorMultiply; return T_MULTIPLY_EQUAL; }
-\/= { yylval->op = OperatorDivide; return T_DIVIDE_EQUAL; }
+= { yylval->op = &AExpression::OpSet; return T_SET; }
+\+= { yylval->op = &AExpression::OpSetPlus; return T_SET_PLUS; }
+-= { yylval->op = &AExpression::OpSetMinus; return T_SET_MINUS; }
+\*= { yylval->op = &AExpression::OpSetMultiply; return T_SET_MULTIPLY; }
+\/= { yylval->op = &AExpression::OpSetDivide; return T_SET_DIVIDE; }
+\+ { yylval->op = &AExpression::OpAdd; return T_PLUS; }
+\- { yylval->op = &AExpression::OpSubtract; return T_MINUS; }
+\* { yylval->op = &AExpression::OpMultiply; return T_MULTIPLY; }
+\/ { yylval->op = &AExpression::OpMultiply; return T_DIVIDE; }
+\& { yylval->op = &AExpression::OpBinaryAnd; return T_BINARY_AND; }
+\| { yylval->op = &AExpression::OpBinaryOr; return T_BINARY_OR; }
+\< { yylval->op = &AExpression::OpLessThan; return T_LESS_THAN; }
+\> { yylval->op = &AExpression::OpLessThan; return T_GREATER_THAN; }
}
. return yytext[0];
diff --git a/lib/config/config_parser.yy b/lib/config/config_parser.yy
index 976f0d4b7..8be7318b5 100644
--- a/lib/config/config_parser.yy
+++ b/lib/config/config_parser.yy
@@ -21,8 +21,6 @@
******************************************************************************/
#include "i2-config.h"
-#include "config/expression.h"
-#include "config/expressionlist.h"
#include "config/configitembuilder.h"
#include "config/configcompiler.h"
#include "config/configcompilercontext.h"
@@ -86,13 +84,10 @@ using namespace icinga;
char *text;
double num;
icinga::Value *variant;
- icinga::ExpressionOperator op;
+ icinga::AExpression::OpCallback op;
icinga::TypeSpecifier type;
std::vector *slist;
- Expression *expr;
- ExpressionList *exprl;
Array *array;
- Value *aexpr;
}
%token T_STRING
@@ -100,23 +95,34 @@ using namespace icinga;
%token T_NUMBER
%token T_NULL
%token T_IDENTIFIER
+
%token T_SET "= (T_SET)"
-%token T_PLUS_EQUAL "+= (T_PLUS_EQUAL)"
-%token T_MINUS_EQUAL "-= (T_MINUS_EQUAL)"
-%token T_MULTIPLY_EQUAL "*= (T_MULTIPLY_EQUAL)"
-%token T_DIVIDE_EQUAL "/= (T_DIVIDE_EQUAL)"
+%token T_SET_PLUS "+= (T_SET_PLUS)"
+%token T_SET_MINUS "-= (T_SET_MINUS)"
+%token T_SET_MULTIPLY "*= (T_SET_MULTIPLY)"
+%token T_SET_DIVIDE "/= (T_SET_DIVIDE)"
+
+%token T_SHIFT_LEFT "<< (T_SHIFT_LEFT)"
+%token T_SHIFT_RIGHT ">> (T_SHIFT_RIGHT)"
+%token T_EQUAL "== (T_EQUAL)"
+%token T_NOT_EQUAL "!= (T_NOT_EQUAL)"
+%token T_IN "in (T_IN)"
+%token T_NOT_IN "!in (T_NOT_IN)"
+%token T_LOGICAL_AND "&& (T_LOGICAL_AND)"
+%token T_LOGICAL_OR "|| (T_LOGICAL_OR)"
+%token T_LESS_THAN_OR_EQUAL "<= (T_LESS_THAN_OR_EQUAL)"
+%token T_GREATER_THAN_OR_EQUAL ">= (T_GREATER_THAN_OR_EQUAL)"
+%token T_PLUS "+ (T_PLUS)"
+%token T_MINUS "- (T_MINUS)"
+%token T_MULTIPLY "* (T_MULTIPLY)"
+%token T_DIVIDE "/ (T_DIVIDE)"
+%token T_BINARY_AND "& (T_BINARY_AND)"
+%token T_BINARY_OR "| (T_BINARY_OR)"
+%token T_LESS_THAN "< (T_LESS_THAN)"
+%token T_GREATER_THAN "> (T_GREATER_THAN)"
+
%token T_VAR "var (T_VAR)"
%token T_CONST "const (T_CONST)"
-%token T_SHIFT_LEFT "<< (T_SHIFT_LEFT)"
-%token T_SHIFT_RIGHT ">> (T_SHIFT_RIGHT)"
-%token T_EQUAL "== (T_EQUAL)"
-%token T_NOT_EQUAL "!= (T_NOT_EQUAL)"
-%token T_IN "in (T_IN)"
-%token T_NOT_IN "!in (T_NOT_IN)"
-%token T_LOGICAL_AND "&& (T_LOGICAL_AND)"
-%token T_LOGICAL_OR "|| (T_LOGICAL_OR)"
-%token T_LESS_THAN_OR_EQUAL "<= (T_LESS_THAN_OR_EQUAL)"
-%token T_GREATER_THAN_OR_EQUAL ">= (T_GREATER_THAN_OR_EQUAL)"
%token T_TYPE_DICTIONARY "dictionary (T_TYPE_DICTIONARY)"
%token T_TYPE_ARRAY "array (T_TYPE_ARRAY)"
%token T_TYPE_NUMBER "number (T_TYPE_NUMBER)"
@@ -139,20 +145,20 @@ using namespace icinga;
%token T_TO "to (T_TO)"
%token T_WHERE "where (T_WHERE)"
%type identifier
-%type array_items
-%type array_items_inner
-%type value
-%type expression
-%type expressions
-%type expressions_inner
-%type expressionlist
+%type rterm_items
+%type rterm_items_inner
+%type lterm_items
+%type lterm_items_inner
%type typerulelist
-%type operator
+%type lbinary_op
+%type rbinary_op
%type type
%type partial_specifier
%type object_inherits_list
%type object_inherits_specifier
-%type aexpression
+%type rterm
+%type rterm_scope
+%type lterm
%type variable_decl
%left T_LOGICAL_OR
%left T_LOGICAL_AND
@@ -179,18 +185,22 @@ void yyerror(YYLTYPE *locp, ConfigCompiler *, const char *err)
int yyparse(ConfigCompiler *context);
-static std::stack m_Arrays;
static bool m_Abstract;
static std::stack m_RuleLists;
static ConfigType::Ptr m_Type;
+static Dictionary::Ptr m_ModuleScope;
+
void ConfigCompiler::Compile(void)
{
+ m_ModuleScope = make_shared();
+
try {
yyparse(this);
} catch (const ConfigError& ex) {
- ConfigCompilerContext::GetInstance()->AddMessage(true, ex.what(), ex.GetDebugInfo());
+ const DebugInfo *di = boost::get_error_info(ex);
+ ConfigCompilerContext::GetInstance()->AddMessage(true, ex.what(), di ? *di : DebugInfo());
} catch (const std::exception& ex) {
ConfigCompilerContext::GetInstance()->AddMessage(true, DiagnosticInformation(ex));
}
@@ -206,12 +216,21 @@ statements: /* empty */
;
statement: object | type | include | include_recursive | library | variable | apply
+ { }
+ | lterm
+ {
+ AExpression::Ptr aexpr = *$1;
+ aexpr->Evaluate(m_ModuleScope);
+ delete $1;
+ }
;
-include: T_INCLUDE value
+include: T_INCLUDE rterm
{
- context->HandleInclude(*$2, false, DebugInfoRange(@1, @2));
+ AExpression::Ptr aexpr = static_cast(*$2);
delete $2;
+
+ context->HandleInclude(aexpr->Evaluate(m_ModuleScope), false, DebugInfoRange(@1, @2));
}
| T_INCLUDE T_STRING_ANGLE
{
@@ -220,16 +239,22 @@ include: T_INCLUDE value
}
;
-include_recursive: T_INCLUDE_RECURSIVE value
+include_recursive: T_INCLUDE_RECURSIVE rterm
{
- context->HandleIncludeRecursive(*$2, "*.conf", DebugInfoRange(@1, @2));
+ AExpression::Ptr aexpr = static_cast(*$2);
delete $2;
+
+ context->HandleIncludeRecursive(aexpr->Evaluate(m_ModuleScope), "*.conf", DebugInfoRange(@1, @2));
}
- | T_INCLUDE_RECURSIVE value value
+ | T_INCLUDE_RECURSIVE rterm rterm
{
- context->HandleIncludeRecursive(*$2, *$3, DebugInfoRange(@1, @3));
+ AExpression::Ptr aexpr1 = static_cast(*$2);
delete $2;
+
+ AExpression::Ptr aexpr2 = static_cast(*$3);
delete $3;
+
+ context->HandleIncludeRecursive(aexpr1->Evaluate(m_ModuleScope), aexpr2->Evaluate(m_ModuleScope), DebugInfoRange(@1, @3));
}
;
@@ -240,22 +265,15 @@ library: T_LIBRARY T_STRING
}
;
-variable: variable_decl identifier T_SET value
+variable: variable_decl identifier T_SET rterm
{
- Value *value = $4;
- if (value->IsObjectType()) {
- Dictionary::Ptr dict = make_shared();
- ExpressionList::Ptr exprl = *value;
- exprl->Execute(dict);
- delete value;
- value = new Value(dict);
- }
+ AExpression::Ptr aexpr = static_cast(*$4);
+ delete $4;
- ScriptVariable::Ptr sv = ScriptVariable::Set($2, *value);
+ ScriptVariable::Ptr sv = ScriptVariable::Set($2, aexpr->Evaluate(m_ModuleScope));
sv->SetConstant(true);
free($2);
- delete value;
}
;
@@ -285,7 +303,7 @@ type: partial_specifier T_TYPE identifier
if (!m_Type) {
if ($1)
- BOOST_THROW_EXCEPTION(ConfigError("Partial type definition for unknown type '" + name + "'", DebugInfoRange(@1, @3)));
+ BOOST_THROW_EXCEPTION(ConfigError("Partial type definition for unknown type '" + name + "'") << errinfo_debuginfo(DebugInfoRange(@1, @3)));
m_Type = make_shared(name, DebugInfoRange(@1, @3));
m_Type->Register();
@@ -393,35 +411,38 @@ object:
{
m_Abstract = false;
}
- object_declaration identifier T_STRING object_inherits_specifier expressionlist
+ object_declaration identifier rterm object_inherits_specifier rterm_scope
{
DebugInfo di = DebugInfoRange(@2, @6);
ConfigItemBuilder::Ptr item = make_shared(di);
- ConfigItem::Ptr oldItem = ConfigItem::GetObject($3, $4);
+ AExpression::Ptr aexpr = static_cast(*$4);
+ delete $4;
+
+ String name = aexpr->Evaluate(m_ModuleScope);
+
+ ConfigItem::Ptr oldItem = ConfigItem::GetObject($3, name);
if (oldItem) {
std::ostringstream msgbuf;
- msgbuf << "Object '" << $4 << "' of type '" << $3 << "' re-defined: " << di << "; previous definition: " << oldItem->GetDebugInfo();
+ msgbuf << "Object '" << name << "' of type '" << $3 << "' re-defined: " << di << "; previous definition: " << oldItem->GetDebugInfo();
free($3);
- free($4);
delete $5;
- BOOST_THROW_EXCEPTION(ConfigError(msgbuf.str(), di));
+ BOOST_THROW_EXCEPTION(ConfigError(msgbuf.str()) << errinfo_debuginfo(di));
}
item->SetType($3);
- if (strchr($4, '!') != NULL) {
+ if (name.FindFirstOf("!") != String::NPos) {
std::ostringstream msgbuf;
- msgbuf << "Name for object '" << $4 << "' of type '" << $3 << "' is invalid: Object names may not contain '!'";
+ msgbuf << "Name for object '" << name << "' of type '" << $3 << "' is invalid: Object names may not contain '!'";
free($3);
- BOOST_THROW_EXCEPTION(ConfigError(msgbuf.str(), @4));
+ BOOST_THROW_EXCEPTION(ConfigError(msgbuf.str()) << errinfo_debuginfo(@4));
}
free($3);
- item->SetName($4);
- free($4);
+ item->SetName(name);
if ($5) {
BOOST_FOREACH(const String& parent, *$5) {
@@ -431,13 +452,16 @@ object:
delete $5;
}
- if ($6) {
- ExpressionList::Ptr exprl = ExpressionList::Ptr($6);
- item->AddExpressionList(exprl);
- }
+ AExpression::Ptr exprl = static_cast(*$6);
+ delete $6;
+
+ exprl->MakeInline();
+ item->AddExpression(exprl);
item->SetAbstract(m_Abstract);
+ item->SetScope(m_ModuleScope);
+
item->Compile()->Register();
item.reset();
}
@@ -481,96 +505,39 @@ object_inherits_specifier:
}
;
-expressionlist: '{' expressions '}'
- {
- if ($2)
- $$ = $2;
- else
- $$ = new ExpressionList();
- }
- ;
-
-expressions: expressions_inner
- {
- $$ = $1;
- }
- | expressions_inner ','
- {
- $$ = $1;
- }
-
-expressions_inner: /* empty */
- {
- $$ = NULL;
- }
- | expression
- {
- $$ = new ExpressionList();
- $$->AddExpression(*$1);
- delete $1;
- }
- | expressions_inner ',' expression
- {
- if ($1)
- $$ = $1;
- else
- $$ = new ExpressionList();
-
- $$->AddExpression(*$3);
- delete $3;
- }
- ;
-
-expression: identifier operator value
- {
- $$ = new Expression($1, $2, *$3, DebugInfoRange(@1, @3));
- free($1);
- delete $3;
- }
- | identifier '[' T_STRING ']' operator value
- {
- Expression subexpr($3, $5, *$6, DebugInfoRange(@1, @6));
- free($3);
- delete $6;
-
- ExpressionList::Ptr subexprl = make_shared();
- subexprl->AddExpression(subexpr);
-
- $$ = new Expression($1, OperatorPlus, subexprl, DebugInfoRange(@1, @6));
- free($1);
- }
- ;
-
-operator: T_SET
- | T_PLUS_EQUAL
- | T_MINUS_EQUAL
- | T_MULTIPLY_EQUAL
- | T_DIVIDE_EQUAL
+lbinary_op: T_SET
+ | T_SET_PLUS
+ | T_SET_MINUS
+ | T_SET_MULTIPLY
+ | T_SET_DIVIDE
{
$$ = $1;
}
;
-array_items: array_items_inner
+comma_or_semicolon: ',' | ';'
+ ;
+
+lterm_items: lterm_items_inner
{
$$ = $1;
}
- | array_items_inner ','
+ | lterm_items_inner comma_or_semicolon
{
$$ = $1;
}
-array_items_inner: /* empty */
+lterm_items_inner: /* empty */
{
- $$ = NULL;
+ $$ = new Array();
}
- | aexpression
+ | lterm
{
$$ = new Array();
$$->Add(*$1);
delete $1;
}
- | array_items_inner ',' aexpression
+ | lterm_items_inner comma_or_semicolon lterm
{
if ($1)
$$ = $1;
@@ -582,168 +549,156 @@ array_items_inner: /* empty */
}
;
-aexpression: T_STRING
+lterm: identifier lbinary_op rterm
{
- $$ = new Value(make_shared(AEReturn, AValue(ATSimple, $1), @1));
+ AExpression::Ptr aexpr = static_cast(*$3);
+ $$ = new Value(make_shared($2, $1, aexpr, DebugInfoRange(@1, @3)));
+ free($1);
+ delete $3;
+ }
+ | identifier '[' T_STRING ']' lbinary_op rterm
+ {
+ AExpression::Ptr subexpr = make_shared($5, $3, static_cast(*$6), DebugInfoRange(@1, @6));
+ free($3);
+ delete $6;
+
+ Array::Ptr subexprl = make_shared();
+ subexprl->Add(subexpr);
+
+ AExpression::Ptr expr = make_shared(&AExpression::OpDict, subexprl, DebugInfoRange(@1, @6));
+ $$ = new Value(make_shared(&AExpression::OpSetPlus, $1, expr, DebugInfoRange(@1, @6)));
free($1);
}
- | T_NUMBER
+ | rterm
{
- $$ = new Value(make_shared(AEReturn, AValue(ATSimple, $1), @1));
+ $$ = $1;
}
- | T_NULL
+ ;
+
+rbinary_op: T_PLUS
+ | T_MINUS
+ | T_MULTIPLY
+ | T_DIVIDE
+ | T_BINARY_AND
+ | T_BINARY_OR
+ | T_LESS_THAN
+ | T_GREATER_THAN
+ | T_LESS_THAN_OR_EQUAL
+ | T_GREATER_THAN_OR_EQUAL
+ | T_EQUAL
+ | T_NOT_EQUAL
+ | T_IN
+ | T_NOT_IN
+ | T_LOGICAL_AND
+ | T_LOGICAL_OR
+ | T_SHIFT_LEFT
+ | T_SHIFT_RIGHT
{
- $$ = new Value(make_shared(AEReturn, AValue(ATSimple, Empty), @1));
+ $$ = $1;
}
- | T_IDENTIFIER '(' array_items ')'
+ ;
+
+rterm_items: rterm_items_inner
{
- Array::Ptr arguments = Array::Ptr($3);
- $$ = new Value(make_shared(AEFunctionCall, AValue(ATSimple, $1), AValue(ATSimple, arguments), DebugInfoRange(@1, @4)));
- free($1);
+ $$ = $1;
}
- | T_IDENTIFIER
+ | rterm_items_inner ','
{
- $$ = new Value(make_shared(AEReturn, AValue(ATVariable, $1), @1));
- free($1);
+ $$ = $1;
}
- | '!' aexpression
+ ;
+
+rterm_items_inner: /* empty */
{
- $$ = new Value(make_shared(AENegate, static_cast(*$2), DebugInfoRange(@1, @2)));
- delete $2;
+ $$ = new Array();
}
- | '~' aexpression
+ | rterm
{
- $$ = new Value(make_shared(AENegate, static_cast(*$2), DebugInfoRange(@1, @2)));
- delete $2;
- }
- | '[' array_items ']'
- {
- $$ = new Value(make_shared(AEArray, AValue(ATSimple, Array::Ptr($2)), DebugInfoRange(@1, @3)));
- }
- | '(' aexpression ')'
- {
- $$ = $2;
- }
- | aexpression '+' aexpression
- {
- $$ = new Value(make_shared(AEAdd, static_cast(*$1), static_cast(*$3), DebugInfoRange(@1, @3)));
+ $$ = new Array();
+ $$->Add(*$1);
delete $1;
- delete $3;
}
- | aexpression '-' aexpression
+ | rterm_items_inner ',' rterm
{
- $$ = new Value(make_shared(AESubtract, static_cast(*$1), static_cast(*$3), DebugInfoRange(@1, @3)));
- delete $1;
- delete $3;
- }
- | aexpression '*' aexpression
- {
- $$ = new Value(make_shared(AEMultiply, static_cast(*$1), static_cast(*$3), DebugInfoRange(@1, @3)));
- delete $1;
- delete $3;
- }
- | aexpression '/' aexpression
- {
- $$ = new Value(make_shared(AEDivide, static_cast(*$1), static_cast(*$3), DebugInfoRange(@1, @3)));
- delete $1;
- delete $3;
- }
- | aexpression '&' aexpression
- {
- $$ = new Value(make_shared(AEBinaryAnd, static_cast(*$1), static_cast(*$3), DebugInfoRange(@1, @3)));
- delete $1;
- delete $3;
- }
- | aexpression '|' aexpression
- {
- $$ = new Value(make_shared(AEBinaryOr, static_cast(*$1), static_cast(*$3), DebugInfoRange(@1, @2)));
- delete $1;
- delete $3;
- }
- | aexpression T_IN aexpression
- {
- $$ = new Value(make_shared(AEIn, static_cast(*$1), static_cast(*$3), DebugInfoRange(@1, @3)));
- delete $1;
- delete $3;
- }
- | aexpression T_NOT_IN aexpression
- {
- $$ = new Value(make_shared(AENotIn, static_cast(*$1), static_cast(*$3), DebugInfoRange(@1, @3)));
- delete $1;
- delete $3;
- }
- | aexpression T_LESS_THAN_OR_EQUAL aexpression
- {
- $$ = new Value(make_shared(AELessThanOrEqual, static_cast(*$1), static_cast(*$3), DebugInfoRange(@1, @3)));
- delete $1;
- delete $3;
- }
- | aexpression T_GREATER_THAN_OR_EQUAL aexpression
- {
- $$ = new Value(make_shared(AEGreaterThanOrEqual, static_cast(*$1), static_cast(*$3), DebugInfoRange(@1, @3)));
- delete $1;
- delete $3;
- }
- | aexpression '<' aexpression
- {
- $$ = new Value(make_shared(AELessThan, static_cast(*$1), static_cast(*$3), DebugInfoRange(@1, @3)));
- delete $1;
- delete $3;
- }
- | aexpression '>' aexpression
- {
- $$ = new Value(make_shared(AEGreaterThan, static_cast(*$1), static_cast(*$3), DebugInfoRange(@1, @3)));
- delete $1;
- delete $3;
- }
- | aexpression T_EQUAL aexpression
- {
- $$ = new Value(make_shared(AEEqual, static_cast(*$1), static_cast(*$3), DebugInfoRange(@1, @3)));
- delete $1;
- delete $3;
- }
- | aexpression T_NOT_EQUAL aexpression
- {
- $$ = new Value(make_shared(AENotEqual, static_cast(*$1), static_cast(*$3), DebugInfoRange(@1, @3)));
- delete $1;
- delete $3;
- }
- | aexpression T_SHIFT_LEFT aexpression
- {
- $$ = new Value(make_shared(AEShiftLeft, static_cast(*$1), static_cast(*$3), DebugInfoRange(@1, @3)));
- delete $1;
- delete $3;
- }
- | aexpression T_SHIFT_RIGHT aexpression
- {
- $$ = new Value(make_shared(AEShiftRight, static_cast(*$1), static_cast(*$3), DebugInfoRange(@1, @3)));
- delete $1;
- delete $3;
- }
- | aexpression T_LOGICAL_AND aexpression
- {
- $$ = new Value(make_shared(AELogicalAnd, static_cast(*$1), static_cast(*$3), DebugInfoRange(@1, @3)));
- delete $1;
- delete $3;
- }
- | aexpression T_LOGICAL_OR aexpression
- {
- $$ = new Value(make_shared(AELogicalOr, static_cast(*$1), static_cast(*$3), DebugInfoRange(@1, @3)));
- delete $1;
+ if ($1)
+ $$ = $1;
+ else
+ $$ = new Array();
+
+ $$->Add(*$3);
delete $3;
}
;
-value: expressionlist
+rbinary_op: '+'
{
- ExpressionList::Ptr exprl = ExpressionList::Ptr($1);
- $$ = new Value(exprl);
+ $$ = &AExpression::OpAdd;
}
- | aexpression
+ ;
+
+rterm_scope: '{' lterm_items '}'
{
- AExpression::Ptr aexpr = *$1;
- $$ = new Value(aexpr->Evaluate(Dictionary::Ptr()));
+ $$ = new Value(make_shared(&AExpression::OpDict, Array::Ptr($2), DebugInfoRange(@1, @3)));
+ }
+ ;
+
+rterm: T_STRING
+ {
+ $$ = new Value(make_shared(&AExpression::OpLiteral, $1, @1));
+ free($1);
+ }
+ | T_NUMBER
+ {
+ $$ = new Value(make_shared(&AExpression::OpLiteral, $1, @1));
+ }
+ | T_NULL
+ {
+ $$ = new Value(make_shared(&AExpression::OpLiteral, Empty, @1));
+ }
+ | T_IDENTIFIER '(' rterm_items ')'
+ {
+ Array::Ptr arguments = Array::Ptr($3);
+ $$ = new Value(make_shared(&AExpression::OpFunctionCall, $1, make_shared(&AExpression::OpLiteral, arguments, @3), DebugInfoRange(@1, @4)));
+ free($1);
+ }
+ | T_IDENTIFIER
+ {
+ $$ = new Value(make_shared(&AExpression::OpVariable, $1, @1));
+ free($1);
+ }
+ | '!' rterm
+ {
+ $$ = new Value(make_shared(&AExpression::OpNegate, static_cast(*$2), DebugInfoRange(@1, @2)));
+ delete $2;
+ }
+ | '~' rterm
+ {
+ $$ = new Value(make_shared(&AExpression::OpNegate, static_cast