From 835cca85ee45dd1b6722d761999c07c33fb97cc9 Mon Sep 17 00:00:00 2001 From: Andreas Stöckel Date: Wed, 4 Feb 2015 01:45:41 +0100 Subject: Implemented parsing of enum types --- src/core/model/Typesystem.cpp | 79 ++++++++++++++++++++++++++++--------------- src/core/model/Typesystem.hpp | 74 ++++++++++++++++++++++++++++++---------- 2 files changed, 107 insertions(+), 46 deletions(-) (limited to 'src/core/model') diff --git a/src/core/model/Typesystem.cpp b/src/core/model/Typesystem.cpp index 7dd5613..a3c5b6d 100644 --- a/src/core/model/Typesystem.cpp +++ b/src/core/model/Typesystem.cpp @@ -67,10 +67,7 @@ bool Type::build(Variant &data, Logger &logger) const return build(data, logger, NullMagicCallback); } -bool Type::doCheckIsa(Handle type) const -{ - return false; -} +bool Type::doCheckIsa(Handle type) const { return false; } bool Type::checkIsa(Handle type) const { @@ -114,6 +111,11 @@ bool StringType::doBuild(Variant &data, Logger &logger, /* Class EnumType */ +EnumType::EnumType(Manager &mgr, std::string name, Handle system) + : Type(mgr, std::move(name), system, false), nextOrdinalValue(0) +{ +} + bool EnumType::doBuild(Variant &data, Logger &logger, const MagicCallback &magicCallback) const { @@ -145,32 +147,45 @@ bool EnumType::doBuild(Variant &data, Logger &logger, throw LoggableException{"Expected integer or identifier", data}; } -Rooted EnumType::createValidated( - Manager &mgr, std::string name, Handle system, - const std::vector &values, Logger &logger) -{ - // Map used to store the unique values of the enum - std::map unique_values; - - // The given vector may not be empty +bool EnumType::doValidate(Logger &logger) const{ + bool ok = true; if (values.empty()) { - logger.error("Enumeration constants may not be empty."); + logger.error("Enum type must have at least one entry", *this); + ok = false; } + return ok & validateName(logger); +} - // Iterate over the input vector, check the constant names for validity and - // uniqueness and insert them into the internal values map - for (size_t i = 0; i < values.size(); i++) { - if (!Utils::isIdentifier(values[i])) { - logger.error(std::string("\"") + values[i] + - "\" is no valid identifier."); - } +void EnumType::addEntry(const std::string &entry, Logger &logger) +{ + if (!Utils::isIdentifier(entry)) { + logger.error(std::string("\"") + entry + + "\" is not a valid identifier."); + return; + } - if (!(unique_values.insert(std::make_pair(values[i], i))).second) { - logger.error(std::string("The value ") + values[i] + - " was duplicated."); - } + if (!values.emplace(entry, nextOrdinalValue).second) { + logger.error(std::string("The enumeration entry ") +entry + + std::string(" was duplicated")); + return; + } + nextOrdinalValue++; +} + +void EnumType::addEntries(const std::vector &entries, Logger &logger) +{ + for (const std::string &entry: entries) { + addEntry(entry, logger); } - return new EnumType{mgr, name, system, unique_values}; +} + +Rooted EnumType::createValidated( + Manager &mgr, std::string name, Handle system, + const std::vector &entries, Logger &logger) +{ + Rooted type = new EnumType{mgr, name, system}; + type->addEntries(entries, logger); + return type; } std::string EnumType::nameOf(Ordinal i) const @@ -390,12 +405,15 @@ bool StructType::buildFromMap(Variant &data, Logger &logger, ok = false; logger.error(std::string("Invalid attribute key \"") + key + std::string("\""), - value); + data); } } // Copy the built array to the result and insert missing default values + // TODO: Nicer way of assigning a new variant value and keeping location? + SourceLocation loc = data.getLocation(); data = arr; + data.setLocation(loc); return insertDefaults(data, set, logger) && ok; } @@ -470,7 +488,6 @@ bool StructType::doCheckIsa(Handle type) const return false; } - Rooted StructType::createValidated( Manager &mgr, std::string name, Handle system, Handle parentStructure, const NodeVector &attributes, @@ -625,7 +642,6 @@ bool ArrayType::doCheckIsa(Handle type) const return t1->checkIsa(t2); } - /* Class UnknownType */ bool UnknownType::doBuild(Variant &, Logger &, const MagicCallback &) const @@ -706,6 +722,13 @@ Rooted Typesystem::createStructType(const std::string &name) return structType; } +Rooted Typesystem::createEnumType(const std::string &name) +{ + Rooted enumType{new EnumType(getManager(), name, this)}; + addType(enumType); + return enumType; +} + Rooted Typesystem::createConstant(const std::string &name, Variant value) { diff --git a/src/core/model/Typesystem.hpp b/src/core/model/Typesystem.hpp index 7581626..819f90d 100644 --- a/src/core/model/Typesystem.hpp +++ b/src/core/model/Typesystem.hpp @@ -371,26 +371,16 @@ public: private: /** - * Map containing the enumeration type values and the associated integer - * representation. + * Value holding the next ordinal value that is to be used when adding a new + * type. */ - const std::map values; + Ordinal nextOrdinalValue; /** - * Private constructor of the EnumType class used to create a new EnumType - * instance from a previously created name to value map. The parameters are - * not checked for validity. - * - * @param mgr is the underlying Manager instance. - * @param name is the name of the EnumType instance. Should be a valid - * identifier. - * @param values is a vector containing the enumeration type constants. + * Map containing the enumeration type values and the associated integer + * representation. */ - EnumType(Manager &mgr, std::string name, Handle system, - std::map values) - : Type(mgr, std::move(name), system, false), values(std::move(values)) - { - } + std::map values; protected: /** @@ -405,7 +395,46 @@ protected: bool doBuild(Variant &data, Logger &logger, const MagicCallback &magicCallback) const override; + /** + * Returns true if the internal value list is non-empty. + * + * @param logger is the logger instance to which validation errors are + * logged. + */ + bool doValidate(Logger &logger) const override; + public: + /** + * Constructor of the EnumType class. + * + * @param mgr is the underlying Manager instance. + * @param name is the name of the EnumType instance. Should be a valid + * identifier. + * @param system is the parent typesystem. + */ + EnumType(Manager &mgr, std::string name, Handle system); + + /** + * Adds a new entry to the enum. The enum element is validated, errors + * are logged in the given logger instance. + * + * @param entry is the name of the enum element that should be added. + * @param logger is the logger instance that should be used to write error + * messages. + */ + void addEntry(const std::string &entry, Logger &logger); + + /** + * Adds a new entry to the enum. The enum element is validated, errors + * are logged in the given logger instance. + * + * @param entires is a list containing the enum elements that should be + * added. + * @param logger is the logger instance that should be used to write error + * messages. + */ + void addEntries(const std::vector &entries, Logger &logger); + /** * Creates a new enum instance and validates the incomming value vector. * @@ -413,14 +442,14 @@ public: * @param name is the name of the EnumType instance. Should be a valid * identifier. * @param system is a reference to the parent Typesystem instance. - * @param values is a vector containing the enumeration type constants. + * @param entries is a vector containing the enumeration type constants. * The constants are checked for validity (must be a valid identifier) and * uniqueness (each value must exist exactly once). * @param logger is the Logger instance into which errors should be written. */ static Rooted createValidated( Manager &mgr, std::string name, Handle system, - const std::vector &values, Logger &logger); + const std::vector &entries, Logger &logger); /** * Creates a Variant containing a valid representation of a variable of this @@ -1134,6 +1163,15 @@ public: */ Rooted createStructType(const std::string &name); + /** + * Creates a new EnumType instance with the given name. Adds the new + * EnumType as member to the typesystem. + * + * @param name is the name of the structure that should be created. + * @return the new EnumType instance. + */ + Rooted createEnumType(const std::string &name); + /** * Creates a new Constant instance with the given name. Adds the new * Constant as member to the typesystem. -- cgit v1.2.3 From a8a911a73793d42f8d39d7a1babf4eb4a9965a5e Mon Sep 17 00:00:00 2001 From: Andreas Stöckel Date: Wed, 4 Feb 2015 02:04:34 +0100 Subject: Improved enum related error messages --- src/core/model/Typesystem.cpp | 36 ++++++++++++++++++++++++++++-------- src/core/model/Typesystem.hpp | 5 +++++ testdata/xmlparser/generic.oxm | 3 ++- 3 files changed, 35 insertions(+), 9 deletions(-) (limited to 'src/core/model') diff --git a/src/core/model/Typesystem.cpp b/src/core/model/Typesystem.cpp index a3c5b6d..bd5e615 100644 --- a/src/core/model/Typesystem.cpp +++ b/src/core/model/Typesystem.cpp @@ -138,16 +138,25 @@ bool EnumType::doBuild(Variant &data, Logger &logger, // Throw an execption if the given string value is not found if (it == values.end()) { throw LoggableException(std::string("Unknown enum constant: \"") + - name + std::string("\""), + name + + std::string("\", expected one of ") + + Utils::join(names(), ", ", "{", "}"), data); } data = it->second; return true; } - throw LoggableException{"Expected integer or identifier", data}; + + // Throw an exception, list possible enum types + throw LoggableException{ + std::string( + "Expected integer or one of the following enum constants: ") + + Utils::join(names(), ", ", "{", "}"), + data}; } -bool EnumType::doValidate(Logger &logger) const{ +bool EnumType::doValidate(Logger &logger) const +{ bool ok = true; if (values.empty()) { logger.error("Enum type must have at least one entry", *this); @@ -165,16 +174,17 @@ void EnumType::addEntry(const std::string &entry, Logger &logger) } if (!values.emplace(entry, nextOrdinalValue).second) { - logger.error(std::string("The enumeration entry ") +entry + - std::string(" was duplicated")); - return; + logger.error(std::string("The enumeration entry ") + entry + + std::string(" was duplicated")); + return; } nextOrdinalValue++; } -void EnumType::addEntries(const std::vector &entries, Logger &logger) +void EnumType::addEntries(const std::vector &entries, + Logger &logger) { - for (const std::string &entry: entries) { + for (const std::string &entry : entries) { addEntry(entry, logger); } } @@ -188,6 +198,16 @@ Rooted EnumType::createValidated( return type; } +std::vector EnumType::names() const +{ + std::vector res; + res.reserve(values.size()); + for (const auto &v : values) { + res.emplace_back(v.first); + } + return res; +} + std::string EnumType::nameOf(Ordinal i) const { if (i >= 0 && i < (int)values.size()) { diff --git a/src/core/model/Typesystem.hpp b/src/core/model/Typesystem.hpp index 819f90d..8e3a3bc 100644 --- a/src/core/model/Typesystem.hpp +++ b/src/core/model/Typesystem.hpp @@ -460,6 +460,11 @@ public: */ Variant create() const override { return Variant{0}; } + /** + * Returns the names of all enum entries. + */ + std::vector names() const; + /** * Returns the name of the given ordinal number. Throws a LoggableException * if the ordinal number is out of range. diff --git a/testdata/xmlparser/generic.oxm b/testdata/xmlparser/generic.oxm index a23d5f8..45803c8 100644 --- a/testdata/xmlparser/generic.oxm +++ b/testdata/xmlparser/generic.oxm @@ -18,11 +18,12 @@ - + +