diff options
| -rw-r--r-- | src/core/model/Typesystem.cpp | 47 | ||||
| -rw-r--r-- | src/core/model/Typesystem.hpp | 200 | ||||
| -rw-r--r-- | test/core/model/TestDomain.hpp | 3 | ||||
| -rw-r--r-- | test/core/model/TypesystemTest.cpp | 51 | 
4 files changed, 220 insertions, 81 deletions
diff --git a/src/core/model/Typesystem.cpp b/src/core/model/Typesystem.cpp index 79157f6..2899e03 100644 --- a/src/core/model/Typesystem.cpp +++ b/src/core/model/Typesystem.cpp @@ -42,15 +42,20 @@ bool Type::build(Variant &var, Logger &logger) const  bool StringType::doBuild(Variant &var, Logger &logger) const  { +	// Cannot convert non-primitive values to strings  	if (!var.isPrimitive()) {  		throw LoggableException{"Expected a string or primitive input."};  	} -	if (!var.isString()) { -		logger.note(std::string("Implicit type conversion from ") + +	// Perform an implicit type conversion +	if (!var.isString() || var.isMagic()) { +		// Convert the variant value to a string and set it +		var = var.toString().c_str(); + +		// Log conversions as these may be potentially unwanted +		logger.note(std::string("Implicit conversion from ") +  		            var.getTypeName() + " to string.");  	} -	var = Variant{var.toString().c_str()};  	return true;  } @@ -75,14 +80,48 @@ bool DoubleType::doBuild(Variant &var, Logger &logger) const  	return true;  } +/* Class BoolType */ + +bool BoolType::doBuild(Variant &var, Logger &logger) const +{ +	if (!var.isBool()) { +		throw LoggableException("Expected boolean value!"); +	} +	return true; +} +  /* Class EnumType */ +bool EnumType::doBuild(Variant &var, Logger &logger) const +{ +	if (var.isInt()) { +		int i = var.asInt(); +		if (i < 0 || i >= (int)values.size()) { +			throw LoggableException("Value is out of range."); +		} +	} else if (var.isMagic()) { +		// Fetch the given constant name and look it up in the value map +		const std::string &name = var.asMagic(); +		auto it = values.find(name); + +		// Throw an execption +		if (it == values.end()) { +			throw LoggableException(std::string("Unknown enum constant: \"") + +			                        name + std::string("\"")); +		} +		var = it->second; +	} +	return true; +} +  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; +	// Map used to store the unique values of the enum +	std::map<std::string, Variant::intType> unique_values; +  	for (size_t i = 0; i < values.size(); i++) {  		if (!Utils::isIdentifier(values[i])) {  			logger.error(values[i] + " is no valid identifier."); diff --git a/src/core/model/Typesystem.hpp b/src/core/model/Typesystem.hpp index 1711f75..3511354 100644 --- a/src/core/model/Typesystem.hpp +++ b/src/core/model/Typesystem.hpp @@ -92,7 +92,9 @@ public:  	/**  	 * Pure virtual function which must construct a valid, default instance of -	 * the type that is being described by the typesystem. +	 * the type that is being described by the typesystem. This function is +	 * usually called as a last resort if an instance of a certain type is +	 * requested but cannot be generated from the given user data.  	 */  	virtual Variant create() const = 0; @@ -160,13 +162,13 @@ public:  };  /** - * The IntType class represents the primitive integer type. There should be  + * The IntType class represents the primitive integer type. There should be   * exactly one instance of this class available in a preloaded type system.   */  class IntType : public Type {  protected:  	/** -	 * Expects the given variant to be an integer. Does not perform any type  +	 * Expects the given variant to be an integer. Does not perform any type  	 * conversion.  	 *  	 * @param var is a variant containing the data that should be checked. @@ -198,9 +200,8 @@ public:  };  /** - * The DoubleType class represents the primitive double type. There should - * exactly be a single instance of this class available in a preloaded type  - * system. + * The DoubleType class represents the primitive double type. There should be + * exactly one instance of this class available in a preloaded type system.   */  class DoubleType : public Type {  protected: @@ -236,22 +237,30 @@ public:  	Variant create() const override { return Variant{0.0}; }  }; +/** + * The BoolType class represents the primitive boolean type. There should be + * exactly one instance of this class available in a preloaded type system. + */  class BoolType : public Type {  protected:  	/** -	 * TODO: DOC +	 * Expects the given variant to be a boolean. Performs no implicit type +	 * conversion. +	 * +	 * @param var is a variant containing the data that should be checked. +	 * @param logger is the Logger instance into which errors should be written. +	 * @return true if the conversion was successful, false otherwise.  	 */ -	bool doBuild(Variant &var, Logger &logger) const override -	{ -		if (!var.isBool()) { -			throw LoggableException("Expected boolean value!"); -		} -		return true; -	} +	bool doBuild(Variant &var, Logger &logger) const override;  public:  	/** -	 * TODO: DOC +	 * Constructor of the BoolType class. Only one instance of BoolType should +	 * exist per project graph. +	 * +	 * @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.  	 */  	BoolType(Manager &mgr, Handle<Typesystem> system)  	    : Type(mgr, "bool", system, true) @@ -259,51 +268,47 @@ public:  	}  	/** -	 * TODO: DOC +	 * Creates a variant with the boolean value false. +	 * +	 * @return a Variant with the boolean value false.  	 */  	Variant create() const override { return Variant{false}; }  }; +/** + * The EnumType class represents a user defined enumeration type. + */  class EnumType : public Type {  private: -	std::map<std::string, size_t> values; +	/** +	 * Map containing the enumeration type values and the associated integer +	 * representation. +	 */ +	const std::map<std::string, Variant::intType> values;  protected:  	/** -	 * TODO: DOC +	 * Converts the given variant to the corresponding enum type representation. +	 * The variant may either be a magic string containing the name of an +	 * enumeration type or an integer. +	 * +	 * @param var is a variant containing the data that should be checked. +	 * @param logger is the Logger instance into which errors should be written. +	 * @return true if the conversion was successful, false otherwise.  	 */ -	bool doBuild(Variant &var, Logger &logger) const override -	{ -		if (var.isInt()) { -			int i = var.asInt(); -			if (i < 0 || i >= (int)values.size()) { -				throw LoggableException("Value is out of range."); -			} -		} else if (var.isString()) { -		} - -		return true; -	} - -	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)) -	{ -	} +	bool doBuild(Variant &var, Logger &logger) const override; -public:  	/** -	 * TODO: DOC +	 * Protected constructor of the EnumType class used to create a new EnumType +	 * instance from a previously created name to value map.  	 */  	EnumType(Manager &mgr, std::string name, Handle<Typesystem> system, -	         const std::vector<std::string> &values) -	    : Type(mgr, std::move(name), system, false) +	         std::map<std::string, Variant::intType> values) +	    : Type(mgr, std::move(name), system, false), values(std::move(values))  	{ -		for (size_t i = 0; i < values.size(); i++) { -			this->values.insert(std::make_pair(values[i], i)); -		}  	} +public:  	/**  	 * TODO: DOC  	 */ @@ -318,27 +323,74 @@ public:  	Variant create() const override { return Variant{0}; }  }; -class StructType : public Type { +/** + * The Attribute class describes a single attribute of a StructuredType entry. + */ +class Attribute : public Node { +private: +	/** +	 * Reference to the actual type of the attribute. +	 */ +	Owned<Type> type; +  public: -	class AttributeDescriptor : public Managed { -	public: -		const std::string name; -		const Variant defaultValue; -		const bool optional; -		const Owned<Type> type; - -		AttributeDescriptor(Manager &mgr, std::string name, -		                    Variant defaultValue, bool optional, -		                    Handle<Type> type) -		    : Managed(mgr), -		      name(name), -		      defaultValue(defaultValue), -		      optional(optional), -		      type(acquire(type)) -		{ -		} -	}; +	/** +	 * Default value of the attribute. +	 */ +	const Variant defaultValue; + +	/** +	 * Flag indicating whether this attribute is actually optional or not. +	 */ +	const bool optional; + +	/** +	 * Constructor of the Attribute class. +	 * +	 * @param mgr is the Manager instance to be used for the Node. +	 * @param type holds a reference to the type descriptor holding the type +	 * of the attribute. +	 * @param defaultValue is the default value of the attribute +	 * @param optional should be set to true if the if the default value should +	 * be used. +	 */ +	Attribute(Manager &mgr, std::string name, Handle<Type> type, +	          Variant defaultValue, bool optional) +	    : Node(mgr, std::move(name)), +	      type(acquire(type)), +	      defaultValue(defaultValue), +	      optional(optional) +	{ +	} + +	/** +	 * Constructor of the Attribute class with no default value. +	 * +	 * @param mgr is the Manager instance to be used for the Node. +	 * @param type holds a reference to the type descriptor holding the type +	 * of the attribute. +	 */ +	Attribute(Manager &mgr, std::string name, Handle<Type> type) +	    : Node(mgr, std::move(name)), +	      type(acquire(type)), +	      defaultValue(nullptr), +	      optional(false) +	{ +	} +	/** +	 * Returns a reference to the type descriptor holding the type of the +	 * attribute. +	 * +	 * @return the underlying type of the Rooted object. +	 */ +	Rooted<Type> getType() const { return type; } +}; + +/** + * The StructType class represents a user defined structure. + */ +class StructType : public Type {  protected:  	/**  	 * TODO: DOC @@ -348,8 +400,8 @@ protected:  		// If we already have an array, we just check that.  		if (var.isArray()) {  			auto arr = var.asArray(); -			for (size_t a = 0; a < attrs.size(); a++) { -				if (!attrs[a]->type->build(arr[a], logger)) { +			for (size_t a = 0; a < attributes.size(); a++) { +				if (!attributes[a]->getType()->build(arr[a], logger)) {  					return false;  				}  			} @@ -363,11 +415,12 @@ protected:  		// We transform the map into an array with the correct values at the  		// correct places.  		Variant::arrayType vec; -		for (auto &a : attrs) { -			auto it = map.find(a->name); +		for (auto &a : attributes) { +			auto it = map.find(a->getName());  			// we use the default if nothing is set. -			if (it == map.end() || !a->type->build(it->second, logger)) { -				logger.note(std::string("Using default value for ") + a->name); +			if (it == map.end() || !a->getType()->build(it->second, logger)) { +				logger.note(std::string("Using default value for ") + +				            a->getName());  				vec.push_back(a->defaultValue);  			} else {  				vec.push_back(it->second); @@ -378,19 +431,18 @@ protected:  	}  public: -	const ManagedVector<AttributeDescriptor> attrs; +	const NodeVector<Attribute> attributes;  	StructType(Manager &mgr, std::string name, Handle<Typesystem> system, -	           ManagedVector<AttributeDescriptor> attrs) +	           ManagedVector<Attribute> attributes)  	    : Type(mgr, std::move(name), system, false), -	      attrs(this, std::move(attrs)) +	      attributes(this, std::move(attributes))  	{  	}  	// TODO  	//	static StructType createValidated(  	//	    Manager &mgr, std::string name, Handle<Typesystem> system, -	//	    Handle<StructType> parent, -	//	    const std::vector<AttributeDescriptor> &attrs, Logger &logger); +	//           ManagedVector<Attribute> attributes);  	Variant create() const override { return Variant{Variant::arrayType{}}; }  }; @@ -463,7 +515,7 @@ public:  class UnknownType : public Type {  protected:  	/** -	 * As the UnknownType carries no type information, it does not modify the  +	 * As the UnknownType carries no type information, it does not modify the  	 * given variant and always succeeds (returns true).  	 *  	 * @return always true. diff --git a/test/core/model/TestDomain.hpp b/test/core/model/TestDomain.hpp index d4421a4..55a5d9b 100644 --- a/test/core/model/TestDomain.hpp +++ b/test/core/model/TestDomain.hpp @@ -36,8 +36,7 @@ static Rooted<Typesystem> constructTypeSystem(Manager &mgr)  	Rooted<StringType> string{new StringType(mgr, sys)};  	sys->addType(string);  	Rooted<StructType> string_struct{new StructType( -	    mgr, "text", sys, {new StructType::AttributeDescriptor( -	                          mgr, "content", "", false, string)})}; +	    mgr, "text", sys, {new Attribute(mgr, "content", string, "", false)})};  	sys->addType(string_struct);  	return sys; diff --git a/test/core/model/TypesystemTest.cpp b/test/core/model/TypesystemTest.cpp index 0e2dc8a..3447b1c 100644 --- a/test/core/model/TypesystemTest.cpp +++ b/test/core/model/TypesystemTest.cpp @@ -144,7 +144,7 @@ TEST(IntType, conversion)  	}  } -/* Class IntType */ +/* Class DoubleType */  TEST(DoubleType, rtti)  { @@ -192,6 +192,55 @@ TEST(DoubleType, conversion)  	}  } +/* Class BoolType */ + +TEST(BoolType, rtti) +{ +	Manager mgr; +	Rooted<BoolType> boolType{new BoolType(mgr, nullptr)}; +	ASSERT_TRUE(boolType->isa(RttiTypes::BoolType)); +	ASSERT_TRUE(boolType->isa(typeOf<Type>())); +	ASSERT_TRUE(boolType->isa(typeOf<Node>())); +} + +TEST(BoolType, creation) +{ +	Manager mgr; +	Rooted<BoolType> boolType{new BoolType(mgr, nullptr)}; +	Variant val = boolType->create(); +	ASSERT_TRUE(val.isBool()); +	ASSERT_FALSE(val.asBool()); +} + +TEST(BoolType, conversion) +{ +	Logger logger; +	Manager mgr; +	Rooted<BoolType> boolType{new BoolType(mgr, nullptr)}; + +	{ +		Variant val{true}; +		ASSERT_TRUE(boolType->build(val, logger)); +		ASSERT_TRUE(val.isBool()); +		ASSERT_TRUE(val.asBool()); +	} + +	{ +		Variant val{false}; +		ASSERT_TRUE(boolType->build(val, logger)); +		ASSERT_TRUE(val.isBool()); +		ASSERT_FALSE(val.asBool()); +	} + +	{ +		Variant val{314}; +		ASSERT_FALSE(boolType->build(val, logger)); +		ASSERT_TRUE(val.isBool()); +		ASSERT_FALSE(val.asBool()); +	} +} + +  /* Class ArrayType */  TEST(ArrayType, rtti)  | 
