summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/core/common/Variant.cpp14
-rw-r--r--src/core/common/VariantReader.cpp157
-rw-r--r--src/core/managed/Managed.hpp25
-rw-r--r--src/core/managed/ManagedType.hpp119
-rw-r--r--src/core/managed/Rtti.cpp (renamed from src/core/managed/ManagedType.cpp)32
-rw-r--r--src/core/managed/Rtti.hpp183
-rw-r--r--src/core/model/Typesystem.cpp51
-rw-r--r--src/core/model/Typesystem.hpp171
8 files changed, 485 insertions, 267 deletions
diff --git a/src/core/common/Variant.cpp b/src/core/common/Variant.cpp
index 6b99add..53286a2 100644
--- a/src/core/common/Variant.cpp
+++ b/src/core/common/Variant.cpp
@@ -132,10 +132,16 @@ Variant::stringType Variant::toString(bool escape) const
return "null";
case Type::BOOL:
return asBool() ? "true" : "false";
- case Type::INT:
- return std::to_string(asInt());
- case Type::DOUBLE:
- return std::to_string(asDouble());
+ case Type::INT: {
+ std::stringstream ss;
+ ss << asInt();
+ return ss.str();
+ }
+ case Type::DOUBLE: {
+ std::stringstream ss;
+ ss << asDouble();
+ return ss.str();
+ }
case Type::STRING: {
// TODO: Use proper serialization function
if (escape) {
diff --git a/src/core/common/VariantReader.cpp b/src/core/common/VariantReader.cpp
index cc25eac..ccc14f8 100644
--- a/src/core/common/VariantReader.cpp
+++ b/src/core/common/VariantReader.cpp
@@ -21,6 +21,8 @@
#include <cmath>
#include <sstream>
+#include <utf8.h>
+
#include "VariantReader.hpp"
#include "Utils.hpp"
@@ -79,11 +81,6 @@ static std::pair<bool, T> unexpected(CharReader &reader, Logger &logger,
class Number {
private:
/**
- * Reprsents the part of the number: Base value a, nominator n, exponent e.
- */
- enum class Part { A, N, E };
-
- /**
* State used in the parser state machine
*/
enum class State {
@@ -117,43 +114,12 @@ private:
return -1;
}
+public:
/**
- * Appends the value of the character c to the internal number
- * representation and reports any errors that might occur.
+ * Reprsents the part of the number: Base value a, nominator n, exponent e.
*/
- bool appendChar(char c, int base, Part p, CharReader &reader,
- Logger &logger)
- {
- // Check whether the given character is valid
- int v = charValue(c);
- if (v < 0 || v >= base) {
- logger.error(unexpectedMsg("digit", c), reader);
- return false;
- }
-
- // Append the number to the specified part
- switch (p) {
- case Part::A:
- a = a * base + v;
- break;
- case Part::N:
- n = n * base + v;
- d = d * base;
- break;
- case Part::E:
- e = e * base + v;
- break;
- }
-
- // Check for any overflows
- if (a < 0 || n < 0 || d < 0 || e < 0) {
- logger.error(ERR_TOO_LARGE, reader);
- return false;
- }
- return true;
- }
+ enum class Part { A, N, E };
-public:
/**
* Sign and exponent sign.
*/
@@ -196,12 +162,51 @@ public:
bool isInt() { return (n == 0) && (d == 1) && (e == 0); }
/**
+ * Appends the value of the character c to the internal number
+ * representation and reports any errors that might occur.
+ */
+ bool appendChar(char c, int base, Part p, CharReader &reader,
+ Logger &logger)
+ {
+ // Check whether the given character is valid
+ int v = charValue(c);
+ if (v < 0 || v >= base) {
+ logger.error(unexpectedMsg("digit", c), reader);
+ return false;
+ }
+
+ // Append the number to the specified part
+ switch (p) {
+ case Part::A:
+ a = a * base + v;
+ break;
+ case Part::N:
+ n = n * base + v;
+ d = d * base;
+ break;
+ case Part::E:
+ e = e * base + v;
+ break;
+ }
+
+ // Check for any overflows
+ if (a < 0 || n < 0 || d < 0 || e < 0) {
+ logger.error(ERR_TOO_LARGE, reader);
+ return false;
+ }
+ return true;
+ }
+
+ /**
* Tries to parse the number from the given stream and loggs any errors to
* the given logger instance. Numbers are terminated by one of the given
* delimiters.
*/
bool parse(CharReader &reader, Logger &logger,
const std::unordered_set<char> &delims);
+
+ bool parseFixedLenInt(CharReader &reader, Logger &logger, int base,
+ int len);
};
bool Number::parse(CharReader &reader, Logger &logger,
@@ -332,6 +337,24 @@ bool Number::parse(CharReader &reader, Logger &logger,
return false;
}
+bool Number::parseFixedLenInt(CharReader &reader, Logger &logger, int base,
+ int len)
+{
+ char c;
+ reader.consumePeek();
+ for (int i = 0; i < len; i++) {
+ if (!reader.peek(c)) {
+ logger.error("Unexpected end of escape sequence", reader);
+ return false;
+ }
+ if (!appendChar(c, base, Number::Part::A, reader, logger)) {
+ return false;
+ }
+ reader.consumePeek();
+ }
+ return true;
+}
+
/* State machine states */
static const int STATE_INIT = 0;
@@ -535,10 +558,32 @@ static std::pair<bool, Variant> parseComplex(CharReader &reader, Logger &logger,
/* Class Reader */
+static bool encodeUtf8(std::stringstream &res, CharReader &reader,
+ Logger &logger, int64_t v, bool latin1)
+{
+ // Encode the unicode codepoint as UTF-8
+ uint32_t cp = static_cast<uint32_t>(v);
+ if (latin1 && cp > 0xFF) {
+ logger.error("Not a valid ISO-8859-1 (Latin-1) character, skipping", reader);
+ return false;
+ }
+
+ // Append the code point to the output stream
+ try {
+ utf8::append(cp, std::ostream_iterator<uint8_t>{res});
+ return true;
+ }
+ catch (utf8::invalid_code_point ex) {
+ logger.error("Invalid Unicode codepoint, skipping", reader);
+ }
+ return false;
+}
+
std::pair<bool, std::string> VariantReader::parseString(
CharReader &reader, Logger &logger, const std::unordered_set<char> *delims)
{
// Initialize the internal state
+ bool hadError = false;
int state = STATE_INIT;
char quote = 0;
std::stringstream res;
@@ -565,7 +610,7 @@ std::pair<bool, std::string> VariantReader::parseString(
case STATE_IN_STRING:
if (c == quote) {
reader.consumePeek();
- return std::make_pair(true, res.str());
+ return std::make_pair(!hadError, res.str());
} else if (c == '\\') {
state = STATE_ESCAPE;
reader.consumePeek();
@@ -608,17 +653,39 @@ std::pair<bool, std::string> VariantReader::parseString(
break;
case '\n':
break;
- case 'x':
- // TODO: Parse Latin-1 sequence hex XX
+ case 'x': {
+ // Parse Latin-1 sequence \xXX
+ Number n;
+ hadError =
+ !(n.parseFixedLenInt(reader, logger, 16, 2) &&
+ encodeUtf8(res, reader, logger, n.intValue(),
+ true)) ||
+ hadError;
break;
- case 'u':
- // TODO: Parse 16-Bit unicode character hex XXXX
+ }
+ case 'u': {
+ // Parse Unicode sequence \uXXXX
+ Number n;
+ hadError =
+ !(n.parseFixedLenInt(reader, logger, 16, 4) &&
+ encodeUtf8(res, reader, logger, n.intValue(),
+ false)) ||
+ hadError;
break;
+ }
default:
if (Utils::isNumeric(c)) {
- // TODO: Parse octal 000 sequence
+ // Parse Latin-1 sequence \000
+ reader.resetPeek();
+ Number n;
+ hadError =
+ !(n.parseFixedLenInt(reader, logger, 8, 3) &&
+ encodeUtf8(res, reader, logger, n.intValue(),
+ true)) ||
+ hadError;
} else {
logger.error(ERR_INVALID_ESCAPE, reader);
+ hadError = true;
}
break;
}
diff --git a/src/core/managed/Managed.hpp b/src/core/managed/Managed.hpp
index 4818c3d..8582702 100644
--- a/src/core/managed/Managed.hpp
+++ b/src/core/managed/Managed.hpp
@@ -19,7 +19,7 @@
#ifndef _OUSIA_MANAGED_HPP_
#define _OUSIA_MANAGED_HPP_
-#include "ManagedType.hpp"
+#include "Rtti.hpp"
#include "Manager.hpp"
namespace ousia {
@@ -108,25 +108,25 @@ public:
bool deleteData(const std::string &key);
/**
- * Returns the ManagedType instance registered for instances of the type
- * of this Managed instance.
+ * Returns the RttiBase instance registered for instances of the type of
+ * this Managed instance.
*
- * @return a reference to the registered ManagedType for this particular
+ * @return a reference to the registered RttiBase for this particular
* Managed class.
*/
- const ManagedType& type() const {
- return ManagedType::typeOf(typeid(*this));
+ const RttiBase &type() const
+ {
+ return typeOf(*this);
}
/**
- * Returns true if this Managed instance is of the given ManagedType.
+ * Returns true if this Managed instance is of the given RttiBase.
*
- * @param true if the ManagedType registered for this particular Managed
- * class is
+ * @param true if the RttiBase registered for this particular Managed
+ * class is of the given type or one of the registered parent types is of
+ * the given type.
*/
- bool isa(const ManagedType &t) const {
- return type().isa(t);
- }
+ bool isa(const RttiBase &t) const { return type().isa(t); }
};
/**
@@ -512,7 +512,6 @@ public:
*/
Managed *getOwner() const { return owner; }
};
-
}
#endif /* _OUSIA_MANAGED_HPP_ */
diff --git a/src/core/managed/ManagedType.hpp b/src/core/managed/ManagedType.hpp
deleted file mode 100644
index f3ed5fd..0000000
--- a/src/core/managed/ManagedType.hpp
+++ /dev/null
@@ -1,119 +0,0 @@
-/*
- Ousía
- Copyright (C) 2014, 2015 Benjamin Paaßen, Andreas Stöckel
-
- 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 3 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, see <http://www.gnu.org/licenses/>.
-*/
-
-#ifndef _OUSIA_MANAGED_TYPE_HPP_
-#define _OUSIA_MANAGED_TYPE_HPP_
-
-#include <typeinfo>
-#include <typeindex>
-#include <unordered_map>
-#include <unordered_set>
-
-namespace ousia {
-
-/**
- * The ManagedType is used to register type information that can be retrieved
- * using the "type" method of the Managed class.
- */
-class ManagedType {
-private:
- /**
- * Used internally to store all registered native types and their
- * corresponding type information.
- */
- static std::unordered_map<std::type_index, ManagedType *>& table() {
- static std::unordered_map<std::type_index, ManagedType *> table;
- return table;
- }
-
- /**
- * Name of the type -- for messages and debug output.
- */
- const std::string name;
-
- /**
- * Set containing references to the parent types.
- */
- const std::unordered_set<ManagedType *> parents;
-
-public:
- /**
- * ManagedType of no particular type.
- */
- static const ManagedType None;
-
- /**
- * Returns the ManagedType for the given type_info structure.
- */
- static const ManagedType &typeOf(const std::type_info &nativeType);
-
- /**
- * Default constructor. Creates a ManagedType instance with name "unknown"
- * and no parents.
- */
- ManagedType() : name("unknown") {}
-
- /**
- * Creates a new ManagedType instance and registers it in the global type
- * table.
- *
- * @param name is the name of the type.
- * @param nativeType is the underlying C++ class the type should be attached
- * to.
- */
- ManagedType(std::string name, const std::type_info &nativeType)
- : name(std::move(name))
- {
- table().emplace(std::make_pair(std::type_index{nativeType}, this));
- }
-
- /**
- * Creates a new ManagedType instance and registers it in the global type
- * table.
- *
- * @param name is the name of the type.
- * @param nativeType is the underlying C++ class the type should be attached
- * to.
- * @param parents is a list of parent types.
- */
- ManagedType(std::string name, const std::type_info &nativeType,
- std::unordered_set<ManagedType *> parents)
- : name(std::move(name)), parents(parents)
- {
- table().emplace(std::make_pair(std::type_index{nativeType}, this));
- }
-
- /**
- * Returns the name of this type.
- */
- std::string getName() const { return name; }
-
- /**
- * Returns true if this ManagedType instance is the given type or has the
- *given
- * type as one of its parents.
- *
- * @param other is the other type for which the relation to this type
- * should be checked.
- */
- bool isa(const ManagedType &other) const;
-};
-}
-
-#endif /* _OUSIA_MANAGED_TYPE_HPP_ */
-
diff --git a/src/core/managed/ManagedType.cpp b/src/core/managed/Rtti.cpp
index ed4c7da..eade524 100644
--- a/src/core/managed/ManagedType.cpp
+++ b/src/core/managed/Rtti.cpp
@@ -16,27 +16,39 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#include "ManagedType.hpp"
+#include "Rtti.hpp"
namespace ousia {
-/* Instantiation of static variables */
+/* Class RttiStore */
-const ManagedType ManagedType::None;
+std::unordered_map<std::type_index, const RttiBase *> &RttiStore::table()
+{
+ static std::unordered_map<std::type_index, const RttiBase *> table;
+ return table;
+}
-/* Class ManagedType */
+void RttiStore::store(const std::type_info &native, const RttiBase *rtti)
+{
+ table().emplace(std::type_index{native}, rtti);
+}
-const ManagedType &ManagedType::typeOf(const std::type_info &nativeType)
+const RttiBase &RttiStore::lookup(const std::type_info &native)
{
- auto it = table().find(std::type_index{nativeType});
- if (it == table().end()) {
- return None;
+ const auto &tbl = table();
+ auto it = tbl.find(std::type_index{native});
+ if (it == tbl.end()) {
+ return RttiBase::None;
} else {
return *(it->second);
}
}
-bool ManagedType::isa(const ManagedType &other) const
+/* Class RttiBase */
+
+const RttiBase RttiBase::None;
+
+bool RttiBase::isa(const RttiBase &other) const
{
if (&other == this) {
return true;
@@ -48,5 +60,7 @@ bool ManagedType::isa(const ManagedType &other) const
}
return false;
}
+
+
}
diff --git a/src/core/managed/Rtti.hpp b/src/core/managed/Rtti.hpp
new file mode 100644
index 0000000..f53fd9b
--- /dev/null
+++ b/src/core/managed/Rtti.hpp
@@ -0,0 +1,183 @@
+/*
+ Ousía
+ Copyright (C) 2014, 2015 Benjamin Paaßen, Andreas Stöckel
+
+ 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 3 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, see <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @file Rtti.hpp
+ *
+ * Classes used for storing runtime type information (RTTI). RTTI is used to
+ * lookup objects in the object graph of a certain type and to attach
+ * information that should be accessible to the script engine.
+ *
+ * @author Andreas Stöckel (astoecke@techfak.uni-bielefeld.de)
+ */
+
+#ifndef _OUSIA_MANAGED_RTTI_HPP_
+#define _OUSIA_MANAGED_RTTI_HPP_
+
+#include <typeinfo>
+#include <typeindex>
+#include <unordered_map>
+#include <vector>
+
+namespace ousia {
+
+class RttiBase;
+
+/**
+ * Helper class used to globally store and access the runtime type information.
+ */
+class RttiStore {
+private:
+ /**
+ * Function used internally to access the static map storing all registered
+ * native types and their corresponding type information.
+ */
+ static std::unordered_map<std::type_index, const RttiBase *> &table();
+
+public:
+ /**
+ * Registers the given pointer to the RttiBase class in the RTTI table. Does
+ * not override information for already registered types.
+ *
+ * @param native is a reference at the native type information provided
+ * by the compiler.
+ * @param rtti is a pointer pointing at the type information that should be
+ * stored for this type.
+ */
+ static void store(const std::type_info &native, const RttiBase *rtti);
+
+ /**
+ * Looks up the type information stored for the given native type
+ * information.
+ */
+ static const RttiBase &lookup(const std::type_info &native);
+};
+
+/**
+ * The Rtti class allows for attaching data to native types that can be accessed
+ * at runtime. This type information can e.g. be retrieved using the "type"
+ * method of the Managed class. This system is used for attaching human readable
+ * names, parent types and script engine functionality. Use the Rtti class for
+ * convenient registration of type information.
+ */
+class RttiBase {
+private:
+ /**
+ * Set containing references to the parent types.
+ */
+ const std::vector<const RttiBase *> parents;
+
+public:
+ /**
+ * Rtti of no particular type.
+ */
+ static const RttiBase None;
+
+ /**
+ * Human readable name associated with the type.
+ */
+ const std::string name;
+
+ /**
+ * Default constructor. Creates a Rtti instance with name "unknown"
+ * and no parents.
+ */
+ RttiBase() : name("unknown") {}
+
+ /**
+ * Creates a new RttiBase instance and registers it in the global type
+ * table. Use the Rtti class for more convinient registration of type
+ * information.
+ *
+ * @param name is the name of the type.
+ * @param native is a reference at the native type information provided by
+ * the compiler.
+ * @param parents is a list of parent types.
+ */
+ RttiBase(std::string name, const std::type_info &native,
+ std::vector<const RttiBase *> parents =
+ std::vector<const RttiBase *>{})
+ : parents(std::move(parents)), name(std::move(name))
+ {
+ RttiStore::store(native, this);
+ }
+
+ /**
+ * Returns true if this Rtti instance is the given type or has the
+ * given type as one of its parents.
+ *
+ * @param other is the other type for which the relation to this type
+ * should be checked.
+ */
+ bool isa(const RttiBase &other) const;
+};
+
+/**
+ * The Rtti class allows for attaching data to native types that can be accessed
+ * at runtime. This type information can e.g. be retrieved using the "type"
+ * method of the Managed class. This system is used for attaching human
+ * readable names, parent types and script engine functionality.
+ *
+ * @tparam T is the class for which the type information should be registered.
+ */
+template <class T>
+class Rtti : public RttiBase {
+public:
+ /**
+ * Creates a new RttiBase instance and registers it in the global type
+ * table.
+ *
+ * @param name is the name of the type.
+ * @param parents is a list of parent types.
+ */
+ Rtti(std::string name, const std::vector<const RttiBase *> &parents =
+ std::vector<const RttiBase *>{})
+ : RttiBase(name, typeid(T), parents)
+ {
+ }
+};
+
+/**
+ * Function that can be used to retrieve the RTTI information of a Managed
+ * object.
+ *
+ * @tparam T is the C++ type for which the type information should be returned.
+ */
+template <typename T>
+inline const RttiBase &typeOf()
+{
+ return RttiStore::lookup(typeid(T));
+}
+
+/**
+ * Function that can be used to retrieve the RTTI information of a Managed
+ * object.
+ *
+ * @tparam T is the C++ type for which the type information should be returned.
+ * @param obj is a dummy object for which the type information should be
+ * returned.
+ */
+template <typename T>
+inline const RttiBase &typeOf(const T &obj)
+{
+ return RttiStore::lookup(typeid(obj));
+}
+}
+
+#endif /* _OUSIA_MANAGED_RTTI_HPP_ */
+
diff --git a/src/core/model/Typesystem.cpp b/src/core/model/Typesystem.cpp
index f3c49dc..724bf0e 100644
--- a/src/core/model/Typesystem.cpp
+++ b/src/core/model/Typesystem.cpp
@@ -23,9 +23,42 @@
namespace ousia {
namespace model {
-EnumerationType EnumerationType::createValidated(
- Manager &mgr, std::string name, Handle<Typesystem> system,
- const std::vector<std::string> &values, Logger &logger)
+/* Class Type */
+
+bool Type::build(Variant &var, Logger &logger) const
+{
+ try {
+ return doBuild(var, logger);
+ }
+ catch (LoggableException ex) {
+ logger.log(ex);
+ var = create();
+ return false;
+ }
+}
+
+/* Class StringType */
+
+bool StringType::doBuild(Variant &var, Logger &logger) const
+{
+ if (!var.isPrimitive()) {
+ throw LoggableException{"Expected a string or primitive input."};
+ }
+
+ if (!var.isString()) {
+ logger.note(std::string("Implicit type conversion from ") +
+ var.getTypeName() + " to string.");
+ }
+ var = Variant{var.toString().c_str()};
+ return true;
+}
+
+/* Class EnumType */
+
+EnumType EnumType::createValidated(Manager &mgr, std::string name,
+ Handle<Typesystem> system,
+ const std::vector<std::string> &values,
+ Logger &logger)
{
std::map<std::string, size_t> unique_values;
for (size_t i = 0; i < values.size(); i++) {
@@ -38,8 +71,18 @@ EnumerationType EnumerationType::createValidated(
" was duplicated.");
}
}
- return std::move(EnumerationType(mgr, name, system, unique_values));
+ return std::move(EnumType(mgr, name, system, unique_values));
}
+
+/* RTTI type registrations */
+
+const Rtti<Type> Type_T("Type");
+const Rtti<StringType> StringType_T("StringType", {&Type_T});
+const Rtti<IntType> IntType_T("IntType", {&Type_T});
+const Rtti<DoubleType> DoubleType_T("DoubleType", {&Type_T});
+const Rtti<BoolType> BoolType_T("BoolType", {&Type_T});
+const Rtti<EnumType> EnumType_T("EnumType", {&Type_T});
+const Rtti<StructType> StructType_T("StructType", {&Type_T});
}
}
diff --git a/src/core/model/Typesystem.hpp b/src/core/model/Typesystem.hpp
index 20c6e8b..c9793e2 100644
--- a/src/core/model/Typesystem.hpp
+++ b/src/core/model/Typesystem.hpp
@@ -19,7 +19,9 @@
/**
* @file Typesystem.hpp
*
- * TODO: Docu
+ * Contains the Entities described in a Typesystem. A Typesystem is a list
+ * of type descriptors, where a type is either primitive or a user defined
+ * type.
*
* @author Andreas Stöckel (astoecke@techfak.uni-bielefeld.de)
*/
@@ -40,79 +42,103 @@ namespace model {
class Typesystem;
+/**
+ * The abstract Type class represents a type descriptor. Each Type node is part
+ * of a Typesystem instance. Concrete instances of the Type class are immutable
+ * (they are guaranteed to represent exactly one type). Note that Type classes
+ * only contain the type description, instances of the Type class do not hold
+ * any data. Data is held by instances of the Variant class. How exactly the
+ * data is represented within the Variant instances is defined by the type
+ * definitions.
+ */
class Type : public Node {
protected:
+ /**
+ * Protected constructor to be called by the classes derived from the Type
+ * class.
+ *
+ * @param mgr is the Manager instance to be used for the Node.
+ * @param name is the name of the type.
+ * @param system is a reference to the parent TypeSystem instance.
+ * @param primitive is set to true for primitive types, such as ints,
+ * doubles, strings and enums.
+ */
Type(Manager &mgr, std::string name, Handle<Typesystem> system,
- bool inheritable, bool primitive)
- : Node(mgr, std::move(name), system),
- inheritable(inheritable),
- primitive(primitive)
+ bool primitive)
+ : Node(mgr, std::move(name), system), primitive(primitive)
{
}
- virtual bool doPrepare(Variant &var, Logger &log) const = 0;
-
-public:
/**
- * TODO: DOC
+ * Validates and completes the given variant. This pure virtual doBuild
+ * method must be overridden by derived classes. This function may throw
+ * an LoggableException in case the given data cannot be converted to
+ * the internal representation given by the type descriptor.
+ *
+ * @param var is a variant containing the data that should be checked and
+ * -- if possible and necessary -- converted to a variant adhering to the
+ * internal representation used by the Type class.
+ * @param logger is the Logger instance into which errors should be written.
+ * @return true if the conversion was successful, false otherwise.
*/
- const bool inheritable;
+ virtual bool doBuild(Variant &var, Logger &logger) const = 0;
+
+public:
/**
- * TODO: DOC
+ * Set to true, if this type descriptor is a primitive type.
*/
const bool primitive;
/**
- * TODO: DOC
+ * Pure virtual function which must construct a valid, default instance of
+ * the type that is being described by the typesystem.
*/
virtual Variant create() const = 0;
/**
- * TODO: DOC
+ * Validates and completes the given variant which was read from a
+ * user-supplied source.
+ *
+ * @param var is a variant containing the data that should be checked and
+ * -- if possible and necessary -- converted to a variant adhering to the
+ * internal representation used by the Type class.
+ * @param logger is the Logger instance into which errors should be written.
+ * @return true if the conversion was successful, false otherwise.
*/
- bool prepare(Variant &var, Logger &log) const
- {
- try {
- return doPrepare(var, log);
- }
- catch (LoggableException ex) {
- log.log(ex);
- var = create();
- return false;
- }
- }
+ bool build(Variant &var, Logger &logger) const;
};
+/**
+ * The StringType class represents the primitive string type. There should
+ * exactly be a single instance of this class available in a preloaded type
+ * system.
+ */
class StringType : public Type {
protected:
/**
- * TODO: DOC
+ * If possible, converts the given variant to a string. Only works, if the
+ * variant contains primitive objects (integers, strings, booleans, etc.).
*/
- bool doPrepare(Variant &var, Logger &log) const override
- {
- if (!var.isPrimitive()) {
- throw LoggableException{"Expected a string or primitive input."};
- }
-
- if (!var.isString()) {
- log.note(std::string("Implicit type conversion from ") +
- var.getTypeName() + " to string.");
- }
- var = Variant{var.toString().c_str()};
- return true;
- }
+ bool doBuild(Variant &var, Logger &logger) const override;
public:
/**
- * TODO: DOC
+ * Constructor of the StringType class. Only one instance of StringType
+ * should exist per project.
+ *
+ * @param mgr is the Manager instance to be used for the Node.
+ * @param name is the name of the type.
+ * @param system is a reference to the parent TypeSystem instance.
*/
StringType(Manager &mgr, Handle<Typesystem> system)
- : Type(mgr, "string", system, false, true)
+ : Type(mgr, "string", system, true)
{
}
/**
- * TODO: DOC
+ * Creates a variant containing an empty string.
+ *
+ * @return a variant containing an empty string.
*/
Variant create() const override { return Variant{""}; }
};
@@ -122,7 +148,7 @@ protected:
/**
* TODO: DOC
*/
- bool doPrepare(Variant &var, Logger &log) const override
+ bool doBuild(Variant &var, Logger &logger) const override
{
if (!var.isInt()) {
throw LoggableException{"Expected an integer value."};
@@ -135,7 +161,7 @@ public:
* TODO: DOC
*/
IntType(Manager &mgr, Handle<Typesystem> system)
- : Type(mgr, "int", system, false, true)
+ : Type(mgr, "int", system, true)
{
}
@@ -150,7 +176,7 @@ protected:
/**
* TODO: DOC
*/
- bool doPrepare(Variant &var, Logger &log) const override
+ bool doBuild(Variant &var, Logger &logger) const override
{
if (!var.isInt() && !var.isDouble()) {
throw LoggableException{"Expected a double value."};
@@ -164,7 +190,7 @@ public:
* TODO: DOC
*/
DoubleType(Manager &mgr, Handle<Typesystem> system)
- : Type(mgr, "double", system, false, true)
+ : Type(mgr, "double", system, true)
{
}
@@ -179,14 +205,14 @@ protected:
/**
* TODO: DOC
*/
- bool doPrepare(Variant &var, Logger &log) const override { return true; }
+ bool doBuild(Variant &var, Logger &logger) const override { return true; }
public:
/**
* TODO: DOC
*/
UnknownType(Manager &mgr, Handle<Typesystem> system)
- : Type(mgr, "unknown", system, false, true)
+ : Type(mgr, "unknown", system, true)
{
}
@@ -201,7 +227,7 @@ protected:
/**
* TODO: DOC
*/
- bool doPrepare(Variant &var, Logger &log) const override
+ bool doBuild(Variant &var, Logger &logger) const override
{
if (!var.isBool()) {
throw LoggableException("Expected boolean value!");
@@ -214,7 +240,7 @@ public:
* TODO: DOC
*/
BoolType(Manager &mgr, Handle<Typesystem> system)
- : Type(mgr, "bool", system, false, true)
+ : Type(mgr, "bool", system, true)
{
}
@@ -224,7 +250,7 @@ public:
Variant create() const override { return Variant{false}; }
};
-class EnumerationType : public Type {
+class EnumType : public Type {
private:
std::map<std::string, size_t> values;
@@ -232,7 +258,7 @@ protected:
/**
* TODO: DOC
*/
- bool doPrepare(Variant &var, Logger &log) const override
+ bool doBuild(Variant &var, Logger &logger) const override
{
if (var.isInt()) {
int i = var.asInt();
@@ -245,10 +271,9 @@ protected:
return true;
}
- EnumerationType(Manager &mgr, std::string name, Handle<Typesystem> system,
- std::map<std::string, size_t> values)
- : Type(mgr, std::move(name), system, false, false),
- values(std::move(values))
+ EnumType(Manager &mgr, std::string name, Handle<Typesystem> system,
+ std::map<std::string, size_t> values)
+ : Type(mgr, std::move(name), system, false), values(std::move(values))
{
}
@@ -256,9 +281,9 @@ public:
/**
* TODO: DOC
*/
- EnumerationType(Manager &mgr, std::string name, Handle<Typesystem> system,
- const std::vector<std::string> &values)
- : Type(mgr, std::move(name), system, false, false)
+ EnumType(Manager &mgr, std::string name, Handle<Typesystem> system,
+ const std::vector<std::string> &values)
+ : Type(mgr, std::move(name), system, false)
{
for (size_t i = 0; i < values.size(); i++) {
this->values.insert(std::make_pair(values[i], i));
@@ -268,9 +293,10 @@ public:
/**
* TODO: DOC
*/
- static EnumerationType createValidated(
- Manager &mgr, std::string name, Handle<Typesystem> system,
- const std::vector<std::string> &values, Logger &logger);
+ static EnumType createValidated(Manager &mgr, std::string name,
+ Handle<Typesystem> system,
+ const std::vector<std::string> &values,
+ Logger &logger);
/**
* TODO: DOC
@@ -300,13 +326,13 @@ protected:
/**
* TODO: DOC
*/
- bool doPrepare(Variant &var, Logger &log) const override
+ bool doBuild(Variant &var, Logger &logger) const override
{
// If we already have an array, we just check that.
- if(var.isArray()){
+ if (var.isArray()) {
auto arr = var.asArray();
- for(size_t a = 0; a < attrs.size(); a++){
- if(!attrs[a].type->prepare(arr[a], log)){
+ for (size_t a = 0; a < attrs.size(); a++) {
+ if (!attrs[a].type->build(arr[a], logger)) {
return false;
}
}
@@ -323,10 +349,10 @@ protected:
for (auto &a : attrs) {
auto it = map.find(a.name);
// we use the default if nothing is set.
- if (it == map.end() || !a.type->prepare(it->second, log)) {
- log.note(std::string("Using default value for ") + a.name);
+ if (it == map.end() || !a.type->build(it->second, logger)) {
+ logger.note(std::string("Using default value for ") + a.name);
vec.push_back(a.defaultValue);
- } else{
+ } else {
vec.push_back(it->second);
}
}
@@ -339,8 +365,7 @@ public:
StructType(Manager &mgr, std::string name, Handle<Typesystem> system,
std::vector<AttributeDescriptor> attrs)
- : Type(mgr, std::move(name), system, true, false),
- attrs(std::move(attrs))
+ : Type(mgr, std::move(name), system, false), attrs(std::move(attrs))
{
}
// TODO
@@ -360,14 +385,14 @@ protected:
/**
* TODO: DOC
*/
- bool doPrepare(Variant &var, Logger &log) const override
+ bool doBuild(Variant &var, Logger &logger) const override
{
if (!var.isArray()) {
throw LoggableException("Expected array!");
}
bool res = true;
for (auto &v : var.asArray()) {
- if (!innerType->prepare(v, log)) {
+ if (!innerType->build(v, logger)) {
res = false;
}
}
@@ -381,7 +406,7 @@ public:
*/
ArrayType(Manager &mgr, std::string name, Handle<Typesystem> system,
Handle<Type> innerType)
- : Type(mgr, std::move(name), system, false, false),
+ : Type(mgr, std::move(name), system, false),
innerType(acquire(innerType))
{
}