Implement constructor-style casts

fixes #8832
This commit is contained in:
Gunnar Beutner 2015-03-21 22:48:23 +01:00
parent 250fc54cd0
commit ed29d06ab6
5 changed files with 58 additions and 7 deletions

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

View 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;
}

View 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 */

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

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