From 729ea17ed17cf81eb19847216406e40686df679d Mon Sep 17 00:00:00 2001 From: Andreas Stöckel Date: Fri, 30 Jan 2015 14:42:06 +0100 Subject: Finished implementing constant importing --- src/core/model/Typesystem.cpp | 34 +++++++--- src/core/model/Typesystem.hpp | 37 ++++++++--- src/core/parser/ParserScope.cpp | 135 ++++++++++++++++------------------------ src/core/parser/ParserScope.hpp | 37 ++++++----- src/plugins/xml/XmlParser.cpp | 45 +++++++------- 5 files changed, 152 insertions(+), 136 deletions(-) (limited to 'src') diff --git a/src/core/model/Typesystem.cpp b/src/core/model/Typesystem.cpp index 591dcbe..dc6df63 100644 --- a/src/core/model/Typesystem.cpp +++ b/src/core/model/Typesystem.cpp @@ -26,7 +26,10 @@ namespace ousia { /* Static helper functions */ -static void NullMagicCallback(Variant &, bool, ManagedUid) {} +static Type::MagicCallbackResult NullMagicCallback(Variant &, const Type *) +{ + return Type::MagicCallbackResult::NOT_FOUND; +} /* Class Type */ @@ -35,13 +38,18 @@ bool Type::build(Variant &data, Logger &logger, { // 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 + switch (magicCallback(data, this)) { + case MagicCallbackResult::NOT_FOUND: + break; + case MagicCallbackResult::FOUND_INVALID: { + // The magic callback has probably already issued an error + // message -- do not print more errors + Logger nullLogger; + return build(data, nullLogger); + } + case MagicCallbackResult::FOUND_VALID: + return true; + } } try { @@ -216,6 +224,10 @@ void Attribute::setDefaultValue(const Variant &defaultValue, Logger &logger) initialize(logger); } +const Variant &Attribute::getDefaultValue() const { return defaultValue; } + +Variant &Attribute::getDefaultValue() { return defaultValue; } + void Attribute::removeDefaultValue() { invalidate(); @@ -224,6 +236,8 @@ void Attribute::removeDefaultValue() optional = false; } +bool Attribute::isOptional() const { return optional; } + void Attribute::setType(Handle type, Logger &logger) { invalidate(); @@ -232,6 +246,8 @@ void Attribute::setType(Handle type, Logger &logger) initialize(logger); } +Rooted Attribute::getType() const { return type; } + /* Class StructType */ bool StructType::resolveIndexKey(const std::string &key, size_t &idx) const @@ -591,6 +607,8 @@ void Constant::setType(Handle type, Logger &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) diff --git a/src/core/model/Typesystem.hpp b/src/core/model/Typesystem.hpp index d88a7e9..9d85d80 100644 --- a/src/core/model/Typesystem.hpp +++ b/src/core/model/Typesystem.hpp @@ -57,19 +57,21 @@ class SystemTypesystem; */ class Type : public Node { public: + enum class MagicCallbackResult { NOT_FOUND, FOUND_INVALID, FOUND_VALID }; + /** * 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. + * @param data is the magic value that should be looked up and the variant + * to which the value of the looked up constant should be written. + * @param type is a const pointer at the type. TODO: Replace this with a + * "ConstHandle". + * @return true if a constant was found, false otherwise. */ - using MagicCallback = std::function; + using MagicCallback = + std::function; protected: /** @@ -503,7 +505,14 @@ 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() { return defaultValue; } + const Variant &getDefaultValue() const; + + /** + * Returns a reference at the default value. + * + * @return a reference at the default value of the attribute. + */ + Variant &getDefaultValue(); /** * Removes any default value from the attribute, making this attribute @@ -517,7 +526,7 @@ public: * * @return true if the attribute is optional, false otherwise. */ - bool isOptional() const { return optional; } + bool isOptional() const; /** * Sets the type of the attribute to the specified value. This will @@ -536,7 +545,7 @@ public: * * @return the underlying type of the Rooted object. */ - Rooted getType() const { return type; } + Rooted getType() const; }; /** @@ -992,6 +1001,14 @@ public: * * @return a const reference to the actual value of the constant. */ + const Variant &getValue() const; + + /** + * Returns a reference pointing at the value of the constant. The value must + * be interpreted with the help of the type of the constant. + * + * @return a reference to the actual value of the constant. + */ Variant &getValue(); /** diff --git a/src/core/parser/ParserScope.cpp b/src/core/parser/ParserScope.cpp index c7a9f2a..efd07d1 100644 --- a/src/core/parser/ParserScope.cpp +++ b/src/core/parser/ParserScope.cpp @@ -18,6 +18,7 @@ #include #include +#include #include #include "ParserScope.hpp" @@ -319,6 +320,44 @@ bool ParserScope::resolveType(const std::string &name, Handle owner, return resolveType(Utils::split(name, '.'), owner, logger, resultCallback); } +bool ParserScope::resolveValue(Variant &data, Handle type, + Handle owner, Logger &logger) +{ + return type->build( + data, logger, + [&](Variant &innerData, + const Type *innerType) mutable -> Type::MagicCallbackResult { + // Try to resolve the node + Rooted constant = + ParserScopeBase::resolve(RttiTypes::Constant, + Utils::split(innerData.asMagic(), '.'), + logger).cast(); + + // Abort if nothing was found + if (constant == nullptr) { + return Type::MagicCallbackResult::NOT_FOUND; + } + + // Set the data to the value of the constant + innerData = constant->getValue(); + + // Check whether the inner type of the constant is correct + // TODO: Use correct "isa" provided by Type + Rooted constantType = constant->getType(); + if (innerType != constantType) { + 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); + return Type::MagicCallbackResult::FOUND_INVALID; + } + return Type::MagicCallbackResult::FOUND_VALID; + }); +} + bool ParserScope::resolveTypeWithValue(const std::vector &path, Handle owner, Variant &value, Logger &logger, @@ -326,90 +365,20 @@ bool ParserScope::resolveTypeWithValue(const std::vector &path, { // Fork the parser scope -- constants need to be resolved in the same // context as this resolve call - std::shared_ptr scope = std::make_shared(fork()); - - return resolveType( - path, owner, logger, - [=](Handle resolved, Handle 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 = resolved.cast(); - 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 isAsync = std::make_shared(false); - std::shared_ptr magicCount = std::make_shared(0); - type->build(value, logger, [=](Variant &magicValue, bool isValid, - ManagedUid innerTypeUid) mutable { - // Fetch the inner type - Rooted innerType = - dynamic_cast(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(constantName, owner, logger, - [=](Handle resolved, - Handle owner, - Logger &logger) mutable { - if (resolved != nullptr) { - // Make sure the constant is of the correct inner type - Rooted constant = resolved.cast(); - Rooted 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; + ParserScope scope = fork(); + Variant *valuePtr = &value; + + return resolveType(path, owner, logger, + [=](Handle resolved, Handle owner, + Logger &logger) mutable { + if (resolved != nullptr) { + Rooted type = resolved.cast(); + scope.resolveValue(*valuePtr, type, owner, logger); + } - // Directly call the callback function if there were no magic values - // involved - if ((*magicCount) == 0) { - resultCallback(resolved, owner, logger); - } - }); + // Call the result callback with the type + resultCallback(resolved, owner, logger); + }); } bool ParserScope::resolveTypeWithValue(const std::string &name, diff --git a/src/core/parser/ParserScope.hpp b/src/core/parser/ParserScope.hpp index c49acd3..2ef33d9 100644 --- a/src/core/parser/ParserScope.hpp +++ b/src/core/parser/ParserScope.hpp @@ -44,6 +44,7 @@ namespace ousia { class CharReader; class Logger; class ParserScope; +class Type; class Variant; /** @@ -60,8 +61,8 @@ using ResolutionImposterCallback = std::function()>; * @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 resolved, - Handle owner, Logger &logger)>; +using ResolutionResultCallback = std::function< + void(Handle resolved, Handle owner, Logger &logger)>; /** * Base class for the @@ -620,15 +621,26 @@ public: bool resolveType(const std::string &name, Handle owner, Logger &logger, ResolutionResultCallback resultCallback); + /** + * Build and resolves a (possibly) magic value with the given typesystem + * type. This function does not perform any deferred lookups. + * + * @param data is a reference at a variant that may contain magic values + * (even in inner structures). The data will be passed to the "build" + * function of the given type. + * @param type is the Typesystem type the data should be interpreted with. + * @param owner is the node for which the resolution takes place. + * @param logger is the logger instance into which resolution problems + * should be logged. + * @return true if the value was successfully built. + */ + bool resolveValue(Variant &data, Handle type, Handle owner, + Logger &logger); + /** * Resolves a type and makes sure the corresponding value is of the correct * type. * - * Warning: 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. @@ -646,17 +658,13 @@ public: */ bool resolveTypeWithValue(const std::vector &path, Handle owner, Variant &value, - Logger &logger, ResolutionResultCallback resultCallback); + Logger &logger, + ResolutionResultCallback resultCallback); /** * Resolves a type and makes sure the corresponding value is of the correct * type. * - * Warning: 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. @@ -674,7 +682,8 @@ public: * later. */ bool resolveTypeWithValue(const std::string &name, Handle owner, - Variant &value, Logger &logger, ResolutionResultCallback resultCallback); + Variant &value, Logger &logger, + ResolutionResultCallback resultCallback); /** * Tries to resolve all currently deferred resolution steps. The list of diff --git a/src/plugins/xml/XmlParser.cpp b/src/plugins/xml/XmlParser.cpp index 70ea48c..88447ed 100644 --- a/src/plugins/xml/XmlParser.cpp +++ b/src/plugins/xml/XmlParser.cpp @@ -214,21 +214,23 @@ public: // Try to resolve the type and default value if (optional) { - scope().resolveTypeWithValue(type, attribute, attribute->getDefaultValue(), logger(), - [](Handle type, Handle attribute, - Logger &logger) { - if (type != nullptr) { - attribute.cast()->setType(type.cast(), logger); - } - }); + scope().resolveTypeWithValue( + type, attribute, attribute->getDefaultValue(), logger(), + [](Handle type, Handle attribute, Logger &logger) { + if (type != nullptr) { + attribute.cast()->setType(type.cast(), + logger); + } + }); } else { - scope().resolveType(type, attribute, logger(), - [](Handle type, Handle attribute, - Logger &logger) { - if (type != nullptr) { - attribute.cast()->setType(type.cast(), logger); - } - }); + scope().resolveType( + type, attribute, logger(), + [](Handle type, Handle attribute, Logger &logger) { + if (type != nullptr) { + attribute.cast()->setType(type.cast(), + logger); + } + }); } } @@ -256,13 +258,14 @@ public: constant->setLocation(location()); // Try to resolve the type - scope().resolveTypeWithValue(type, constant, constant->getValue(), logger(), - [](Handle type, Handle constant, - Logger &logger) { - if (type != nullptr) { - constant.cast()->setType(type.cast(), logger); - } - }); + scope().resolveTypeWithValue( + type, constant, constant->getValue(), logger(), + [](Handle type, Handle constant, Logger &logger) { + if (type != nullptr) { + constant.cast()->setType(type.cast(), + logger); + } + }); } void end() override {} -- cgit v1.2.3