Support for YAML Merge keys ( <<: [*dict1, *dict2] ) is added. The merge key is a specific scalar with value << (and tag !!merge) that implies that during node construction, the map (or sequence of maps) are merged into the current map. The priority rules are that each key from maps within the value associated with << are added iff the key is not yet present in the current map (and first map gets higher priority). Test cases have been added accordingly.
306 lines
11 KiB
C++
306 lines
11 KiB
C++
#ifndef EXCEPTIONS_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
|
#define EXCEPTIONS_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
|
|
|
#if defined(_MSC_VER) || \
|
|
(defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || \
|
|
(__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4
|
|
#pragma once
|
|
#endif
|
|
|
|
#include "yaml-cpp/mark.h"
|
|
#include "yaml-cpp/noexcept.h"
|
|
#include "yaml-cpp/traits.h"
|
|
#include <sstream>
|
|
#include <stdexcept>
|
|
#include <string>
|
|
|
|
namespace YAML {
|
|
// error messages
|
|
namespace ErrorMsg {
|
|
const char* const YAML_DIRECTIVE_ARGS =
|
|
"YAML directives must have exactly one argument";
|
|
const char* const YAML_VERSION = "bad YAML version: ";
|
|
const char* const YAML_MAJOR_VERSION = "YAML major version too large";
|
|
const char* const REPEATED_YAML_DIRECTIVE = "repeated YAML directive";
|
|
const char* const TAG_DIRECTIVE_ARGS =
|
|
"TAG directives must have exactly two arguments";
|
|
const char* const REPEATED_TAG_DIRECTIVE = "repeated TAG directive";
|
|
const char* const CHAR_IN_TAG_HANDLE =
|
|
"illegal character found while scanning tag handle";
|
|
const char* const TAG_WITH_NO_SUFFIX = "tag handle with no suffix";
|
|
const char* const END_OF_VERBATIM_TAG = "end of verbatim tag not found";
|
|
const char* const END_OF_MAP = "end of map not found";
|
|
const char* const END_OF_MAP_FLOW = "end of map flow not found";
|
|
const char* const END_OF_SEQ = "end of sequence not found";
|
|
const char* const END_OF_SEQ_FLOW = "end of sequence flow not found";
|
|
const char* const MULTIPLE_TAGS =
|
|
"cannot assign multiple tags to the same node";
|
|
const char* const MULTIPLE_ANCHORS =
|
|
"cannot assign multiple anchors to the same node";
|
|
const char* const MULTIPLE_ALIASES =
|
|
"cannot assign multiple aliases to the same node";
|
|
const char* const ALIAS_CONTENT =
|
|
"aliases can't have any content, *including* tags";
|
|
const char* const INVALID_HEX = "bad character found while scanning hex number";
|
|
const char* const INVALID_UNICODE = "invalid unicode: ";
|
|
const char* const INVALID_ESCAPE = "unknown escape character: ";
|
|
const char* const UNKNOWN_TOKEN = "unknown token";
|
|
const char* const DOC_IN_SCALAR = "illegal document indicator in scalar";
|
|
const char* const EOF_IN_SCALAR = "illegal EOF in scalar";
|
|
const char* const CHAR_IN_SCALAR = "illegal character in scalar";
|
|
const char* const TAB_IN_INDENTATION =
|
|
"illegal tab when looking for indentation";
|
|
const char* const FLOW_END = "illegal flow end";
|
|
const char* const BLOCK_ENTRY = "illegal block entry";
|
|
const char* const MAP_KEY = "illegal map key";
|
|
const char* const MAP_VALUE = "illegal map value";
|
|
const char* const ALIAS_NOT_FOUND = "alias not found after *";
|
|
const char* const ANCHOR_NOT_FOUND = "anchor not found after &";
|
|
const char* const CHAR_IN_ALIAS =
|
|
"illegal character found while scanning alias";
|
|
const char* const CHAR_IN_ANCHOR =
|
|
"illegal character found while scanning anchor";
|
|
const char* const ZERO_INDENT_IN_BLOCK =
|
|
"cannot set zero indentation for a block scalar";
|
|
const char* const CHAR_IN_BLOCK = "unexpected character in block scalar";
|
|
const char* const AMBIGUOUS_ANCHOR =
|
|
"cannot assign the same alias to multiple nodes";
|
|
const char* const UNKNOWN_ANCHOR = "the referenced anchor is not defined: ";
|
|
|
|
const char* const INVALID_NODE =
|
|
"invalid node; this may result from using a map iterator as a sequence "
|
|
"iterator, or vice-versa";
|
|
const char* const INVALID_SCALAR = "invalid scalar";
|
|
const char* const KEY_NOT_FOUND = "key not found";
|
|
const char* const BAD_CONVERSION = "bad conversion";
|
|
const char* const BAD_DEREFERENCE = "bad dereference";
|
|
const char* const BAD_SUBSCRIPT = "operator[] call on a scalar";
|
|
const char* const BAD_PUSHBACK = "appending to a non-sequence";
|
|
const char* const BAD_INSERT = "inserting in a non-convertible-to-map";
|
|
|
|
const char* const UNMATCHED_GROUP_TAG = "unmatched group tag";
|
|
const char* const UNEXPECTED_END_SEQ = "unexpected end sequence token";
|
|
const char* const UNEXPECTED_END_MAP = "unexpected end map token";
|
|
const char* const SINGLE_QUOTED_CHAR =
|
|
"invalid character in single-quoted string";
|
|
const char* const INVALID_ANCHOR = "invalid anchor";
|
|
const char* const INVALID_ALIAS = "invalid alias";
|
|
const char* const INVALID_TAG = "invalid tag";
|
|
const char* const BAD_FILE = "bad file";
|
|
const char* const MERGE_KEY_NEEDS_SINGLE_OR_SEQUENCE_OF_MAPS =
|
|
"merge key needs either single map or sequence of maps";
|
|
|
|
template <typename T>
|
|
inline const std::string KEY_NOT_FOUND_WITH_KEY(
|
|
const T&, typename disable_if<is_numeric<T>>::type* = 0) {
|
|
return KEY_NOT_FOUND;
|
|
}
|
|
|
|
inline const std::string KEY_NOT_FOUND_WITH_KEY(const std::string& key) {
|
|
std::stringstream stream;
|
|
stream << KEY_NOT_FOUND << ": " << key;
|
|
return stream.str();
|
|
}
|
|
|
|
inline const std::string KEY_NOT_FOUND_WITH_KEY(const char* key) {
|
|
std::stringstream stream;
|
|
stream << KEY_NOT_FOUND << ": " << key;
|
|
return stream.str();
|
|
}
|
|
|
|
template <typename T>
|
|
inline const std::string KEY_NOT_FOUND_WITH_KEY(
|
|
const T& key, typename enable_if<is_numeric<T>>::type* = 0) {
|
|
std::stringstream stream;
|
|
stream << KEY_NOT_FOUND << ": " << key;
|
|
return stream.str();
|
|
}
|
|
|
|
template <typename T>
|
|
inline const std::string BAD_SUBSCRIPT_WITH_KEY(
|
|
const T&, typename disable_if<is_numeric<T>>::type* = nullptr) {
|
|
return BAD_SUBSCRIPT;
|
|
}
|
|
|
|
inline const std::string BAD_SUBSCRIPT_WITH_KEY(const std::string& key) {
|
|
std::stringstream stream;
|
|
stream << BAD_SUBSCRIPT << " (key: \"" << key << "\")";
|
|
return stream.str();
|
|
}
|
|
|
|
inline const std::string BAD_SUBSCRIPT_WITH_KEY(const char* key) {
|
|
std::stringstream stream;
|
|
stream << BAD_SUBSCRIPT << " (key: \"" << key << "\")";
|
|
return stream.str();
|
|
}
|
|
|
|
template <typename T>
|
|
inline const std::string BAD_SUBSCRIPT_WITH_KEY(
|
|
const T& key, typename enable_if<is_numeric<T>>::type* = nullptr) {
|
|
std::stringstream stream;
|
|
stream << BAD_SUBSCRIPT << " (key: \"" << key << "\")";
|
|
return stream.str();
|
|
}
|
|
|
|
inline const std::string INVALID_NODE_WITH_KEY(const std::string& key) {
|
|
std::stringstream stream;
|
|
if (key.empty()) {
|
|
return INVALID_NODE;
|
|
}
|
|
stream << "invalid node; first invalid key: \"" << key << "\"";
|
|
return stream.str();
|
|
}
|
|
} // namespace ErrorMsg
|
|
|
|
class YAML_CPP_API Exception : public std::runtime_error {
|
|
public:
|
|
Exception(const Mark& mark_, const std::string& msg_)
|
|
: std::runtime_error(build_what(mark_, msg_)), mark(mark_), msg(msg_) {}
|
|
~Exception() YAML_CPP_NOEXCEPT override;
|
|
|
|
Exception(const Exception&) = default;
|
|
|
|
Mark mark;
|
|
std::string msg;
|
|
|
|
private:
|
|
static const std::string build_what(const Mark& mark,
|
|
const std::string& msg) {
|
|
if (mark.is_null()) {
|
|
return msg;
|
|
}
|
|
|
|
std::stringstream output;
|
|
output << "yaml-cpp: error at line " << mark.line + 1 << ", column "
|
|
<< mark.column + 1 << ": " << msg;
|
|
return output.str();
|
|
}
|
|
};
|
|
|
|
class YAML_CPP_API ParserException : public Exception {
|
|
public:
|
|
ParserException(const Mark& mark_, const std::string& msg_)
|
|
: Exception(mark_, msg_) {}
|
|
ParserException(const ParserException&) = default;
|
|
~ParserException() YAML_CPP_NOEXCEPT override;
|
|
};
|
|
|
|
class YAML_CPP_API RepresentationException : public Exception {
|
|
public:
|
|
RepresentationException(const Mark& mark_, const std::string& msg_)
|
|
: Exception(mark_, msg_) {}
|
|
RepresentationException(const RepresentationException&) = default;
|
|
~RepresentationException() YAML_CPP_NOEXCEPT override;
|
|
};
|
|
|
|
// representation exceptions
|
|
class YAML_CPP_API InvalidScalar : public RepresentationException {
|
|
public:
|
|
InvalidScalar(const Mark& mark_)
|
|
: RepresentationException(mark_, ErrorMsg::INVALID_SCALAR) {}
|
|
InvalidScalar(const InvalidScalar&) = default;
|
|
~InvalidScalar() YAML_CPP_NOEXCEPT override;
|
|
};
|
|
|
|
class YAML_CPP_API KeyNotFound : public RepresentationException {
|
|
public:
|
|
template <typename T>
|
|
KeyNotFound(const Mark& mark_, const T& key_)
|
|
: RepresentationException(mark_, ErrorMsg::KEY_NOT_FOUND_WITH_KEY(key_)) {
|
|
}
|
|
KeyNotFound(const KeyNotFound&) = default;
|
|
~KeyNotFound() YAML_CPP_NOEXCEPT override;
|
|
};
|
|
|
|
template <typename T>
|
|
class YAML_CPP_API TypedKeyNotFound : public KeyNotFound {
|
|
public:
|
|
TypedKeyNotFound(const Mark& mark_, const T& key_)
|
|
: KeyNotFound(mark_, key_), key(key_) {}
|
|
~TypedKeyNotFound() YAML_CPP_NOEXCEPT override = default;
|
|
|
|
T key;
|
|
};
|
|
|
|
template <typename T>
|
|
inline TypedKeyNotFound<T> MakeTypedKeyNotFound(const Mark& mark,
|
|
const T& key) {
|
|
return TypedKeyNotFound<T>(mark, key);
|
|
}
|
|
|
|
class YAML_CPP_API InvalidNode : public RepresentationException {
|
|
public:
|
|
InvalidNode(const std::string& key)
|
|
: RepresentationException(Mark::null_mark(),
|
|
ErrorMsg::INVALID_NODE_WITH_KEY(key)) {}
|
|
InvalidNode(const InvalidNode&) = default;
|
|
~InvalidNode() YAML_CPP_NOEXCEPT override;
|
|
};
|
|
|
|
class YAML_CPP_API BadConversion : public RepresentationException {
|
|
public:
|
|
explicit BadConversion(const Mark& mark_)
|
|
: RepresentationException(mark_, ErrorMsg::BAD_CONVERSION) {}
|
|
BadConversion(const BadConversion&) = default;
|
|
~BadConversion() YAML_CPP_NOEXCEPT override;
|
|
};
|
|
|
|
template <typename T>
|
|
class TypedBadConversion : public BadConversion {
|
|
public:
|
|
explicit TypedBadConversion(const Mark& mark_) : BadConversion(mark_) {}
|
|
};
|
|
|
|
class YAML_CPP_API BadDereference : public RepresentationException {
|
|
public:
|
|
BadDereference()
|
|
: RepresentationException(Mark::null_mark(), ErrorMsg::BAD_DEREFERENCE) {}
|
|
BadDereference(const BadDereference&) = default;
|
|
~BadDereference() YAML_CPP_NOEXCEPT override;
|
|
};
|
|
|
|
class YAML_CPP_API BadSubscript : public RepresentationException {
|
|
public:
|
|
template <typename Key>
|
|
BadSubscript(const Mark& mark_, const Key& key)
|
|
: RepresentationException(mark_, ErrorMsg::BAD_SUBSCRIPT_WITH_KEY(key)) {}
|
|
BadSubscript(const BadSubscript&) = default;
|
|
~BadSubscript() YAML_CPP_NOEXCEPT override;
|
|
};
|
|
|
|
class YAML_CPP_API BadPushback : public RepresentationException {
|
|
public:
|
|
BadPushback()
|
|
: RepresentationException(Mark::null_mark(), ErrorMsg::BAD_PUSHBACK) {}
|
|
BadPushback(const BadPushback&) = default;
|
|
~BadPushback() YAML_CPP_NOEXCEPT override;
|
|
};
|
|
|
|
class YAML_CPP_API BadInsert : public RepresentationException {
|
|
public:
|
|
BadInsert()
|
|
: RepresentationException(Mark::null_mark(), ErrorMsg::BAD_INSERT) {}
|
|
BadInsert(const BadInsert&) = default;
|
|
~BadInsert() YAML_CPP_NOEXCEPT override;
|
|
};
|
|
|
|
class YAML_CPP_API EmitterException : public Exception {
|
|
public:
|
|
EmitterException(const std::string& msg_)
|
|
: Exception(Mark::null_mark(), msg_) {}
|
|
EmitterException(const EmitterException&) = default;
|
|
~EmitterException() YAML_CPP_NOEXCEPT override;
|
|
};
|
|
|
|
class YAML_CPP_API BadFile : public Exception {
|
|
public:
|
|
explicit BadFile(const std::string& filename)
|
|
: Exception(Mark::null_mark(),
|
|
std::string(ErrorMsg::BAD_FILE) + ": " + filename) {}
|
|
BadFile(const BadFile&) = default;
|
|
~BadFile() YAML_CPP_NOEXCEPT override;
|
|
};
|
|
} // namespace YAML
|
|
|
|
#endif // EXCEPTIONS_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|