diff options
Diffstat (limited to 'src')
-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 | 157 | ||||
-rw-r--r-- | src/core/parser/ParserScope.hpp | 115 | ||||
-rw-r--r-- | src/plugins/xml/XmlParser.cpp | 42 |
5 files changed, 434 insertions, 103 deletions
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 b76bb28..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" @@ -100,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, @@ -267,6 +278,149 @@ bool ParserScope::resolve(const Rtti &type, 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 @@ -305,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 e01acfe..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,12 +44,13 @@ namespace ousia { class CharReader; class Logger; class ParserScope; +class Variant; /** * Callback function type used for creating a dummy object while no correct * object is available for resolution. */ -using ResolutionImposterCallback = Rooted<Node>(*)(); +using ResolutionImposterCallback = std::function<Rooted<Node>()>; /** * Callback function type called whenever the result of a resolution is @@ -60,8 +60,8 @@ using ResolutionImposterCallback = Rooted<Node>(*)(); * @param owner is the node that was passed as "owner". * @param logger is the logger to which errors should be logged. */ -using ResolutionResultCallback = void (*)(Handle<Node> resolved, - Handle<Node> owner, Logger &logger); +using ResolutionResultCallback = std::function<void(Handle<Node> resolved, + Handle<Node> owner, Logger &logger)>; /** * Base class for the @@ -171,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); }; /** @@ -555,12 +564,12 @@ 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. @@ -574,6 +583,100 @@ public: } /** + * 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 5e30fec..70ea48c 100644 --- a/src/plugins/xml/XmlParser.cpp +++ b/src/plugins/xml/XmlParser.cpp @@ -171,8 +171,10 @@ public: parent, structType, logger(), [](Handle<Node> parent, Handle<Node> structType, Logger &logger) { - structType.cast<StructType>()->setParentStructure( - parent.cast<StructType>(), logger); + if (parent != nullptr) { + structType.cast<StructType>()->setParentStructure( + parent.cast<StructType>(), logger); + } }); } @@ -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,12 +212,24 @@ public: structType->createAttribute(name, defaultValue, optional, logger()); attribute->setLocation(location()); - // Try to resolve the type - scope().resolve<Type>( - type, attribute, logger(), - [](Handle<Node> type, Handle<Node> attribute, Logger &logger) { - attribute.cast<Attribute>()->setType(type.cast<Type>(), logger); + // 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 {} @@ -242,11 +256,13 @@ public: constant->setLocation(location()); // Try to resolve the type - scope().resolve<Type>( - type, constant, logger(), - [](Handle<Node> type, Handle<Node> constant, Logger &logger) { - constant.cast<Constant>()->setType(type.cast<Type>(), logger); - }); + 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 {} |