mirror of
https://github.com/loot/yaml-cpp.git
synced 2026-07-27 14:13:42 -07:00
Compare commits
19
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7c4cc9bf5f | ||
|
|
fa885d1813 | ||
|
|
da4614eb8b | ||
|
|
4dcd222d1f | ||
|
|
7bdd31b34b | ||
|
|
a4b8521efe | ||
|
|
7037562998 | ||
|
|
f3ff6ffc55 | ||
|
|
e3ff87ecde | ||
|
|
45ac700fff | ||
|
|
2aab5acab4 | ||
|
|
e9d760eea9 | ||
|
|
d485d0a834 | ||
|
|
973ac4b3bd | ||
|
|
e91a152e06 | ||
|
|
5217149ed4 | ||
|
|
e7ac6b3bf1 | ||
|
|
9a1f4f9a0d | ||
|
|
07443495c8 |
+1
-1
@@ -15,7 +15,7 @@ endif(CMAKE_COMPILER_IS_GNUCC)
|
||||
|
||||
set(YAML_CPP_VERSION_MAJOR "0")
|
||||
set(YAML_CPP_VERSION_MINOR "2")
|
||||
set(YAML_CPP_VERSION_PATCH "0")
|
||||
set(YAML_CPP_VERSION_PATCH "1")
|
||||
set(YAML_CPP_VERSION "${YAML_CPP_VERSION_MAJOR}.${YAML_CPP_VERSION_MINOR}.${YAML_CPP_VERSION_PATCH}")
|
||||
|
||||
enable_testing()
|
||||
|
||||
+24
-26
@@ -10,36 +10,34 @@
|
||||
|
||||
namespace YAML
|
||||
{
|
||||
template <typename T>
|
||||
struct Converter {
|
||||
static bool Convert(const std::string& input, T& output);
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
bool Convert(const std::string& input, T& output) {
|
||||
return Converter<T>::Convert(input, output);
|
||||
}
|
||||
|
||||
// this is the one to specialize
|
||||
template <typename T>
|
||||
inline bool Converter<T>::Convert(const std::string& input, T& output) {
|
||||
std::stringstream stream(input);
|
||||
stream >> output;
|
||||
return !stream.fail();
|
||||
}
|
||||
|
||||
// specializations
|
||||
template <>
|
||||
inline bool Converter<std::string>::Convert(const std::string& input, std::string& output) {
|
||||
inline bool Convert(const std::string& input, std::string& output) {
|
||||
output = input;
|
||||
return true;
|
||||
}
|
||||
|
||||
template <>
|
||||
bool Converter<bool>::Convert(const std::string& input, bool& output);
|
||||
|
||||
template <>
|
||||
bool Converter<_Null>::Convert(const std::string& input, _Null& output);
|
||||
bool Convert(const std::string& input, bool& output);
|
||||
bool Convert(const std::string& input, _Null& output);
|
||||
|
||||
#define YAML_MAKE_STREAM_CONVERT(type) \
|
||||
inline bool Convert(const std::string& input, type& output) { \
|
||||
std::stringstream stream(input); \
|
||||
stream >> output; \
|
||||
return !stream.fail(); \
|
||||
}
|
||||
|
||||
YAML_MAKE_STREAM_CONVERT(char)
|
||||
YAML_MAKE_STREAM_CONVERT(unsigned char)
|
||||
YAML_MAKE_STREAM_CONVERT(int)
|
||||
YAML_MAKE_STREAM_CONVERT(unsigned int)
|
||||
YAML_MAKE_STREAM_CONVERT(short)
|
||||
YAML_MAKE_STREAM_CONVERT(unsigned short)
|
||||
YAML_MAKE_STREAM_CONVERT(long)
|
||||
YAML_MAKE_STREAM_CONVERT(unsigned long)
|
||||
YAML_MAKE_STREAM_CONVERT(float)
|
||||
YAML_MAKE_STREAM_CONVERT(double)
|
||||
YAML_MAKE_STREAM_CONVERT(long double)
|
||||
|
||||
#undef YAML_MAKE_STREAM_CONVERT
|
||||
}
|
||||
|
||||
#endif // CONVERSION_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
|
||||
@@ -53,6 +53,9 @@ namespace YAML
|
||||
|
||||
template <typename T>
|
||||
const T Read() const;
|
||||
|
||||
template <typename T>
|
||||
operator T() const;
|
||||
|
||||
template <typename T>
|
||||
friend void operator >> (const Node& node, T& value);
|
||||
@@ -109,8 +112,27 @@ namespace YAML
|
||||
const Node *m_pIdentity;
|
||||
mutable bool m_referenced;
|
||||
};
|
||||
|
||||
// comparisons with auto-conversion
|
||||
template <typename T>
|
||||
bool operator == (const T& value, const Node& node);
|
||||
|
||||
template <typename T>
|
||||
bool operator == (const Node& node, const T& value);
|
||||
|
||||
template <typename T>
|
||||
bool operator != (const T& value, const Node& node);
|
||||
|
||||
template <typename T>
|
||||
bool operator != (const Node& node, const T& value);
|
||||
|
||||
bool operator == (const char *value, const Node& node);
|
||||
bool operator == (const Node& node, const char *value);
|
||||
bool operator != (const char *value, const Node& node);
|
||||
bool operator != (const Node& node, const char *value);
|
||||
}
|
||||
|
||||
#include "nodeimpl.h"
|
||||
#include "nodereadimpl.h"
|
||||
|
||||
#endif // NODE_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
|
||||
+43
-10
@@ -9,15 +9,6 @@
|
||||
namespace YAML
|
||||
{
|
||||
// implementation of templated things
|
||||
template <typename T>
|
||||
inline bool Node::Read(T& value) const {
|
||||
std::string scalar;
|
||||
if(!GetScalar(scalar))
|
||||
return false;
|
||||
|
||||
return Convert(scalar, value);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline const T Node::Read() const {
|
||||
T value;
|
||||
@@ -25,9 +16,14 @@ namespace YAML
|
||||
return value;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
Node::operator T() const {
|
||||
return Read<T>();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline void operator >> (const Node& node, T& value) {
|
||||
if(!node.Read(value))
|
||||
if(!ConvertScalar(node, value))
|
||||
throw InvalidScalar(node.m_mark);
|
||||
}
|
||||
|
||||
@@ -80,6 +76,43 @@ namespace YAML
|
||||
inline const Node& Node::operator [] (const char *key) const {
|
||||
return GetValue(std::string(key));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline bool operator == (const T& value, const Node& node) {
|
||||
return value == node.Read<T>();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline bool operator == (const Node& node, const T& value) {
|
||||
return value == node.Read<T>();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline bool operator != (const T& value, const Node& node) {
|
||||
return value != node.Read<T>();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline bool operator != (const Node& node, const T& value) {
|
||||
return value != node.Read<T>();
|
||||
}
|
||||
|
||||
inline bool operator == (const char *value, const Node& node) {
|
||||
return std::string(value) == node;
|
||||
}
|
||||
|
||||
inline bool operator == (const Node& node, const char *value) {
|
||||
return std::string(value) == node;
|
||||
}
|
||||
|
||||
inline bool operator != (const char *value, const Node& node) {
|
||||
return std::string(value) != node;
|
||||
}
|
||||
|
||||
inline bool operator != (const Node& node, const char *value) {
|
||||
return std::string(value) != node;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif // NODEIMPL_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
#pragma once
|
||||
|
||||
namespace YAML
|
||||
{
|
||||
// implementation for Node::Read
|
||||
// (the goal is to call ConvertScalar if we can, and fall back to operator >> if not)
|
||||
// thanks to litb from stackoverflow.com
|
||||
// http://stackoverflow.com/questions/1386183/how-to-call-a-templated-function-if-it-exists-and-something-else-otherwise/1386390#1386390
|
||||
|
||||
template<bool>
|
||||
struct read_impl;
|
||||
|
||||
// ConvertScalar available
|
||||
template<>
|
||||
struct read_impl<true> {
|
||||
template<typename T>
|
||||
static bool read(const Node& node, T& value) {
|
||||
return ConvertScalar(node, value);
|
||||
}
|
||||
};
|
||||
|
||||
// ConvertScalar not available
|
||||
template<>
|
||||
struct read_impl<false> {
|
||||
template<typename T>
|
||||
static bool read(const Node& node, T& value) {
|
||||
try {
|
||||
node >> value;
|
||||
} catch(const Exception&) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
namespace fallback {
|
||||
// sizeof > 1
|
||||
struct flag { char c[2]; };
|
||||
flag Convert(...);
|
||||
|
||||
int operator,(flag, flag);
|
||||
|
||||
template<typename T>
|
||||
void operator,(flag, T const&);
|
||||
|
||||
char operator,(int, flag);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline bool Node::Read(T& value) const {
|
||||
using namespace fallback;
|
||||
|
||||
return read_impl<sizeof (fallback::flag(), Convert(std::string(), value), fallback::flag()) != 1>::read(*this, value);
|
||||
}
|
||||
|
||||
// the main conversion function
|
||||
template <typename T>
|
||||
inline bool ConvertScalar(const Node& node, T& value) {
|
||||
std::string scalar;
|
||||
if(!node.GetScalar(scalar))
|
||||
return false;
|
||||
|
||||
return Convert(scalar, value);
|
||||
}
|
||||
}
|
||||
+2
-4
@@ -49,8 +49,7 @@ namespace
|
||||
|
||||
namespace YAML
|
||||
{
|
||||
template <>
|
||||
bool Converter<bool>::Convert(const std::string& input, bool& b)
|
||||
bool Convert(const std::string& input, bool& b)
|
||||
{
|
||||
// we can't use iostream bool extraction operators as they don't
|
||||
// recognize all possible values in the table below (taken from
|
||||
@@ -82,8 +81,7 @@ namespace YAML
|
||||
return false;
|
||||
}
|
||||
|
||||
template <>
|
||||
bool Converter<_Null>::Convert(const std::string& input, _Null& /*output*/)
|
||||
bool Convert(const std::string& input, _Null& /*output*/)
|
||||
{
|
||||
return input.empty() || input == "~" || input == "null" || input == "Null" || input == "NULL";
|
||||
}
|
||||
|
||||
@@ -83,7 +83,7 @@ namespace YAML
|
||||
} else {
|
||||
// TODO: for the common escaped characters, give their usual symbol
|
||||
std::stringstream str;
|
||||
str << "\\x" << std::hex << std::setfill('0') << std::setw(2) << static_cast <int>(ch);
|
||||
str << "\\x" << std::hex << std::setfill('0') << std::setw(2) << static_cast<unsigned int>(static_cast<unsigned char>(ch));
|
||||
out << str.str();
|
||||
}
|
||||
}
|
||||
|
||||
+4
-3
@@ -83,7 +83,7 @@ namespace YAML
|
||||
|
||||
// now do the slash (we're not gonna check if it's a slash - you better pass one!)
|
||||
switch(ch) {
|
||||
case '0': return "\0";
|
||||
case '0': return std::string(1, '\x00');
|
||||
case 'a': return "\x07";
|
||||
case 'b': return "\x08";
|
||||
case 't':
|
||||
@@ -97,8 +97,9 @@ namespace YAML
|
||||
case '\"': return "\"";
|
||||
case '\'': return "\'";
|
||||
case '\\': return "\\";
|
||||
case 'N': return "\xC2\x85"; // NEL (#x85)
|
||||
case '_': return "\xC2\xA0"; // #xA0
|
||||
case '/': return "/";
|
||||
case 'N': return "\x85";
|
||||
case '_': return "\xA0";
|
||||
case 'L': return "\xE2\x80\xA8"; // LS (#x2028)
|
||||
case 'P': return "\xE2\x80\xA9"; // PS (#x2029)
|
||||
case 'x': return Escape(in, 2);
|
||||
|
||||
+13
-11
@@ -53,6 +53,11 @@ namespace YAML
|
||||
return true;
|
||||
}
|
||||
|
||||
std::size_t Map::GetSize() const
|
||||
{
|
||||
return m_data.size();
|
||||
}
|
||||
|
||||
void Map::Parse(Scanner *pScanner, const ParserState& state)
|
||||
{
|
||||
Clear();
|
||||
@@ -117,24 +122,21 @@ namespace YAML
|
||||
pScanner->pop();
|
||||
break;
|
||||
}
|
||||
|
||||
// now it better be a key
|
||||
if(token.type != Token::KEY)
|
||||
throw ParserException(token.mark, ErrorMsg::END_OF_MAP_FLOW);
|
||||
|
||||
pScanner->pop();
|
||||
|
||||
|
||||
std::auto_ptr <Node> pKey(new Node), pValue(new Node);
|
||||
|
||||
// grab key
|
||||
pKey->Parse(pScanner, state);
|
||||
|
||||
// grab key (if non-null)
|
||||
if(token.type == Token::KEY) {
|
||||
pScanner->pop();
|
||||
pKey->Parse(pScanner, state);
|
||||
}
|
||||
|
||||
// now grab value (optional)
|
||||
if(!pScanner->empty() && pScanner->peek().type == Token::VALUE) {
|
||||
pScanner->pop();
|
||||
pValue->Parse(pScanner, state);
|
||||
}
|
||||
|
||||
|
||||
// now eat the separator (or could be a map end, which we ignore - but if it's neither, then it's a bad node)
|
||||
Token& nextToken = pScanner->peek();
|
||||
if(nextToken.type == Token::FLOW_ENTRY)
|
||||
|
||||
@@ -26,6 +26,7 @@ namespace YAML
|
||||
|
||||
virtual bool GetBegin(std::map <Node *, Node *, ltnode>::const_iterator& it) const;
|
||||
virtual bool GetEnd(std::map <Node *, Node *, ltnode>::const_iterator& it) const;
|
||||
virtual std::size_t GetSize() const;
|
||||
virtual void Parse(Scanner *pScanner, const ParserState& state);
|
||||
virtual void Write(Emitter& out) const;
|
||||
|
||||
|
||||
+12
-8
@@ -171,8 +171,11 @@ namespace YAML
|
||||
{
|
||||
while(1) {
|
||||
// first eat whitespace
|
||||
while(INPUT && IsWhitespaceToBeEaten(INPUT.peek()))
|
||||
while(INPUT && IsWhitespaceToBeEaten(INPUT.peek())) {
|
||||
if(InBlockContext() && Exp::Tab.Matches(INPUT))
|
||||
m_simpleKeyAllowed = false;
|
||||
INPUT.eat(1);
|
||||
}
|
||||
|
||||
// then eat a comment
|
||||
if(Exp::Comment.Matches(INPUT)) {
|
||||
@@ -202,18 +205,19 @@ namespace YAML
|
||||
// Misc. helpers
|
||||
|
||||
// IsWhitespaceToBeEaten
|
||||
// . We can eat whitespace if:
|
||||
// 1. It's a space
|
||||
// 2. It's a tab, and we're either:
|
||||
// a. In the flow context
|
||||
// b. In the block context but not where a simple key could be allowed
|
||||
// (i.e., not at the beginning of a line, or following '-', '?', or ':')
|
||||
// . We can eat whitespace if it's a space or tab
|
||||
// . Note: originally tabs in block context couldn't be eaten
|
||||
// "where a simple key could be allowed
|
||||
// (i.e., not at the beginning of a line, or following '-', '?', or ':')"
|
||||
// I think this is wrong, since tabs can be non-content whitespace; it's just
|
||||
// that they can't contribute to indentation, so once you've seen a tab in a
|
||||
// line, you can't start a simple key
|
||||
bool Scanner::IsWhitespaceToBeEaten(char ch)
|
||||
{
|
||||
if(ch == ' ')
|
||||
return true;
|
||||
|
||||
if(ch == '\t' && (InFlowContext() || !m_simpleKeyAllowed))
|
||||
if(ch == '\t')
|
||||
return true;
|
||||
|
||||
return false;
|
||||
|
||||
+50
-17
@@ -19,14 +19,19 @@ namespace YAML
|
||||
// and different places in the above flow.
|
||||
std::string ScanScalar(Stream& INPUT, ScanScalarParams& params)
|
||||
{
|
||||
bool foundNonEmptyLine = false, pastOpeningBreak = false;
|
||||
bool foundNonEmptyLine = false;
|
||||
bool pastOpeningBreak = (params.fold == FOLD_FLOW);
|
||||
bool emptyLine = false, moreIndented = false;
|
||||
int foldedNewlineCount = 0;
|
||||
bool foldedNewlineStartedMoreIndented = false;
|
||||
std::string scalar;
|
||||
params.leadingSpaces = false;
|
||||
|
||||
while(INPUT) {
|
||||
// ********************************
|
||||
// Phase #1: scan until line ending
|
||||
|
||||
std::size_t lastNonWhitespaceChar = scalar.size();
|
||||
while(!params.end.Matches(INPUT) && !Exp::Break.Matches(INPUT)) {
|
||||
if(!INPUT)
|
||||
break;
|
||||
@@ -46,17 +51,22 @@ namespace YAML
|
||||
if(params.escape == '\\' && Exp::EscBreak.Matches(INPUT)) {
|
||||
int n = Exp::EscBreak.Match(INPUT);
|
||||
INPUT.eat(n);
|
||||
lastNonWhitespaceChar = scalar.size();
|
||||
continue;
|
||||
}
|
||||
|
||||
// escape this?
|
||||
if(INPUT.peek() == params.escape) {
|
||||
scalar += Exp::Escape(INPUT);
|
||||
lastNonWhitespaceChar = scalar.size();
|
||||
continue;
|
||||
}
|
||||
|
||||
// otherwise, just add the damn character
|
||||
scalar += INPUT.get();
|
||||
char ch = INPUT.get();
|
||||
scalar += ch;
|
||||
if(ch != ' ' && ch != '\t')
|
||||
lastNonWhitespaceChar = scalar.size();
|
||||
}
|
||||
|
||||
// eof? if we're looking to eat something, then we throw
|
||||
@@ -77,7 +87,11 @@ namespace YAML
|
||||
INPUT.eat(n);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
// do we remove trailing whitespace?
|
||||
if(params.fold == FOLD_FLOW)
|
||||
scalar.erase(lastNonWhitespaceChar);
|
||||
|
||||
// ********************************
|
||||
// Phase #2: eat line ending
|
||||
n = Exp::Break.Match(INPUT);
|
||||
@@ -108,19 +122,38 @@ namespace YAML
|
||||
|
||||
// was this an empty line?
|
||||
bool nextEmptyLine = Exp::Break.Matches(INPUT);
|
||||
bool nextMoreIndented = (INPUT.peek() == ' ');
|
||||
bool nextMoreIndented = Exp::Blank.Matches(INPUT);
|
||||
if(params.fold == FOLD_BLOCK && foldedNewlineCount == 0 && nextEmptyLine)
|
||||
foldedNewlineStartedMoreIndented = moreIndented;
|
||||
|
||||
// for block scalars, we always start with a newline, so we should ignore it (not fold or keep)
|
||||
bool useNewLine = pastOpeningBreak;
|
||||
// and for folded scalars, we don't fold the very last newline to a space
|
||||
if(params.fold && !emptyLine && INPUT.column() < params.indent)
|
||||
useNewLine = false;
|
||||
|
||||
if(useNewLine) {
|
||||
if(params.fold && !emptyLine && !nextEmptyLine && !moreIndented && !nextMoreIndented)
|
||||
scalar += " ";
|
||||
else
|
||||
scalar += "\n";
|
||||
if(pastOpeningBreak) {
|
||||
switch(params.fold) {
|
||||
case DONT_FOLD:
|
||||
scalar += "\n";
|
||||
break;
|
||||
case FOLD_BLOCK:
|
||||
if(!emptyLine && !nextEmptyLine && !moreIndented && !nextMoreIndented && INPUT.column() >= params.indent)
|
||||
scalar += " ";
|
||||
else if(nextEmptyLine)
|
||||
foldedNewlineCount++;
|
||||
else
|
||||
scalar += "\n";
|
||||
|
||||
if(!nextEmptyLine && foldedNewlineCount > 0) {
|
||||
scalar += std::string(foldedNewlineCount - 1, '\n');
|
||||
if(foldedNewlineStartedMoreIndented || nextMoreIndented)
|
||||
scalar += "\n";
|
||||
foldedNewlineCount = 0;
|
||||
}
|
||||
break;
|
||||
case FOLD_FLOW:
|
||||
if(nextEmptyLine)
|
||||
scalar += "\n";
|
||||
else if(!emptyLine && !nextEmptyLine)
|
||||
scalar += " ";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
emptyLine = nextEmptyLine;
|
||||
@@ -141,11 +174,11 @@ namespace YAML
|
||||
scalar.erase(pos + 1);
|
||||
}
|
||||
|
||||
if(params.chomp <= 0) {
|
||||
if(params.chomp == STRIP || params.chomp == CLIP) {
|
||||
std::size_t pos = scalar.find_last_not_of('\n');
|
||||
if(params.chomp == 0 && pos + 1 < scalar.size())
|
||||
if(params.chomp == CLIP && pos + 1 < scalar.size())
|
||||
scalar.erase(pos + 2);
|
||||
else if(params.chomp == -1 && pos < scalar.size())
|
||||
else if(params.chomp == STRIP && pos < scalar.size())
|
||||
scalar.erase(pos + 1);
|
||||
}
|
||||
|
||||
|
||||
+3
-2
@@ -12,9 +12,10 @@ namespace YAML
|
||||
{
|
||||
enum CHOMP { STRIP = -1, CLIP, KEEP };
|
||||
enum ACTION { NONE, BREAK, THROW };
|
||||
enum FOLD { DONT_FOLD, FOLD_BLOCK, FOLD_FLOW };
|
||||
|
||||
struct ScanScalarParams {
|
||||
ScanScalarParams(): eatEnd(false), indent(0), detectIndent(false), eatLeadingWhitespace(0), escape(0), fold(false),
|
||||
ScanScalarParams(): eatEnd(false), indent(0), detectIndent(false), eatLeadingWhitespace(0), escape(0), fold(DONT_FOLD),
|
||||
trimTrailingSpaces(0), chomp(CLIP), onDocIndicator(NONE), onTabInIndentation(NONE), leadingSpaces(false) {}
|
||||
|
||||
// input:
|
||||
@@ -24,7 +25,7 @@ namespace YAML
|
||||
bool detectIndent; // should we try to autodetect the indent?
|
||||
bool eatLeadingWhitespace; // should we continue eating this delicious indentation after 'indent' spaces?
|
||||
char escape; // what character do we escape on (i.e., slash or single quote) (0 for none)
|
||||
bool fold; // do we fold line ends?
|
||||
FOLD fold; // how do we fold line ends?
|
||||
bool trimTrailingSpaces; // do we remove all trailing spaces (at the very end)
|
||||
CHOMP chomp; // do we strip, clip, or keep trailing newlines (at the very end)
|
||||
// Note: strip means kill all, clip means keep at most one, keep means keep all
|
||||
|
||||
+5
-7
@@ -182,9 +182,6 @@ namespace YAML
|
||||
// Value
|
||||
void Scanner::ScanValue()
|
||||
{
|
||||
// just in case we have an empty key
|
||||
InsertPotentialSimpleKey();
|
||||
|
||||
// and check that simple key
|
||||
bool isSimpleKey = VerifySimpleKey();
|
||||
|
||||
@@ -290,10 +287,10 @@ namespace YAML
|
||||
params.end = (InFlowContext() ? Exp::EndScalarInFlow : Exp::EndScalar) || (Exp::BlankOrBreak + Exp::Comment);
|
||||
params.eatEnd = false;
|
||||
params.indent = (InFlowContext() ? 0 : GetTopIndent() + 1);
|
||||
params.fold = true;
|
||||
params.fold = FOLD_BLOCK;
|
||||
params.eatLeadingWhitespace = true;
|
||||
params.trimTrailingSpaces = true;
|
||||
params.chomp = CLIP;
|
||||
params.chomp = STRIP;
|
||||
params.onDocIndicator = BREAK;
|
||||
params.onTabInIndentation = THROW;
|
||||
|
||||
@@ -330,7 +327,7 @@ namespace YAML
|
||||
params.eatEnd = true;
|
||||
params.escape = (single ? '\'' : '\\');
|
||||
params.indent = 0;
|
||||
params.fold = true;
|
||||
params.fold = FOLD_FLOW;
|
||||
params.eatLeadingWhitespace = true;
|
||||
params.trimTrailingSpaces = false;
|
||||
params.chomp = CLIP;
|
||||
@@ -368,9 +365,10 @@ namespace YAML
|
||||
// eat block indicator ('|' or '>')
|
||||
Mark mark = INPUT.mark();
|
||||
char indicator = INPUT.get();
|
||||
params.fold = (indicator == Keys::FoldedScalar);
|
||||
params.fold = (indicator == Keys::FoldedScalar ? FOLD_BLOCK : DONT_FOLD);
|
||||
|
||||
// eat chomping/indentation indicators
|
||||
params.chomp = CLIP;
|
||||
int n = Exp::Chomp.Match(INPUT);
|
||||
for(int i=0;i<n;i++) {
|
||||
char ch = INPUT.get();
|
||||
|
||||
@@ -179,6 +179,10 @@
|
||||
RelativePath=".\yaml-reader\parsertests.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\yaml-reader\spectests.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\yaml-reader\tests.cpp"
|
||||
>
|
||||
@@ -189,6 +193,18 @@
|
||||
Filter="h;hpp;hxx;hm;inl;inc;xsd"
|
||||
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
|
||||
>
|
||||
<File
|
||||
RelativePath=".\yaml-reader\emittertests.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\yaml-reader\parsertests.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\yaml-reader\spectests.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\yaml-reader\tests.h"
|
||||
>
|
||||
|
||||
@@ -534,4 +534,94 @@ namespace Test
|
||||
out << YAML::EndSeq;
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
void RunEmitterTest(void (*test)(YAML::Emitter&, std::string&), const std::string& name, int& passed, int& total) {
|
||||
YAML::Emitter out;
|
||||
std::string desiredOutput;
|
||||
test(out, desiredOutput);
|
||||
std::string output = out.c_str();
|
||||
|
||||
if(output == desiredOutput) {
|
||||
passed++;
|
||||
} else {
|
||||
std::cout << "Emitter test failed: " << name << "\n";
|
||||
std::cout << "Output:\n";
|
||||
std::cout << output << "<<<\n";
|
||||
std::cout << "Desired output:\n";
|
||||
std::cout << desiredOutput << "<<<\n";
|
||||
}
|
||||
total++;
|
||||
}
|
||||
|
||||
void RunEmitterErrorTest(void (*test)(YAML::Emitter&, std::string&), const std::string& name, int& passed, int& total) {
|
||||
YAML::Emitter out;
|
||||
std::string desiredError;
|
||||
test(out, desiredError);
|
||||
std::string lastError = out.GetLastError();
|
||||
if(!out.good() && lastError == desiredError) {
|
||||
passed++;
|
||||
} else {
|
||||
std::cout << "Emitter test failed: " << name << "\n";
|
||||
if(out.good())
|
||||
std::cout << "No error detected\n";
|
||||
else
|
||||
std::cout << "Detected error: " << lastError << "\n";
|
||||
std::cout << "Expected error: " << desiredError << "\n";
|
||||
}
|
||||
total++;
|
||||
}
|
||||
}
|
||||
|
||||
bool RunEmitterTests()
|
||||
{
|
||||
int passed = 0;
|
||||
int total = 0;
|
||||
RunEmitterTest(&Emitter::SimpleScalar, "simple scalar", passed, total);
|
||||
RunEmitterTest(&Emitter::SimpleSeq, "simple seq", passed, total);
|
||||
RunEmitterTest(&Emitter::SimpleFlowSeq, "simple flow seq", passed, total);
|
||||
RunEmitterTest(&Emitter::EmptyFlowSeq, "empty flow seq", passed, total);
|
||||
RunEmitterTest(&Emitter::NestedBlockSeq, "nested block seq", passed, total);
|
||||
RunEmitterTest(&Emitter::NestedFlowSeq, "nested flow seq", passed, total);
|
||||
RunEmitterTest(&Emitter::SimpleMap, "simple map", passed, total);
|
||||
RunEmitterTest(&Emitter::SimpleFlowMap, "simple flow map", passed, total);
|
||||
RunEmitterTest(&Emitter::MapAndList, "map and list", passed, total);
|
||||
RunEmitterTest(&Emitter::ListAndMap, "list and map", passed, total);
|
||||
RunEmitterTest(&Emitter::NestedBlockMap, "nested block map", passed, total);
|
||||
RunEmitterTest(&Emitter::NestedFlowMap, "nested flow map", passed, total);
|
||||
RunEmitterTest(&Emitter::MapListMix, "map list mix", passed, total);
|
||||
RunEmitterTest(&Emitter::SimpleLongKey, "simple long key", passed, total);
|
||||
RunEmitterTest(&Emitter::SingleLongKey, "single long key", passed, total);
|
||||
RunEmitterTest(&Emitter::ComplexLongKey, "complex long key", passed, total);
|
||||
RunEmitterTest(&Emitter::AutoLongKey, "auto long key", passed, total);
|
||||
RunEmitterTest(&Emitter::ScalarFormat, "scalar format", passed, total);
|
||||
RunEmitterTest(&Emitter::AutoLongKeyScalar, "auto long key scalar", passed, total);
|
||||
RunEmitterTest(&Emitter::LongKeyFlowMap, "long key flow map", passed, total);
|
||||
RunEmitterTest(&Emitter::BlockMapAsKey, "block map as key", passed, total);
|
||||
RunEmitterTest(&Emitter::AliasAndAnchor, "alias and anchor", passed, total);
|
||||
RunEmitterTest(&Emitter::AliasAndAnchorWithNull, "alias and anchor with null", passed, total);
|
||||
RunEmitterTest(&Emitter::ComplexDoc, "complex doc", passed, total);
|
||||
RunEmitterTest(&Emitter::STLContainers, "STL containers", passed, total);
|
||||
RunEmitterTest(&Emitter::SimpleComment, "simple comment", passed, total);
|
||||
RunEmitterTest(&Emitter::MultiLineComment, "multi-line comment", passed, total);
|
||||
RunEmitterTest(&Emitter::ComplexComments, "complex comments", passed, total);
|
||||
RunEmitterTest(&Emitter::Indentation, "indentation", passed, total);
|
||||
RunEmitterTest(&Emitter::SimpleGlobalSettings, "simple global settings", passed, total);
|
||||
RunEmitterTest(&Emitter::ComplexGlobalSettings, "complex global settings", passed, total);
|
||||
RunEmitterTest(&Emitter::Null, "null", passed, total);
|
||||
|
||||
RunEmitterErrorTest(&Emitter::ExtraEndSeq, "extra EndSeq", passed, total);
|
||||
RunEmitterErrorTest(&Emitter::ExtraEndMap, "extra EndMap", passed, total);
|
||||
RunEmitterErrorTest(&Emitter::BadSingleQuoted, "bad single quoted string", passed, total);
|
||||
RunEmitterErrorTest(&Emitter::InvalidAnchor, "invalid anchor", passed, total);
|
||||
RunEmitterErrorTest(&Emitter::InvalidAlias, "invalid alias", passed, total);
|
||||
RunEmitterErrorTest(&Emitter::MissingKey, "missing key", passed, total);
|
||||
RunEmitterErrorTest(&Emitter::MissingValue, "missing value", passed, total);
|
||||
RunEmitterErrorTest(&Emitter::UnexpectedKey, "unexpected key", passed, total);
|
||||
RunEmitterErrorTest(&Emitter::UnexpectedValue, "unexpected value", passed, total);
|
||||
|
||||
std::cout << "Emitter tests: " << passed << "/" << total << " passed\n";
|
||||
return passed == total;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
#pragma once
|
||||
|
||||
#ifndef EMITTERTESTS_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
#define EMITTERTESTS_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
|
||||
namespace Test {
|
||||
bool RunEmitterTests();
|
||||
}
|
||||
|
||||
#endif // EMITTERTESTS_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
|
||||
@@ -611,4 +611,278 @@ namespace Test
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
void RunScalarParserTest(void (*test)(std::string&, std::string&), const std::string& name, int& passed, int& total) {
|
||||
std::string error;
|
||||
std::string inputScalar, desiredOutput;
|
||||
std::string output;
|
||||
bool ok = true;
|
||||
try {
|
||||
test(inputScalar, desiredOutput);
|
||||
std::stringstream stream(inputScalar);
|
||||
YAML::Parser parser(stream);
|
||||
YAML::Node doc;
|
||||
parser.GetNextDocument(doc);
|
||||
doc >> output;
|
||||
} catch(const YAML::Exception& e) {
|
||||
ok = false;
|
||||
error = e.msg;
|
||||
}
|
||||
if(ok && output == desiredOutput) {
|
||||
passed++;
|
||||
} else {
|
||||
std::cout << "Parser test failed: " << name << "\n";
|
||||
if(error != "")
|
||||
std::cout << "Caught exception: " << error << "\n";
|
||||
else {
|
||||
std::cout << "Output:\n" << output << "<<<\n";
|
||||
std::cout << "Desired output:\n" << desiredOutput << "<<<\n";
|
||||
}
|
||||
}
|
||||
total++;
|
||||
}
|
||||
|
||||
void RunParserTest(bool (*test)(), const std::string& name, int& passed, int& total) {
|
||||
std::string error;
|
||||
bool ok = true;
|
||||
try {
|
||||
ok = test();
|
||||
} catch(const YAML::Exception& e) {
|
||||
ok = false;
|
||||
error = e.msg;
|
||||
}
|
||||
if(ok) {
|
||||
passed++;
|
||||
} else {
|
||||
std::cout << "Parser test failed: " << name << "\n";
|
||||
if(error != "")
|
||||
std::cout << "Caught exception: " << error << "\n";
|
||||
}
|
||||
total++;
|
||||
}
|
||||
|
||||
typedef void (*EncodingFn)(std::ostream&, int);
|
||||
|
||||
inline char Byte(int ch)
|
||||
{
|
||||
return static_cast<char>(static_cast<unsigned char>(static_cast<unsigned int>(ch)));
|
||||
}
|
||||
|
||||
void EncodeToUtf8(std::ostream& stream, int ch)
|
||||
{
|
||||
if (ch <= 0x7F)
|
||||
{
|
||||
stream << Byte(ch);
|
||||
}
|
||||
else if (ch <= 0x7FF)
|
||||
{
|
||||
stream << Byte(0xC0 | (ch >> 6));
|
||||
stream << Byte(0x80 | (ch & 0x3F));
|
||||
}
|
||||
else if (ch <= 0xFFFF)
|
||||
{
|
||||
stream << Byte(0xE0 | (ch >> 12));
|
||||
stream << Byte(0x80 | ((ch >> 6) & 0x3F));
|
||||
stream << Byte(0x80 | (ch & 0x3F));
|
||||
}
|
||||
else if (ch <= 0x1FFFFF)
|
||||
{
|
||||
stream << Byte(0xF0 | (ch >> 18));
|
||||
stream << Byte(0x80 | ((ch >> 12) & 0x3F));
|
||||
stream << Byte(0x80 | ((ch >> 6) & 0x3F));
|
||||
stream << Byte(0x80 | (ch & 0x3F));
|
||||
}
|
||||
}
|
||||
|
||||
bool SplitUtf16HighChar(std::ostream& stream, EncodingFn encoding, int ch)
|
||||
{
|
||||
int biasedValue = ch - 0x10000;
|
||||
if (biasedValue < 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
int high = 0xD800 | (biasedValue >> 10);
|
||||
int low = 0xDC00 | (biasedValue & 0x3FF);
|
||||
encoding(stream, high);
|
||||
encoding(stream, low);
|
||||
return true;
|
||||
}
|
||||
|
||||
void EncodeToUtf16LE(std::ostream& stream, int ch)
|
||||
{
|
||||
if (!SplitUtf16HighChar(stream, &EncodeToUtf16LE, ch))
|
||||
{
|
||||
stream << Byte(ch & 0xFF) << Byte(ch >> 8);
|
||||
}
|
||||
}
|
||||
|
||||
void EncodeToUtf16BE(std::ostream& stream, int ch)
|
||||
{
|
||||
if (!SplitUtf16HighChar(stream, &EncodeToUtf16BE, ch))
|
||||
{
|
||||
stream << Byte(ch >> 8) << Byte(ch & 0xFF);
|
||||
}
|
||||
}
|
||||
|
||||
void EncodeToUtf32LE(std::ostream& stream, int ch)
|
||||
{
|
||||
stream << Byte(ch & 0xFF) << Byte((ch >> 8) & 0xFF)
|
||||
<< Byte((ch >> 16) & 0xFF) << Byte((ch >> 24) & 0xFF);
|
||||
}
|
||||
|
||||
void EncodeToUtf32BE(std::ostream& stream, int ch)
|
||||
{
|
||||
stream << Byte((ch >> 24) & 0xFF) << Byte((ch >> 16) & 0xFF)
|
||||
<< Byte((ch >> 8) & 0xFF) << Byte(ch & 0xFF);
|
||||
}
|
||||
|
||||
class EncodingTester
|
||||
{
|
||||
public:
|
||||
EncodingTester(EncodingFn encoding, bool declareEncoding)
|
||||
{
|
||||
if (declareEncoding)
|
||||
{
|
||||
encoding(m_yaml, 0xFEFF);
|
||||
}
|
||||
|
||||
AddEntry(encoding, 0x0021, 0x007E); // Basic Latin
|
||||
AddEntry(encoding, 0x00A1, 0x00FF); // Latin-1 Supplement
|
||||
AddEntry(encoding, 0x0660, 0x06FF); // Arabic (largest contiguous block)
|
||||
|
||||
// CJK unified ideographs (multiple lines)
|
||||
AddEntry(encoding, 0x4E00, 0x4EFF);
|
||||
AddEntry(encoding, 0x4F00, 0x4FFF);
|
||||
AddEntry(encoding, 0x5000, 0x51FF); // 512 character line
|
||||
AddEntry(encoding, 0x5200, 0x54FF); // 768 character line
|
||||
AddEntry(encoding, 0x5500, 0x58FF); // 1024 character line
|
||||
|
||||
AddEntry(encoding, 0x103A0, 0x103C3); // Old Persian
|
||||
|
||||
m_yaml.seekg(0, std::ios::beg);
|
||||
}
|
||||
|
||||
std::istream& stream() {return m_yaml;}
|
||||
const std::vector<std::string>& entries() {return m_entries;}
|
||||
|
||||
private:
|
||||
std::stringstream m_yaml;
|
||||
std::vector<std::string> m_entries;
|
||||
|
||||
void AddEntry(EncodingFn encoding, int startCh, int endCh)
|
||||
{
|
||||
encoding(m_yaml, '-');
|
||||
encoding(m_yaml, ' ');
|
||||
encoding(m_yaml, '|');
|
||||
encoding(m_yaml, '\n');
|
||||
encoding(m_yaml, ' ');
|
||||
encoding(m_yaml, ' ');
|
||||
|
||||
std::stringstream entry;
|
||||
for (int ch = startCh; ch <= endCh; ++ch)
|
||||
{
|
||||
encoding(m_yaml, ch);
|
||||
EncodeToUtf8(entry, ch);
|
||||
}
|
||||
encoding(m_yaml, '\n');
|
||||
|
||||
m_entries.push_back(entry.str());
|
||||
}
|
||||
};
|
||||
|
||||
void RunEncodingTest(EncodingFn encoding, bool declareEncoding, const std::string& name, int& passed, int& total)
|
||||
{
|
||||
EncodingTester tester(encoding, declareEncoding);
|
||||
std::string error;
|
||||
bool ok = true;
|
||||
try {
|
||||
YAML::Parser parser(tester.stream());
|
||||
YAML::Node doc;
|
||||
parser.GetNextDocument(doc);
|
||||
|
||||
YAML::Iterator itNode = doc.begin();
|
||||
std::vector<std::string>::const_iterator itEntry = tester.entries().begin();
|
||||
for (; (itNode != doc.end()) && (itEntry != tester.entries().end()); ++itNode, ++itEntry)
|
||||
{
|
||||
std::string stScalarValue;
|
||||
if (!itNode->GetScalar(stScalarValue) && (stScalarValue == *itEntry))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ((itNode != doc.end()) || (itEntry != tester.entries().end()))
|
||||
{
|
||||
ok = false;
|
||||
}
|
||||
} catch(const YAML::Exception& e) {
|
||||
ok = false;
|
||||
error = e.msg;
|
||||
}
|
||||
if(ok) {
|
||||
passed++;
|
||||
} else {
|
||||
std::cout << "Parser test failed: " << name << "\n";
|
||||
if(error != "")
|
||||
std::cout << "Caught exception: " << error << "\n";
|
||||
}
|
||||
total++;
|
||||
}
|
||||
}
|
||||
|
||||
bool RunParserTests()
|
||||
{
|
||||
int passed = 0;
|
||||
int total = 0;
|
||||
RunScalarParserTest(&Parser::SimpleScalar, "simple scalar", passed, total);
|
||||
RunScalarParserTest(&Parser::MultiLineScalar, "multi-line scalar", passed, total);
|
||||
RunScalarParserTest(&Parser::LiteralScalar, "literal scalar", passed, total);
|
||||
RunScalarParserTest(&Parser::FoldedScalar, "folded scalar", passed, total);
|
||||
RunScalarParserTest(&Parser::ChompedFoldedScalar, "chomped folded scalar", passed, total);
|
||||
RunScalarParserTest(&Parser::ChompedLiteralScalar, "chomped literal scalar", passed, total);
|
||||
RunScalarParserTest(&Parser::FoldedScalarWithIndent, "folded scalar with indent", passed, total);
|
||||
RunScalarParserTest(&Parser::ColonScalar, "colon scalar", passed, total);
|
||||
RunScalarParserTest(&Parser::QuotedScalar, "quoted scalar", passed, total);
|
||||
RunScalarParserTest(&Parser::CommaScalar, "comma scalar", passed, total);
|
||||
RunScalarParserTest(&Parser::DashScalar, "dash scalar", passed, total);
|
||||
RunScalarParserTest(&Parser::URLScalar, "url scalar", passed, total);
|
||||
|
||||
RunParserTest(&Parser::SimpleSeq, "simple seq", passed, total);
|
||||
RunParserTest(&Parser::SimpleMap, "simple map", passed, total);
|
||||
RunParserTest(&Parser::FlowSeq, "flow seq", passed, total);
|
||||
RunParserTest(&Parser::FlowMap, "flow map", passed, total);
|
||||
RunParserTest(&Parser::FlowMapWithOmittedKey, "flow map with omitted key", passed, total);
|
||||
RunParserTest(&Parser::FlowMapWithOmittedValue, "flow map with omitted value", passed, total);
|
||||
RunParserTest(&Parser::FlowMapWithSoloEntry, "flow map with solo entry", passed, total);
|
||||
RunParserTest(&Parser::FlowMapEndingWithSoloEntry, "flow map ending with solo entry", passed, total);
|
||||
RunParserTest(&Parser::QuotedSimpleKeys, "quoted simple keys", passed, total);
|
||||
RunParserTest(&Parser::CompressedMapAndSeq, "compressed map and seq", passed, total);
|
||||
RunParserTest(&Parser::NullBlockSeqEntry, "null block seq entry", passed, total);
|
||||
RunParserTest(&Parser::NullBlockMapKey, "null block map key", passed, total);
|
||||
RunParserTest(&Parser::NullBlockMapValue, "null block map value", passed, total);
|
||||
RunParserTest(&Parser::SimpleAlias, "simple alias", passed, total);
|
||||
RunParserTest(&Parser::AliasWithNull, "alias with null", passed, total);
|
||||
RunParserTest(&Parser::AnchorInSimpleKey, "anchor in simple key", passed, total);
|
||||
RunParserTest(&Parser::AliasAsSimpleKey, "alias as simple key", passed, total);
|
||||
RunParserTest(&Parser::ExplicitDoc, "explicit doc", passed, total);
|
||||
RunParserTest(&Parser::MultipleDocs, "multiple docs", passed, total);
|
||||
RunParserTest(&Parser::ExplicitEndDoc, "explicit end doc", passed, total);
|
||||
RunParserTest(&Parser::MultipleDocsWithSomeExplicitIndicators, "multiple docs with some explicit indicators", passed, total);
|
||||
|
||||
RunEncodingTest(&EncodeToUtf8, false, "UTF-8, no BOM", passed, total);
|
||||
RunEncodingTest(&EncodeToUtf8, true, "UTF-8 with BOM", passed, total);
|
||||
RunEncodingTest(&EncodeToUtf16LE, false, "UTF-16LE, no BOM", passed, total);
|
||||
RunEncodingTest(&EncodeToUtf16LE, true, "UTF-16LE with BOM", passed, total);
|
||||
RunEncodingTest(&EncodeToUtf16BE, false, "UTF-16BE, no BOM", passed, total);
|
||||
RunEncodingTest(&EncodeToUtf16BE, true, "UTF-16BE with BOM", passed, total);
|
||||
RunEncodingTest(&EncodeToUtf32LE, false, "UTF-32LE, no BOM", passed, total);
|
||||
RunEncodingTest(&EncodeToUtf32LE, true, "UTF-32LE with BOM", passed, total);
|
||||
RunEncodingTest(&EncodeToUtf32BE, false, "UTF-32BE, no BOM", passed, total);
|
||||
RunEncodingTest(&EncodeToUtf32BE, true, "UTF-32BE with BOM", passed, total);
|
||||
|
||||
std::cout << "Parser tests: " << passed << "/" << total << " passed\n";
|
||||
return passed == total;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
#pragma once
|
||||
|
||||
#ifndef PARSERTESTS_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
#define PARSERTESTS_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
|
||||
namespace Test {
|
||||
bool RunParserTests();
|
||||
}
|
||||
|
||||
#endif // PARSERTESTS_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
|
||||
+1217
-42
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user