summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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
-rw-r--r--test/core/model/TypesystemTest.cpp6
-rw-r--r--test/plugins/xml/XmlParserTest.cpp2
-rw-r--r--testdata/xmlparser/generic.oxm242
8 files changed, 444 insertions, 343 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 {}
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>