summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/core/model/Typesystem.cpp107
-rw-r--r--src/core/model/Typesystem.hpp116
-rw-r--r--src/core/parser/ParserScope.cpp157
-rw-r--r--src/core/parser/ParserScope.hpp115
-rw-r--r--src/plugins/xml/XmlParser.cpp42
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 {}