]> granicus.if.org Git - icinga2/commitdiff
Implement constructor-style casts
authorGunnar Beutner <gunnar@beutner.name>
Sat, 21 Mar 2015 21:48:23 +0000 (22:48 +0100)
committerGunnar Beutner <gunnar@beutner.name>
Sat, 21 Mar 2015 21:48:23 +0000 (22:48 +0100)
fixes #8832

lib/base/function.cpp
lib/base/primitivetype.cpp
lib/base/primitivetype.hpp
lib/config/expression.cpp
lib/config/vmops.hpp

index 2b9ccb0d3b2604888931afd66cf378a339d51c7b..f33cde8c1b311c460c35b966a42d80ee5400ff4f 100644 (file)
@@ -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)
index ae0c78386e38d447c8ad8beb1b41e7678f9aacc8..fd2e485c935383dd774371576e9e80830568b047 100644 (file)
@@ -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;
 }
 
index 93a5d88b1b292fc21056da39f49f22da39b1349d..53aa901cd1ffffff60030c0f1ca8092d116941dc 100644 (file)
@@ -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<type>)
+
+#define REGISTER_PRIMITIVE_TYPE_NOINST(type, prototype)                                \
+       REGISTER_PRIMITIVE_TYPE_FACTORY(type, prototype, NULL)
+
 }
 
 #endif /* PRIMITIVETYPE_H */
index 7350a97ae9a27210e4caeb9b7b7c18ade44a0aff..f1b9611810a18e83af5b797bea7522181dc8d0f8 100644 (file)
@@ -395,6 +395,18 @@ ExpressionResult FunctionCallExpression::DoEvaluate(ScriptFrame& frame, DebugHin
                vfunc = vfuncres.GetValue();
        }
 
+       if (vfunc.IsObjectType<Type>()) {
+               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<Function>())
                BOOST_THROW_EXCEPTION(ScriptError("Argument is not a callable object.", m_DebugInfo));
 
index 2642381a49fe545a3fc62ddf22e42c6133a1d510..a01448e1bed65ca5f9bca18616bdbfd81cca5112 100644 (file)
@@ -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<Value>& arguments)
        {
                boost::shared_ptr<ScriptFrame> vframe;