From eb0892273edde9c971f6fa35f84fc19d8140aef5 Mon Sep 17 00:00:00 2001 From: Gunnar Beutner Date: Tue, 29 Mar 2016 12:45:22 +0200 Subject: [PATCH] Implement the DateTime class fixes #9839 --- lib/base/CMakeLists.txt | 3 +- lib/base/convert.cpp | 16 +++++++ lib/base/convert.hpp | 3 ++ lib/base/datetime-script.cpp | 47 +++++++++++++++++++++ lib/base/datetime.cpp | 75 +++++++++++++++++++++++++++++++++ lib/base/datetime.hpp | 57 +++++++++++++++++++++++++ lib/base/datetime.ti | 32 ++++++++++++++ lib/base/object.hpp | 30 +++++++++++-- lib/base/primitivetype.hpp | 3 ++ lib/base/type.cpp | 4 +- lib/base/type.hpp | 2 +- lib/base/value-operators.cpp | 25 +++++++++++ lib/config/expression.cpp | 14 +++--- lib/config/vmops.hpp | 53 +++++++++++------------ tools/mkclass/class_lexer.ll | 1 + tools/mkclass/classcompiler.cpp | 4 +- tools/mkclass/classcompiler.hpp | 3 +- 17 files changed, 327 insertions(+), 45 deletions(-) create mode 100644 lib/base/datetime-script.cpp create mode 100644 lib/base/datetime.cpp create mode 100644 lib/base/datetime.hpp create mode 100644 lib/base/datetime.ti diff --git a/lib/base/CMakeLists.txt b/lib/base/CMakeLists.txt index 1ccc4d1c8..9c179b2bd 100644 --- a/lib/base/CMakeLists.txt +++ b/lib/base/CMakeLists.txt @@ -17,6 +17,7 @@ mkclass_target(application.ti application.tcpp application.thpp) mkclass_target(configobject.ti configobject.tcpp configobject.thpp) +mkclass_target(datetime.ti datetime.tcpp datetime.thpp) mkclass_target(filelogger.ti filelogger.tcpp filelogger.thpp) mkclass_target(logger.ti logger.tcpp logger.thpp) mkclass_target(streamlogger.ti streamlogger.tcpp streamlogger.thpp) @@ -25,7 +26,7 @@ mkclass_target(sysloglogger.ti sysloglogger.tcpp sysloglogger.thpp) set(base_SOURCES application.cpp application.thpp application-version.cpp array.cpp array-script.cpp boolean.cpp boolean-script.cpp console.cpp context.cpp - convert.cpp debuginfo.cpp dictionary.cpp dictionary-script.cpp + convert.cpp datetime.cpp datetime.thpp datetime-script.cpp debuginfo.cpp dictionary.cpp dictionary-script.cpp configobject.cpp configobject.thpp configobject-script.cpp configtype.cpp configwriter.cpp dependencygraph.cpp exception.cpp fifo.cpp filelogger.cpp filelogger.thpp initialize.cpp json.cpp json-script.cpp loader.cpp logger.cpp logger.thpp math-script.cpp diff --git a/lib/base/convert.cpp b/lib/base/convert.cpp index 23da66b25..3495fdd05 100644 --- a/lib/base/convert.cpp +++ b/lib/base/convert.cpp @@ -18,6 +18,7 @@ ******************************************************************************/ #include "base/convert.hpp" +#include "base/datetime.hpp" #include using namespace icinga; @@ -31,3 +32,18 @@ String Convert::ToString(const Value& val) { return val; } + +double Convert::ToDateTimeValue(double val) +{ + return val; +} + +double Convert::ToDateTimeValue(const Value& val) +{ + if (val.IsNumber()) + return val; + else if (val.IsObjectType()) + return static_cast(val)->GetValue(); + else + BOOST_THROW_EXCEPTION(std::invalid_argument("Not a DateTime value.")); +} diff --git a/lib/base/convert.hpp b/lib/base/convert.hpp index f14be8455..fd2daa3a6 100644 --- a/lib/base/convert.hpp +++ b/lib/base/convert.hpp @@ -83,6 +83,9 @@ public: static String ToString(const String& val); static String ToString(const Value& val); + static double ToDateTimeValue(double val); + static double ToDateTimeValue(const Value& val); + private: Convert(void); }; diff --git a/lib/base/datetime-script.cpp b/lib/base/datetime-script.cpp new file mode 100644 index 000000000..e0210a9b6 --- /dev/null +++ b/lib/base/datetime-script.cpp @@ -0,0 +1,47 @@ +/****************************************************************************** + * Icinga 2 * + * Copyright (C) 2012-2016 Icinga Development Team (https://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 "base/datetime.hpp" +#include "base/function.hpp" +#include "base/functionwrapper.hpp" +#include "base/scriptframe.hpp" +#include "base/objectlock.hpp" + +using namespace icinga; + +static String DateTimeFormat(const String& format) +{ + ScriptFrame *vframe = ScriptFrame::GetCurrentFrame(); + DateTime::Ptr self = static_cast(vframe->Self); + + return self->Format(format); +} + +Object::Ptr DateTime::GetPrototype(void) +{ + static Dictionary::Ptr prototype; + + if (!prototype) { + prototype = new Dictionary(); + prototype->Set("format", new Function(WrapFunction(DateTimeFormat))); + } + + return prototype; +} + diff --git a/lib/base/datetime.cpp b/lib/base/datetime.cpp new file mode 100644 index 000000000..a765fd588 --- /dev/null +++ b/lib/base/datetime.cpp @@ -0,0 +1,75 @@ +/****************************************************************************** + * Icinga 2 * + * Copyright (C) 2012-2016 Icinga Development Team (https://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 "base/datetime.hpp" +#include "base/datetime.tcpp" +#include "base/utility.hpp" +#include "base/primitivetype.hpp" + +using namespace icinga; + +REGISTER_TYPE_WITH_PROTOTYPE(DateTime, DateTime::GetPrototype()); + +DateTime::DateTime(double value) + : m_Value(value) +{ } + +DateTime::DateTime(const std::vector& args) +{ + if (args.empty()) + m_Value = Utility::GetTime(); + else if (args.size() == 3 || args.size() == 6) { + struct tm tms; + tms.tm_year = args[0] - 1900; + tms.tm_mon = args[1] - 1; + tms.tm_mday = args[2]; + + if (args.size() == 6) { + tms.tm_hour = args[3]; + tms.tm_min = args[4]; + tms.tm_sec = args[5]; + } else { + tms.tm_hour = 0; + tms.tm_min = 0; + tms.tm_sec = 0; + } + + tms.tm_isdst = -1; + + m_Value = mktime(&tms); + } else if (args.size() == 1) + m_Value = args[0]; + else + BOOST_THROW_EXCEPTION(std::invalid_argument("Invalid number of arguments for the DateTime constructor.")); +} + +double DateTime::GetValue(void) const +{ + return m_Value; +} + +String DateTime::Format(const String& format) const +{ + return Utility::FormatDateTime(format.CStr(), m_Value); +} + +String DateTime::ToString(void) const +{ + return Format("%Y-%m-%d %H:%M:%S %z"); +} diff --git a/lib/base/datetime.hpp b/lib/base/datetime.hpp new file mode 100644 index 000000000..ef3eb8e40 --- /dev/null +++ b/lib/base/datetime.hpp @@ -0,0 +1,57 @@ +/****************************************************************************** + * Icinga 2 * + * Copyright (C) 2012-2016 Icinga Development Team (https://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 DATETIME_H +#define DATETIME_H + +#include "base/i2-base.hpp" +#include "base/datetime.thpp" +#include "base/value.hpp" +#include + +namespace icinga +{ + +/** + * A date/time value. + * + * @ingroup base + */ +class I2_BASE_API DateTime : public ObjectImpl +{ +public: + DECLARE_OBJECT(DateTime); + + DateTime(double value); + DateTime(const std::vector& args); + + String Format(const String& format) const; + + virtual double GetValue(void) const override; + virtual String ToString(void) const override; + + static Object::Ptr GetPrototype(void); + +private: + double m_Value; +}; + +} + +#endif /* DATETIME_H */ diff --git a/lib/base/datetime.ti b/lib/base/datetime.ti new file mode 100644 index 000000000..2b6d178dc --- /dev/null +++ b/lib/base/datetime.ti @@ -0,0 +1,32 @@ +/****************************************************************************** + * Icinga 2 * + * Copyright (C) 2012-2016 Icinga Development Team (https://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. * + ******************************************************************************/ + +library base; + +namespace icinga +{ + +vararg_constructor class DateTime +{ + [state, no_storage] double value { + get; + }; +}; + +} diff --git a/lib/base/object.hpp b/lib/base/object.hpp index c68f22fe5..2cb77263d 100644 --- a/lib/base/object.hpp +++ b/lib/base/object.hpp @@ -25,6 +25,7 @@ #include #include #include +#include using boost::intrusive_ptr; using boost::dynamic_pointer_cast; @@ -61,15 +62,29 @@ extern I2_BASE_API Value Empty; IMPL_TYPE_LOOKUP(); template -intrusive_ptr DefaultObjectFactory(void) +intrusive_ptr DefaultObjectFactory(const std::vector& args) { + if (!args.empty()) + BOOST_THROW_EXCEPTION(std::invalid_argument("Constructor does not take any arguments.")); + return new T(); } -typedef intrusive_ptr (*ObjectFactory)(void); - template +intrusive_ptr DefaultObjectFactoryVA(const std::vector& args) +{ + return new T(args); +} + +typedef intrusive_ptr (*ObjectFactory)(const std::vector&); + +template struct TypeHelper +{ +}; + +template +struct TypeHelper { static ObjectFactory GetFactory(void) { @@ -77,6 +92,15 @@ struct TypeHelper } }; +template +struct TypeHelper +{ + static ObjectFactory GetFactory(void) + { + return DefaultObjectFactoryVA; + } +}; + /** * Base class for all heap-allocated objects. At least one of its methods * has to be virtual for RTTI to work. diff --git a/lib/base/primitivetype.hpp b/lib/base/primitivetype.hpp index 50f37b3de..1d80b0e1e 100644 --- a/lib/base/primitivetype.hpp +++ b/lib/base/primitivetype.hpp @@ -75,6 +75,9 @@ private: #define REGISTER_PRIMITIVE_TYPE(type, base, prototype) \ REGISTER_PRIMITIVE_TYPE_FACTORY(type, base, prototype, DefaultObjectFactory) +#define REGISTER_PRIMITIVE_TYPE_VA(type, base, prototype) \ + REGISTER_PRIMITIVE_TYPE_FACTORY(type, base, prototype, DefaultObjectFactoryVA) + #define REGISTER_PRIMITIVE_TYPE_NOINST(type, base, prototype) \ REGISTER_PRIMITIVE_TYPE_FACTORY(type, base, prototype, NULL) diff --git a/lib/base/type.cpp b/lib/base/type.cpp index c4be806be..211eaa13d 100644 --- a/lib/base/type.cpp +++ b/lib/base/type.cpp @@ -67,14 +67,14 @@ String Type::GetPluralName(void) const return name + "s"; } -Object::Ptr Type::Instantiate(void) const +Object::Ptr Type::Instantiate(const std::vector& args) const { ObjectFactory factory = GetFactory(); if (!factory) BOOST_THROW_EXCEPTION(std::runtime_error("Type does not have a factory function.")); - return factory(); + return factory(args); } bool Type::IsAbstract(void) const diff --git a/lib/base/type.hpp b/lib/base/type.hpp index 000ef9e43..20aba2631 100644 --- a/lib/base/type.hpp +++ b/lib/base/type.hpp @@ -86,7 +86,7 @@ public: String GetPluralName(void) const; - Object::Ptr Instantiate(void) const; + Object::Ptr Instantiate(const std::vector& args = std::vector()) const; bool IsAssignableFrom(const Type::Ptr& other) const; diff --git a/lib/base/value-operators.cpp b/lib/base/value-operators.cpp index 9c18f7faa..ad2691a59 100644 --- a/lib/base/value-operators.cpp +++ b/lib/base/value-operators.cpp @@ -20,6 +20,8 @@ #include "base/value.hpp" #include "base/array.hpp" #include "base/dictionary.hpp" +#include "base/datetime.hpp" +#include "base/convert.hpp" #include "base/utility.hpp" #include "base/objectlock.hpp" #include @@ -177,6 +179,13 @@ bool Value::operator==(const Value& rhs) const return false; if (IsObject()) { + if (IsObjectType() && rhs.IsObjectType()) { + DateTime::Ptr dt1 = *this; + DateTime::Ptr dt2 = rhs; + + return dt1->GetValue() == dt2->GetValue(); + } + if (IsObjectType() && rhs.IsObjectType()) { Array::Ptr arr1 = *this; Array::Ptr arr2 = rhs; @@ -234,6 +243,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()) && !(lhs.IsEmpty() && rhs.IsEmpty())) return static_cast(lhs) + static_cast(rhs); + else if (lhs.IsObjectType() && rhs.IsNumber()) + return new DateTime(Convert::ToDateTimeValue(lhs) + rhs); else if ((lhs.IsObjectType() || lhs.IsEmpty()) && (rhs.IsObjectType() || rhs.IsEmpty()) && !(lhs.IsEmpty() && rhs.IsEmpty()) && !(lhs.IsEmpty() && rhs.IsEmpty())) { Array::Ptr result = new Array(); if (!lhs.IsEmpty()) @@ -277,6 +288,12 @@ Value icinga::operator-(const Value& lhs, const Value& rhs) { if ((lhs.IsNumber() || lhs.IsEmpty()) && !lhs.IsString() && (rhs.IsNumber() || rhs.IsEmpty()) && !rhs.IsString() && !(lhs.IsEmpty() && rhs.IsEmpty())) return static_cast(lhs) - static_cast(rhs); + else if (lhs.IsObjectType() && rhs.IsNumber()) + return new DateTime(Convert::ToDateTimeValue(lhs) - rhs); + else if (lhs.IsObjectType() && rhs.IsObjectType()) + return Convert::ToDateTimeValue(lhs) - Convert::ToDateTimeValue(rhs); + else if ((lhs.IsObjectType() || lhs.IsEmpty()) && (rhs.IsObjectType() || rhs.IsEmpty()) && !(lhs.IsEmpty() && rhs.IsEmpty()) && !(lhs.IsEmpty() && rhs.IsEmpty())) + return new DateTime(Convert::ToDateTimeValue(lhs) - Convert::ToDateTimeValue(rhs)); else if ((lhs.IsObjectType() || lhs.IsEmpty()) && (rhs.IsObjectType() || rhs.IsEmpty()) && !(lhs.IsEmpty() && rhs.IsEmpty())) { if (lhs.IsEmpty()) return new Array(); @@ -567,6 +584,8 @@ bool 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() || lhs.IsEmpty()) && (rhs.IsObjectType() || rhs.IsEmpty()) && !(lhs.IsEmpty() && rhs.IsEmpty()) && !(lhs.IsEmpty() && rhs.IsEmpty())) + return Convert::ToDateTimeValue(lhs) < Convert::ToDateTimeValue(rhs); else BOOST_THROW_EXCEPTION(std::invalid_argument("Operator < cannot be applied to values of type '" + lhs.GetTypeName() + "' and '" + rhs.GetTypeName() + "'")); } @@ -597,6 +616,8 @@ bool 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() || lhs.IsEmpty()) && (rhs.IsObjectType() || rhs.IsEmpty()) && !(lhs.IsEmpty() && rhs.IsEmpty()) && !(lhs.IsEmpty() && rhs.IsEmpty())) + return Convert::ToDateTimeValue(lhs) > Convert::ToDateTimeValue(rhs); else BOOST_THROW_EXCEPTION(std::invalid_argument("Operator > cannot be applied to values of type '" + lhs.GetTypeName() + "' and '" + rhs.GetTypeName() + "'")); } @@ -627,6 +648,8 @@ bool 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() || lhs.IsEmpty()) && (rhs.IsObjectType() || rhs.IsEmpty()) && !(lhs.IsEmpty() && rhs.IsEmpty()) && !(lhs.IsEmpty() && rhs.IsEmpty())) + return Convert::ToDateTimeValue(lhs) <= Convert::ToDateTimeValue(rhs); else BOOST_THROW_EXCEPTION(std::invalid_argument("Operator <= cannot be applied to values of type '" + lhs.GetTypeName() + "' and '" + rhs.GetTypeName() + "'")); } @@ -657,6 +680,8 @@ bool 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() || lhs.IsEmpty()) && (rhs.IsObjectType() || rhs.IsEmpty()) && !(lhs.IsEmpty() && rhs.IsEmpty()) && !(lhs.IsEmpty() && rhs.IsEmpty())) + return Convert::ToDateTimeValue(lhs) >= Convert::ToDateTimeValue(rhs); 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/expression.cpp b/lib/config/expression.cpp index c87e6d1d8..f2ef686f5 100644 --- a/lib/config/expression.cpp +++ b/lib/config/expression.cpp @@ -424,15 +424,15 @@ ExpressionResult FunctionCallExpression::DoEvaluate(ScriptFrame& frame, DebugHin } 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); + std::vector arguments; + BOOST_FOREACH(Expression *arg, m_Args) { + ExpressionResult argres = arg->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)); + arguments.push_back(argres.GetValue()); + } + + return VMOps::ConstructorCall(vfunc, arguments, m_DebugInfo); } if (!vfunc.IsObjectType()) diff --git a/lib/config/vmops.hpp b/lib/config/vmops.hpp index 174cc76ff..d0c0f9b6d 100644 --- a/lib/config/vmops.hpp +++ b/lib/config/vmops.hpp @@ -55,36 +55,33 @@ public: return ScriptGlobal::Get(name); } - static inline Value CopyConstructorCall(const Type::Ptr& type, const Value& value, const DebugInfo& debugInfo = DebugInfo()) + static inline Value ConstructorCall(const Type::Ptr& type, const std::vector& args, 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 (!value.IsEmpty() && !type->IsAssignableFrom(value.GetReflectionType())) - BOOST_THROW_EXCEPTION(ScriptError("Invalid cast: Tried to cast object of type '" + value.GetReflectionType()->GetName() + "' to type '" + type->GetName() + "'", debugInfo)); + if (type->GetName() == "String") { + if (args.empty()) + return ""; + else if (args.size() == 1) + return Convert::ToString(args[0]); + else + BOOST_THROW_EXCEPTION(ScriptError("Too many arguments for constructor.")); + } else if (type->GetName() == "Number") { + if (args.empty()) + return 0; + else if (args.size() == 1) + return Convert::ToDouble(args[0]); + else + BOOST_THROW_EXCEPTION(ScriptError("Too many arguments for constructor.")); + } else if (type->GetName() == "Boolean") { + if (args.empty()) + return 0; + else if (args.size() == 1) + return Convert::ToBool(args[0]); + else + BOOST_THROW_EXCEPTION(ScriptError("Too many arguments for constructor.")); + } else if (args.size() == 1 && type->IsAssignableFrom(args[0].GetReflectionType())) + return args[0]; 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; - } + return type->Instantiate(args); } static inline Value FunctionCall(ScriptFrame& frame, const Value& self, const Function::Ptr& func, const std::vector& arguments) diff --git a/tools/mkclass/class_lexer.ll b/tools/mkclass/class_lexer.ll index 0afb22729..128424d69 100644 --- a/tools/mkclass/class_lexer.ll +++ b/tools/mkclass/class_lexer.ll @@ -137,6 +137,7 @@ code { return T_CODE; } load_after { return T_LOAD_AFTER; } library { return T_LIBRARY; } abstract { yylval->num = TAAbstract; return T_CLASS_ATTRIBUTE; } +vararg_constructor { yylval->num = TAVarArgConstructor; return T_CLASS_ATTRIBUTE; } config { yylval->num = FAConfig; return T_FIELD_ATTRIBUTE; } state { yylval->num = FAState; return T_FIELD_ATTRIBUTE; } enum { yylval->num = FAEnum; return T_FIELD_ATTRIBUTE; } diff --git a/tools/mkclass/classcompiler.cpp b/tools/mkclass/classcompiler.cpp index d0aab97a9..98071ae16 100644 --- a/tools/mkclass/classcompiler.cpp +++ b/tools/mkclass/classcompiler.cpp @@ -222,7 +222,7 @@ void ClassCompiler::HandleClass(const Klass& klass, const ClassDebugInfo&) /* TypeHelper */ if (klass.Attributes & TAAbstract) { m_Header << "template<>" << std::endl - << "struct TypeHelper<" << klass.Name << ">" << std::endl + << "struct TypeHelper<" << klass.Name << ", " << ((klass.Attributes & TAVarArgConstructor) ? "true" : "false") << ">" << std::endl << "{" << std::endl << "\t" << "static ObjectFactory GetFactory(void)" << std::endl << "\t" << "{" << std::endl @@ -412,7 +412,7 @@ void ClassCompiler::HandleClass(const Klass& klass, const ClassDebugInfo&) m_Impl << "ObjectFactory TypeImpl<" << klass.Name << ">::GetFactory(void) const" << std::endl << "{" << std::endl - << "\t" << "return TypeHelper<" << klass.Name << ">::GetFactory();" << std::endl + << "\t" << "return TypeHelper<" << klass.Name << ", " << ((klass.Attributes & TAVarArgConstructor) ? "true" : "false") << ">::GetFactory();" << std::endl << "}" << std::endl << std::endl; /* GetLoadDependencies */ diff --git a/tools/mkclass/classcompiler.hpp b/tools/mkclass/classcompiler.hpp index 2369253bc..05e0b1a44 100644 --- a/tools/mkclass/classcompiler.hpp +++ b/tools/mkclass/classcompiler.hpp @@ -159,7 +159,8 @@ struct Field enum TypeAttribute { - TAAbstract = 1 + TAAbstract = 1, + TAVarArgConstructor = 2 }; struct Klass -- 2.50.1