diff --git a/lib/base/function.cpp b/lib/base/function.cpp index 2b9ccb0d3..f33cde8c1 100644 --- a/lib/base/function.cpp +++ b/lib/base/function.cpp @@ -23,7 +23,7 @@ using namespace icinga; -REGISTER_PRIMITIVE_TYPE(Function, Function::GetPrototype()); +REGISTER_PRIMITIVE_TYPE_NOINST(Function, Function::GetPrototype()); Function::Function(const Callback& function) : m_Callback(function) diff --git a/lib/base/primitivetype.cpp b/lib/base/primitivetype.cpp index ae0c78386..fd2e485c9 100644 --- a/lib/base/primitivetype.cpp +++ b/lib/base/primitivetype.cpp @@ -22,8 +22,8 @@ using namespace icinga; -PrimitiveType::PrimitiveType(const String& name) - : m_Name(name) +PrimitiveType::PrimitiveType(const String& name, const ObjectFactory& factory) + : m_Name(name), m_Factory(factory) { } String PrimitiveType::GetName(void) const @@ -58,6 +58,6 @@ int PrimitiveType::GetFieldCount(void) const ObjectFactory PrimitiveType::GetFactory(void) const { - return NULL; + return m_Factory; } diff --git a/lib/base/primitivetype.hpp b/lib/base/primitivetype.hpp index 93a5d88b1..53aa901cd 100644 --- a/lib/base/primitivetype.hpp +++ b/lib/base/primitivetype.hpp @@ -30,7 +30,7 @@ namespace icinga class I2_BASE_API PrimitiveType : public Type { public: - PrimitiveType(const String& name); + PrimitiveType(const String& name, const ObjectFactory& factory = ObjectFactory()); virtual String GetName(void) const; virtual Type::Ptr GetBaseType(void) const; @@ -44,6 +44,7 @@ protected: private: String m_Name; + ObjectFactory m_Factory; }; #define REGISTER_BUILTIN_TYPE(type, prototype) \ @@ -57,11 +58,11 @@ private: INITIALIZE_ONCE_WITH_PRIORITY(RegisterBuiltinType, 15); \ } } } -#define REGISTER_PRIMITIVE_TYPE(type, prototype) \ +#define REGISTER_PRIMITIVE_TYPE_FACTORY(type, prototype, factory) \ namespace { namespace UNIQUE_NAME(prt) { namespace prt ## type { \ void RegisterPrimitiveType(void) \ { \ - icinga::Type::Ptr t = new PrimitiveType(#type); \ + icinga::Type::Ptr t = new PrimitiveType(#type, factory);\ t->SetPrototype(prototype); \ icinga::Type::Register(t); \ type::TypeInstance = t; \ @@ -70,6 +71,12 @@ private: } } } \ DEFINE_TYPE_INSTANCE(type) +#define REGISTER_PRIMITIVE_TYPE(type, prototype) \ + REGISTER_PRIMITIVE_TYPE_FACTORY(type, prototype, DefaultObjectFactory) + +#define REGISTER_PRIMITIVE_TYPE_NOINST(type, prototype) \ + REGISTER_PRIMITIVE_TYPE_FACTORY(type, prototype, NULL) + } #endif /* PRIMITIVETYPE_H */ diff --git a/lib/config/expression.cpp b/lib/config/expression.cpp index 7350a97ae..f1b961181 100644 --- a/lib/config/expression.cpp +++ b/lib/config/expression.cpp @@ -395,6 +395,18 @@ ExpressionResult FunctionCallExpression::DoEvaluate(ScriptFrame& frame, DebugHin vfunc = vfuncres.GetValue(); } + if (vfunc.IsObjectType()) { + if (m_Args.empty()) + return VMOps::ConstructorCall(vfunc, m_DebugInfo); + else if (m_Args.size() == 1) { + ExpressionResult argres = m_Args[0]->Evaluate(frame); + CHECK_RESULT(argres); + + return VMOps::CopyConstructorCall(vfunc, argres.GetValue(), m_DebugInfo); + } else + BOOST_THROW_EXCEPTION(ScriptError("Too many arguments for constructor.", m_DebugInfo)); + } + if (!vfunc.IsObjectType()) BOOST_THROW_EXCEPTION(ScriptError("Argument is not a callable object.", m_DebugInfo)); diff --git a/lib/config/vmops.hpp b/lib/config/vmops.hpp index 2642381a4..a01448e1b 100644 --- a/lib/config/vmops.hpp +++ b/lib/config/vmops.hpp @@ -54,6 +54,38 @@ public: return ScriptGlobal::Get(name); } + static inline Value CopyConstructorCall(const Type::Ptr& type, const Value& value, const DebugInfo& debugInfo = DebugInfo()) + { + if (type->GetName() == "String") + return Convert::ToString(value); + else if (type->GetName() == "Number") + return Convert::ToDouble(value); + else if (type->GetName() == "Boolean") + return Convert::ToBool(value); + else if (!type->IsAssignableFrom(value.GetReflectionType())) + BOOST_THROW_EXCEPTION(ScriptError("Invalid cast: Tried to cast object of type '" + value.GetReflectionType()->GetName() + "' to type '" + type->GetName() + "'", debugInfo)); + else + return value; + } + + static inline Value ConstructorCall(const Type::Ptr& type, const DebugInfo& debugInfo = DebugInfo()) + { + if (type->GetName() == "String") + return ""; + else if (type->GetName() == "Number") + return 0; + else if (type->GetName() == "Boolean") + return false; + else { + Object::Ptr object = type->Instantiate(); + + if (!object) + BOOST_THROW_EXCEPTION(ScriptError("Failed to instantiate object of type '" + type->GetName() + "'", debugInfo)); + + return object; + } + } + static inline Value FunctionCall(ScriptFrame& frame, const Value& self, const Function::Ptr& func, const std::vector& arguments) { boost::shared_ptr vframe;