From 235b8ce21d6a24f01e73ed745f32487553b6d231 Mon Sep 17 00:00:00 2001 From: Andreas Stöckel Date: Mon, 16 Feb 2015 11:03:27 +0100 Subject: Fixed bug #61 and added unit test --- src/core/common/VariantReader.cpp | 24 +++++++++++++++--------- test/core/common/VariantReaderTest.cpp | 12 ++++++++++++ 2 files changed, 27 insertions(+), 9 deletions(-) diff --git a/src/core/common/VariantReader.cpp b/src/core/common/VariantReader.cpp index fb93ad0..601d086 100644 --- a/src/core/common/VariantReader.cpp +++ b/src/core/common/VariantReader.cpp @@ -848,17 +848,23 @@ std::pair VariantReader::parseGenericToken( std::pair VariantReader::parseGenericString( const std::string &str, Logger &logger, SourceId sourceId, size_t offs) { - CharReader reader{str, sourceId, offs}; - LoggerFork loggerFork = logger.fork(); + // If the given string is empty, just return it as a string (there is no + // other type for which something empty would be valid) + // TODO: How to integrate this into parseGenericToken? + if (!str.empty()) { + CharReader reader{str, sourceId, offs}; + LoggerFork loggerFork = logger.fork(); - // Try to parse a single token - std::pair res = - parseGenericToken(reader, loggerFork, std::unordered_set{}, true); + // Try to parse a single token + std::pair res = parseGenericToken( + reader, loggerFork, std::unordered_set{}, true); - // If the string was actually consisted of a single token, return that token - if (reader.atEnd()) { - loggerFork.commit(); - return res; + // If the string was actually consisted of a single token, return that + // token + if (reader.atEnd()) { + loggerFork.commit(); + return res; + } } // Otherwise return the given string as a string, set the location of the diff --git a/test/core/common/VariantReaderTest.cpp b/test/core/common/VariantReaderTest.cpp index a23af09..79e567b 100644 --- a/test/core/common/VariantReaderTest.cpp +++ b/test/core/common/VariantReaderTest.cpp @@ -1153,6 +1153,18 @@ TEST(VariantReader, parseGenericString) ASSERT_EQ(0U, loc.getStart()); ASSERT_EQ(15U, loc.getEnd()); } + + // Parse empty string + { + auto res = VariantReader::parseGenericString("", logger); + ASSERT_TRUE(res.first); + ASSERT_TRUE(res.second.isString()); + ASSERT_EQ("", res.second.asString()); + + SourceLocation loc = res.second.getLocation(); + ASSERT_EQ(0U, loc.getStart()); + ASSERT_EQ(0U, loc.getEnd()); + } } TEST(VariantReader, parseGenericComplex) -- cgit v1.2.3 From 39fa4b6d0f6492c46b83489e16a7cbdbf279bbda Mon Sep 17 00:00:00 2001 From: Andreas Stöckel Date: Mon, 16 Feb 2015 11:03:44 +0100 Subject: Using Variant location in VariantConverter error messages --- src/core/common/VariantConverter.cpp | 46 ++++++++++++++++++------------------ 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/src/core/common/VariantConverter.cpp b/src/core/common/VariantConverter.cpp index 271fe75..a9ca467 100644 --- a/src/core/common/VariantConverter.cpp +++ b/src/core/common/VariantConverter.cpp @@ -81,7 +81,7 @@ bool VariantConverter::toBool(Variant &var, Logger &logger, Mode mode) } // No conversion possible, assign default value and log error - logger.error(msgUnexpectedType(var, VariantType::BOOL)); + logger.error(msgUnexpectedType(var, VariantType::BOOL), var); var = false; return false; } @@ -129,7 +129,7 @@ bool VariantConverter::toInt(Variant &var, Logger &logger, Mode mode) } } catch (LoggableException ex) { - logger.log(ex); + logger.log(ex, var); break; } } @@ -148,7 +148,7 @@ bool VariantConverter::toInt(Variant &var, Logger &logger, Mode mode) } // No conversion possible, assign default value and log error - logger.error(msgUnexpectedType(var, VariantType::INT)); + logger.error(msgUnexpectedType(var, VariantType::INT), var); var = 0; return false; } @@ -195,7 +195,7 @@ bool VariantConverter::toDouble(Variant &var, Logger &logger, Mode mode) return true; } catch (LoggableException ex) { - logger.log(ex); + logger.log(ex, var); break; } } @@ -214,7 +214,7 @@ bool VariantConverter::toDouble(Variant &var, Logger &logger, Mode mode) } // No conversion possible, assign default value and log error - logger.error(msgUnexpectedType(var, VariantType::DOUBLE)); + logger.error(msgUnexpectedType(var, VariantType::DOUBLE), var); var = 0.0; return false; } @@ -225,22 +225,22 @@ bool VariantConverter::toString(Variant &var, Logger &logger, Mode mode) const VariantType type = var.getType(); switch (type) { case VariantType::NULLPTR: - logger.warning(msgImplicitConversion(type, VariantType::STRING)); + logger.warning(msgImplicitConversion(type, VariantType::STRING), var); var = "null"; return true; case VariantType::BOOL: - logger.warning(msgImplicitConversion(type, VariantType::STRING)); + logger.warning(msgImplicitConversion(type, VariantType::STRING), var); var = var.asBool() ? "true" : "false"; return true; case VariantType::INT: { - logger.warning(msgImplicitConversion(type, VariantType::STRING)); + logger.warning(msgImplicitConversion(type, VariantType::STRING), var); std::stringstream ss; ss << var.asInt(); var = ss.str().c_str(); return true; } case VariantType::DOUBLE: { - logger.warning(msgImplicitConversion(type, VariantType::STRING)); + logger.warning(msgImplicitConversion(type, VariantType::STRING), var); std::stringstream ss; ss << var.asDouble(); var = ss.str().c_str(); @@ -325,7 +325,7 @@ bool VariantConverter::toString(Variant &var, Logger &logger, Mode mode) } // No conversion possible, assign default value and log error - logger.error(msgUnexpectedType(var, VariantType::STRING)); + logger.error(msgUnexpectedType(var, VariantType::STRING), var); var = ""; return false; } @@ -357,7 +357,7 @@ bool VariantConverter::toArray(Variant &var, const Rtti *innerType, } // No conversion possible, assign the default value and log an error - logger.error(msgUnexpectedType(var, VariantType::ARRAY)); + logger.error(msgUnexpectedType(var, VariantType::ARRAY), var); var.setArray(Variant::arrayType{}); return false; } @@ -384,7 +384,7 @@ bool VariantConverter::toMap(Variant &var, const Rtti *innerType, } // No conversion possible, assign the default value and log an error - logger.error(msgUnexpectedType(var, VariantType::MAP)); + logger.error(msgUnexpectedType(var, VariantType::MAP), var); var.setMap(Variant::mapType{}); return false; } @@ -401,7 +401,7 @@ bool VariantConverter::toCardinality(Variant &var, Logger &logger, Mode mode) Variant::cardinalityType &card = var.asCardinality(); if (value < 0) { logger.error( - "A value smaller 0 can not be converted to a cardinality!"); + "A value smaller 0 can not be converted to a cardinality!", var); return false; } card.merge({(unsigned int)value}); @@ -432,7 +432,7 @@ bool VariantConverter::toCardinality(Variant &var, Logger &logger, Mode mode) if (value < 0) { logger.error( "A value smaller 0 can not be converted to a " - "cardinality!"); + "cardinality!", var); return false; } card.merge({(unsigned int)value}); @@ -448,14 +448,14 @@ bool VariantConverter::toCardinality(Variant &var, Logger &logger, Mode mode) if (!startVar.isInt()) { logger.error( "A non-integer can not be interpreted as the start " - "of a range"); + "of a range", startVar); return false; } int start = startVar.asInt(); if (start < 0) { logger.error( "A value smaller 0 can not be converted to a " - "cardinality!"); + "cardinality!", startVar); return false; } it++; @@ -466,7 +466,7 @@ bool VariantConverter::toCardinality(Variant &var, Logger &logger, Mode mode) if (!endVar.isInt()) { logger.error( "A non-integer can not be interpreted as the end " - "of a range"); + "of a range", endVar); return false; } int end = endVar.asInt(); @@ -475,7 +475,7 @@ bool VariantConverter::toCardinality(Variant &var, Logger &logger, Mode mode) std::string("The supposed start value ") + std::to_string(start) + " was bigger than the supposed end value " + - std::to_string(end) + " of the Range."); + std::to_string(end) + " of the Range.", endVar); return false; } card.merge({(unsigned int)start, (unsigned int)end}); @@ -500,7 +500,7 @@ bool VariantConverter::toCardinality(Variant &var, Logger &logger, Mode mode) } // No conversion possible, assign the default value and log an error - logger.error(msgUnexpectedType(var, VariantType::CARDINALITY)); + logger.error(msgUnexpectedType(var, VariantType::CARDINALITY), var); var.setCardinality(Variant::cardinalityType{}); return false; } @@ -512,7 +512,7 @@ bool VariantConverter::toFunction(Variant &var, Logger &logger) } // No conversion possible, assign the default value and log an error - logger.error(msgUnexpectedType(var, VariantType::FUNCTION)); + logger.error(msgUnexpectedType(var, VariantType::FUNCTION), var); var.setFunction(std::shared_ptr{new FunctionStub()}); return false; } @@ -527,7 +527,7 @@ bool VariantConverter::convert(Variant &var, const Rtti *type, } else if (type == &RttiTypes::Nullptr) { // Make sure the variant is set to null if (!var.isNull()) { - logger.error(msgUnexpectedType(var, VariantType::NULLPTR)); + logger.error(msgUnexpectedType(var, VariantType::NULLPTR), var); var.setNull(); return false; } @@ -553,7 +553,7 @@ bool VariantConverter::convert(Variant &var, const Rtti *type, // If none of the above primitive types is requested, we were // obviously asked for a managed object. if (!var.isObject()) { - logger.error(msgUnexpectedType(var, VariantType::OBJECT)); + logger.error(msgUnexpectedType(var, VariantType::OBJECT), var); var.setObject(nullptr); return false; } @@ -561,7 +561,7 @@ bool VariantConverter::convert(Variant &var, const Rtti *type, // Make sure the object type is correct if (!var.getRtti()->isa(type)) { logger.error(std::string("Expected object of type ") + type->name + - " but got object of type " + var.getRtti()->name); + " but got object of type " + var.getRtti()->name, var); var.setObject(nullptr); return false; } -- cgit v1.2.3 From 0a60bc28b222451a5ed20318ceff3a93564d5d8e Mon Sep 17 00:00:00 2001 From: Andreas Stöckel Date: Mon, 16 Feb 2015 11:39:03 +0100 Subject: Implemented support for numeric arguments in Argument --- src/core/common/Argument.cpp | 51 +++++++++++++++++++++++++++++++++------ src/core/common/Argument.hpp | 11 ++++++--- test/core/common/ArgumentTest.cpp | 24 +++++++++++++++--- 3 files changed, 71 insertions(+), 15 deletions(-) diff --git a/src/core/common/Argument.cpp b/src/core/common/Argument.cpp index b10fad3..ee129a3 100644 --- a/src/core/common/Argument.cpp +++ b/src/core/common/Argument.cpp @@ -54,7 +54,8 @@ Argument Argument::Any(std::string name) Argument Argument::Any(std::string name, Variant defaultValue) { - return Argument{name, &RttiTypes::None, &RttiTypes::None, defaultValue, true}; + return Argument{name, &RttiTypes::None, &RttiTypes::None, defaultValue, + true}; } Argument Argument::Bool(std::string name) @@ -95,7 +96,8 @@ Argument Argument::String(std::string name) Argument Argument::String(std::string name, const Variant::stringType &defaultValue) { - return Argument{name, &RttiTypes::String, Variant::fromString(defaultValue)}; + return Argument{name, &RttiTypes::String, + Variant::fromString(defaultValue)}; } Argument Argument::Object(std::string name, const Rtti *type) @@ -158,7 +160,8 @@ Argument Argument::Map(std::string name, const Variant::mapType &defaultValue) Argument Argument::Map(std::string name, const Rtti *innerType) { - return Argument(std::move(name), &RttiTypes::Map, innerType, nullptr, false); + return Argument(std::move(name), &RttiTypes::Map, innerType, nullptr, + false); } Argument Argument::Map(std::string name, const Rtti *innerType, @@ -276,7 +279,7 @@ bool Arguments::validateArray(Variant::arrayType &arr, Logger &logger) const } bool Arguments::validateMap(Variant::mapType &map, Logger &logger, - bool ignoreUnknown) const + bool ignoreUnknown, bool allowNumericIndices) const { // Abort if no arguments were explicitly given -- everything is valid if (!valid) { @@ -289,28 +292,60 @@ bool Arguments::validateMap(Variant::mapType &map, Logger &logger, const size_t N = arguments.size(); std::vector set(N); bool ok = true; + std::unordered_map keyReplacements; // Iterate over the map entries and search for the corresponding argument for (auto &e : map) { // Check whether an argument with the name of the current entry exists - auto it = names.find(e.first); + const std::string &key = e.first; + auto it = names.find(key); + ssize_t idx = -1; if (it != names.end()) { // Fetch the corresponding index in the "arguments" array - size_t idx = it->second; + idx = it->second; + } else if (!key.empty() && key[0] == '#' && allowNumericIndices) { + // Read the numeric index + try { + size_t i = stoul(key.substr(1)); + if (i >= 0 && i < arguments.size()) { + idx = i; + keyReplacements.emplace(key, arguments[i].getName()); + } else { + ok = false; + } + } + catch (std::exception ex) { + logger.error( + std::string("Invalid key \"") + key + std::string("\""), + e.second); + ok = false; + } + } + + // If the key could be resolved to an index, validate the argument + if (idx >= 0) { set[idx] = arguments[idx].validate(e.second, logger); ok = ok && set[idx]; } else { if (ignoreUnknown) { logger.note(std::string("Ignoring argument \"") + e.first + - std::string("\""), e.second); + std::string("\""), + e.second); } else { logger.error(std::string("Unknown argument \"") + e.first + - std::string("\""), e.second); + std::string("\""), + e.second); ok = false; } } } + // Execute all the key replacements + for (const auto &replacement : keyReplacements) { + map[replacement.second] = std::move(map[replacement.first]); + map.erase(replacement.first); + } + // Insert all unset arguments for (size_t a = 0; a < N; a++) { if (!set[a]) { diff --git a/src/core/common/Argument.hpp b/src/core/common/Argument.hpp index 679b4a5..39b3bb6 100644 --- a/src/core/common/Argument.hpp +++ b/src/core/common/Argument.hpp @@ -61,13 +61,13 @@ private: /** * Type that should be returned by the Variant rttiType function. */ - Rtti const* type; + Rtti const *type; /** * Describes the inner type of the variant -- e.g. the type of the elements * inside an array. Normally set to RttiTypes::None. */ - Rtti const* innerType; + Rtti const *innerType; /** * Default value. Note that a value of nullptr does not indicate that no @@ -421,7 +421,7 @@ public: * @return the default value that was given in the constructor (may be * nullptr) and nullptr if no default value was given. */ - const Variant& getDefaultValue() const; + const Variant &getDefaultValue() const; /** * Returns true if a default value was set in the constructor. @@ -502,10 +502,13 @@ public: * @param ignoreUnknown if set to true, unknown map entries are ignored * (a note is issued). This behaviour can be usefull if forward * compatibility must be achieved (such as for XML based formats). + * @param allowNumericIndices if set to true, allows numeric indices in the + * input map (such as "#1"). * @return true if the operation was successful, false if an error occured. */ bool validateMap(Variant::mapType &map, Logger &logger, - bool ignoreUnknown = false) const; + bool ignoreUnknown = false, + bool allowNumericIndices = false) const; }; } diff --git a/test/core/common/ArgumentTest.cpp b/test/core/common/ArgumentTest.cpp index 0a2dcfa..ca93f45 100644 --- a/test/core/common/ArgumentTest.cpp +++ b/test/core/common/ArgumentTest.cpp @@ -792,8 +792,8 @@ TEST(Arguments, invalid) Variant::arrayType arr{1}; - ASSERT_TRUE(argsInvalid.validateArray(arr, logger)); // No error message - ASSERT_FALSE(argsValid.validateArray(arr, logger)); // Too many arguments + ASSERT_TRUE(argsInvalid.validateArray(arr, logger)); // No error message + ASSERT_FALSE(argsValid.validateArray(arr, logger)); // Too many arguments } TEST(Arguments, validateArray) @@ -879,6 +879,25 @@ TEST(Arguments, validateMap) {{"a", 2}, {"b", "test"}, {"c", true}, {"d", nullptr}}), map); } + + { + Variant::mapType map{{"#0", 2}, {"#1", "bla"}, {"#2", false}}; + ASSERT_FALSE(args.validateMap(map, logger, false, false)); + ASSERT_EQ(Variant::mapType({{"#0", 2}, + {"#1", "bla"}, + {"#2", false}, + {"a", 0}, + {"b", "test"}, + {"c", true}}), + map); + } + + { + Variant::mapType map{{"#0", 2}, {"#1", "bla"}, {"#2", false}}; + ASSERT_TRUE(args.validateMap(map, logger, false, true)); + ASSERT_EQ(Variant::mapType({{"a", 2}, {"b", "bla"}, {"c", false}}), + map); + } } TEST(Arguments, validateMissing) @@ -897,6 +916,5 @@ TEST(Arguments, validateMissing) ASSERT_EQ(Variant::arrayType({""}), arr); } } - } -- cgit v1.2.3 From 3cc0c9fffa35f83d45209030407465f3756df3fd Mon Sep 17 00:00:00 2001 From: Andreas Stöckel Date: Mon, 16 Feb 2015 11:39:18 +0100 Subject: Allowing numeric argument keys for static handlers --- src/core/parser/stack/Stack.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/core/parser/stack/Stack.cpp b/src/core/parser/stack/Stack.cpp index 905edb4..b98cddb 100644 --- a/src/core/parser/stack/Stack.cpp +++ b/src/core/parser/stack/Stack.cpp @@ -361,9 +361,10 @@ void Stack::command(const Variant &name, const Variant::mapType &args) info.valid = false; if (validStack) { // Canonicalize the arguments (if this has not already been done), - // allow additional arguments + // allow additional arguments and numeric indices Variant::mapType canonicalArgs = args; - targetState->arguments.validateMap(canonicalArgs, loggerFork, true); + targetState->arguments.validateMap(canonicalArgs, loggerFork, true, + true); handler->setLogger(loggerFork); try { -- cgit v1.2.3 From 33a70e7dc2624a674094169dbd234959d5433d81 Mon Sep 17 00:00:00 2001 From: Andreas Stöckel Date: Mon, 16 Feb 2015 11:39:35 +0100 Subject: Modified simple_book.osml to use numeric arguments --- testdata/osmlparser/simple_book.osml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/testdata/osmlparser/simple_book.osml b/testdata/osmlparser/simple_book.osml index cdcaf58..19f5543 100644 --- a/testdata/osmlparser/simple_book.osml +++ b/testdata/osmlparser/simple_book.osml @@ -1,5 +1,5 @@ -\import{../osxmlparser/book_domain.osxml} -\import{../osxmlparser/headings_domain.osxml} +\import[domain]{../osxmlparser/book_domain.osxml} +\import[domain]{../osxmlparser/headings_domain.osxml} \begin{book} This might be some introductory text or a dedication. -- cgit v1.2.3 From 3cca090a650d2e8268977b57aa0dfdb0fb2cae85 Mon Sep 17 00:00:00 2001 From: Benjamin Paassen Date: Mon, 16 Feb 2015 11:57:08 +0100 Subject: added return value in addFieldDescriptor related methods to indicate whether the order of fields had to be changed. --- src/core/model/Domain.cpp | 49 +++++++++++-------------- src/core/model/Domain.hpp | 31 +++++++++++----- src/core/parser/stack/DocumentHandler.cpp | 2 +- src/core/parser/stack/DomainHandler.cpp | 60 +++++++++++++++++++++---------- test/core/model/DocumentTest.cpp | 8 ++--- test/core/model/DomainTest.cpp | 30 ++++++++-------- test/core/model/TestAdvanced.hpp | 2 +- test/core/model/TestDomain.hpp | 14 ++++---- 8 files changed, 115 insertions(+), 81 deletions(-) diff --git a/src/core/model/Domain.cpp b/src/core/model/Domain.cpp index ac0699e..f6c3956 100644 --- a/src/core/model/Domain.cpp +++ b/src/core/model/Domain.cpp @@ -558,7 +558,7 @@ Rooted Descriptor::getFieldDescriptor( } } -void Descriptor::addAndSortFieldDescriptor(Handle fd, +bool Descriptor::addAndSortFieldDescriptor(Handle fd, Logger &logger) { // only add it if we need to. @@ -571,37 +571,25 @@ void Descriptor::addAndSortFieldDescriptor(Handle fd, fd->getFieldType() != FieldDescriptor::FieldType::TREE) { // if so we add the new field before the TREE field. fieldDescriptors.insert(fieldDescriptors.end() - 1, fd); - - // if the new field was from the same domain we warn the user - // because that is bad coding style. - if (fd->getParent() != nullptr && - fd->getParent().cast()->getParent() == - getParent()) { - logger.warning( - std::string("Field \"") + fd->getName() + - "\" was declared after main field \"" + - fds.back()->getName() + - "\". The order of fields was changed to make the " - "main field the last field.", - *fd); - } + return true; } else { fieldDescriptors.push_back(fd); } } + return false; } -void Descriptor::addFieldDescriptor(Handle fd, Logger &logger) +bool Descriptor::addFieldDescriptor(Handle fd, Logger &logger) { - addAndSortFieldDescriptor(fd, logger); if (fd->getParent() == nullptr) { fd->setParent(this); } + return addAndSortFieldDescriptor(fd, logger); } -void Descriptor::moveFieldDescriptor(Handle fd, Logger &logger) +bool Descriptor::moveFieldDescriptor(Handle fd, Logger &logger) { - addAndSortFieldDescriptor(fd, logger); + bool sorted = addAndSortFieldDescriptor(fd, logger); Handle par = fd->getParent(); if (par != this) { if (par != nullptr) { @@ -610,9 +598,10 @@ void Descriptor::moveFieldDescriptor(Handle fd, Logger &logger) } fd->setParent(this); } + return sorted; } -void Descriptor::copyFieldDescriptor(Handle fd, Logger &logger) +bool Descriptor::copyFieldDescriptor(Handle fd, Logger &logger) { Rooted copy; if (fd->isPrimitive()) { @@ -631,7 +620,7 @@ void Descriptor::copyFieldDescriptor(Handle fd, Logger &logger) copy->addChild(c); } } - addFieldDescriptor(copy, logger); + return addFieldDescriptor(copy, logger); } bool Descriptor::removeFieldDescriptor(Handle fd) @@ -646,25 +635,27 @@ bool Descriptor::removeFieldDescriptor(Handle fd) return false; } -Rooted Descriptor::createPrimitiveFieldDescriptor( - Handle primitiveType, Logger &logger, - FieldDescriptor::FieldType fieldType, std::string name, bool optional) +std::pair, bool> +Descriptor::createPrimitiveFieldDescriptor(Handle primitiveType, + Logger &logger, + FieldDescriptor::FieldType fieldType, + std::string name, bool optional) { Rooted fd{new FieldDescriptor(getManager(), primitiveType, this, fieldType, std::move(name), optional)}; - addFieldDescriptor(fd, logger); - return fd; + bool sorted = addFieldDescriptor(fd, logger); + return std::make_pair(fd, sorted); } -Rooted Descriptor::createFieldDescriptor( +std::pair, bool> Descriptor::createFieldDescriptor( Logger &logger, FieldDescriptor::FieldType fieldType, std::string name, bool optional) { Rooted fd{new FieldDescriptor( getManager(), this, fieldType, std::move(name), optional)}; - addFieldDescriptor(fd, logger); - return fd; + bool sorted = addFieldDescriptor(fd, logger); + return std::make_pair(fd, sorted); } /* Class StructuredClass */ diff --git a/src/core/model/Domain.hpp b/src/core/model/Domain.hpp index 350c7ba..476a38c 100644 --- a/src/core/model/Domain.hpp +++ b/src/core/model/Domain.hpp @@ -469,7 +469,7 @@ private: Owned attributesDescriptor; NodeVector fieldDescriptors; - void addAndSortFieldDescriptor(Handle fd, Logger &logger); + bool addAndSortFieldDescriptor(Handle fd, Logger &logger); protected: void doResolve(ResolutionState &state) override; @@ -557,8 +557,11 @@ public: * parent of the given FieldDescriptor if it is not set yet. * * @param fd is a FieldDescriptor. + * @return returns true if the given FieldDescriptor was not added at the + * end one place before because a TREE field already existed and + * the TREE field has to be at the end. */ - void addFieldDescriptor(Handle fd, Logger &logger); + bool addFieldDescriptor(Handle fd, Logger &logger); /** * Adds the given FieldDescriptor to this Descriptor. This also sets the @@ -566,16 +569,22 @@ public: * already and removes it from the old parent Descriptor. * * @param fd is a FieldDescriptor. + * @return returns true if the given FieldDescriptor was not added at the + * end one place before because a TREE field already existed and + * the TREE field has to be at the end. */ - void moveFieldDescriptor(Handle fd, Logger &logger); + bool moveFieldDescriptor(Handle fd, Logger &logger); /** * Copies a FieldDescriptor that belongs to another Descriptor to this * Descriptor. * * @param fd some FieldDescriptor belonging to another Descriptor. + * @return returns true if the given FieldDescriptor was not added at the + * end one place before because a TREE field already existed and + * the TREE field has to be at the end. */ - void copyFieldDescriptor(Handle fd, Logger &logger); + bool copyFieldDescriptor(Handle fd, Logger &logger); /** * Removes the given FieldDescriptor from this Descriptor. This also sets @@ -598,9 +607,12 @@ public: * filled in order for an instance of the parent * Descriptor to be valid. * - * @return the newly created FieldDescriptor. + * @return the newly created FieldDescriptor and a bool + * indicating whether the order of FieldDescriptors had + * to be changed for the TREE field to be in the last + * spot. */ - Rooted createPrimitiveFieldDescriptor( + std::pair, bool> createPrimitiveFieldDescriptor( Handle primitiveType, Logger &logger, FieldDescriptor::FieldType fieldType = FieldDescriptor::FieldType::TREE, std::string name = "", bool optional = false); @@ -617,9 +629,12 @@ public: * filled in order for an instance of the parent * Descriptor to be valid. * - * @return the newly created FieldDescriptor. + * @return the newly created FieldDescriptor and a bool + * indicating whether the order of FieldDescriptors had + * to be changed for the TREE field to be in the last + * spot. */ - Rooted createFieldDescriptor( + std::pair, bool> createFieldDescriptor( Logger &logger, FieldDescriptor::FieldType fieldType = FieldDescriptor::FieldType::TREE, std::string name = "", bool optional = false); diff --git a/src/core/parser/stack/DocumentHandler.cpp b/src/core/parser/stack/DocumentHandler.cpp index d514701..41ca8ec 100644 --- a/src/core/parser/stack/DocumentHandler.cpp +++ b/src/core/parser/stack/DocumentHandler.cpp @@ -348,4 +348,4 @@ namespace RttiTypes { const Rtti DocumentField = RttiBuilder( "DocumentField").parent(&Node); } -} +} \ No newline at end of file diff --git a/src/core/parser/stack/DomainHandler.cpp b/src/core/parser/stack/DomainHandler.cpp index a2c8eec..ddec1ee 100644 --- a/src/core/parser/stack/DomainHandler.cpp +++ b/src/core/parser/stack/DomainHandler.cpp @@ -133,11 +133,18 @@ bool DomainFieldHandler::start(Variant::mapType &args) Rooted parent = scope().selectOrThrow(); - Rooted field = parent->createFieldDescriptor( + auto res = parent->createFieldDescriptor( logger(), type, args["name"].asString(), args["optional"].asBool()); - field->setLocation(location()); + res.first->setLocation(location()); + if (res.second) { + logger().warning( + std::string("Field \"") + res.first->getName() + + "\" was declared after main field. The order of fields " + "was changed to make the main field the last field.", + *res.first); + } - scope().push(field); + scope().push(res.first); return true; } @@ -150,14 +157,24 @@ bool DomainFieldRefHandler::start(Variant::mapType &args) Rooted parent = scope().selectOrThrow(); const std::string &name = args["ref"].asString(); - scope().resolveFieldDescriptor( - name, parent, logger(), - [](Handle field, Handle parent, Logger &logger) { - if (field != nullptr) { - parent.cast()->addFieldDescriptor( - field.cast(), logger); - } - }); + + auto loc = location(); + + scope().resolveFieldDescriptor(name, parent, logger(), + [loc](Handle field, + Handle parent, Logger &logger) { + if (field != nullptr) { + if (parent.cast()->addFieldDescriptor( + field.cast(), logger)) { + logger.warning( + std::string("Field \"") + field->getName() + + "\" was referenced after main field was declared. The " + "order of fields was changed to make the main field " + "the last field.", + loc); + } + } + }); return true; } @@ -176,13 +193,20 @@ bool DomainPrimitiveHandler::start(Variant::mapType &args) fieldType = FieldDescriptor::FieldType::TREE; } - Rooted field = parent->createPrimitiveFieldDescriptor( + auto res = parent->createPrimitiveFieldDescriptor( new UnknownType(manager()), logger(), fieldType, args["name"].asString(), args["optional"].asBool()); - field->setLocation(location()); + res.first->setLocation(location()); + if (res.second) { + logger().warning( + std::string("Field \"") + res.first->getName() + + "\" was declared after main field. The order of fields " + "was changed to make the main field the last field.", + *res.first); + } const std::string &type = args["type"].asString(); - scope().resolve(type, field, logger(), + scope().resolve(type, res.first, logger(), [](Handle type, Handle field, Logger &logger) { if (type != nullptr) { @@ -190,7 +214,7 @@ bool DomainPrimitiveHandler::start(Variant::mapType &args) } }); - scope().push(field); + scope().push(res.first); return true; } @@ -254,8 +278,8 @@ bool DomainParentFieldHandler::start(Variant::mapType &args) Logger &logger) { if (parent != nullptr) { Rooted field = - parent.cast()->createFieldDescriptor( - logger, type, name, optional); + (parent.cast()->createFieldDescriptor( + logger, type, name, optional)).first; field->addChild(strct.cast()); } }); @@ -390,4 +414,4 @@ namespace RttiTypes { const Rtti DomainParent = RttiBuilder( "DomainParent").parent(&Node); } -} +} \ No newline at end of file diff --git a/test/core/model/DocumentTest.cpp b/test/core/model/DocumentTest.cpp index 0c6eea6..1bb2356 100644 --- a/test/core/model/DocumentTest.cpp +++ b/test/core/model/DocumentTest.cpp @@ -147,7 +147,7 @@ TEST(Document, validate) // now let's extend the rootClass with a default field. Rooted rootField = - rootClass->createFieldDescriptor(logger); + rootClass->createFieldDescriptor(logger).first; // and add a child class for it. Rooted childClass{ new StructuredClass(mgr, "child", domain, single)}; @@ -194,7 +194,7 @@ TEST(Document, validate) * instances now. */ Rooted childField = - childClass->createFieldDescriptor(logger); + childClass->createFieldDescriptor(logger).first; childField->addChild(childClass); { /* @@ -214,7 +214,7 @@ TEST(Document, validate) */ Rooted childSubField = childSubClass->createFieldDescriptor( - logger, FieldDescriptor::FieldType::TREE, "dummy", true); + logger, FieldDescriptor::FieldType::TREE, "dummy", true).first; // add a child pro forma to make it valid. childSubField->addChild(childSubClass); { @@ -234,7 +234,7 @@ TEST(Document, validate) Rooted primitive_field = childSubClass->createPrimitiveFieldDescriptor( sys->getIntType(), logger, FieldDescriptor::FieldType::SUBTREE, - "int", false); + "int", false).first; { /* * Now a document with one instance of the Child subclass should be diff --git a/test/core/model/DomainTest.cpp b/test/core/model/DomainTest.cpp index 4cb4331..d68648e 100644 --- a/test/core/model/DomainTest.cpp +++ b/test/core/model/DomainTest.cpp @@ -186,21 +186,21 @@ TEST(Descriptor, pathToAdvanced) new StructuredClass(mgr, "target", domain, Cardinality::any())}; // We create a field for A - Rooted A_field = A->createFieldDescriptor(logger); + Rooted A_field = A->createFieldDescriptor(logger).first; A_field->addChild(B); A_field->addChild(D); // We create no field for B // One for C - Rooted C_field = C->createFieldDescriptor(logger); + Rooted C_field = C->createFieldDescriptor(logger).first; C_field->addChild(target); // One for D - Rooted D_field = D->createFieldDescriptor(logger); + Rooted D_field = D->createFieldDescriptor(logger).first; D_field->addChild(E); // One for E - Rooted E_field = E->createFieldDescriptor(logger); + Rooted E_field = E->createFieldDescriptor(logger).first; E_field->addChild(target); ASSERT_TRUE(domain->validate(logger)); @@ -239,7 +239,7 @@ TEST(Descriptor, getDefaultFields) // create a field. Rooted A_prim_field = - A->createPrimitiveFieldDescriptor(sys->getStringType(), logger); + A->createPrimitiveFieldDescriptor(sys->getStringType(), logger).first; // now we should find that. auto fields = A->getDefaultFields(); ASSERT_EQ(1U, fields.size()); @@ -262,7 +262,7 @@ TEST(Descriptor, getDefaultFields) ASSERT_EQ(A_prim_field, fields[0]); // and we should not be able to find it if we override the field. - Rooted A_field = A->createFieldDescriptor(logger); + Rooted A_field = A->createFieldDescriptor(logger).first; ASSERT_TRUE(A->getDefaultFields().empty()); // add a transparent child class. @@ -273,7 +273,7 @@ TEST(Descriptor, getDefaultFields) // add a primitive field for it. Rooted C_field = - C->createPrimitiveFieldDescriptor(sys->getStringType(), logger); + C->createPrimitiveFieldDescriptor(sys->getStringType(), logger).first; // now we should find that. fields = A->getDefaultFields(); @@ -285,14 +285,14 @@ TEST(Descriptor, getDefaultFields) Rooted D{new StructuredClass( mgr, "D", domain, Cardinality::any(), nullptr, true, false)}; A_field->addChild(D); - Rooted D_field = D->createFieldDescriptor(logger); + Rooted D_field = D->createFieldDescriptor(logger).first; Rooted E{new StructuredClass( mgr, "E", domain, Cardinality::any(), nullptr, true, false)}; D_field->addChild(E); Rooted F{new StructuredClass( mgr, "E", domain, Cardinality::any(), E, true, false)}; Rooted F_field = - F->createPrimitiveFieldDescriptor(sys->getStringType(), logger); + F->createPrimitiveFieldDescriptor(sys->getStringType(), logger).first; // now we should find both primitive fields, but the C field first. fields = A->getDefaultFields(); @@ -436,7 +436,7 @@ TEST(Domain, validate) ASSERT_TRUE(domain->validate(logger)); // Let's add a primitive field (without a primitive type at first) Rooted base_field = - base->createPrimitiveFieldDescriptor(nullptr, logger); + base->createPrimitiveFieldDescriptor(nullptr, logger).first; // this should not be valid. ASSERT_EQ(ValidationState::UNKNOWN, domain->getValidationState()); ASSERT_FALSE(domain->validate(logger)); @@ -464,7 +464,8 @@ TEST(Domain, validate) ASSERT_TRUE(domain->validate(logger)); ASSERT_EQ(base, sub->getSuperclass()); // add a non-primitive field to the child class. - Rooted sub_field = sub->createFieldDescriptor(logger); + Rooted sub_field = + sub->createFieldDescriptor(logger).first; // this should not be valid because we allow no children. ASSERT_EQ(ValidationState::UNKNOWN, domain->getValidationState()); ASSERT_FALSE(domain->validate(logger)); @@ -489,8 +490,9 @@ TEST(Domain, validate) ASSERT_EQ(ValidationState::UNKNOWN, domain->getValidationState()); ASSERT_TRUE(domain->validate(logger)); // It should be invalid if we set another TREE field. - Rooted sub_field2 = sub->createFieldDescriptor( - logger, FieldDescriptor::FieldType::TREE, "test", false); + Rooted sub_field2 = + sub->createFieldDescriptor(logger, FieldDescriptor::FieldType::TREE, + "test", false).first; ASSERT_EQ(ValidationState::UNKNOWN, domain->getValidationState()); ASSERT_FALSE(domain->validate(logger)); // but valid again if we remove it @@ -499,4 +501,4 @@ TEST(Domain, validate) ASSERT_TRUE(domain->validate(logger)); } } -} +} \ No newline at end of file diff --git a/test/core/model/TestAdvanced.hpp b/test/core/model/TestAdvanced.hpp index 27f33cc..8e81554 100644 --- a/test/core/model/TestAdvanced.hpp +++ b/test/core/model/TestAdvanced.hpp @@ -66,7 +66,7 @@ static Rooted constructHeadingDomain(Manager &mgr, for (auto &s : secclasses) { Rooted desc = resolveDescriptor(bookDomain, s); Rooted heading_field = desc->createFieldDescriptor( - logger, FieldDescriptor::FieldType::SUBTREE, "heading", true); + logger, FieldDescriptor::FieldType::SUBTREE, "heading", true).first; heading_field->addChild(heading); } return domain; diff --git a/test/core/model/TestDomain.hpp b/test/core/model/TestDomain.hpp index c107a0d..779ef03 100644 --- a/test/core/model/TestDomain.hpp +++ b/test/core/model/TestDomain.hpp @@ -42,7 +42,8 @@ static Rooted constructBookDomain(Manager &mgr, mgr, "book", domain, single, {nullptr}, false, true)}; // The structure field of it. - Rooted book_field = book->createFieldDescriptor(logger); + Rooted book_field = + book->createFieldDescriptor(logger).first; // From there on the "section". Rooted section{ @@ -51,7 +52,7 @@ static Rooted constructBookDomain(Manager &mgr, // And the field of it. Rooted section_field = - section->createFieldDescriptor(logger); + section->createFieldDescriptor(logger).first; // We also add the "paragraph", which is transparent. Rooted paragraph{new StructuredClass( @@ -61,7 +62,7 @@ static Rooted constructBookDomain(Manager &mgr, // And the field of it. Rooted paragraph_field = - paragraph->createFieldDescriptor(logger); + paragraph->createFieldDescriptor(logger).first; // We append "subsection" to section. Rooted subsection{ @@ -70,7 +71,7 @@ static Rooted constructBookDomain(Manager &mgr, // And the field of it. Rooted subsection_field = - subsection->createFieldDescriptor(logger); + subsection->createFieldDescriptor(logger).first; // and we add the paragraph to subsections fields subsection_field->addChild(paragraph); @@ -82,10 +83,11 @@ static Rooted constructBookDomain(Manager &mgr, // ... and has a primitive field. Rooted text_field = - text->createPrimitiveFieldDescriptor(sys->getStringType(), logger); + text->createPrimitiveFieldDescriptor(sys->getStringType(), logger) + .first; return domain; } } -#endif /* _TEST_DOMAIN_HPP_ */ +#endif /* _TEST_DOMAIN_HPP_ */ \ No newline at end of file -- cgit v1.2.3 From 658692f5ae3657c5e16b3958f62707d4dacc34b0 Mon Sep 17 00:00:00 2001 From: Andreas Stöckel Date: Mon, 16 Feb 2015 13:42:33 +0100 Subject: Included explicit encoding and standalone flag in xml output --- src/plugins/xml/XmlOutput.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/xml/XmlOutput.cpp b/src/plugins/xml/XmlOutput.cpp index 68edc0e..e1f1c31 100644 --- a/src/plugins/xml/XmlOutput.cpp +++ b/src/plugins/xml/XmlOutput.cpp @@ -44,7 +44,7 @@ void XmlTransformer::writeXml(Handle doc, std::ostream &out, transformStructuredEntity(document, doc->getRoot(), logger, pretty); document->addChild(root); // then serialize. - document->serialize(out, "", pretty); + document->serialize(out, "", pretty); } Rooted XmlTransformer::transformStructuredEntity( -- cgit v1.2.3 From e2a765fc4eaf559bce04b53ca1a1538b1f5f1628 Mon Sep 17 00:00:00 2001 From: Andreas Stöckel Date: Mon, 16 Feb 2015 13:49:47 +0100 Subject: Allow typesystem references in Document --- src/core/model/Document.cpp | 8 ++++++-- src/core/model/Document.hpp | 23 ++++++++++++++++++++++- 2 files changed, 28 insertions(+), 3 deletions(-) diff --git a/src/core/model/Document.cpp b/src/core/model/Document.cpp index 4e101fc..848142d 100644 --- a/src/core/model/Document.cpp +++ b/src/core/model/Document.cpp @@ -674,6 +674,7 @@ void Document::doResolve(ResolutionState &state) continueResolveCompositum(root, state); } continueResolveReferences(domains, state); + continueResolveReferences(typesystems, state); } bool Document::doValidate(Logger &logger) const @@ -713,11 +714,14 @@ void Document::doReference(Handle node) if (node->isa(&RttiTypes::Domain)) { referenceDomain(node.cast()); } + if (node->isa(&RttiTypes::Typesystem)) { + referenceTypesystem(node.cast()); + } } RttiSet Document::doGetReferenceTypes() const { - return RttiSet{&RttiTypes::Domain}; + return RttiSet{&RttiTypes::Domain, &RttiTypes::Typesystem}; } Rooted Document::createRootStructuredEntity( @@ -821,4 +825,4 @@ const Rtti AnnotationEntity = .parent(&Node) .composedOf({&StructuredEntity, &DocumentPrimitive, &Anchor}); } -} \ No newline at end of file +} diff --git a/src/core/model/Document.hpp b/src/core/model/Document.hpp index 5f06eb0..e314304 100644 --- a/src/core/model/Document.hpp +++ b/src/core/model/Document.hpp @@ -754,6 +754,7 @@ private: Owned root; NodeVector annotations; NodeVector domains; + NodeVector typesystems; protected: void doResolve(ResolutionState &state) override; @@ -771,7 +772,8 @@ public: Document(Manager &mgr, std::string name) : RootNode(mgr, std::move(name), nullptr), annotations(this), - domains(this) + domains(this), + typesystems(this) { } @@ -890,6 +892,25 @@ public: domains.insert(domains.end(), d.begin(), d.end()); } + /** + * Adds a Typesystem reference to this Document. + */ + void referenceTypesystem(Handle d) + { + invalidate(); + typesystems.push_back(d); + } + + /** + * Adds multiple Typesystem references to this Document. + */ + void referenceTypesystems(const std::vector> &d) + { + invalidate(); + typesystems.insert(typesystems.end(), d.begin(), d.end()); + } + + /** * Returns true if and only if the given StructureNode is part of this * document, meaning that there is a path of parent references in the -- cgit v1.2.3 From f69518b192ba5015e7ececddbfcf3a3695487d00 Mon Sep 17 00:00:00 2001 From: Andreas Stöckel Date: Mon, 16 Feb 2015 14:03:36 +0100 Subject: Renamed oxm files to generic osxml --- data/domain/book.osxml | 3 + data/domain/book.oxm | 3 - data/domain/structure.osxml | 3 + data/domain/structure.oxm | 3 - data/typesystem/color.osxml | 246 ++++++++++++++++++++++++++++ data/typesystem/color.oxm | 246 ---------------------------- test/plugins/filesystem/FileLocatorTest.cpp | 12 +- 7 files changed, 258 insertions(+), 258 deletions(-) create mode 100644 data/domain/book.osxml delete mode 100644 data/domain/book.oxm create mode 100644 data/domain/structure.osxml delete mode 100644 data/domain/structure.oxm create mode 100644 data/typesystem/color.osxml delete mode 100644 data/typesystem/color.oxm diff --git a/data/domain/book.osxml b/data/domain/book.osxml new file mode 100644 index 0000000..9659334 --- /dev/null +++ b/data/domain/book.osxml @@ -0,0 +1,3 @@ + + + diff --git a/data/domain/book.oxm b/data/domain/book.oxm deleted file mode 100644 index 9659334..0000000 --- a/data/domain/book.oxm +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/data/domain/structure.osxml b/data/domain/structure.osxml new file mode 100644 index 0000000..63d0c5c --- /dev/null +++ b/data/domain/structure.osxml @@ -0,0 +1,3 @@ + + + diff --git a/data/domain/structure.oxm b/data/domain/structure.oxm deleted file mode 100644 index 63d0c5c..0000000 --- a/data/domain/structure.oxm +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/data/typesystem/color.osxml b/data/typesystem/color.osxml new file mode 100644 index 0000000..782c856 --- /dev/null +++ b/data/typesystem/color.osxml @@ -0,0 +1,246 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/data/typesystem/color.oxm b/data/typesystem/color.oxm deleted file mode 100644 index 782c856..0000000 --- a/data/typesystem/color.oxm +++ /dev/null @@ -1,246 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/test/plugins/filesystem/FileLocatorTest.cpp b/test/plugins/filesystem/FileLocatorTest.cpp index 87a9223..361a3ca 100644 --- a/test/plugins/filesystem/FileLocatorTest.cpp +++ b/test/plugins/filesystem/FileLocatorTest.cpp @@ -213,11 +213,11 @@ TEST(FileLocator, testDefaultSearchPaths) FileLocator locator; locator.addDefaultSearchPaths(); - assert_not_located(locator, "book.oxm", "", ResourceType::UNKNOWN); - assert_located(locator, "domain/book.oxm", "", ResourceType::UNKNOWN); - assert_located(locator, "book.oxm", "", ResourceType::DOMAIN_DESC); - assert_not_located(locator, "color.oxm", "", ResourceType::UNKNOWN); - assert_located(locator, "typesystem/color.oxm", "", ResourceType::UNKNOWN); - assert_located(locator, "color.oxm", "", ResourceType::TYPESYSTEM); + assert_not_located(locator, "book.osxml", "", ResourceType::UNKNOWN); + assert_located(locator, "domain/book.osxml", "", ResourceType::UNKNOWN); + assert_located(locator, "book.osxml", "", ResourceType::DOMAIN_DESC); + assert_not_located(locator, "color.osxml", "", ResourceType::UNKNOWN); + assert_located(locator, "typesystem/color.osxml", "", ResourceType::UNKNOWN); + assert_located(locator, "color.osxml", "", ResourceType::TYPESYSTEM); } } -- cgit v1.2.3 From 585ebd4afab08434f4dadd46085bf7822c7188c1 Mon Sep 17 00:00:00 2001 From: Benjamin Paassen Date: Mon, 16 Feb 2015 18:47:38 +0100 Subject: added creation methods that reference fields by index instead of name. --- src/core/model/Document.cpp | 54 +++++++++++++++++- src/core/model/Document.hpp | 134 +++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 179 insertions(+), 9 deletions(-) diff --git a/src/core/model/Document.cpp b/src/core/model/Document.cpp index 4e101fc..76835a1 100644 --- a/src/core/model/Document.cpp +++ b/src/core/model/Document.cpp @@ -314,7 +314,7 @@ const NodeVector &DocumentEntity::getField( return fields[idx]; } -void DocumentEntity::addStructureNode(Handle s, const int &i) +void DocumentEntity::addStructureNode(Handle s, const size_t &i) { // only add the new node if we don't have it already. auto it = fields[i].find(s); @@ -419,6 +419,15 @@ Rooted DocumentEntity::createChildStructuredEntity( fieldName, std::move(name))}; } +Rooted DocumentEntity::createChildStructuredEntity( + Handle descriptor, const size_t &fieldIdx, + Variant attributes, std::string name) +{ + return Rooted{ + new StructuredEntity(subInst->getManager(), subInst, descriptor, + fieldIdx, std::move(attributes), std::move(name))}; +} + Rooted DocumentEntity::createChildDocumentPrimitive( Variant content, const std::string &fieldName) { @@ -426,11 +435,22 @@ Rooted DocumentEntity::createChildDocumentPrimitive( subInst->getManager(), subInst, std::move(content), fieldName)}; } +Rooted DocumentEntity::createChildDocumentPrimitive( + Variant content, const size_t &fieldIdx) +{ + return Rooted{new DocumentPrimitive( + subInst->getManager(), subInst, std::move(content), fieldIdx)}; +} + Rooted DocumentEntity::createChildAnchor(const std::string &fieldName) { return Rooted{ new Anchor(subInst->getManager(), subInst, fieldName)}; } +Rooted DocumentEntity::createChildAnchor(const size_t &fieldIdx) +{ + return Rooted{new Anchor(subInst->getManager(), subInst, fieldIdx)}; +} /* Class StructureNode */ @@ -468,6 +488,19 @@ StructureNode::StructureNode(Manager &mgr, std::string name, } } +StructureNode::StructureNode(Manager &mgr, std::string name, + Handle parent, const size_t &fieldIdx) + : Node(mgr, std::move(name), parent) +{ + if (parent->isa(&RttiTypes::StructuredEntity)) { + parent.cast()->addStructureNode(this, fieldIdx); + } else if (parent->isa(&RttiTypes::AnnotationEntity)) { + parent.cast()->addStructureNode(this, fieldIdx); + } else { + throw OusiaException("The proposed parent was no DocumentEntity!"); + } +} + /* Class StructuredEntity */ StructuredEntity::StructuredEntity(Manager &mgr, Handle doc, @@ -489,8 +522,25 @@ StructuredEntity::StructuredEntity(Manager &mgr, Handle parent, bool StructuredEntity::doValidate(Logger &logger) const { + bool valid = true; + // check the parent. + if (getDescriptor() == nullptr) { + logger.error("The descriptor is not set!", *this); + valid = false; + } else if (!getDescriptor()->isa(&RttiTypes::StructuredClass)) { + logger.error("The descriptor is not a structure descriptor!", *this); + valid = false; + } else if (transparent && + !getDescriptor().cast()->isTransparent()) { + logger.error( + "The entity is marked as transparent but the descriptor " + "does not allow transparency!", + *this); + valid = false; + } + // check the validity as a StructureNode and as a DocumentEntity. - return StructureNode::doValidate(logger) & + return valid & StructureNode::doValidate(logger) & DocumentEntity::doValidate(logger); } diff --git a/src/core/model/Document.hpp b/src/core/model/Document.hpp index 5f06eb0..57a4b1a 100644 --- a/src/core/model/Document.hpp +++ b/src/core/model/Document.hpp @@ -246,7 +246,7 @@ public: * FieldDescriptor in the Domain description. * @return a NodeVector of all StructuredEntities in that field. */ - const NodeVector &getField(const size_t& idx ) const; + const NodeVector &getField(const size_t &idx) const; /** * This adds a StructureNode to the field with the given index. @@ -259,7 +259,7 @@ public: * @param fieldIdx is the index of a field as specified in the * FieldDescriptor in the Domain description. */ - void addStructureNode(Handle s, const int &fieldIdx); + void addStructureNode(Handle s, const size_t &fieldIdx); /** * This adds a StructureNode to the field with the given name. * @@ -403,6 +403,23 @@ public: Variant attributes = Variant::mapType{}, const std::string &fieldName = DEFAULT_FIELD_NAME, std::string name = ""); + + /** + * This creates a new StructuredEntity as child of this DocumentEntity. + * + * @param descriptor is the StructuredClass of this StructuredEntity. + * @param attributes is a Map Variant containing attribute fillings for this + * StructuredEntity. It is empty per default. + * @param fieldIdx is the index of the field, where the newly created + * StructuredEntity shall be added to this DocumentEntity. + * @param name is some name for this StructuredEntity that may be used + * for later reference. It is empty per default. + * + * @return the newly created StructuredEntity. + */ + Rooted createChildStructuredEntity( + Handle descriptor, const size_t &fieldIdx, + Variant attributes = Variant::mapType{}, std::string name = ""); /* * Creates a new DocumentPrimitive as child of this DocumentEntity. * @@ -416,8 +433,21 @@ public: * @return the newly created DocumentPrimitive. */ Rooted createChildDocumentPrimitive( - Variant content = {}, - const std::string &fieldName = DEFAULT_FIELD_NAME); + Variant content, const std::string &fieldName = DEFAULT_FIELD_NAME); + /* + * Creates a new DocumentPrimitive as child of this DocumentEntity. + * + * @param fieldIdx is the index of the field, where the newly created + * StructuredEntity shall be added to this DocumentEntity. + * @param content is a Variant containing the content of this + * DocumentPrimitive. The Type of this Variant is + * specified at the parents Descriptor for the given + * fieldName. + * + * @return the newly created DocumentPrimitive. + */ + Rooted createChildDocumentPrimitive( + Variant content, const size_t &fieldIdx); /** * Creates a new Anchor as child of this DocumentEntity. @@ -429,6 +459,16 @@ public: */ Rooted createChildAnchor( const std::string &fieldName = DEFAULT_FIELD_NAME); + + /** + * Creates a new Anchor as child of this DocumentEntity. + * + * @param fieldIdx is the index of the field, where the newly created + * Anchor shall be added to this DocumentEntity. + * + * @return the newly created Anchor. + */ + Rooted createChildAnchor(const size_t &fieldIdx); }; /** @@ -447,6 +487,11 @@ public: */ StructureNode(Manager &mgr, std::string name, Handle parent, const std::string &fieldName); + /** + * Constructor for a StructureNode in the StructureTree. + */ + StructureNode(Manager &mgr, std::string name, Handle parent, + const size_t &fieldIdx); /** * Constructor for an empty StructureNode. @@ -465,6 +510,9 @@ public: class StructuredEntity : public StructureNode, public DocumentEntity { friend Document; +private: + bool transparent = false; + protected: bool doValidate(Logger &logger) const override; @@ -494,6 +542,30 @@ public: DocumentEntity(this, descriptor, std::move(attributes)) { } + /** + * Constructor for a StructuredEntity in the Structure Tree. + * + * @param mgr is the Manager instance. + * @param parent is the parent DocumentEntity of this StructuredEntity + * in the DocumentTree. Note that this StructuredEntity + * will automatically register itself as child of this + * parent. + * @param descriptor is the StructuredClass of this StructuredEntity. + * @param fieldIdx is the index of the field in the parent DocumentEntity + * where this StructuredEntity shall be added. + * @param attributes is a Map Variant containing attribute fillings for this + * StructuredEntity. It is empty per default. + * @param name is some name for this StructuredEntity that may be used + * for later reference. It is empty per default. + */ + StructuredEntity(Manager &mgr, Handle parent, + Handle descriptor, const size_t &fieldIdx, + Variant attributes = Variant::mapType{}, + std::string name = "") + : StructureNode(mgr, std::move(name), parent, fieldIdx), + DocumentEntity(this, descriptor, std::move(attributes)) + { + } /** * Constructor for a StructuredEntity at the document root. @@ -530,6 +602,20 @@ public: Handle descriptor = nullptr, Variant attributes = Variant::mapType{}, std::string name = ""); + + /** + * Returns true if and only if this element was created using transparency/ + * if and only if this is an implicit element. + * + * @return true if and only if this element was created using transparency. + */ + bool isTransparent() const { return transparent; } + + /** + * @param trans true if and only if this element was created using + * transparency/if and only if this is an implicit element. + */ + void setTransparent(bool trans) { transparent = trans; } }; /** @@ -557,11 +643,31 @@ public: * @param fieldName is the name of the field in the parent DocumentEntity * where this DocumentPrimitive shall be added. */ - DocumentPrimitive(Manager &mgr, Handle parent, Variant content = {}, + DocumentPrimitive(Manager &mgr, Handle parent, Variant content, const std::string &fieldName = DEFAULT_FIELD_NAME) : StructureNode(mgr, "", parent, fieldName), content(content) { } + /** + * Constructor for a DocumentPrimitive. + * + * @param mgr is the Manager instance. + * @param parent is the parent DocumentEntity of this DocumentPrimitive + * in the DocumentTree. Note that this DocumentPrimitive + * will automatically register itself as child of this + * parent. + * @param content is a Variant containing the content of this + * DocumentPrimitive. The Type of this Variant is + * specified at the parents Descriptor for the given + * fieldName. + * @param fieldIdx is the index of the field in the parent DocumentEntity + * where this DocumentPrimitive shall be added. + */ + DocumentPrimitive(Manager &mgr, Handle parent, Variant content, + const size_t &fieldIdx) + : StructureNode(mgr, "", parent, fieldIdx), content(content) + { + } /** * Returns the content of this DocumentPrimitive. @@ -612,6 +718,21 @@ public: : StructureNode(mgr, "", parent, fieldName) { } + /** + * Constructor for Anchor. + * + * @param mgr is the Manager instance. + * @param parent is the parent of this Anchor in the Structure Tree (!), + * not the AnnotationEntity that references this Anchor. + * Note that this Anchor will automatically register itself + * as child of the given parent. + * @param fieldIdx is the index of the field in the parent DocumentEntity + * where this Anchor shall be added. + */ + Anchor(Manager &mgr, Handle parent, const size_t &fieldIdx) + : StructureNode(mgr, "", parent, fieldIdx) + { + } /** * Returns the AnnotationEntity this Anchor belongs to. @@ -913,5 +1034,4 @@ extern const Rtti Anchor; } } -#endif /* _OUSIA_MODEL_DOCUMENT_HPP_ */ - +#endif /* _OUSIA_MODEL_DOCUMENT_HPP_ */ \ No newline at end of file -- cgit v1.2.3 From fe1e817f29de61cdbc48dc4945dcfc235cf71a41 Mon Sep 17 00:00:00 2001 From: Benjamin Paassen Date: Mon, 16 Feb 2015 18:48:10 +0100 Subject: smaller fixes in testdata --- testdata/osmlparser/simple_book.osml | 18 +++++++++++++++--- testdata/osxmlparser/bibliography_domain.osxml | 6 +++--- testdata/osxmlparser/book_domain.osxml | 4 ++-- 3 files changed, 20 insertions(+), 8 deletions(-) diff --git a/testdata/osmlparser/simple_book.osml b/testdata/osmlparser/simple_book.osml index 19f5543..21751b9 100644 --- a/testdata/osmlparser/simple_book.osml +++ b/testdata/osmlparser/simple_book.osml @@ -1,19 +1,31 @@ \import[domain]{../osxmlparser/book_domain.osxml} \import[domain]{../osxmlparser/headings_domain.osxml} +%\domain#stuff +% \import[typesystem]{../osxmlparser/color.osxml} +% \struct#fancy +% \primitive#bla[type=color] +% \parentRef[ref=book] +% \fieldRef[ref=$default] + \begin{book} This might be some introductory text or a dedication. -\chapter#myFirstChapter -\heading{My first chapter} +\chapter#myFirstChapter{My first chapter} Here we might have an introduction to the chapter. \section#myFirstSection \heading{A rather curious experiment} -Here we might find the actual section content. +\paragraph{!Here we might find the actual section content. +\heading{test}} \section#mySndSection Here we might find the actual section content. + +bla + +%\fancy{aquamarine} + \end{book} diff --git a/testdata/osxmlparser/bibliography_domain.osxml b/testdata/osxmlparser/bibliography_domain.osxml index 6418c61..53ba531 100644 --- a/testdata/osxmlparser/bibliography_domain.osxml +++ b/testdata/osxmlparser/bibliography_domain.osxml @@ -13,14 +13,14 @@ - - - + + + diff --git a/testdata/osxmlparser/book_domain.osxml b/testdata/osxmlparser/book_domain.osxml index 4218915..5a8cc67 100644 --- a/testdata/osxmlparser/book_domain.osxml +++ b/testdata/osxmlparser/book_domain.osxml @@ -75,7 +75,7 @@ - +