diff options
-rw-r--r-- | src/core/model/Node.cpp | 26 | ||||
-rw-r--r-- | src/core/model/Node.hpp | 17 | ||||
-rw-r--r-- | src/core/model/Typesystem.cpp | 107 | ||||
-rw-r--r-- | src/core/model/Typesystem.hpp | 116 | ||||
-rw-r--r-- | src/core/parser/ParserScope.cpp | 192 | ||||
-rw-r--r-- | src/core/parser/ParserScope.hpp | 196 | ||||
-rw-r--r-- | src/plugins/xml/XmlParser.cpp | 56 | ||||
-rw-r--r-- | test/core/model/DomainTest.cpp | 26 | ||||
-rw-r--r-- | test/core/model/NodeTest.cpp | 62 | ||||
-rw-r--r-- | test/core/model/TestAdvanced.hpp | 2 | ||||
-rw-r--r-- | test/core/model/TestDocumentBuilder.hpp | 2 | ||||
-rw-r--r-- | test/core/model/TypesystemTest.cpp | 6 | ||||
-rw-r--r-- | test/plugins/xml/XmlParserTest.cpp | 2 | ||||
-rw-r--r-- | testdata/xmlparser/generic.oxm | 242 |
14 files changed, 572 insertions, 480 deletions
diff --git a/src/core/model/Node.cpp b/src/core/model/Node.cpp index 6c00e89..7cbbbe1 100644 --- a/src/core/model/Node.cpp +++ b/src/core/model/Node.cpp @@ -60,14 +60,14 @@ using VisitorSet = class SharedResolutionState { public: /** - * Actual path (name pattern) that was requested for resolution. + * Type of the node that was requested for resolution. */ - const std::vector<std::string> &path; + const Rtti &type; /** - * Type of the node that was requested for resolution. + * Actual path (name pattern) that was requested for resolution. */ - const Rtti &type; + const std::vector<std::string> &path; /** * Tracks all nodes that have already been visited. @@ -82,13 +82,13 @@ public: /** * Constructor of the SharedResolutionState class. * + * @param type is the type of the node that should be resolved. * @param path is a const reference to the actual path that should be * resolved. - * @param type is the type of the node that should be resolved. */ - SharedResolutionState(const std::vector<std::string> &path, - const Rtti &type) - : path(path), type(type) + SharedResolutionState(const Rtti &type, + const std::vector<std::string> &path) + : type(type), path(path) { } }; @@ -329,10 +329,10 @@ bool Node::continueResolveReference(Handle<Node> h, ResolutionState &state) } std::vector<ResolutionResult> Node::resolve( - const std::vector<std::string> &path, const Rtti &type) + const Rtti &type, const std::vector<std::string> &path) { // Create the state variables - SharedResolutionState sharedState(path, type); + SharedResolutionState sharedState(type, path); ResolutionState state(sharedState, this); // Kickstart the resolution process by treating this very node as compositum @@ -344,11 +344,11 @@ std::vector<ResolutionResult> Node::resolve( return sharedState.result; } -std::vector<ResolutionResult> Node::resolve(const std::string &name, - const Rtti &type) +std::vector<ResolutionResult> Node::resolve(const Rtti &type, + const std::string &name) { // Place the name in a vector and call the corresponding resolve function - return resolve(std::vector<std::string>{name}, type); + return resolve(type, std::vector<std::string>{name}); } bool Node::checkDuplicate(Handle<Node> elem, diff --git a/src/core/model/Node.hpp b/src/core/model/Node.hpp index 036bcae..61bf418 100644 --- a/src/core/model/Node.hpp +++ b/src/core/model/Node.hpp @@ -223,7 +223,7 @@ private: * @param thisRef is the Node of which the reference should be returned. * @return the value of the reference. */ - using NodeReferenceCallback = const Node* (const Node* thisRef); + using NodeReferenceCallback = const Node *(const Node *thisRef); /** * Checks whether the a certain property is acyclic. @@ -400,7 +400,8 @@ protected: * @return true if the parent reference is acyclic, false otherwise. */ bool validateIsAcyclic(const std::string &name, - NodeReferenceCallback callback, Logger &logger) const; + NodeReferenceCallback callback, + Logger &logger) const; /** * Makes sure the "parent" reference is not cyclic. @@ -538,26 +539,26 @@ public: * Function which resolves a name path to a list of possible nodes starting * from this node. * + * @param type specifies the type of the node that should be located. * @param path is a list specifying a path of node names meant to specify a * certain named node. - * @param type specifies the type of the node that should be located. * @return a vector containing ResolutionResult structures which describe * the resolved elements. */ - std::vector<ResolutionResult> resolve(const std::vector<std::string> &path, - const Rtti &type); + std::vector<ResolutionResult> resolve(const Rtti &type, + const std::vector<std::string> &path); /** * Function which resolves a single name to a list of possible nodes * starting from this node. * - * @param name is the name which should be resolved. * @param type specifies the type of the node that should be located. + * @param name is the name which should be resolved. * @return a vector containing ResolutionResult structures which describe * the resolved elements. */ - std::vector<ResolutionResult> resolve(const std::string &name, - const Rtti &type); + std::vector<ResolutionResult> resolve(const Rtti &type, + const std::string &name); /** * Checks whether this node is valid and returns true if it is and false diff --git a/src/core/model/Typesystem.cpp b/src/core/model/Typesystem.cpp index 8a50492..591dcbe 100644 --- a/src/core/model/Typesystem.cpp +++ b/src/core/model/Typesystem.cpp @@ -24,12 +24,28 @@ namespace ousia { +/* Static helper functions */ + +static void NullMagicCallback(Variant &, bool, ManagedUid) {} + /* Class Type */ -bool Type::build(Variant &data, Logger &logger) const +bool Type::build(Variant &data, Logger &logger, + const MagicCallback &magicCallback) const { + // If the given variant is marked as "magic", try to resolve the real value + if (data.isMagic()) { + Variant strData = Variant::fromString(data.asString()); + Logger nullLogger; + bool valid = isValid(strData, nullLogger); + magicCallback(data, valid, + getUid()); + build(strData, nullLogger); + return true; // Just return true for now + } + try { - return doBuild(data, logger); + return doBuild(data, logger, magicCallback); } catch (LoggableException ex) { logger.log(ex); @@ -38,37 +54,47 @@ bool Type::build(Variant &data, Logger &logger) const } } +bool Type::build(Variant &data, Logger &logger) const +{ + return build(data, logger, NullMagicCallback); +} + /* Class BoolType */ -bool BoolType::doBuild(Variant &data, Logger &logger) const +bool BoolType::doBuild(Variant &data, Logger &logger, + const MagicCallback &magicCallback) const { return VariantConverter::toBool(data, logger); } /* Class IntType */ -bool IntType::doBuild(Variant &data, Logger &logger) const +bool IntType::doBuild(Variant &data, Logger &logger, + const MagicCallback &magicCallback) const { return VariantConverter::toInt(data, logger); } /* Class DoubleType */ -bool DoubleType::doBuild(Variant &data, Logger &logger) const +bool DoubleType::doBuild(Variant &data, Logger &logger, + const MagicCallback &magicCallback) const { return VariantConverter::toDouble(data, logger); } /* Class StringType */ -bool StringType::doBuild(Variant &data, Logger &logger) const +bool StringType::doBuild(Variant &data, Logger &logger, + const MagicCallback &magicCallback) const { return VariantConverter::toString(data, logger); } /* Class EnumType */ -bool EnumType::doBuild(Variant &data, Logger &logger) const +bool EnumType::doBuild(Variant &data, Logger &logger, + const MagicCallback &magicCallback) const { // If the variant is an int, check whether the value is in range if (data.isInt()) { @@ -152,7 +178,7 @@ Attribute::Attribute(Manager &mgr, std::string name, Handle<Type> type, Variant defaultValue, bool optional) : Node(mgr, std::move(name)), type(acquire(type)), - rawDefaultValue(defaultValue), + defaultValue(std::move(defaultValue)), optional(optional) { ExceptionLogger logger; @@ -173,7 +199,6 @@ Attribute::Attribute(Manager &mgr, std::string name, Variant defaultValue, void Attribute::initialize(Logger &logger) { if (optional) { - defaultValue = rawDefaultValue; type->build(defaultValue, logger); } } @@ -187,7 +212,6 @@ void Attribute::setDefaultValue(const Variant &defaultValue, Logger &logger) { invalidate(); - rawDefaultValue = defaultValue; optional = true; initialize(logger); } @@ -196,7 +220,6 @@ void Attribute::removeDefaultValue() { invalidate(); - rawDefaultValue = nullptr; defaultValue = nullptr; optional = false; } @@ -264,7 +287,9 @@ bool StructType::insertDefaults(Variant &data, const std::vector<bool> &set, return ok; } -bool StructType::buildFromArray(Variant &data, Logger &logger, bool trim) const +bool StructType::buildFromArray(Variant &data, Logger &logger, + const MagicCallback &magicCallback, + bool trim) const { bool ok = true; Variant::arrayType &arr = data.asArray(); @@ -286,14 +311,16 @@ bool StructType::buildFromArray(Variant &data, Logger &logger, bool trim) const // Make sure the given attributes have to correct type const size_t len = std::min(n, N); for (size_t a = 0; a < len; a++) { - set[a] = attributes[a]->getType()->build(arr[a], logger); + set[a] = attributes[a]->getType()->build(arr[a], logger, magicCallback); ok = ok && set[a]; } return insertDefaults(data, set, logger) && ok; } -bool StructType::buildFromMap(Variant &data, Logger &logger, bool trim) const +bool StructType::buildFromMap(Variant &data, Logger &logger, + const MagicCallback &magicCallback, + bool trim) const { bool ok = true; const Variant::mapType &map = data.asMap(); @@ -323,7 +350,8 @@ bool StructType::buildFromMap(Variant &data, Logger &logger, bool trim) const // Convert the value to the type of the attribute arr[idx] = value; - set[idx] = attributes[idx]->getType()->build(arr[idx], logger); + set[idx] = attributes[idx]->getType()->build(arr[idx], logger, + magicCallback); } else if (!trim) { ok = false; logger.error(std::string("Invalid attribute key \"") + key + @@ -337,13 +365,14 @@ bool StructType::buildFromMap(Variant &data, Logger &logger, bool trim) const } bool StructType::buildFromArrayOrMap(Variant &data, Logger &logger, + const MagicCallback &magicCallback, bool trim) const { if (data.isArray()) { - return buildFromArray(data, logger, trim); + return buildFromArray(data, logger, magicCallback, trim); } if (data.isMap()) { - return buildFromMap(data, logger, trim); + return buildFromMap(data, logger, magicCallback, trim); } throw LoggableException( std::string( @@ -375,9 +404,10 @@ void StructType::initialize(Logger &logger) } } -bool StructType::doBuild(Variant &data, Logger &logger) const +bool StructType::doBuild(Variant &data, Logger &logger, + const MagicCallback &magicCallback) const { - return buildFromArrayOrMap(data, logger, false); + return buildFromArrayOrMap(data, logger, magicCallback, false); } bool StructType::doValidate(Logger &logger) const @@ -491,7 +521,7 @@ bool StructType::derivedFrom(Handle<StructType> other) const bool StructType::cast(Variant &data, Logger &logger) const { - return buildFromArrayOrMap(data, logger, true); + return buildFromArrayOrMap(data, logger, NullMagicCallback, true); } ssize_t StructType::indexOf(const std::string &name) const @@ -510,7 +540,8 @@ bool StructType::hasAttribute(const std::string &name) const /* Class ArrayType */ -bool ArrayType::doBuild(Variant &data, Logger &logger) const +bool ArrayType::doBuild(Variant &data, Logger &logger, + const MagicCallback &magicCallback) const { if (!data.isArray()) { throw LoggableException(std::string("Expected array, but got ") + @@ -518,23 +549,32 @@ bool ArrayType::doBuild(Variant &data, Logger &logger) const } bool res = true; for (auto &v : data.asArray()) { - if (!innerType->build(v, logger)) { + if (!innerType->build(v, logger, magicCallback)) { res = false; } } return res; } +/* Class UnknownType */ + +bool UnknownType::doBuild(Variant &, Logger &, const MagicCallback &) const +{ + return true; +} + +UnknownType::UnknownType(Manager &mgr) : Type(mgr, "unknown", nullptr, false) {} + +Variant UnknownType::create() const { return Variant{nullptr}; } + /* Class Constant */ Constant::Constant(Manager &mgr, std::string name, Handle<Typesystem> system, Handle<Type> type, Variant value) - : Node(mgr, std::move(name), system), - type(acquire(type)), - rawValue(std::move(value)) + : Node(mgr, std::move(name), system), type(acquire(type)), value(value) { ExceptionLogger logger; - initialize(logger); + this->type->build(this->value, logger); } Constant::Constant(Manager &mgr, std::string name, Handle<Typesystem> system, @@ -543,27 +583,20 @@ Constant::Constant(Manager &mgr, std::string name, Handle<Typesystem> system, { } -void Constant::initialize(Logger &logger) -{ - value = rawValue; - type->build(value, logger); -} - Rooted<Type> Constant::getType() const { return type; } void Constant::setType(Handle<Type> type, Logger &logger) { this->type = acquire(type); - initialize(logger); + this->type->build(this->value, logger); } -const Variant &Constant::getValue() const { return value; } +Variant &Constant::getValue() { return value; } void Constant::setValue(Variant value, Logger &logger) { - this->rawValue = value; this->value = std::move(value); - initialize(logger); + this->type->build(this->value, logger); } /* Class Typesystem */ @@ -571,7 +604,7 @@ void Constant::setValue(Variant value, Logger &logger) void Typesystem::doResolve(ResolutionState &state) { continueResolveComposita(constants, constants.getIndex(), state); - continueResolveComposita(types, constants.getIndex(), state); + continueResolveComposita(types, types.getIndex(), state); continueResolveReferences(typesystems, state); } diff --git a/src/core/model/Typesystem.hpp b/src/core/model/Typesystem.hpp index 5b1254a..d88a7e9 100644 --- a/src/core/model/Typesystem.hpp +++ b/src/core/model/Typesystem.hpp @@ -29,6 +29,7 @@ #ifndef _OUSIA_MODEL_TYPESYSTEM_HPP_ #define _OUSIA_MODEL_TYPESYSTEM_HPP_ +#include <functional> #include <map> #include <vector> @@ -55,6 +56,21 @@ class SystemTypesystem; * definitions. */ class Type : public Node { +public: + /** + * Callback function called when a variant with "magic" value is reached. + * This callback allows to transform these magic values into something else. + * This mechanism is used to resolve constants. + * + * @param data is the magic value that should be looked up. + * @param isValid is set to true if the magic value does not necessarily + * have to be looked up, in this case no error message has to be generated + * if the lookup for a constant fails. + * @param type is the managed uid of the underlying Type for which the magic + * value should be looked up. + */ + using MagicCallback = std::function<void(Variant &data, bool isValid, ManagedUid Type)>; + protected: /** * Protected constructor to be called by the classes derived from the Type @@ -82,9 +98,12 @@ protected: * -- 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. + * @param magicCallback is a callback that should be called to other "build" + * functions. * @return true if the conversion was successful, false otherwise. */ - virtual bool doBuild(Variant &data, Logger &logger) const = 0; + virtual bool doBuild(Variant &data, Logger &logger, + const MagicCallback &magicCallback) const = 0; public: /** @@ -109,6 +128,22 @@ public: * internal representation used by the Type class. * @param logger is the Logger instance into which errors should be * written. + * @param magicCallback is the callback function to be called whenever + * a variant with "magic" value is reached. + * @return true if the conversion was successful, false otherwise. + */ + bool build(Variant &data, Logger &logger, + const MagicCallback &magicCallback) const; + + /** + * Validates and completes the given variant which was read from a + * user-supplied source. + * + * @param data 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 build(Variant &data, Logger &logger) const; @@ -154,7 +189,8 @@ protected: * @param logger is the Logger instance into which errors should be written. * @return true if the conversion was successful, false otherwise. */ - bool doBuild(Variant &data, Logger &logger) const override; + bool doBuild(Variant &data, Logger &logger, + const MagicCallback &magicCallback) const override; public: /** @@ -192,7 +228,8 @@ protected: * @param logger is the Logger instance into which errors should be written. * @return true if the conversion was successful, false otherwise. */ - bool doBuild(Variant &data, Logger &logger) const override; + bool doBuild(Variant &data, Logger &logger, + const MagicCallback &magicCallback) const override; public: /** @@ -230,7 +267,8 @@ protected: * @param logger is the Logger instance into which errors should be written. * @return true if the conversion was successful, false otherwise. */ - bool doBuild(Variant &data, Logger &logger) const override; + bool doBuild(Variant &data, Logger &logger, + const MagicCallback &magicCallback) const override; public: /** @@ -268,7 +306,8 @@ protected: * @param logger is the Logger instance into which errors should be written. * @return true if the conversion was successful, false otherwise. */ - bool doBuild(Variant &data, Logger &logger) const override; + bool doBuild(Variant &data, Logger &logger, + const MagicCallback &magicCallback) const override; public: /** @@ -332,7 +371,8 @@ protected: * @param logger is the Logger instance into which errors should be written. * @return true if the conversion was successful, false otherwise. */ - bool doBuild(Variant &data, Logger &logger) const override; + bool doBuild(Variant &data, Logger &logger, + const MagicCallback &magicCallback) const override; public: /** @@ -384,12 +424,6 @@ private: Owned<Type> type; /** - * Initial default value passed to the constructor of the Attribute class - * that has not been passed through the "build" method of the type. - */ - Variant rawDefaultValue; - - /** * Default value of the attribute. */ Variant defaultValue; @@ -400,11 +434,7 @@ private: bool optional; /** - * Reinitializes the default value from the raw default value with the - * current type. - * - * @param logger is the logger instance to which errors while building the - * default value should be passed. + * Function used to parse the Attribute default value with the current type. */ void initialize(Logger &logger); @@ -473,7 +503,7 @@ public: * @return the default value of the attribute. If no default value has been * given a null variant is returned (the opposite does not hold). */ - Variant getDefaultValue() const { return defaultValue; } + Variant& getDefaultValue() { return defaultValue; } /** * Removes any default value from the attribute, making this attribute @@ -589,7 +619,8 @@ private: * of attributes (as needed when casting from a derived type). * @return true if the operation is successful, false otherwise. */ - bool buildFromArray(Variant &data, Logger &logger, bool trim) const; + bool buildFromArray(Variant &data, Logger &logger, + const MagicCallback &magicCallback, bool trim) const; /** * Checks a map and its entries for validity and if possible updates its @@ -601,7 +632,8 @@ private: * when casting from a derived type. * @return true if the operation is successful, false otherwise. */ - bool buildFromMap(Variant &data, Logger &logger, bool trim) const; + bool buildFromMap(Variant &data, Logger &logger, + const MagicCallback &magicCallback, bool trim) const; /** * Checks a map or an array for validity and if possible updates its content @@ -613,7 +645,9 @@ private: * when casting from a derived type. * @return true if the operation is successful, false otherwise. */ - bool buildFromArrayOrMap(Variant &data, Logger &logger, bool trim) const; + bool buildFromArrayOrMap(Variant &data, Logger &logger, + const MagicCallback &magicCallback, + bool trim) const; /** * Rebuilds the internal index and attribute list depending on the parent @@ -645,7 +679,8 @@ protected: * @param logger is the Logger instance into which errors should be written. * @return true if the conversion was successful, false otherwise. */ - bool doBuild(Variant &data, Logger &logger) const override; + bool doBuild(Variant &data, Logger &logger, + const MagicCallback &magicCallback) const override; /** * Checks the struct descriptor for being valid. @@ -819,17 +854,18 @@ protected: * @param logger is the Logger instance into which errors should be written. * @return true if the conversion was successful, false otherwise. */ - bool doBuild(Variant &data, Logger &logger) const override; + bool doBuild(Variant &data, Logger &logger, + const MagicCallback &magicCallback) const override; public: /** * Constructor of the ArrayType class. * - * @param mgr is the Manager instance to be used for the Node. * @param innerType is the type of the elements stored in the array. */ - ArrayType(Manager &mgr, Handle<Type> innerType) - : Type(mgr, "", innerType->getTypesystem(), false), + ArrayType(Handle<Type> innerType) + : Type(innerType->getManager(), innerType->getName() + "[]", + innerType->getTypesystem(), false), innerType(acquire(innerType)) { } @@ -869,7 +905,7 @@ protected: * * @return always true. */ - bool doBuild(Variant &, Logger &) const override { return true; } + bool doBuild(Variant &, Logger &, const MagicCallback &) const override; public: /** @@ -878,14 +914,14 @@ public: * * @param mgr is the Manager instance to be used for the Node. */ - UnknownType(Manager &mgr) : Type(mgr, "unknown", nullptr, false) {} + UnknownType(Manager &mgr); /** * Returns a nullptr variant. * * @return a Variant instance with nullptr value. */ - Variant create() const override { return Variant{nullptr}; } + Variant create() const override; }; /** @@ -900,23 +936,10 @@ private: Owned<Type> type; /** - * Value of the value before a proper type was set. - */ - Variant rawValue; - - /** * Actual value of the constant. */ Variant value; - /** - * Reinitializes the value from the raw value with the current type. - * - * @param logger is the logger instance to which errors while building the - * value should be passed. - */ - void initialize(Logger &logger); - public: /** * Constructor of the Constant node. @@ -952,9 +975,10 @@ public: Rooted<Type> getType() const; /** - * Sets the type of the constant to the given type. This will cause the raw - * value of the variant to be reparsed and any error to be logged in the - * given logger. + * Sets the type of the constant to the given type. This will cause the + * value of the variant to be built with the given type and any error to be + * logged in the given logger. Note: This operation is possibly lossy and + * will destroy values if the current variant value doesn't match the type. * * @param type is the new type of the constant. * @param logger is the logger instance to which errors that occur during @@ -968,7 +992,7 @@ public: * * @return a const reference to the actual value of the constant. */ - const Variant &getValue() const; + Variant &getValue(); /** * Sets the value of the constant. The value will be passed to the "build" diff --git a/src/core/parser/ParserScope.cpp b/src/core/parser/ParserScope.cpp index 0de0dbf..c7a9f2a 100644 --- a/src/core/parser/ParserScope.cpp +++ b/src/core/parser/ParserScope.cpp @@ -18,6 +18,7 @@ #include <core/common/Exceptions.hpp> #include <core/common/Utils.hpp> +#include <core/model/Typesystem.hpp> #include "ParserScope.hpp" @@ -31,12 +32,13 @@ ParserScopeBase::ParserScopeBase(const NodeVector<Node> &nodes) : nodes(nodes) { } -Rooted<Node> ParserScopeBase::resolve(const std::vector<std::string> &path, - const Rtti &type, Logger &logger) +Rooted<Node> ParserScopeBase::resolve(const Rtti &type, + const std::vector<std::string> &path, + Logger &logger) { // Go up the stack and try to resolve the for (auto it = nodes.rbegin(); it != nodes.rend(); it++) { - std::vector<ResolutionResult> res = (*it)->resolve(path, type); + std::vector<ResolutionResult> res = (*it)->resolve(type, path); // Abort if the object could not be resolved if (res.empty()) { @@ -79,14 +81,14 @@ bool DeferredResolution::resolve( // Fork the logger to prevent error messages from being shown if we actively // ignore the resolution result LoggerFork loggerFork = logger.fork(); - Rooted<Node> res = scope.resolve(path, type, loggerFork); + Rooted<Node> res = scope.resolve(type, path, loggerFork); if (res != nullptr) { if (!ignore.count(res.get())) { loggerFork.commit(); try { // Push the location onto the logger default location stack GuardedLogger loggerGuard(logger, *owner); - resultCallback(res, logger); + resultCallback(res, owner, logger); } catch (LoggableException ex) { logger.log(ex); @@ -99,6 +101,16 @@ bool DeferredResolution::resolve( return false; } +void DeferredResolution::fail(Logger &logger) +{ + try { + resultCallback(nullptr, owner, logger); + } + catch (LoggableException ex) { + logger.log(ex); + } +} + /* Class ParserScope */ ParserScope::ParserScope(const NodeVector<Node> &nodes, @@ -227,29 +239,29 @@ bool ParserScope::getFlag(ParserFlag flag) return false; } -bool ParserScope::resolve(const std::vector<std::string> &path, - const Rtti &type, Logger &logger, +bool ParserScope::resolve(const Rtti &type, + const std::vector<std::string> &path, + Handle<Node> owner, Logger &logger, ResolutionImposterCallback imposterCallback, - ResolutionResultCallback resultCallback, - Handle<Node> owner) + ResolutionResultCallback resultCallback) { - if (!resolve(path, type, logger, resultCallback, owner)) { - resultCallback(imposterCallback(), logger); + if (!resolve(type, path, owner, logger, resultCallback)) { + resultCallback(imposterCallback(), owner, logger); return false; } return true; } -bool ParserScope::resolve(const std::vector<std::string> &path, - const Rtti &type, Logger &logger, - ResolutionResultCallback resultCallback, - Handle<Node> owner) +bool ParserScope::resolve(const Rtti &type, + const std::vector<std::string> &path, + Handle<Node> owner, Logger &logger, + ResolutionResultCallback resultCallback) { // Try to directly resolve the node - Rooted<Node> res = ParserScopeBase::resolve(path, type, logger); + Rooted<Node> res = ParserScopeBase::resolve(type, path, logger); if (res != nullptr && !awaitingResolution.count(res.get())) { try { - resultCallback(res, logger); + resultCallback(res, owner, logger); } catch (LoggableException ex) { logger.log(ex, *owner); @@ -266,6 +278,149 @@ bool ParserScope::resolve(const std::vector<std::string> &path, return false; } +bool ParserScope::resolveType(const std::vector<std::string> &path, + Handle<Node> owner, Logger &logger, + ResolutionResultCallback resultCallback) +{ + // Check whether the given path denotes an array, if yes recursively resolve + // the inner type and wrap it in an array type (this allows multi + // dimensional arrays). + if (!path.empty()) { + const std::string &last = path.back(); + if (last.size() >= 2 && last.substr(last.size() - 2, 2) == "[]") { + // Type ends with "[]", remove this from the last element in the + // list + std::vector<std::string> p = path; + p.back() = p.back().substr(0, last.size() - 2); + + // Resolve the rest of the type + return resolveType(p, owner, logger, + [resultCallback](Handle<Node> resolved, + Handle<Node> owner, + Logger &logger) { + if (resolved != nullptr) { + Rooted<ArrayType> arr{new ArrayType{resolved.cast<Type>()}}; + resultCallback(arr, owner, logger); + } else { + resultCallback(nullptr, owner, logger); + } + }); + } + } + + // Requested type is not an array, call the usual resolve function + return resolve(RttiTypes::Type, path, owner, logger, resultCallback); +} + +bool ParserScope::resolveType(const std::string &name, Handle<Node> owner, + Logger &logger, + ResolutionResultCallback resultCallback) +{ + return resolveType(Utils::split(name, '.'), owner, logger, resultCallback); +} + +bool ParserScope::resolveTypeWithValue(const std::vector<std::string> &path, + Handle<Node> owner, Variant &value, + Logger &logger, + ResolutionResultCallback resultCallback) +{ + // Fork the parser scope -- constants need to be resolved in the same + // context as this resolve call + std::shared_ptr<ParserScope> scope = std::make_shared<ParserScope>(fork()); + + return resolveType( + path, owner, logger, + [=](Handle<Node> resolved, Handle<Node> owner, Logger &logger) mutable { + // Abort if the lookup failed + if (resolved == nullptr) { + resultCallback(resolved, owner, logger); + return; + } + + // Fetch the type reference and the manager reference + Rooted<Type> type = resolved.cast<Type>(); + Manager *mgr = &type->getManager(); + + // The type has been resolved, try to resolve magic values as + // constants and postpone calling the callback function until + // all magic values have been resolved + std::shared_ptr<bool> isAsync = std::make_shared<bool>(false); + std::shared_ptr<int> magicCount = std::make_shared<int>(0); + type->build(value, logger, [=](Variant &magicValue, bool isValid, + ManagedUid innerTypeUid) mutable { + // Fetch the inner type + Rooted<Type> innerType = + dynamic_cast<Type *>(mgr->getManaged(innerTypeUid)); + if (innerType == nullptr) { + return; + } + + // Fetch a pointer at the variant + Variant *magicValuePtr = &magicValue; + + // Increment the number of encountered magic values + (*magicCount)++; + + // Try to resolve the value as constant + std::string constantName = magicValue.asMagic(); + scope->resolve<Constant>(constantName, owner, logger, + [=](Handle<Node> resolved, + Handle<Node> owner, + Logger &logger) mutable { + if (resolved != nullptr) { + // Make sure the constant is of the correct inner type + Rooted<Constant> constant = resolved.cast<Constant>(); + Rooted<Type> constantType = constant->getType(); + if (constantType != innerType) { + logger.error( + std::string("Expected value of type \"") + + innerType->getName() + + std::string("\" but found constant \"") + + constant->getName() + + std::string(" of type \"") + + constantType->getName() + "\" instead.", + *owner); + } else if (!isValid) { + logger.error("Identifier \"" + constantName + + "\" is not a valid " + + innerType->getName(), + *owner); + } + + // Nevertheless, no matter what happened, set the value + // of the original magic variant to the given constant + *magicValuePtr = constant->getValue(); + } + + // Decrement the number of magic values, call the callback + // function if all magic values have been resolved + (*magicCount)--; + if ((*magicCount) == 0 && (*isAsync)) { + resultCallback(resolved, owner, logger); + } + }); + }); + + // Now we are asynchronous + (*isAsync) = true; + + // Directly call the callback function if there were no magic values + // involved + if ((*magicCount) == 0) { + resultCallback(resolved, owner, logger); + } + }); +} + +bool ParserScope::resolveTypeWithValue(const std::string &name, + Handle<Node> owner, Variant &value, + Logger &logger, + ResolutionResultCallback resultCallback) +{ + return resolveTypeWithValue(Utils::split(name, '.'), owner, value, logger, + resultCallback); +} + bool ParserScope::performDeferredResolution(Logger &logger) { // Repeat the resolution process as long as something has changed in the @@ -304,7 +459,8 @@ bool ParserScope::performDeferredResolution(Logger &logger) // Output error messages for all elements for which resolution did not // succeed. - for (const auto &failed : deferred) { + for (auto &failed : deferred) { + failed.fail(logger); logger.error(std::string("Could not resolve ") + failed.type.name + std::string(" \"") + Utils::join(failed.path, ".") + std::string("\""), diff --git a/src/core/parser/ParserScope.hpp b/src/core/parser/ParserScope.hpp index 2378967..c49acd3 100644 --- a/src/core/parser/ParserScope.hpp +++ b/src/core/parser/ParserScope.hpp @@ -33,8 +33,7 @@ * @file ParserScope.hpp * * Contains the ParserScope class used for resolving references based on the - *current - * parser state. + * current parser state. * * @author Andreas Stöckel (astoecke@techfak.uni-bielefeld.de) */ @@ -45,6 +44,7 @@ namespace ousia { class CharReader; class Logger; class ParserScope; +class Variant; /** * Callback function type used for creating a dummy object while no correct @@ -55,9 +55,13 @@ using ResolutionImposterCallback = std::function<Rooted<Node>()>; /** * Callback function type called whenever the result of a resolution is * available. + * + * @param resolved is the new, resolved node. + * @param owner is the node that was passed as "owner". + * @param logger is the logger to which errors should be logged. */ -using ResolutionResultCallback = - std::function<void(Handle<Node>, Logger &logger)>; +using ResolutionResultCallback = std::function<void(Handle<Node> resolved, + Handle<Node> owner, Logger &logger)>; /** * Base class for the @@ -90,14 +94,14 @@ public: * Tries to resolve a node for the given type and path for all nodes that * are currently in the stack, starting with the topmost node on the stack. * - * @param path is the path for which a node should be resolved. * @param type is the type of the node that should be resolved. + * @param path is the path for which a node should be resolved. * @param logger is the logger instance into which resolution problems * should be logged. * @return a reference at a resolved node or nullptr if no node could be * found. */ - Rooted<Node> resolve(const std::vector<std::string> &path, const Rtti &type, + Rooted<Node> resolve(const Rtti &type, const std::vector<std::string> &path, Logger &logger); }; @@ -167,6 +171,15 @@ public: */ bool resolve(const std::unordered_multiset<const Node *> &ignore, Logger &logger); + + /** + * Inform the callee about the failure by calling the callback function with + * "nullptr" as resolved element. + * + * @param logger is the logger instance to which error messages should be + * logged. + */ + void fail(Logger &logger); }; /** @@ -396,8 +409,9 @@ public: * temporary) and another time if the resolution turned out to be * successful at a later point in time. * - * @param path is the path for which a node should be resolved. * @param type is the type of the node that should be resolved. + * @param path is the path for which a node should be resolved. + * @param owner is the node for which the resolution takes place. * @param logger is the logger instance into which resolution problems * should be logged. * @param imposterCallback is the callback function that is called if @@ -410,15 +424,14 @@ public: * the resolved object directly when this function is called. If the * resolution was not successful the first time, it may be called another * time later in the context of the "performDeferredResolution" function. - * @param owner is the node for which the resolution takes place. * @return true if the resolution was immediately successful. This does * not mean, that the resolved object does not exist, as it may be resolved * later. */ - bool resolve(const std::vector<std::string> &path, const Rtti &type, - Logger &logger, ResolutionImposterCallback imposterCallback, - ResolutionResultCallback resultCallback, - Handle<Node> owner = nullptr); + bool resolve(const Rtti &type, const std::vector<std::string> &path, + Handle<Node> owner, Logger &logger, + ResolutionImposterCallback imposterCallback, + ResolutionResultCallback resultCallback); /** * Tries to resolve a node for the given type and path for all nodes @@ -426,21 +439,21 @@ public: * The "resultCallback" is called when the resolution was successful, which * may be at a later point in time. * - * @param path is the path for which a node should be resolved. * @param type is the type of the node that should be resolved. + * @param path is the path for which a node should be resolved. + * @param owner is the node for which the resolution takes place. * @param logger is the logger instance into which resolution problems * should be logged. * @param resultCallback is the callback function to which the result of * the resolution process is passed. This function is called once the * resolution was successful. - * @param owner is the node for which the resolution takes place. * @return true if the resolution was immediately successful. This does not * mean, that the resolved object does not exist, as it may be resolved * later. */ - bool resolve(const std::vector<std::string> &path, const Rtti &type, - Logger &logger, ResolutionResultCallback resultCallback, - Handle<Node> owner = nullptr); + bool resolve(const Rtti &type, const std::vector<std::string> &path, + Handle<Node> owner, Logger &logger, + ResolutionResultCallback resultCallback); /** * Tries to resolve a node for the given type and path for all nodes @@ -453,6 +466,7 @@ public: * * @tparam T is the type of the node that should be resolved. * @param path is the path for which a node should be resolved. + * @param owner is the node for which the resolution takes place. * @param logger is the logger instance into which resolution problems * should be logged. * @param imposterCallback is the callback function that is called if @@ -465,24 +479,17 @@ public: * resolved object directly when this function is called. If the resolution * was not successful the first time, it may be called another time later * in the context of the "performDeferredResolution" function. - * @param owner is the node for which the resolution takes place. * @return true if the resolution was immediately successful. This does not * mean, that the resolved object does not exist, as it may be resolved * later. */ template <class T> - bool resolve(const std::vector<std::string> &path, Logger &logger, - std::function<Rooted<T>()> imposterCallback, - std::function<void(Handle<T>, Logger &)> resultCallback, - Handle<Node> owner = nullptr) + bool resolve(const std::vector<std::string> &path, Handle<Node> owner, + Logger &logger, ResolutionImposterCallback imposterCallback, + ResolutionResultCallback resultCallback) { - return resolve( - path, typeOf<T>(), logger, - [imposterCallback]() -> Rooted<Node> { return imposterCallback(); }, - [resultCallback](Handle<Node> node, Logger &logger) { - resultCallback(node.cast<T>(), logger); - }, - owner); + return resolve(typeOf<T>(), path, owner, logger, imposterCallback, + resultCallback); } /** @@ -493,26 +500,21 @@ public: * * @tparam T is the type of the node that should be resolved. * @param path is the path for which a node should be resolved. + * @param owner is the node for which the resolution takes place. * @param logger is the logger instance into which resolution problems * should be logged. * @param resultCallback is the callback function to which the result of * the resolution process is passed. This function is called once the * resolution was successful. - * @param owner is the node for which the resolution takes place. * @return true if the resolution was immediately successful. This does not * mean, that the resolved object does not exist, as it may be resolved * later. */ template <class T> - bool resolve(const std::vector<std::string> &path, Logger &logger, - std::function<void(Handle<T>, Logger &)> resultCallback, - Handle<Node> owner = nullptr) + bool resolve(const std::vector<std::string> &path, Handle<Node> owner, + Logger &logger, ResolutionResultCallback resultCallback) { - return resolve(path, typeOf<T>(), logger, - [resultCallback](Handle<Node> node, Logger &logger) { - resultCallback(node.cast<T>(), logger); - }, - owner); + return resolve(typeOf<T>(), path, owner, logger, resultCallback); } /** @@ -527,6 +529,7 @@ public: * @tparam T is the type of the node that should be resolved. * @param name is the path for which a node should be resolved. The name is * split at '.' to form a path. + * @param owner is the node for which the resolution takes place. * @param logger is the logger instance into which resolution problems * should be logged. * @param imposterCallback is the callback function that is called if @@ -539,19 +542,17 @@ public: * resolved object directly when this function is called. If the resolution * was not successful the first time, it may be called another time later * in the context of the "performDeferredResolution" function. - * @param owner is the node for which the resolution takes place. * @return true if the resolution was immediately successful. This does not * mean, that the resolved object does not exist, as it may be resolved * later. */ template <class T> - bool resolve(const std::string &name, Logger &logger, - std::function<Rooted<T>()> imposterCallback, - std::function<void(Handle<T>, Logger &)> resultCallback, - Handle<Node> owner = nullptr) + bool resolve(const std::string &name, Handle<Node> owner, Logger &logger, + ResolutionImposterCallback imposterCallback, + ResolutionResultCallback resultCallback) { - return resolve<T>(Utils::split(name, '.'), logger, imposterCallback, - resultCallback, owner); + return resolve<T>(Utils::split(name, '.'), owner, logger, + imposterCallback, resultCallback); } /** @@ -563,26 +564,119 @@ public: * @tparam T is the type of the node that should be resolved. * @param name is the path for which a node should be resolved. The name is * split at '.' to form a path. + * @param owner is the node for which the resolution takes place. * @param logger is the logger instance into which resolution problems * should be logged. * @param resultCallback is the callback function to which the result of * the resolution process is passed. This function is called once the * resolution was successful. - * @param owner is the node for which the resolution takes place. * @return true if the resolution was immediately successful. This does not * mean, that the resolved object does not exist, as it may be resolved * later. */ template <class T> - bool resolve(const std::string &name, Logger &logger, - std::function<void(Handle<T>, Logger &)> resultCallback, - Handle<Node> owner = nullptr) + bool resolve(const std::string &name, Handle<Node> owner, Logger &logger, + ResolutionResultCallback resultCallback) { - return resolve<T>(Utils::split(name, '.'), logger, resultCallback, - owner); + return resolve<T>(Utils::split(name, '.'), owner, logger, + resultCallback); } /** + * Resolves a typesystem type. Makes sure an array type is returned if an + * array type is requested. + * + * @param path is the path for which a node should be resolved. + * @param owner is the node for which the resolution takes place. + * @param logger is the logger instance into which resolution problems + * should be logged. + * @param resultCallback is the callback function to which the result of + * the resolution process is passed. This function is called once the + * resolution was successful. + * @return true if the resolution was immediately successful. This does not + * mean, that the resolved object does not exist, as it may be resolved + * later. + */ + bool resolveType(const std::vector<std::string> &path, Handle<Node> owner, + Logger &logger, ResolutionResultCallback resultCallback); + + /** + * Resolves a typesystem type. Makes sure an array type is returned if an + * array type is requested. + * + * @tparam T is the type of the node that should be resolved. + * @param name is the path for which a node should be resolved. The name is + * split at '.' to form a path. + * @param owner is the node for which the resolution takes place. + * @param logger is the logger instance into which resolution problems + * should be logged. + * @param resultCallback is the callback function to which the result of + * the resolution process is passed. This function is called once the + * resolution was successful. + * @return true if the resolution was immediately successful. This does not + * mean, that the resolved object does not exist, as it may be resolved + * later. + */ + bool resolveType(const std::string &name, Handle<Node> owner, + Logger &logger, ResolutionResultCallback resultCallback); + + /** + * Resolves a type and makes sure the corresponding value is of the correct + * type. + * + * <b>Warning:</b> This function is extremely dangerous as you have to make + * sure that the "value" reference stays alife as long as the "owner" is + * valid. This is especially problematic as internally references at parts + * of "value" may be kept. Test usages of this function well! + * + * @tparam T is the type of the node that should be resolved. + * @param path is the path for which a node should be resolved. + * @param owner is the node for which the resolution takes place. + * @param value is a reference at the Variant that represents the value for + * which the type should be looked up. The value must be valid as long as + * the owner node is valid (so it should be a part of the owner). + * @param logger is the logger instance into which resolution problems + * should be logged. + * @param resultCallback is the callback function to which the result of + * the resolution process is passed. This function is called once the + * resolution was successful. + * @return true if the resolution was immediately successful. This does not + * mean, that the resolved object does not exist, as it may be resolved + * later. + */ + bool resolveTypeWithValue(const std::vector<std::string> &path, + Handle<Node> owner, Variant &value, + Logger &logger, ResolutionResultCallback resultCallback); + + /** + * Resolves a type and makes sure the corresponding value is of the correct + * type. + * + * <b>Warning:</b> This function is extremely dangerous as you have to make + * sure that the "value" reference stays alife as long as the "owner" is + * valid. This is especially problematic as internally references at parts + * of "value" may be kept. Test usages of this function well! + * + * @tparam T is the type of the node that should be resolved. + * @param name is the path for which a node should be resolved. The name is + * split at '.' to form a path. + * @param owner is the node for which the resolution takes place. + * @param value is a reference at the Variant that represents the value for + * which the type should be looked up. The value must be valid as long as + * the owner node is valid (so it should be a part of the owner). + * @param logger is the logger instance into which resolution problems + * should be logged. + * @param resultCallback is the callback function to which the result of + * the resolution process is passed. This function is called once the + * resolution was successful. + * @return true if the resolution was immediately successful. This does not + * mean, that the resolved object does not exist, as it may be resolved + * later. + */ + bool resolveTypeWithValue(const std::string &name, Handle<Node> owner, + Variant &value, Logger &logger, ResolutionResultCallback resultCallback); + + /** * Tries to resolve all currently deferred resolution steps. The list of * pending deferred resolutions is cleared after this function has run. * diff --git a/src/plugins/xml/XmlParser.cpp b/src/plugins/xml/XmlParser.cpp index 6e0fea0..70ea48c 100644 --- a/src/plugins/xml/XmlParser.cpp +++ b/src/plugins/xml/XmlParser.cpp @@ -167,13 +167,15 @@ public: // Try to resolve the parent type and set it as parent structure if (!parent.empty()) { - scope().resolve<StructType>(parent, logger(), - [structType](Handle<StructType> parent, - Logger &logger) mutable { - structType->setParentStructure( - parent, logger); - }, - structType); + scope().resolve<StructType>( + parent, structType, logger(), + [](Handle<Node> parent, Handle<Node> structType, + Logger &logger) { + if (parent != nullptr) { + structType.cast<StructType>()->setParentStructure( + parent.cast<StructType>(), logger); + } + }); } // Descend into the struct type @@ -201,7 +203,7 @@ public: // Read the argument values const std::string &name = args["name"].asString(); const std::string &type = args["type"].asString(); - const Variant &defaultValue = args["default"]; // Build! + const Variant &defaultValue = args["default"]; const bool optional = !(defaultValue.isObject() && defaultValue.asObject() == nullptr); @@ -210,13 +212,24 @@ public: structType->createAttribute(name, defaultValue, optional, logger()); attribute->setLocation(location()); - // Try to resolve the type - scope().resolve<Type>( - type, logger(), - [attribute](Handle<Type> type, Logger &logger) mutable { - attribute->setType(type, logger); - }, - attribute); + // Try to resolve the type and default value + if (optional) { + scope().resolveTypeWithValue(type, attribute, attribute->getDefaultValue(), logger(), + [](Handle<Node> type, Handle<Node> attribute, + Logger &logger) { + if (type != nullptr) { + attribute.cast<Attribute>()->setType(type.cast<Type>(), logger); + } + }); + } else { + scope().resolveType(type, attribute, logger(), + [](Handle<Node> type, Handle<Node> attribute, + Logger &logger) { + if (type != nullptr) { + attribute.cast<Attribute>()->setType(type.cast<Type>(), logger); + } + }); + } } void end() override {} @@ -243,12 +256,13 @@ public: constant->setLocation(location()); // Try to resolve the type - scope().resolve<Type>( - type, logger(), - [constant](Handle<Type> type, Logger &logger) mutable { - constant->setType(type, logger); - }, - constant); + scope().resolveTypeWithValue(type, constant, constant->getValue(), logger(), + [](Handle<Node> type, Handle<Node> constant, + Logger &logger) { + if (type != nullptr) { + constant.cast<Constant>()->setType(type.cast<Type>(), logger); + } + }); } void end() override {} diff --git a/test/core/model/DomainTest.cpp b/test/core/model/DomainTest.cpp index 8bf1a47..767ac0c 100644 --- a/test/core/model/DomainTest.cpp +++ b/test/core/model/DomainTest.cpp @@ -50,41 +50,41 @@ TEST(Domain, testDomainResolving) std::vector<ResolutionResult> res; // There is one domain called "book" - res = domain->resolve("book", typeOf<Domain>()); + res = domain->resolve(RttiTypes::Domain, "book"); ASSERT_EQ(1U, res.size()); - assert_path(res[0], typeOf<Domain>(), {"book"}); + assert_path(res[0], RttiTypes::Domain, {"book"}); // There is one domain called "book" - res = domain->resolve("book", typeOf<StructuredClass>()); + res = domain->resolve(RttiTypes::StructuredClass, "book"); ASSERT_EQ(1U, res.size()); - assert_path(res[0], typeOf<StructuredClass>(), {"book", "book"}); + assert_path(res[0], RttiTypes::StructuredClass, {"book", "book"}); // If we explicitly ask for the "book, book" path, then only the // StructuredClass should be returned. - res = domain->resolve(std::vector<std::string>{"book", "book"}, - typeOf<Domain>()); + res = domain->resolve(RttiTypes::Domain, + std::vector<std::string>{"book", "book"}); ASSERT_EQ(0U, res.size()); - res = domain->resolve(std::vector<std::string>{"book", "book"}, - typeOf<StructuredClass>()); + res = domain->resolve(RttiTypes::StructuredClass, + std::vector<std::string>{"book", "book"}); ASSERT_EQ(1U, res.size()); // If we ask for "section" the result should be unique as well. - res = domain->resolve("section", typeOf<StructuredClass>()); + res = domain->resolve(RttiTypes::StructuredClass, "section"); ASSERT_EQ(1U, res.size()); - assert_path(res[0], typeOf<StructuredClass>(), {"book", "section"}); + assert_path(res[0], RttiTypes::StructuredClass, {"book", "section"}); // If we ask for "paragraph" it is referenced two times in the Domain graph, // but should be returned only once. - res = domain->resolve("paragraph", typeOf<StructuredClass>()); + res = domain->resolve(RttiTypes::StructuredClass, "paragraph"); ASSERT_EQ(1U, res.size()); - assert_path(res[0], typeOf<StructuredClass>(), {"book", "paragraph"}); + assert_path(res[0], RttiTypes::StructuredClass, {"book", "paragraph"}); } Rooted<StructuredClass> getClass(const std::string name, Handle<Domain> dom) { std::vector<ResolutionResult> res = - dom->resolve(name, RttiTypes::StructuredClass); + dom->resolve(RttiTypes::StructuredClass, name); return res[0].node.cast<StructuredClass>(); } diff --git a/test/core/model/NodeTest.cpp b/test/core/model/NodeTest.cpp index a9a699d..d9ca5bb 100644 --- a/test/core/model/NodeTest.cpp +++ b/test/core/model/NodeTest.cpp @@ -61,8 +61,8 @@ public: namespace RttiTypes { const Rtti TestNode = RttiBuilder<ousia::TestNode>("TestNode") - .parent(&RttiTypes::Node) - .composedOf(&TestNode); + .parent(&RttiTypes::Node) + .composedOf(&TestNode); } TEST(Node, isRoot) @@ -85,18 +85,18 @@ TEST(Node, resolveCompositaSimple) child1->addCompositum(new TestNode(mgr, "child11")); std::vector<ResolutionResult> res; - res = root->resolve(std::vector<std::string>{"root", "child1", "child11"}, - RttiTypes::TestNode); + res = root->resolve(RttiTypes::TestNode, + std::vector<std::string>{"root", "child1", "child11"}); ASSERT_EQ(1U, res.size()); ASSERT_TRUE(child11 == res[0].node); - res = root->resolve(std::vector<std::string>{"child1", "child11"}, - RttiTypes::TestNode); + res = root->resolve(RttiTypes::TestNode, + std::vector<std::string>{"child1", "child11"}); ASSERT_EQ(1U, res.size()); ASSERT_TRUE(child11 == res[0].node); res = - root->resolve(std::vector<std::string>{"child11"}, RttiTypes::TestNode); + root->resolve(RttiTypes::TestNode, std::vector<std::string>{"child11"}); ASSERT_EQ(1U, res.size()); ASSERT_TRUE(child11 == res[0].node); } @@ -111,18 +111,18 @@ TEST(Node, resolveCompositaDouble) child1->addCompositum(new TestNode(mgr, "child11")); std::vector<ResolutionResult> res; - res = root->resolve(std::vector<std::string>{"root", "child1", "child11"}, - RttiTypes::TestNode); + res = root->resolve(RttiTypes::TestNode, + std::vector<std::string>{"root", "child1", "child11"}); ASSERT_EQ(1U, res.size()); ASSERT_TRUE(child11 == res[0].node); - res = root->resolve(std::vector<std::string>{"child1", "child11"}, - RttiTypes::TestNode); + res = root->resolve(RttiTypes::TestNode, + std::vector<std::string>{"child1", "child11"}); ASSERT_EQ(1U, res.size()); ASSERT_TRUE(child11 == res[0].node); res = - root->resolve(std::vector<std::string>{"child11"}, RttiTypes::TestNode); + root->resolve(RttiTypes::TestNode, std::vector<std::string>{"child11"}); ASSERT_EQ(1U, res.size()); ASSERT_TRUE(child11 == res[0].node); } @@ -141,14 +141,14 @@ TEST(Node, resolveAmbigousComposita) child12->addCompositum(new TestNode(mgr, "child11")); std::vector<ResolutionResult> res; - res = root->resolve(std::vector<std::string>{"child1", "child11"}, - RttiTypes::TestNode); + res = root->resolve(RttiTypes::TestNode, + std::vector<std::string>{"child1", "child11"}); ASSERT_EQ(2U, res.size()); ASSERT_TRUE(child11 == res[0].node || child11 == res[1].node); ASSERT_TRUE(child112 == res[0].node || child112 == res[1].node); res = - root->resolve(std::vector<std::string>{"child11"}, RttiTypes::TestNode); + root->resolve(RttiTypes::TestNode, std::vector<std::string>{"child11"}); ASSERT_EQ(2U, res.size()); ASSERT_TRUE(child11 == res[0].node || child11 == res[1].node); ASSERT_TRUE(child112 == res[0].node || child112 == res[1].node); @@ -168,30 +168,30 @@ TEST(Node, resolveReferences) child12->addCompositum(new TestNode(mgr, "child11")); std::vector<ResolutionResult> res; - res = root->resolve(std::vector<std::string>{"a", "child1", "child11"}, - RttiTypes::TestNode); + res = root->resolve(RttiTypes::TestNode, + std::vector<std::string>{"a", "child1", "child11"}); ASSERT_EQ(1U, res.size()); ASSERT_TRUE(child11 == res[0].node); - res = root->resolve(std::vector<std::string>{"b", "child1", "child11"}, - RttiTypes::TestNode); + res = root->resolve(RttiTypes::TestNode, + std::vector<std::string>{"b", "child1", "child11"}); ASSERT_EQ(1U, res.size()); ASSERT_TRUE(child112 == res[0].node); - res = root->resolve(std::vector<std::string>{"child1", "child11"}, - RttiTypes::TestNode); + res = root->resolve(RttiTypes::TestNode, + std::vector<std::string>{"child1", "child11"}); ASSERT_EQ(2U, res.size()); ASSERT_TRUE(child11 == res[0].node || child11 == res[1].node); ASSERT_TRUE(child112 == res[0].node || child112 == res[1].node); res = - root->resolve(std::vector<std::string>{"child11"}, RttiTypes::TestNode); + root->resolve(RttiTypes::TestNode, std::vector<std::string>{"child11"}); ASSERT_EQ(2U, res.size()); ASSERT_TRUE(child11 == res[0].node || child11 == res[1].node); ASSERT_TRUE(child112 == res[0].node || child112 == res[1].node); res = - root->resolve(std::vector<std::string>{"child1"}, RttiTypes::TestNode); + root->resolve(RttiTypes::TestNode, std::vector<std::string>{"child1"}); ASSERT_EQ(2U, res.size()); ASSERT_TRUE(child1 == res[0].node || child1 == res[1].node); ASSERT_TRUE(child12 == res[0].node || child12 == res[1].node); @@ -212,31 +212,31 @@ TEST(Node, resolveReferencesAndComposita) Rooted<TestNode> child13 = root->addCompositum(new TestNode(mgr, "child1")); std::vector<ResolutionResult> res; - res = root->resolve(std::vector<std::string>{"a", "child1", "child11"}, - RttiTypes::TestNode); + res = root->resolve(RttiTypes::TestNode, + std::vector<std::string>{"a", "child1", "child11"}); ASSERT_EQ(1U, res.size()); ASSERT_TRUE(child11 == res[0].node); - res = root->resolve(std::vector<std::string>{"b", "child1", "child11"}, - RttiTypes::TestNode); + res = root->resolve(RttiTypes::TestNode, + std::vector<std::string>{"b", "child1", "child11"}); ASSERT_EQ(1U, res.size()); ASSERT_TRUE(child112 == res[0].node); - res = root->resolve(std::vector<std::string>{"child1", "child11"}, - RttiTypes::TestNode); + res = root->resolve(RttiTypes::TestNode, + std::vector<std::string>{"child1", "child11"}); ASSERT_EQ(2U, res.size()); ASSERT_TRUE(child11 == res[0].node || child11 == res[1].node); ASSERT_TRUE(child112 == res[0].node || child112 == res[1].node); res = - root->resolve(std::vector<std::string>{"child11"}, RttiTypes::TestNode); + root->resolve(RttiTypes::TestNode, std::vector<std::string>{"child11"}); ASSERT_EQ(2U, res.size()); ASSERT_TRUE(child11 == res[0].node || child11 == res[1].node); ASSERT_TRUE(child112 == res[0].node || child112 == res[1].node); // Resolving for "child1" should not descend into the referenced nodes res = - root->resolve(std::vector<std::string>{"child1"}, RttiTypes::TestNode); + root->resolve(RttiTypes::TestNode, std::vector<std::string>{"child1"}); ASSERT_EQ(1U, res.size()); ASSERT_TRUE(child13 == res[0].node); } diff --git a/test/core/model/TestAdvanced.hpp b/test/core/model/TestAdvanced.hpp index d90f917..e3744b8 100644 --- a/test/core/model/TestAdvanced.hpp +++ b/test/core/model/TestAdvanced.hpp @@ -32,7 +32,7 @@ static Rooted<StructuredClass> resolveDescriptor(Handle<Domain> domain, { // use the actual resolve method. std::vector<ResolutionResult> resolved = - domain->resolve(className, typeOf<StructuredClass>()); + domain->resolve(RttiTypes::StructuredClass, className); // take the first valid result. for (auto &r : resolved) { return r.node.cast<StructuredClass>(); diff --git a/test/core/model/TestDocumentBuilder.hpp b/test/core/model/TestDocumentBuilder.hpp index 149b88e..71b353d 100644 --- a/test/core/model/TestDocumentBuilder.hpp +++ b/test/core/model/TestDocumentBuilder.hpp @@ -48,7 +48,7 @@ static Rooted<Descriptor> resolveDescriptor(Handle<Document> doc, const Rtti &type) { // use the actual resolve method. - std::vector<ResolutionResult> resolved = doc->resolve(path, type); + std::vector<ResolutionResult> resolved = doc->resolve(type, path); // if we don't find anything, log an error if (resolved.size() == 0) { logger.error(std::string("Could not resolve ") + getPathString(path)); diff --git a/test/core/model/TypesystemTest.cpp b/test/core/model/TypesystemTest.cpp index 7d05f56..9a40db7 100644 --- a/test/core/model/TypesystemTest.cpp +++ b/test/core/model/TypesystemTest.cpp @@ -774,7 +774,7 @@ TEST(ArrayType, rtti) { Manager mgr; Rooted<StringType> stringType{new StringType(mgr, nullptr)}; - Rooted<ArrayType> arrayType{new ArrayType(mgr, stringType)}; + Rooted<ArrayType> arrayType{new ArrayType(stringType)}; ASSERT_TRUE(arrayType->isa(RttiTypes::ArrayType)); ASSERT_TRUE(arrayType->isa(typeOf<Type>())); ASSERT_TRUE(arrayType->isa(typeOf<Node>())); @@ -797,7 +797,7 @@ TEST(ArrayType, creation) { Manager mgr; Rooted<StringType> stringType{new StringType(mgr, nullptr)}; - Rooted<ArrayType> arrayType{new ArrayType(mgr, stringType)}; + Rooted<ArrayType> arrayType{new ArrayType(stringType)}; Variant val = arrayType->create(); ASSERT_TRUE(val.isArray()); @@ -808,7 +808,7 @@ TEST(ArrayType, conversion) { Manager mgr; Rooted<StringType> stringType{new StringType(mgr, nullptr)}; - Rooted<ArrayType> arrayType{new ArrayType(mgr, stringType)}; + Rooted<ArrayType> arrayType{new ArrayType(stringType)}; { Variant val{{1, "test", false, 42.5}}; diff --git a/test/plugins/xml/XmlParserTest.cpp b/test/plugins/xml/XmlParserTest.cpp index 0802d5b..6ac962d 100644 --- a/test/plugins/xml/XmlParserTest.cpp +++ b/test/plugins/xml/XmlParserTest.cpp @@ -67,7 +67,7 @@ TEST(XmlParser, generic) XmlStandaloneEnvironment env(logger); env.parse("generic.oxm", "", "", RttiSet{&RttiTypes::Typesystem}); #ifdef MANAGER_GRAPHVIZ_EXPORT -// env.manager.exportGraphviz("xmlDocument.dot"); + env.manager.exportGraphviz("xmlDocument.dot"); #endif } } diff --git a/testdata/xmlparser/generic.oxm b/testdata/xmlparser/generic.oxm index 8ada0bb..23b8d66 100644 --- a/testdata/xmlparser/generic.oxm +++ b/testdata/xmlparser/generic.oxm @@ -6,244 +6,14 @@ <field name="g" type="int"/> <field name="b" type="int"/> </struct> + <struct name="structWithColor"> + <field name="color" type="color" default="black" /> + </struct> </types> <constants> - <constant name="aquamarine1" type="color" value="[127,255,212]"/> - <constant name="aquamarine2" type="color" value="[118,238,198]"/> - <constant name="aquamarine3" type="color" value="[102,205,170]"/> - <constant name="aquamarine" type="color" value="[127,255,212]"/> - <constant name="azure1" type="color" value="[240,255,255]"/> - <constant name="azure2" type="color" value="[224,238,238]"/> - <constant name="azure3" type="color" value="[193,205,205]"/> - <constant name="azure4" type="color" value="[131,139,139]"/> - <constant name="azure" type="color" value="[240,255,255]"/> - <constant name="beige" type="color" value="[245,245,220]"/> - <constant name="bisque1" type="color" value="[255,228,196]"/> - <constant name="bisque2" type="color" value="[238,213,183]"/> - <constant name="bisque3" type="color" value="[205,183,158]"/> - <constant name="bisque4" type="color" value="[139,125,107]"/> - <constant name="bisque" type="color" value="[255,228,196]"/> - <constant name="brown" type="color" value="[165,42,42]"/> - <constant name="burlywood1" type="color" value="[255,211,155]"/> - <constant name="burlywood2" type="color" value="[238,197,145]"/> - <constant name="burlywood3" type="color" value="[205,170,125]"/> - <constant name="burlywood" type="color" value="[222,184,135]"/> - <constant name="chartreuse" type="color" value="[127,255,0]"/> - <constant name="chocolate" type="color" value="[210,105,30]"/> - <constant name="coral" type="color" value="[255,127,80]"/> - <constant name="cornsilk1" type="color" value="[255,248,220]"/> - <constant name="cornsilk2" type="color" value="[238,232,205]"/> - <constant name="cornsilk3" type="color" value="[205,200,177]"/> - <constant name="cornsilk4" type="color" value="[139,136,120]"/> - <constant name="cornsilk" type="color" value="[255,248,220]"/> - <constant name="crimson" type="color" value="[220,20,60]"/> - <constant name="firebrick" type="color" value="[178,34,34]"/> - <constant name="fuchsia" type="color" value="[255,0,255]"/> - <constant name="gainsboro" type="color" value="[220,220,220]"/> - <constant name="goldenrod" type="color" value="[218,165,32]"/> - <constant name="gold" type="color" value="[255,215,0]"/> - <constant name="gray100" type="color" value="[255,255,255]"/> - <constant name="gray40" type="color" value="[102,102,102]"/> - <constant name="gray41" type="color" value="[105,105,105]"/> - <constant name="gray42" type="color" value="[107,107,107]"/> - <constant name="gray43" type="color" value="[110,110,110]"/> - <constant name="gray44" type="color" value="[112,112,112]"/> - <constant name="gray45" type="color" value="[115,115,115]"/> - <constant name="gray46" type="color" value="[117,117,117]"/> - <constant name="gray47" type="color" value="[120,120,120]"/> - <constant name="gray48" type="color" value="[122,122,122]"/> - <constant name="gray49" type="color" value="[125,125,125]"/> - <constant name="gray50" type="color" value="[127,127,127]"/> - <constant name="gray51" type="color" value="[130,130,130]"/> - <constant name="gray52" type="color" value="[133,133,133]"/> - <constant name="gray53" type="color" value="[135,135,135]"/> - <constant name="gray54" type="color" value="[138,138,138]"/> - <constant name="gray55" type="color" value="[140,140,140]"/> - <constant name="gray56" type="color" value="[143,143,143]"/> - <constant name="gray57" type="color" value="[145,145,145]"/> - <constant name="gray58" type="color" value="[148,148,148]"/> - <constant name="gray59" type="color" value="[150,150,150]"/> - <constant name="gray60" type="color" value="[153,153,153]"/> - <constant name="gray61" type="color" value="[156,156,156]"/> - <constant name="gray62" type="color" value="[158,158,158]"/> - <constant name="gray63" type="color" value="[161,161,161]"/> - <constant name="gray64" type="color" value="[163,163,163]"/> - <constant name="gray65" type="color" value="[166,166,166]"/> - <constant name="gray66" type="color" value="[168,168,168]"/> - <constant name="gray67" type="color" value="[171,171,171]"/> - <constant name="gray68" type="color" value="[173,173,173]"/> - <constant name="gray69" type="color" value="[176,176,176]"/> - <constant name="gray70" type="color" value="[179,179,179]"/> - <constant name="gray71" type="color" value="[181,181,181]"/> - <constant name="gray72" type="color" value="[184,184,184]"/> - <constant name="gray73" type="color" value="[186,186,186]"/> - <constant name="gray74" type="color" value="[189,189,189]"/> - <constant name="gray75" type="color" value="[191,191,191]"/> - <constant name="gray76" type="color" value="[194,194,194]"/> - <constant name="gray77" type="color" value="[196,196,196]"/> - <constant name="gray78" type="color" value="[199,199,199]"/> - <constant name="gray79" type="color" value="[201,201,201]"/> - <constant name="gray80" type="color" value="[204,204,204]"/> - <constant name="gray81" type="color" value="[207,207,207]"/> - <constant name="gray82" type="color" value="[209,209,209]"/> - <constant name="gray83" type="color" value="[212,212,212]"/> - <constant name="gray84" type="color" value="[214,214,214]"/> - <constant name="gray85" type="color" value="[217,217,217]"/> - <constant name="gray86" type="color" value="[219,219,219]"/> - <constant name="gray87" type="color" value="[222,222,222]"/> - <constant name="gray88" type="color" value="[224,224,224]"/> - <constant name="gray89" type="color" value="[227,227,227]"/> - <constant name="gray90" type="color" value="[229,229,229]"/> - <constant name="gray91" type="color" value="[232,232,232]"/> - <constant name="gray92" type="color" value="[235,235,235]"/> - <constant name="gray93" type="color" value="[237,237,237]"/> - <constant name="gray94" type="color" value="[240,240,240]"/> - <constant name="gray95" type="color" value="[242,242,242]"/> - <constant name="gray96" type="color" value="[245,245,245]"/> - <constant name="gray97" type="color" value="[247,247,247]"/> - <constant name="gray98" type="color" value="[250,250,250]"/> - <constant name="gray99" type="color" value="[252,252,252]"/> - <constant name="gray" type="color" value="[190,190,190]"/> - <constant name="grey100" type="color" value="[255,255,255]"/> - <constant name="grey40" type="color" value="[102,102,102]"/> - <constant name="grey41" type="color" value="[105,105,105]"/> - <constant name="grey42" type="color" value="[107,107,107]"/> - <constant name="grey43" type="color" value="[110,110,110]"/> - <constant name="grey44" type="color" value="[112,112,112]"/> - <constant name="grey45" type="color" value="[115,115,115]"/> - <constant name="grey46" type="color" value="[117,117,117]"/> - <constant name="grey47" type="color" value="[120,120,120]"/> - <constant name="grey48" type="color" value="[122,122,122]"/> - <constant name="grey49" type="color" value="[125,125,125]"/> - <constant name="grey50" type="color" value="[127,127,127]"/> - <constant name="grey51" type="color" value="[130,130,130]"/> - <constant name="grey52" type="color" value="[133,133,133]"/> - <constant name="grey53" type="color" value="[135,135,135]"/> - <constant name="grey54" type="color" value="[138,138,138]"/> - <constant name="grey55" type="color" value="[140,140,140]"/> - <constant name="grey56" type="color" value="[143,143,143]"/> - <constant name="grey57" type="color" value="[145,145,145]"/> - <constant name="grey58" type="color" value="[148,148,148]"/> - <constant name="grey59" type="color" value="[150,150,150]"/> - <constant name="grey60" type="color" value="[153,153,153]"/> - <constant name="grey61" type="color" value="[156,156,156]"/> - <constant name="grey62" type="color" value="[158,158,158]"/> - <constant name="grey63" type="color" value="[161,161,161]"/> - <constant name="grey64" type="color" value="[163,163,163]"/> - <constant name="grey65" type="color" value="[166,166,166]"/> - <constant name="grey66" type="color" value="[168,168,168]"/> - <constant name="grey67" type="color" value="[171,171,171]"/> - <constant name="grey68" type="color" value="[173,173,173]"/> - <constant name="grey69" type="color" value="[176,176,176]"/> - <constant name="grey70" type="color" value="[179,179,179]"/> - <constant name="grey71" type="color" value="[181,181,181]"/> - <constant name="grey72" type="color" value="[184,184,184]"/> - <constant name="grey73" type="color" value="[186,186,186]"/> - <constant name="grey74" type="color" value="[189,189,189]"/> - <constant name="grey75" type="color" value="[191,191,191]"/> - <constant name="grey76" type="color" value="[194,194,194]"/> - <constant name="grey77" type="color" value="[196,196,196]"/> - <constant name="grey78" type="color" value="[199,199,199]"/> - <constant name="grey79" type="color" value="[201,201,201]"/> - <constant name="grey80" type="color" value="[204,204,204]"/> - <constant name="grey81" type="color" value="[207,207,207]"/> - <constant name="grey82" type="color" value="[209,209,209]"/> - <constant name="grey83" type="color" value="[212,212,212]"/> - <constant name="grey84" type="color" value="[214,214,214]"/> - <constant name="grey85" type="color" value="[217,217,217]"/> - <constant name="grey86" type="color" value="[219,219,219]"/> - <constant name="grey87" type="color" value="[222,222,222]"/> - <constant name="grey88" type="color" value="[224,224,224]"/> - <constant name="grey89" type="color" value="[227,227,227]"/> - <constant name="grey90" type="color" value="[229,229,229]"/> - <constant name="grey91" type="color" value="[232,232,232]"/> - <constant name="grey92" type="color" value="[235,235,235]"/> - <constant name="grey93" type="color" value="[237,237,237]"/> - <constant name="grey94" type="color" value="[240,240,240]"/> - <constant name="grey95" type="color" value="[242,242,242]"/> - <constant name="grey96" type="color" value="[245,245,245]"/> - <constant name="grey97" type="color" value="[247,247,247]"/> - <constant name="grey98" type="color" value="[250,250,250]"/> - <constant name="grey99" type="color" value="[252,252,252]"/> - <constant name="grey" type="color" value="[190,190,190]"/> - <constant name="honeydew1" type="color" value="[240,255,240]"/> - <constant name="honeydew2" type="color" value="[224,238,224]"/> - <constant name="honeydew3" type="color" value="[193,205,193]"/> - <constant name="honeydew4" type="color" value="[131,139,131]"/> - <constant name="honeydew" type="color" value="[240,255,240]"/> - <constant name="ivory1" type="color" value="[255,255,240]"/> - <constant name="ivory2" type="color" value="[238,238,224]"/> - <constant name="ivory3" type="color" value="[205,205,193]"/> - <constant name="ivory4" type="color" value="[139,139,131]"/> - <constant name="ivory" type="color" value="[255,255,240]"/> - <constant name="khaki1" type="color" value="[255,246,143]"/> - <constant name="khaki2" type="color" value="[238,230,133]"/> - <constant name="khaki3" type="color" value="[205,198,115]"/> - <constant name="khaki" type="color" value="[240,230,140]"/> - <constant name="lavender" type="color" value="[230,230,250]"/> - <constant name="linen" type="color" value="[250,240,230]"/> - <constant name="magenta1" type="color" value="[255,0,255]"/> - <constant name="magenta2" type="color" value="[238,0,238]"/> - <constant name="magenta3" type="color" value="[205,0,205]"/> - <constant name="magenta4" type="color" value="[139,0,139]"/> - <constant name="magenta" type="color" value="[255,0,255]"/> - <constant name="maroon1" type="color" value="[255,52,179]"/> - <constant name="maroon2" type="color" value="[238,48,167]"/> - <constant name="maroon3" type="color" value="[205,41,144]"/> - <constant name="maroon" type="color" value="[176,48,96]"/> - <constant name="moccasin" type="color" value="[255,228,181]"/> - <constant name="olive" type="color" value="[128,128,0]"/> - <constant name="orange" type="color" value="[255,165,0]"/> - <constant name="orchid1" type="color" value="[255,131,250]"/> - <constant name="orchid2" type="color" value="[238,122,233]"/> - <constant name="orchid3" type="color" value="[205,105,201]"/> - <constant name="orchid4" type="color" value="[139,71,137]"/> - <constant name="orchid" type="color" value="[218,112,214]"/> - <constant name="peru" type="color" value="[205,133,63]"/> - <constant name="pink1" type="color" value="[255,181,197]"/> - <constant name="pink2" type="color" value="[238,169,184]"/> - <constant name="pink3" type="color" value="[205,145,158]"/> - <constant name="pink4" type="color" value="[139,99,108]"/> - <constant name="pink" type="color" value="[255,192,203]"/> - <constant name="plum1" type="color" value="[255,187,255]"/> - <constant name="plum2" type="color" value="[238,174,238]"/> - <constant name="plum3" type="color" value="[205,150,205]"/> - <constant name="plum4" type="color" value="[139,102,139]"/> - <constant name="plum" type="color" value="[221,160,221]"/> - <constant name="purple1" type="color" value="[155,48,255]"/> - <constant name="purple2" type="color" value="[145,44,238]"/> - <constant name="purple3" type="color" value="[125,38,205]"/> - <constant name="purple" type="color" value="[160,32,240]"/> - <constant name="red" type="color" value="[255,0,0]"/> - <constant name="salmon1" type="color" value="[255,140,105]"/> - <constant name="salmon" type="color" value="[250,128,114]"/> - <constant name="seashell1" type="color" value="[255,245,238]"/> - <constant name="seashell2" type="color" value="[238,229,222]"/> - <constant name="seashell3" type="color" value="[205,197,191]"/> - <constant name="seashell4" type="color" value="[139,134,130]"/> - <constant name="seashell" type="color" value="[255,245,238]"/> - <constant name="sienna" type="color" value="[160,82,45]"/> - <constant name="silver" type="color" value="[192,192,192]"/> - <constant name="snow1" type="color" value="[255,250,250]"/> - <constant name="snow2" type="color" value="[238,233,233]"/> - <constant name="snow3" type="color" value="[205,201,201]"/> - <constant name="snow4" type="color" value="[139,137,137]"/> - <constant name="snow" type="color" value="[255,250,250]"/> - <constant name="tan" type="color" value="[210,180,140]"/> - <constant name="thistle1" type="color" value="[255,225,255]"/> - <constant name="thistle2" type="color" value="[238,210,238]"/> - <constant name="thistle3" type="color" value="[205,181,205]"/> - <constant name="thistle4" type="color" value="[139,123,139]"/> - <constant name="thistle" type="color" value="[216,191,216]"/> - <constant name="tomato" type="color" value="[255,99,71]"/> - <constant name="violet" type="color" value="[238,130,238]"/> - <constant name="wheat1" type="color" value="[255,231,186]"/> - <constant name="wheat2" type="color" value="[238,216,174]"/> - <constant name="wheat3" type="color" value="[205,186,150]"/> - <constant name="wheat4" type="color" value="[139,126,102]"/> - <constant name="wheat" type="color" value="[245,222,179]"/> - <constant name="white" type="color" value="[255,255,255]"/> - <constant name="yellow" type="color" value="[255,255,0]"/> + <constant name="zero" value="42" type="string" /> + <constant name="black" value="[0, zero, 0]" type="color" /> + <constant name="err" value="0" type="int" /> </constants> </typesystem> |