diff options
author | Benjamin Paassen <bpaassen@techfak.uni-bielefeld.de> | 2015-02-16 11:57:16 +0100 |
---|---|---|
committer | Benjamin Paassen <bpaassen@techfak.uni-bielefeld.de> | 2015-02-16 11:57:16 +0100 |
commit | 9556bd8ac1374daf01700e18e4a025c02b5d3857 (patch) | |
tree | 06ae86031eb13892e1606d5ffdad4e267abe77bd /src | |
parent | 3cca090a650d2e8268977b57aa0dfdb0fb2cae85 (diff) | |
parent | 33a70e7dc2624a674094169dbd234959d5433d81 (diff) |
Merge branch 'master' of somweyr.de:ousia
Diffstat (limited to 'src')
-rw-r--r-- | src/core/common/Argument.cpp | 51 | ||||
-rw-r--r-- | src/core/common/Argument.hpp | 11 | ||||
-rw-r--r-- | src/core/common/VariantConverter.cpp | 46 | ||||
-rw-r--r-- | src/core/common/VariantReader.cpp | 24 | ||||
-rw-r--r-- | src/core/parser/stack/Stack.cpp | 5 |
5 files changed, 91 insertions, 46 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<bool> set(N); bool ok = true; + std::unordered_map<std::string, std::string> 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/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<Function>{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; } 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<bool, Variant> VariantReader::parseGenericToken( std::pair<bool, Variant> 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<bool, Variant> res = - parseGenericToken(reader, loggerFork, std::unordered_set<char>{}, true); + // Try to parse a single token + std::pair<bool, Variant> res = parseGenericToken( + reader, loggerFork, std::unordered_set<char>{}, 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/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 { |