diff --git a/lib/base/CMakeLists.txt b/lib/base/CMakeLists.txt index 05e2b9324..2004572af 100644 --- a/lib/base/CMakeLists.txt +++ b/lib/base/CMakeLists.txt @@ -23,13 +23,13 @@ mkclass_target(streamlogger.ti streamlogger.thpp) mkclass_target(sysloglogger.ti sysloglogger.thpp) set(base_SOURCES - application.cpp application-version.cpp application.thpp array.cpp console.cpp context.cpp - convert.cpp debuginfo.cpp dictionary.cpp dynamicobject.cpp dynamicobject.thpp dynamictype.cpp + application.cpp application-version.cpp application.thpp array.cpp array-script.cpp boolean.cpp boolean-script.cpp console.cpp context.cpp + convert.cpp debuginfo.cpp dictionary.cpp dictionary-script.cpp dynamicobject.cpp dynamicobject.thpp dynamictype.cpp exception.cpp fifo.cpp filelogger.cpp filelogger.thpp initialize.cpp json.cpp logger.cpp logger.thpp - netstring.cpp networkstream.cpp object.cpp primitivetype.cpp process.cpp + netstring.cpp networkstream.cpp number.cpp number-script.cpp object.cpp object-script.cpp primitivetype.cpp process.cpp ringbuffer.cpp scripterror.cpp scriptfunction.cpp scriptfunctionwrapper.cpp scriptsignal.cpp scriptutils.cpp scriptvariable.cpp serializer.cpp socket.cpp stacktrace.cpp - statsfunction.cpp stdiostream.cpp stream.cpp streamlogger.cpp streamlogger.thpp string.cpp + statsfunction.cpp stdiostream.cpp stream.cpp streamlogger.cpp streamlogger.thpp string.cpp string-script.cpp sysloglogger.cpp sysloglogger.thpp tcpsocket.cpp thinmutex.cpp threadpool.cpp timer.cpp tlsstream.cpp tlsutility.cpp type.cpp unixsocket.cpp utility.cpp value.cpp value-operators.cpp workqueue.cpp diff --git a/lib/base/array-script.cpp b/lib/base/array-script.cpp new file mode 100644 index 000000000..6488f0f53 --- /dev/null +++ b/lib/base/array-script.cpp @@ -0,0 +1,93 @@ +/****************************************************************************** + * 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 "base/array.hpp" +#include "base/scriptfunction.hpp" +#include "base/scriptfunctionwrapper.hpp" +#include "config/vmframe.hpp" + +using namespace icinga; + +static double ArrayLen(void) +{ + VMFrame *vframe = VMFrame::GetCurrentFrame(); + Array::Ptr self = static_cast(vframe->Self); + return self->GetLength(); +} + +static void ArraySet(int index, const Value& value) +{ + VMFrame *vframe = VMFrame::GetCurrentFrame(); + Array::Ptr self = static_cast(vframe->Self); + self->Set(index, value); +} + +static void ArrayAdd(const Value& value) +{ + VMFrame *vframe = VMFrame::GetCurrentFrame(); + Array::Ptr self = static_cast(vframe->Self); + self->Add(value); +} + +static void ArrayRemove(int index) +{ + VMFrame *vframe = VMFrame::GetCurrentFrame(); + Array::Ptr self = static_cast(vframe->Self); + self->Remove(index); +} + +static bool ArrayContains(const Value& value) +{ + VMFrame *vframe = VMFrame::GetCurrentFrame(); + Array::Ptr self = static_cast(vframe->Self); + return self->Contains(value); +} + +static void ArrayClear(void) +{ + VMFrame *vframe = VMFrame::GetCurrentFrame(); + Array::Ptr self = static_cast(vframe->Self); + self->Clear(); +} + +static void ArrayClone(void) +{ + VMFrame *vframe = VMFrame::GetCurrentFrame(); + Array::Ptr self = static_cast(vframe->Self); + self->ShallowClone(); +} + +Object::Ptr Array::GetPrototype(void) +{ + static Dictionary::Ptr prototype; + + if (!prototype) { + prototype = new Dictionary(); + prototype->Set("len", new ScriptFunction(WrapScriptFunction(ArrayLen))); + prototype->Set("set", new ScriptFunction(WrapScriptFunction(ArraySet))); + prototype->Set("add", new ScriptFunction(WrapScriptFunction(ArrayAdd))); + prototype->Set("remove", new ScriptFunction(WrapScriptFunction(ArrayRemove))); + prototype->Set("contains", new ScriptFunction(WrapScriptFunction(ArrayContains))); + prototype->Set("clear", new ScriptFunction(WrapScriptFunction(ArrayClear))); + prototype->Set("clone", new ScriptFunction(WrapScriptFunction(ArrayClone))); + } + + return prototype; +} + diff --git a/lib/base/array.cpp b/lib/base/array.cpp index d9ffbb825..9e8c10fbf 100644 --- a/lib/base/array.cpp +++ b/lib/base/array.cpp @@ -21,11 +21,12 @@ #include "base/objectlock.hpp" #include "base/debug.hpp" #include "base/primitivetype.hpp" +#include "base/dictionary.hpp" #include using namespace icinga; -REGISTER_PRIMITIVE_TYPE(Array); +REGISTER_PRIMITIVE_TYPE(Array, Array::GetPrototype()); /** * Restrieves a value from an array. diff --git a/lib/base/array.hpp b/lib/base/array.hpp index dc18ef2c2..2f8041e7e 100644 --- a/lib/base/array.hpp +++ b/lib/base/array.hpp @@ -65,6 +65,8 @@ public: void CopyTo(const Array::Ptr& dest) const; Array::Ptr ShallowClone(void) const; + static Object::Ptr GetPrototype(void); + private: std::vector m_Data; /**< The data for the array. */ }; diff --git a/lib/base/boolean-script.cpp b/lib/base/boolean-script.cpp new file mode 100644 index 000000000..faa5e840b --- /dev/null +++ b/lib/base/boolean-script.cpp @@ -0,0 +1,46 @@ +/****************************************************************************** + * 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 "base/boolean.hpp" +#include "base/convert.hpp" +#include "base/scriptfunction.hpp" +#include "base/scriptfunctionwrapper.hpp" +#include "config/vmframe.hpp" + +using namespace icinga; + +static String BooleanToString(void) +{ + VMFrame *vframe = VMFrame::GetCurrentFrame(); + bool self = vframe->Self; + return self ? "true" : "false"; +} + +Object::Ptr Boolean::GetPrototype(void) +{ + static Dictionary::Ptr prototype; + + if (!prototype) { + prototype = new Dictionary(); + prototype->Set("to_string", new ScriptFunction(WrapScriptFunction(BooleanToString))); + } + + return prototype; +} + diff --git a/lib/base/boolean.cpp b/lib/base/boolean.cpp new file mode 100644 index 000000000..fc367a3be --- /dev/null +++ b/lib/base/boolean.cpp @@ -0,0 +1,26 @@ +/****************************************************************************** + * 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 "base/boolean.hpp" +#include "base/primitivetype.hpp" + +using namespace icinga; + +REGISTER_BUILTIN_TYPE(Boolean, Boolean::GetPrototype()); + diff --git a/lib/base/boolean.hpp b/lib/base/boolean.hpp new file mode 100644 index 000000000..8154b807e --- /dev/null +++ b/lib/base/boolean.hpp @@ -0,0 +1,44 @@ +/****************************************************************************** + * 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 BOOLEAN_H +#define BOOLEAN_H + +#include "base/i2-base.hpp" +#include "base/object.hpp" + +namespace icinga { + +class Value; + +/** + * Boolean class. + */ +class I2_BASE_API Boolean +{ +public: + static Object::Ptr GetPrototype(void); + +private: + Boolean(void); +}; + +} + +#endif /* BOOLEAN_H */ diff --git a/lib/base/dictionary-script.cpp b/lib/base/dictionary-script.cpp new file mode 100644 index 000000000..6815ad255 --- /dev/null +++ b/lib/base/dictionary-script.cpp @@ -0,0 +1,77 @@ +/****************************************************************************** + * 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 "base/dictionary.hpp" +#include "base/scriptfunction.hpp" +#include "base/scriptfunctionwrapper.hpp" +#include "config/vmframe.hpp" + +using namespace icinga; + +static double DictionaryLen(void) +{ + VMFrame *vframe = VMFrame::GetCurrentFrame(); + Dictionary::Ptr self = static_cast(vframe->Self); + return self->GetLength(); +} + +static void DictionarySet(const String& key, const Value& value) +{ + VMFrame *vframe = VMFrame::GetCurrentFrame(); + Dictionary::Ptr self = static_cast(vframe->Self); + self->Set(key, value); +} + +static void DictionaryRemove(const String& key) +{ + VMFrame *vframe = VMFrame::GetCurrentFrame(); + Dictionary::Ptr self = static_cast(vframe->Self); + self->Remove(key); +} + +static bool DictionaryContains(const String& key) +{ + VMFrame *vframe = VMFrame::GetCurrentFrame(); + Dictionary::Ptr self = static_cast(vframe->Self); + return self->Contains(key); +} + +static void DictionaryClone(void) +{ + VMFrame *vframe = VMFrame::GetCurrentFrame(); + Dictionary::Ptr self = static_cast(vframe->Self); + self->ShallowClone(); +} + +Object::Ptr Dictionary::GetPrototype(void) +{ + static Dictionary::Ptr prototype; + + if (!prototype) { + prototype = new Dictionary(); + prototype->Set("len", new ScriptFunction(WrapScriptFunction(DictionaryLen))); + prototype->Set("set", new ScriptFunction(WrapScriptFunction(DictionarySet))); + prototype->Set("remove", new ScriptFunction(WrapScriptFunction(DictionaryRemove))); + prototype->Set("contains", new ScriptFunction(WrapScriptFunction(DictionaryContains))); + prototype->Set("clone", new ScriptFunction(WrapScriptFunction(DictionaryClone))); + } + + return prototype; +} + diff --git a/lib/base/dictionary.cpp b/lib/base/dictionary.cpp index bf03c782c..9403ce8a6 100644 --- a/lib/base/dictionary.cpp +++ b/lib/base/dictionary.cpp @@ -25,7 +25,7 @@ using namespace icinga; -REGISTER_PRIMITIVE_TYPE(Dictionary); +REGISTER_PRIMITIVE_TYPE(Dictionary, Dictionary::GetPrototype()); /** * Compares dictionary keys using the less operator. diff --git a/lib/base/dictionary.hpp b/lib/base/dictionary.hpp index c90f5f170..1f1753d56 100644 --- a/lib/base/dictionary.hpp +++ b/lib/base/dictionary.hpp @@ -64,6 +64,8 @@ public: void CopyTo(const Dictionary::Ptr& dest) const; Dictionary::Ptr ShallowClone(void) const; + static Object::Ptr GetPrototype(void); + private: std::map m_Data; /**< The data for the dictionary. */ }; diff --git a/lib/base/number-script.cpp b/lib/base/number-script.cpp new file mode 100644 index 000000000..ad8d9722b --- /dev/null +++ b/lib/base/number-script.cpp @@ -0,0 +1,46 @@ +/****************************************************************************** + * 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 "base/number.hpp" +#include "base/convert.hpp" +#include "base/scriptfunction.hpp" +#include "base/scriptfunctionwrapper.hpp" +#include "config/vmframe.hpp" + +using namespace icinga; + +static String NumberToString(void) +{ + VMFrame *vframe = VMFrame::GetCurrentFrame(); + double self = vframe->Self; + return Convert::ToString(self); +} + +Object::Ptr Number::GetPrototype(void) +{ + static Dictionary::Ptr prototype; + + if (!prototype) { + prototype = new Dictionary(); + prototype->Set("to_string", new ScriptFunction(WrapScriptFunction(NumberToString))); + } + + return prototype; +} + diff --git a/lib/base/number.cpp b/lib/base/number.cpp new file mode 100644 index 000000000..34ce8433b --- /dev/null +++ b/lib/base/number.cpp @@ -0,0 +1,26 @@ +/****************************************************************************** + * 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 "base/number.hpp" +#include "base/primitivetype.hpp" + +using namespace icinga; + +REGISTER_BUILTIN_TYPE(Number, Number::GetPrototype()); + diff --git a/lib/base/number.hpp b/lib/base/number.hpp new file mode 100644 index 000000000..eace633b0 --- /dev/null +++ b/lib/base/number.hpp @@ -0,0 +1,44 @@ +/****************************************************************************** + * 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 NUMBER_H +#define NUMBER_H + +#include "base/i2-base.hpp" +#include "base/object.hpp" + +namespace icinga { + +class Value; + +/** + * Number class. + */ +class I2_BASE_API Number +{ +public: + static Object::Ptr GetPrototype(void); + +private: + Number(void); +}; + +} + +#endif /* NUMBER_H */ diff --git a/lib/base/object-script.cpp b/lib/base/object-script.cpp new file mode 100644 index 000000000..af78afb87 --- /dev/null +++ b/lib/base/object-script.cpp @@ -0,0 +1,46 @@ +/****************************************************************************** + * 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 "base/object.hpp" +#include "base/dictionary.hpp" +#include "base/scriptfunction.hpp" +#include "base/scriptfunctionwrapper.hpp" +#include "config/vmframe.hpp" + +using namespace icinga; + +static String ObjectToString(void) +{ + VMFrame *vframe = VMFrame::GetCurrentFrame(); + Object::Ptr self = static_cast(vframe->Self); + return self->ToString(); +} + +Object::Ptr Object::GetPrototype(void) +{ + static Dictionary::Ptr prototype; + + if (!prototype) { + prototype = new Dictionary(); + prototype->Set("to_string", new ScriptFunction(WrapScriptFunction(ObjectToString))); + } + + return prototype; +} + diff --git a/lib/base/object.cpp b/lib/base/object.cpp index 224516689..1c219b7cf 100644 --- a/lib/base/object.cpp +++ b/lib/base/object.cpp @@ -19,12 +19,24 @@ #include "base/object.hpp" #include "base/value.hpp" +#include "base/dictionary.hpp" #include "base/primitivetype.hpp" #include "base/utility.hpp" using namespace icinga; -REGISTER_PRIMITIVE_TYPE(Object); +static Object::Ptr GetObjectPrototype(void) +{ + static Dictionary::Ptr prototype; + + if (!prototype) { + prototype = new Dictionary(); + } + + return prototype; +} + +REGISTER_PRIMITIVE_TYPE(Object, GetObjectPrototype()); /** * Default constructor for the Object class. diff --git a/lib/base/object.hpp b/lib/base/object.hpp index 49b068a09..d21907b22 100644 --- a/lib/base/object.hpp +++ b/lib/base/object.hpp @@ -104,6 +104,8 @@ public: void InflateMutex(void); + static Object::Ptr GetPrototype(void); + private: Object(const Object& other); Object& operator=(const Object& rhs); diff --git a/lib/base/primitivetype.cpp b/lib/base/primitivetype.cpp index 4debd405f..217062cd6 100644 --- a/lib/base/primitivetype.cpp +++ b/lib/base/primitivetype.cpp @@ -18,12 +18,10 @@ ******************************************************************************/ #include "base/primitivetype.hpp" +#include "base/dictionary.hpp" using namespace icinga; -REGISTER_BUILTIN_TYPE(Number); -REGISTER_BUILTIN_TYPE(Boolean); - PrimitiveType::PrimitiveType(const String& name) : m_Name(name) { } diff --git a/lib/base/primitivetype.hpp b/lib/base/primitivetype.hpp index 0a7226e7d..0f57abc26 100644 --- a/lib/base/primitivetype.hpp +++ b/lib/base/primitivetype.hpp @@ -46,21 +46,23 @@ private: String m_Name; }; -#define REGISTER_BUILTIN_TYPE(type) \ +#define REGISTER_BUILTIN_TYPE(type, prototype) \ namespace { namespace UNIQUE_NAME(prt) { namespace prt ## type { \ void RegisterBuiltinType(void) \ { \ icinga::Type::Ptr t = new PrimitiveType(#type); \ + t->SetPrototype(prototype); \ icinga::Type::Register(t); \ } \ INITIALIZE_ONCE(RegisterBuiltinType); \ } } } -#define REGISTER_PRIMITIVE_TYPE(type) \ +#define REGISTER_PRIMITIVE_TYPE(type, prototype) \ namespace { namespace UNIQUE_NAME(prt) { namespace prt ## type { \ void RegisterPrimitiveType(void) \ { \ icinga::Type::Ptr t = new PrimitiveType(#type); \ + t->SetPrototype(prototype); \ icinga::Type::Register(t); \ type::TypeInstance = t; \ } \ diff --git a/lib/base/scriptfunction.cpp b/lib/base/scriptfunction.cpp index 2a21add14..ee400234f 100644 --- a/lib/base/scriptfunction.cpp +++ b/lib/base/scriptfunction.cpp @@ -20,10 +20,22 @@ #include "base/scriptfunction.hpp" #include "base/scriptvariable.hpp" #include "base/primitivetype.hpp" +#include "base/dictionary.hpp" using namespace icinga; -REGISTER_PRIMITIVE_TYPE(ScriptFunction); +static Object::Ptr GetScriptFunctionPrototype(void) +{ + static Dictionary::Ptr prototype; + + if (!prototype) { + prototype = new Dictionary(); + } + + return prototype; +} + +REGISTER_PRIMITIVE_TYPE(ScriptFunction, GetScriptFunctionPrototype()); ScriptFunction::ScriptFunction(const Callback& function) : m_Callback(function) diff --git a/lib/base/string-script.cpp b/lib/base/string-script.cpp new file mode 100644 index 000000000..a7244e188 --- /dev/null +++ b/lib/base/string-script.cpp @@ -0,0 +1,53 @@ +/****************************************************************************** + * 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 "base/object.hpp" +#include "base/dictionary.hpp" +#include "base/scriptfunction.hpp" +#include "base/scriptfunctionwrapper.hpp" +#include "config/vmframe.hpp" + +using namespace icinga; + +static int StringLen(void) +{ + VMFrame *vframe = VMFrame::GetCurrentFrame(); + String self = vframe->Self; + return self.GetLength(); +} + +static String StringToString(void) +{ + VMFrame *vframe = VMFrame::GetCurrentFrame(); + return vframe->Self; +} + +Object::Ptr String::GetPrototype(void) +{ + static Dictionary::Ptr prototype; + + if (!prototype) { + prototype = new Dictionary(); + prototype->Set("len", new ScriptFunction(WrapScriptFunction(StringLen))); + prototype->Set("to_string", new ScriptFunction(WrapScriptFunction(StringToString))); + } + + return prototype; +} + diff --git a/lib/base/string.cpp b/lib/base/string.cpp index d2fa2744a..767cf8df3 100644 --- a/lib/base/string.cpp +++ b/lib/base/string.cpp @@ -20,12 +20,13 @@ #include "base/string.hpp" #include "base/value.hpp" #include "base/primitivetype.hpp" +#include "base/dictionary.hpp" #include #include using namespace icinga; -REGISTER_BUILTIN_TYPE(String); +REGISTER_BUILTIN_TYPE(String, String::GetPrototype()); const String::SizeType String::NPos = std::string::npos; diff --git a/lib/base/string.hpp b/lib/base/string.hpp index dd27693f8..4bff931c1 100644 --- a/lib/base/string.hpp +++ b/lib/base/string.hpp @@ -21,6 +21,7 @@ #define STRING_H #include "base/i2-base.hpp" +#include "base/object.hpp" #include #include #include @@ -246,6 +247,8 @@ public: static const SizeType NPos; + static Object::Ptr GetPrototype(void); + private: std::string m_Data; }; diff --git a/lib/base/type.cpp b/lib/base/type.cpp index 5a9f1b7f7..50f6dfd11 100644 --- a/lib/base/type.cpp +++ b/lib/base/type.cpp @@ -74,3 +74,13 @@ bool Type::IsAssignableFrom(const Type::Ptr& other) const return false; } +Object::Ptr Type::GetPrototype(void) const +{ + return m_Prototype; +} + +void Type::SetPrototype(const Object::Ptr& object) +{ + m_Prototype = object; +} + diff --git a/lib/base/type.hpp b/lib/base/type.hpp index 8eb853d73..be51c4269 100644 --- a/lib/base/type.hpp +++ b/lib/base/type.hpp @@ -75,11 +75,17 @@ public: bool IsAbstract(void) const; + Object::Ptr GetPrototype(void) const; + void SetPrototype(const Object::Ptr& object); + static void Register(const Type::Ptr& type); static Type::Ptr GetByName(const String& name); protected: virtual ObjectFactory GetFactory(void) const = 0; + +private: + Object::Ptr m_Prototype; }; template diff --git a/lib/base/value.cpp b/lib/base/value.cpp index 3ec73880a..782e4dd3e 100644 --- a/lib/base/value.cpp +++ b/lib/base/value.cpp @@ -85,3 +85,22 @@ String Value::GetTypeName(void) const return "Invalid"; } } + +Type::Ptr Value::GetReflectionType(void) const +{ + switch (GetType()) { + case ValueEmpty: + return Type::GetByName("Object"); + case ValueNumber: + return Type::GetByName("Number"); + case ValueBoolean: + return Type::GetByName("Boolean"); + case ValueString: + return Type::GetByName("String"); + case ValueObject: + return static_cast(*this)->GetReflectionType(); + default: + return Type::Ptr(); + } +} + diff --git a/lib/base/value.hpp b/lib/base/value.hpp index 52cdd14e0..58b8b0375 100644 --- a/lib/base/value.hpp +++ b/lib/base/value.hpp @@ -234,6 +234,8 @@ public: String GetTypeName(void) const; + Type::Ptr GetReflectionType(void) const; + private: boost::variant m_Value; diff --git a/lib/config/expression.cpp b/lib/config/expression.cpp index acd794e3b..709866aa9 100644 --- a/lib/config/expression.cpp +++ b/lib/config/expression.cpp @@ -224,18 +224,13 @@ Value LogicalOrExpression::DoEvaluate(VMFrame& frame, DebugHint *dhint) const Value FunctionCallExpression::DoEvaluate(VMFrame& frame, DebugHint *dhint) const { - Object::Ptr self; - Value funcName; + Value self, funcName; if (!m_IName.empty()) { Value result = m_IName[0]->Evaluate(frame); - if (m_IName.size() == 2) { - if (!result.IsObject()) - BOOST_THROW_EXCEPTION(ScriptError("Tried to invoke method on something that is not an Object.", GetDebugInfo())); - + if (m_IName.size() == 2) self = result; - } for (int i = 1; i < m_IName.size(); i++) { if (result.IsEmpty()) @@ -244,12 +239,8 @@ Value FunctionCallExpression::DoEvaluate(VMFrame& frame, DebugHint *dhint) const Value index = m_IName[i]->Evaluate(frame); result = VMOps::GetField(result, index, GetDebugInfo()); - if (i == m_IName.size() - 2) { - if (!result.IsObject()) - BOOST_THROW_EXCEPTION(ScriptError("Tried to invoke method on something that is not an Object.", GetDebugInfo())); - + if (i == m_IName.size() - 2) self = result; - } } funcName = result; @@ -336,9 +327,12 @@ Value SetExpression::DoEvaluate(VMFrame& frame, DebugHint *dhint) const psdhint = &sdhint; } - if (i == 0) - parent = m_Local ? frame.Locals : frame.Self; - else + if (i == 0) { + if (m_Local) + parent = frame.Locals; + else + parent = frame.Self; + } else parent = object; if (i == m_Indexer.size() - 1) { diff --git a/lib/config/vmframe.hpp b/lib/config/vmframe.hpp index 1c8e9fd3d..4efa1a204 100644 --- a/lib/config/vmframe.hpp +++ b/lib/config/vmframe.hpp @@ -30,7 +30,7 @@ namespace icinga struct VMFrame { Dictionary::Ptr Locals; - Object::Ptr Self; + Value Self; VMFrame *NextFrame; VMFrame(void) @@ -40,7 +40,7 @@ struct VMFrame SetCurrentFrame(this); } - VMFrame(const Object::Ptr& self) + VMFrame(const Value& self) : Locals(new Dictionary()), Self(self) { NextFrame = GetCurrentFrame(); diff --git a/lib/config/vmops.hpp b/lib/config/vmops.hpp index 3673dc64d..6a69304fe 100644 --- a/lib/config/vmops.hpp +++ b/lib/config/vmops.hpp @@ -52,13 +52,13 @@ public: if (frame.Locals && frame.Locals->Contains(name)) return frame.Locals->Get(name); - else if (frame.Locals != frame.Self && HasField(frame.Self, name)) + else if (frame.Self.IsObject() && frame.Locals != static_cast(frame.Self) && HasField(frame.Self, name)) return GetField(frame.Self, name, debugInfo); else return ScriptVariable::Get(name); } - static inline Value FunctionCall(VMFrame& frame, const Object::Ptr& self, const Value& funcName, const std::vector& arguments) + static inline Value FunctionCall(VMFrame& frame, const Value& self, const Value& funcName, const std::vector& arguments) { ScriptFunction::Ptr func; @@ -72,7 +72,7 @@ public: boost::shared_ptr vframe; - if (self) + if (!self.IsEmpty()) vframe = boost::make_shared(self); /* passes self to the callee using a TLS variable */ else vframe = boost::make_shared(); @@ -232,30 +232,49 @@ public: } } + static inline Value GetPrototypeField(const Value& context, const String& field, const DebugInfo& debugInfo = DebugInfo()) + { + Type::Ptr type = context.GetReflectionType(); + + do { + Object::Ptr object = type->GetPrototype(); + + if (HasField(object, field)) + return GetField(object, field); + + type = type->GetBaseType(); + } while (type); + + return Empty; + } + static inline Value GetField(const Value& context, const String& field, const DebugInfo& debugInfo = DebugInfo()) { - if (context.IsString()) { - String str = context; - int index = Convert::ToLong(field); - if (index < 0 || index >= str.GetLength()) - BOOST_THROW_EXCEPTION(ScriptError("Index is out of bounds", debugInfo)); - return String(1, str[index]); - } - if (!context.IsObject()) - BOOST_THROW_EXCEPTION(ScriptError("Tried to access invalid field '" + field + "' on object of type '" + context.GetTypeName() + "'", debugInfo)); + return GetPrototypeField(context, field); Object::Ptr object = context; Dictionary::Ptr dict = dynamic_pointer_cast(object); - if (dict) - return dict->Get(field); + if (dict) { + if (dict->Contains(field)) + return dict->Get(field); + else + return GetPrototypeField(context, field); + } Array::Ptr arr = dynamic_pointer_cast(object); if (arr) { - int index = Convert::ToLong(field); + int index; + + try { + index = Convert::ToLong(field); + } catch (...) { + return GetPrototypeField(context, field); + } + return arr->Get(index); } @@ -267,7 +286,7 @@ public: int fid = type->GetFieldId(field); if (fid == -1) - return Empty; + return GetPrototypeField(context, field); return object->GetField(fid); } diff --git a/test/config-ops.cpp b/test/config-ops.cpp index 0c85bde01..458ae1b15 100644 --- a/test/config-ops.cpp +++ b/test/config-ops.cpp @@ -294,10 +294,6 @@ BOOST_AUTO_TEST_CASE(advanced) expr = ConfigCompiler::CompileText("", "7 & 15 > 6"); BOOST_CHECK(expr->Evaluate(frame)); delete expr; - - expr = ConfigCompiler::CompileText("", "s = \"test\"; s[2]"); - BOOST_CHECK(expr->Evaluate(frame) == "s"); - delete expr; } BOOST_AUTO_TEST_SUITE_END()