Compare commits

..

35 Commits

Author SHA1 Message Date
Jesse Beder
326899815f Added overloads for parsing stl maps and vectors 2010-03-15 04:25:17 +00:00
Jesse Beder
083a97b171 Set alias nodes to return the tag of their anchor 2010-03-15 04:10:36 +00:00
Jesse Beder
2226987442 Disabled those warnings in the release version of the .svn too. 2010-03-03 05:33:07 +00:00
Jesse Beder
bca7737463 Updated to remove most of the warnings in Visual Studio. (There's still the one about all control paths returning a value left.) Fixed one warning (when an istream converts to void * to then convert to bool), and disabled three. 2010-03-03 05:30:06 +00:00
Jesse Beder
6f40b09525 Added newline to install and license files 2009-12-21 20:35:27 +00:00
Jesse Beder
3a755de572 Added missing include 2009-12-02 05:59:18 +00:00
Jesse Beder
9718e58120 Added test for duplicate key 2009-12-02 01:29:16 +00:00
Jesse Beder
8723b8f358 Fixed leak when adding duplicate keys (and actually changed the behavior - now we take the first instance, not the last) 2009-12-02 01:01:45 +00:00
Jesse Beder
03df73a7b0 Refactored emitter operator << overloads to not template them, so it's easier to overload for pointer types 2009-11-17 20:21:22 +00:00
Jesse Beder
3307f0941c Refactored the traits a bit, and added displaying the key to string and numeric key not found errors 2009-11-12 17:00:12 +00:00
Jesse Beder
54b68230ae Small bug from switching static initialized regexes to lazy ones 2009-11-12 05:45:47 +00:00
Jesse Beder
32491166ac Replaced conversion macros with SFINAE 2009-11-10 21:23:52 +00:00
Jesse Beder
6f94f954bb Overloaded more integral types for emitting 2009-11-06 03:24:12 +00:00
Jesse Beder
90fd24d149 Fixed the return value of the integral conversion functions, and also unset the dec flag so it reads other bases (just a temporary fix, since we're officially supposed to read binary too) 2009-11-06 03:13:54 +00:00
Jesse Beder
9a21a3ec8d Switched the Exp:: regexes to functions that lazily evaluate their regexes 2009-11-04 22:56:59 +00:00
Jesse Beder
3779e4255d Fixed silly bug in node cloning 2009-10-30 20:29:14 +00:00
Jesse Beder
ec62dc547e Added some block scalar tests (with errors) 2009-10-30 18:16:26 +00:00
Jesse Beder
a9b9e1ccec Updated the Visual Studio solution for the new files/renaming. 2009-10-30 04:52:13 +00:00
Jesse Beder
e04be7890a Fixed bug with block maps with null value (the next key was being read as the value) 2009-10-30 01:06:19 +00:00
Jesse Beder
ecb30132e9 Fixed the whitespace tracking when we escape a newline in a double-quoted string 2009-10-29 22:55:50 +00:00
Jesse Beder
52be1ccfb9 Fixed mistake in test 2009-10-29 22:39:53 +00:00
Jesse Beder
3405a6fe01 Refactored the compact map notation, which made it easy to implement explicit keys for compact maps 2009-10-29 22:09:50 +00:00
Jesse Beder
d372729b92 Added case for parsing a compact key: value pair in a flow sequence with a null key 2009-10-29 22:01:01 +00:00
Jesse Beder
fadc2ad39f Implemented adjacent key:value pairs when the key is JSON-like 2009-10-29 21:05:48 +00:00
Jesse Beder
a5607f82a3 Added test 2009-10-29 20:45:20 +00:00
Jesse Beder
f4c683ac22 Added flow collection tests 2009-10-29 20:35:07 +00:00
Jesse Beder
8c9c9d90da Added ability to read compact maps in a flow sequence 2009-10-29 19:41:46 +00:00
Jesse Beder
a372bfdc60 Merged r295:305 from the tags branch to the trunk 2009-10-29 15:48:06 +00:00
Jesse Beder
fe57829aca Removed crt stuff (we can do memory leak checking in Linux easier) 2009-10-27 14:55:01 +00:00
Jesse Beder
b5c53d9e3a Removed unused test yaml file 2009-10-27 14:48:01 +00:00
Jesse Beder
f2a2d25ec0 Now actually removed yaml-reader 2009-10-27 14:47:08 +00:00
Jesse Beder
a706ffaf62 Reverted yaml-reader name change 2009-10-27 14:45:14 +00:00
Jesse Beder
8f48e693fe Renamed yaml-reader test (try 2) 2009-10-27 14:39:48 +00:00
Jesse Beder
a0bf12e7a1 Renamed yaml-reader test 2009-10-27 14:38:53 +00:00
Jesse Beder
2314c04d5d Tagged version 0.2.4 2009-10-25 20:27:31 +00:00
67 changed files with 2477 additions and 522 deletions

View File

@@ -10,17 +10,22 @@ if(IPHONE)
endif(IPHONE) endif(IPHONE)
if(CMAKE_COMPILER_IS_GNUCC) if(CMAKE_COMPILER_IS_GNUCC)
set(CMAKE_CXX_FLAGS "-O2 -Wall -pedantic -Wextra ${CMAKE_CXX_FLAGS}") set(CMAKE_CXX_FLAGS "-O2 -Wall -Wextra -pedantic -Wno-long-long ${CMAKE_CXX_FLAGS}")
endif(CMAKE_COMPILER_IS_GNUCC) endif(CMAKE_COMPILER_IS_GNUCC)
if(MSVC)
set(LIB_TYPE) # I can't figure out how CMake handles Windows shared libraries
set(CMAKE_CXX_FLAGS "/W3 /wd4127 /wd4355 /D_SCL_SECURE_NO_WARNINGS ${CMAKE_CXX_FLAGS}")
endif(MSVC)
set(YAML_CPP_VERSION_MAJOR "0") set(YAML_CPP_VERSION_MAJOR "0")
set(YAML_CPP_VERSION_MINOR "2") set(YAML_CPP_VERSION_MINOR "2")
set(YAML_CPP_VERSION_PATCH "3") set(YAML_CPP_VERSION_PATCH "4")
set(YAML_CPP_VERSION "${YAML_CPP_VERSION_MAJOR}.${YAML_CPP_VERSION_MINOR}.${YAML_CPP_VERSION_PATCH}") set(YAML_CPP_VERSION "${YAML_CPP_VERSION_MAJOR}.${YAML_CPP_VERSION_MINOR}.${YAML_CPP_VERSION_PATCH}")
enable_testing() enable_testing()
option(YAML_CPP_BUILD_TOOLS "Enables or disables yaml-reader and parse tools" true) option(YAML_CPP_BUILD_TOOLS "Enables or disables testing and parse tools" true)
if(WIN32) if(WIN32)
set(_library_dir bin) # .dll are in PATH, like executables set(_library_dir bin) # .dll are in PATH, like executables
@@ -67,6 +72,6 @@ if(UNIX)
endif(UNIX) endif(UNIX)
if(YAML_CPP_BUILD_TOOLS) if(YAML_CPP_BUILD_TOOLS)
add_subdirectory (yaml-reader) add_subdirectory (test)
add_subdirectory (util) add_subdirectory (util)
endif(YAML_CPP_BUILD_TOOLS) endif(YAML_CPP_BUILD_TOOLS)

View File

@@ -5,6 +5,7 @@
#include "null.h" #include "null.h"
#include "traits.h"
#include <string> #include <string>
#include <sstream> #include <sstream>
@@ -18,26 +19,13 @@ namespace YAML
bool Convert(const std::string& input, bool& output); bool Convert(const std::string& input, bool& output);
bool Convert(const std::string& input, _Null& output); bool Convert(const std::string& input, _Null& output);
#define YAML_MAKE_STREAM_CONVERT(type) \ template <typename T>
inline bool Convert(const std::string& input, type& output) { \ inline bool Convert(const std::string& input, T& output, typename enable_if<is_numeric<T> >::type * = 0) {
std::stringstream stream(input); \ std::stringstream stream(input);
stream >> output; \ stream.unsetf(std::ios::dec);
return !stream.fail(); \ stream >> output;
return !!stream;
} }
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 #endif // CONVERSION_H_62B23520_7C8E_11DE_8A39_0800200C9A66

View File

@@ -1,17 +0,0 @@
#pragma once
#ifndef CRT_H_62B23520_7C8E_11DE_8A39_0800200C9A66
#define CRT_H_62B23520_7C8E_11DE_8A39_0800200C9A66
// for detecting memory leaks
#ifdef _DEBUG
#define _CRTDBG_MAP_ALLOC
#include <stdlib.h>
#include <crtdbg.h>
#endif // _DEBUG
#endif // CRT_H_62B23520_7C8E_11DE_8A39_0800200C9A66

View File

@@ -9,6 +9,7 @@
#include "null.h" #include "null.h"
#include <memory> #include <memory>
#include <string> #include <string>
#include <sstream>
namespace YAML namespace YAML
{ {
@@ -45,16 +46,23 @@ namespace YAML
// overloads of write // overloads of write
Emitter& Write(const std::string& str); Emitter& Write(const std::string& str);
Emitter& Write(const char *str);
Emitter& Write(int i);
Emitter& Write(bool b); Emitter& Write(bool b);
Emitter& Write(float f);
Emitter& Write(double d);
Emitter& Write(const _Alias& alias); Emitter& Write(const _Alias& alias);
Emitter& Write(const _Anchor& anchor); Emitter& Write(const _Anchor& anchor);
Emitter& Write(const _Tag& tag);
Emitter& Write(const _Comment& comment); Emitter& Write(const _Comment& comment);
Emitter& Write(const _Null& null); Emitter& Write(const _Null& null);
template <typename T>
Emitter& WriteIntegralType(T value);
template <typename T>
Emitter& WriteStreamable(T value);
private:
void PreWriteIntegralType(std::stringstream& str);
void PostWriteIntegralType(const std::stringstream& str);
private: private:
enum ATOMIC_TYPE { AT_SCALAR, AT_SEQ, AT_BLOCK_SEQ, AT_FLOW_SEQ, AT_MAP, AT_BLOCK_MAP, AT_FLOW_MAP }; enum ATOMIC_TYPE { AT_SCALAR, AT_SEQ, AT_BLOCK_SEQ, AT_FLOW_SEQ, AT_MAP, AT_BLOCK_MAP, AT_FLOW_MAP };
@@ -75,18 +83,61 @@ namespace YAML
std::auto_ptr <EmitterState> m_pState; std::auto_ptr <EmitterState> m_pState;
}; };
// overloads of insertion
template <typename T> template <typename T>
inline Emitter& operator << (Emitter& emitter, T v) { inline Emitter& Emitter::WriteIntegralType(T value)
return emitter.Write(v); {
if(!good())
return *this;
std::stringstream str;
PreWriteIntegralType(str);
str << value;
PostWriteIntegralType(str);
return *this;
} }
template <> template <typename T>
inline Emitter& Emitter::WriteStreamable(T value)
{
if(!good())
return *this;
PreAtomicWrite();
EmitSeparationIfNecessary();
std::stringstream str;
str << value;
m_stream << str.str();
PostAtomicWrite();
return *this;
}
// overloads of insertion
inline Emitter& operator << (Emitter& emitter, const std::string& v) { return emitter.Write(v); }
inline Emitter& operator << (Emitter& emitter, bool v) { return emitter.Write(v); }
inline Emitter& operator << (Emitter& emitter, const _Alias& v) { return emitter.Write(v); }
inline Emitter& operator << (Emitter& emitter, const _Anchor& v) { return emitter.Write(v); }
inline Emitter& operator << (Emitter& emitter, const _Tag& v) { return emitter.Write(v); }
inline Emitter& operator << (Emitter& emitter, const _Comment& v) { return emitter.Write(v); }
inline Emitter& operator << (Emitter& emitter, const _Null& v) { return emitter.Write(v); }
inline Emitter& operator << (Emitter& emitter, const char *v) { return emitter.Write(std::string(v)); }
inline Emitter& operator << (Emitter& emitter, int v) { return emitter.WriteIntegralType(v); }
inline Emitter& operator << (Emitter& emitter, unsigned int v) { return emitter.WriteIntegralType(v); }
inline Emitter& operator << (Emitter& emitter, short v) { return emitter.WriteIntegralType(v); }
inline Emitter& operator << (Emitter& emitter, unsigned short v) { return emitter.WriteIntegralType(v); }
inline Emitter& operator << (Emitter& emitter, long v) { return emitter.WriteIntegralType(v); }
inline Emitter& operator << (Emitter& emitter, unsigned long v) { return emitter.WriteIntegralType(v); }
inline Emitter& operator << (Emitter& emitter, float v) { return emitter.WriteStreamable(v); }
inline Emitter& operator << (Emitter& emitter, double v) { return emitter.WriteStreamable(v); }
inline Emitter& operator << (Emitter& emitter, EMITTER_MANIP value) { inline Emitter& operator << (Emitter& emitter, EMITTER_MANIP value) {
return emitter.SetLocalValue(value); return emitter.SetLocalValue(value);
} }
template <>
inline Emitter& operator << (Emitter& emitter, _Indent indent) { inline Emitter& operator << (Emitter& emitter, _Indent indent) {
return emitter.SetLocalIndent(indent); return emitter.SetLocalIndent(indent);
} }

View File

@@ -81,6 +81,16 @@ namespace YAML
return _Anchor(content); return _Anchor(content);
} }
struct _Tag {
_Tag(const std::string& content_): content(content_), verbatim(true) {}
std::string content;
bool verbatim;
};
inline _Tag VerbatimTag(const std::string& content) {
return _Tag(content);
}
struct _Comment { struct _Comment {
_Comment(const std::string& content_): content(content_) {} _Comment(const std::string& content_): content(content_) {}
std::string content; std::string content;

View File

@@ -5,6 +5,7 @@
#include "mark.h" #include "mark.h"
#include "traits.h"
#include <exception> #include <exception>
#include <string> #include <string>
#include <sstream> #include <sstream>
@@ -17,7 +18,12 @@ namespace YAML
const std::string YAML_DIRECTIVE_ARGS = "YAML directives must have exactly one argument"; const std::string YAML_DIRECTIVE_ARGS = "YAML directives must have exactly one argument";
const std::string YAML_VERSION = "bad YAML version: "; const std::string YAML_VERSION = "bad YAML version: ";
const std::string YAML_MAJOR_VERSION = "YAML major version too large"; const std::string YAML_MAJOR_VERSION = "YAML major version too large";
const std::string REPEATED_YAML_DIRECTIVE= "repeated YAML directive";
const std::string TAG_DIRECTIVE_ARGS = "TAG directives must have exactly two arguments"; const std::string TAG_DIRECTIVE_ARGS = "TAG directives must have exactly two arguments";
const std::string REPEATED_TAG_DIRECTIVE = "repeated TAG directive";
const std::string CHAR_IN_TAG_HANDLE = "illegal character found while scanning tag handle";
const std::string TAG_WITH_NO_SUFFIX = "tag handle with no suffix";
const std::string END_OF_VERBATIM_TAG = "end of verbatim tag not found";
const std::string END_OF_MAP = "end of map not found"; const std::string END_OF_MAP = "end of map not found";
const std::string END_OF_MAP_FLOW = "end of map flow not found"; const std::string END_OF_MAP_FLOW = "end of map flow not found";
const std::string END_OF_SEQ = "end of sequence not found"; const std::string END_OF_SEQ = "end of sequence not found";
@@ -57,10 +63,27 @@ namespace YAML
const std::string SINGLE_QUOTED_CHAR = "invalid character in single-quoted string"; const std::string SINGLE_QUOTED_CHAR = "invalid character in single-quoted string";
const std::string INVALID_ANCHOR = "invalid anchor"; const std::string INVALID_ANCHOR = "invalid anchor";
const std::string INVALID_ALIAS = "invalid alias"; const std::string INVALID_ALIAS = "invalid alias";
const std::string INVALID_TAG = "invalid tag";
const std::string EXPECTED_KEY_TOKEN = "expected key token"; const std::string EXPECTED_KEY_TOKEN = "expected key token";
const std::string EXPECTED_VALUE_TOKEN = "expected value token"; const std::string EXPECTED_VALUE_TOKEN = "expected value token";
const std::string UNEXPECTED_KEY_TOKEN = "unexpected key token"; const std::string UNEXPECTED_KEY_TOKEN = "unexpected key token";
const std::string UNEXPECTED_VALUE_TOKEN = "unexpected value token"; const std::string UNEXPECTED_VALUE_TOKEN = "unexpected value token";
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) {
return KEY_NOT_FOUND + ": " + key;
}
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();
}
} }
class Exception: public std::exception { class Exception: public std::exception {
@@ -102,22 +125,23 @@ namespace YAML
class KeyNotFound: public RepresentationException { class KeyNotFound: public RepresentationException {
public: public:
KeyNotFound(const Mark& mark_) template <typename T>
: RepresentationException(mark_, ErrorMsg::KEY_NOT_FOUND) {} KeyNotFound(const Mark& mark_, const T& key_)
: RepresentationException(mark_, ErrorMsg::KEY_NOT_FOUND_WITH_KEY(key_)) {}
}; };
template <typename T> template <typename T>
class TypedKeyNotFound: public KeyNotFound { class TypedKeyNotFound: public KeyNotFound {
public: public:
TypedKeyNotFound(const Mark& mark_, const T& key_) TypedKeyNotFound(const Mark& mark_, const T& key_)
: KeyNotFound(mark_), key(key_) {} : KeyNotFound(mark_, key_), key(key_) {}
~TypedKeyNotFound() throw() {} virtual ~TypedKeyNotFound() throw() {}
T key; T key;
}; };
template <typename T> template <typename T>
TypedKeyNotFound <T> MakeTypedKeyNotFound(const Mark& mark, const T& key) { inline TypedKeyNotFound <T> MakeTypedKeyNotFound(const Mark& mark, const T& key) {
return TypedKeyNotFound <T> (mark, key); return TypedKeyNotFound <T> (mark, key);
} }

View File

@@ -9,7 +9,6 @@
#include "iterator.h" #include "iterator.h"
#include "mark.h" #include "mark.h"
#include "noncopyable.h" #include "noncopyable.h"
#include "parserstate.h"
#include <iostream> #include <iostream>
#include <string> #include <string>
#include <vector> #include <vector>
@@ -21,6 +20,7 @@ namespace YAML
class Content; class Content;
class Scanner; class Scanner;
class Emitter; class Emitter;
struct ParserState;
enum CONTENT_TYPE { CT_NONE, CT_SCALAR, CT_SEQUENCE, CT_MAP }; enum CONTENT_TYPE { CT_NONE, CT_SCALAR, CT_SEQUENCE, CT_MAP };
@@ -32,7 +32,7 @@ namespace YAML
void Clear(); void Clear();
std::auto_ptr<Node> Clone() const; std::auto_ptr<Node> Clone() const;
void Parse(Scanner *pScanner, const ParserState& state); void Parse(Scanner *pScanner, ParserState& state);
CONTENT_TYPE GetType() const; CONTENT_TYPE GetType() const;
@@ -76,6 +76,9 @@ namespace YAML
bool IsAlias() const { return m_alias; } bool IsAlias() const { return m_alias; }
bool IsReferenced() const { return m_referenced; } bool IsReferenced() const { return m_referenced; }
// for tags
const std::string GetTag() const { return IsAlias() ? m_pIdentity->GetTag() : m_tag; }
// emitting // emitting
friend Emitter& operator << (Emitter& out, const Node& node); friend Emitter& operator << (Emitter& out, const Node& node);
@@ -99,10 +102,10 @@ namespace YAML
Node(const Mark& mark, const std::string& anchor, const std::string& tag, const Content *pContent); Node(const Mark& mark, const std::string& anchor, const std::string& tag, const Content *pContent);
// helpers for parsing // helpers for parsing
void ParseHeader(Scanner *pScanner, const ParserState& state); void ParseHeader(Scanner *pScanner, ParserState& state);
void ParseTag(Scanner *pScanner, const ParserState& state); void ParseTag(Scanner *pScanner, ParserState& state);
void ParseAnchor(Scanner *pScanner, const ParserState& state); void ParseAnchor(Scanner *pScanner, ParserState& state);
void ParseAlias(Scanner *pScanner, const ParserState& state); void ParseAlias(Scanner *pScanner, ParserState& state);
private: private:
Mark m_mark; Mark m_mark;

View File

@@ -52,9 +52,10 @@ namespace YAML
int operator,(flag, flag); int operator,(flag, flag);
template<typename T> template<typename T>
void operator,(flag, T const&); char operator,(flag, T const&);
char operator,(int, flag); char operator,(int, flag);
int operator,(char, flag);
} }
template <typename T> template <typename T>

View File

@@ -5,7 +5,6 @@
#include "node.h" #include "node.h"
#include "parserstate.h"
#include "noncopyable.h" #include "noncopyable.h"
#include <ios> #include <ios>
#include <string> #include <string>
@@ -16,6 +15,7 @@
namespace YAML namespace YAML
{ {
class Scanner; class Scanner;
struct ParserState;
struct Token; struct Token;
class Parser: private noncopyable class Parser: private noncopyable
@@ -33,13 +33,13 @@ namespace YAML
private: private:
void ParseDirectives(); void ParseDirectives();
void HandleDirective(Token *pToken); void HandleDirective(const Token& token);
void HandleYamlDirective(Token *pToken); void HandleYamlDirective(const Token& token);
void HandleTagDirective(Token *pToken); void HandleTagDirective(const Token& token);
private: private:
std::auto_ptr<Scanner> m_pScanner; std::auto_ptr<Scanner> m_pScanner;
ParserState m_state; std::auto_ptr<ParserState> m_pState;
}; };
} }

View File

@@ -1,26 +0,0 @@
#pragma once
#ifndef PARSERSTATE_H_62B23520_7C8E_11DE_8A39_0800200C9A66
#define PARSERSTATE_H_62B23520_7C8E_11DE_8A39_0800200C9A66
#include <string>
#include <map>
namespace YAML
{
struct Version {
int major, minor;
};
struct ParserState
{
Version version;
std::map <std::string, std::string> tags;
void Reset();
std::string TranslateTag(const std::string& handle) const;
};
}
#endif // PARSERSTATE_H_62B23520_7C8E_11DE_8A39_0800200C9A66

36
include/stlnode.h Normal file
View File

@@ -0,0 +1,36 @@
#pragma once
#ifndef STLNODE_H_62B23520_7C8E_11DE_8A39_0800200C9A66
#define STLNODE_H_62B23520_7C8E_11DE_8A39_0800200C9A66
#include <vector>
#include <map>
namespace YAML
{
template <typename T>
void operator >> (const Node& node, std::vector<T>& v)
{
v.clear();
v.resize(node.size());
for(unsigned i=0;i<node.size();++i)
node[i] >> v[i];
}
template <typename K, typename V>
void operator >> (const Node& node, std::map<K, V>& m)
{
m.clear();
for(Iterator it=node.begin();it!=node.end();++it) {
K k;
V v;
it.first() >> k;
it.second() >> v;
m[k] = v;
}
}
}
#endif // STLNODE_H_62B23520_7C8E_11DE_8A39_0800200C9A66

50
include/traits.h Normal file
View File

@@ -0,0 +1,50 @@
#pragma once
#ifndef TRAITS_H_62B23520_7C8E_11DE_8A39_0800200C9A66
#define TRAITS_H_62B23520_7C8E_11DE_8A39_0800200C9A66
namespace YAML
{
template <typename>
struct is_numeric { enum { value = false }; };
template <> struct is_numeric <char> { enum { value = true }; };
template <> struct is_numeric <unsigned char> { enum { value = true }; };
template <> struct is_numeric <int> { enum { value = true }; };
template <> struct is_numeric <unsigned int> { enum { value = true }; };
template <> struct is_numeric <long int> { enum { value = true }; };
template <> struct is_numeric <unsigned long int> { enum { value = true }; };
template <> struct is_numeric <short int> { enum { value = true }; };
template <> struct is_numeric <unsigned short int> { enum { value = true }; };
template <> struct is_numeric <long long> { enum { value = true }; };
template <> struct is_numeric <unsigned long long> { enum { value = true }; };
template <> struct is_numeric <float> { enum { value = true }; };
template <> struct is_numeric <double> { enum { value = true }; };
template <> struct is_numeric <long double> { enum { value = true }; };
template <bool, class T = void>
struct enable_if_c {
typedef T type;
};
template <class T>
struct enable_if_c<false, T> {};
template <class Cond, class T = void>
struct enable_if : public enable_if_c<Cond::value, T> {};
template <bool, class T = void>
struct disable_if_c {
typedef T type;
};
template <class T>
struct disable_if_c<true, T> {};
template <class Cond, class T = void>
struct disable_if : public disable_if_c<Cond::value, T> {};
}
#endif // TRAITS_H_62B23520_7C8E_11DE_8A39_0800200C9A66

View File

@@ -4,9 +4,9 @@
#define YAML_H_62B23520_7C8E_11DE_8A39_0800200C9A66 #define YAML_H_62B23520_7C8E_11DE_8A39_0800200C9A66
#include "crt.h"
#include "parser.h" #include "parser.h"
#include "node.h" #include "node.h"
#include "stlnode.h"
#include "iterator.h" #include "iterator.h"
#include "emitter.h" #include "emitter.h"
#include "stlemitter.h" #include "stlemitter.h"

View File

@@ -2,9 +2,9 @@
<VisualStudioProject <VisualStudioProject
ProjectType="Visual C++" ProjectType="Visual C++"
Version="9.00" Version="9.00"
Name="yaml-reader" Name="parse"
ProjectGUID="{E8CC0D8A-D784-4A6B-B78B-ACEA13F9FB0B}" ProjectGUID="{CD007B57-7812-4930-A5E2-6E5E56338814}"
RootNamespace="yamlreader" RootNamespace="parse"
TargetFrameworkVersion="196613" TargetFrameworkVersion="196613"
> >
<Platforms> <Platforms>
@@ -39,13 +39,15 @@
/> />
<Tool <Tool
Name="VCCLCompilerTool" Name="VCCLCompilerTool"
AdditionalOptions="/D_SCL_SECURE_NO_WARNINGS"
Optimization="0" Optimization="0"
AdditionalIncludeDirectories="include" AdditionalIncludeDirectories="include"
MinimalRebuild="true" MinimalRebuild="true"
BasicRuntimeChecks="3" BasicRuntimeChecks="3"
RuntimeLibrary="3" RuntimeLibrary="3"
WarningLevel="3" WarningLevel="3"
DebugInformationFormat="3" DebugInformationFormat="4"
DisableSpecificWarnings="4127;4355"
/> />
<Tool <Tool
Name="VCManagedResourceCompilerTool" Name="VCManagedResourceCompilerTool"
@@ -110,13 +112,15 @@
/> />
<Tool <Tool
Name="VCCLCompilerTool" Name="VCCLCompilerTool"
AdditionalOptions="/D_SCL_SECURE_NO_WARNINGS"
Optimization="2" Optimization="2"
EnableIntrinsicFunctions="true" EnableIntrinsicFunctions="true"
AdditionalIncludeDirectories="include" AdditionalIncludeDirectories="include"
RuntimeLibrary="2" RuntimeLibrary="2"
EnableFunctionLevelLinking="true" EnableFunctionLevelLinking="true"
WarningLevel="4" WarningLevel="3"
DebugInformationFormat="3" DebugInformationFormat="3"
DisableSpecificWarnings="4127;4355"
/> />
<Tool <Tool
Name="VCManagedResourceCompilerTool" Name="VCManagedResourceCompilerTool"
@@ -168,23 +172,7 @@
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}" UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
> >
<File <File
RelativePath=".\yaml-reader\emittertests.cpp" RelativePath=".\util\parse.cpp"
>
</File>
<File
RelativePath=".\yaml-reader\main.cpp"
>
</File>
<File
RelativePath=".\yaml-reader\parsertests.cpp"
>
</File>
<File
RelativePath=".\yaml-reader\spectests.cpp"
>
</File>
<File
RelativePath=".\yaml-reader\tests.cpp"
> >
</File> </File>
</Filter> </Filter>
@@ -193,22 +181,12 @@
Filter="h;hpp;hxx;hm;inl;inc;xsd" Filter="h;hpp;hxx;hm;inl;inc;xsd"
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}" UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
> >
<File </Filter>
RelativePath=".\yaml-reader\emittertests.h" <Filter
Name="Resource Files"
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
> >
</File>
<File
RelativePath=".\yaml-reader\parsertests.h"
>
</File>
<File
RelativePath=".\yaml-reader\spectests.h"
>
</File>
<File
RelativePath=".\yaml-reader\tests.h"
>
</File>
</Filter> </Filter>
</Files> </Files>
<Globals> <Globals>

View File

@@ -1,4 +1,3 @@
#include "crt.h"
#include "aliascontent.h" #include "aliascontent.h"
namespace YAML namespace YAML
@@ -13,7 +12,7 @@ namespace YAML
return 0; // TODO: how to clone an alias? return 0; // TODO: how to clone an alias?
} }
void AliasContent::Parse(Scanner * /*pScanner*/, const ParserState& /*state*/) void AliasContent::Parse(Scanner * /*pScanner*/, ParserState& /*state*/)
{ {
} }

View File

@@ -15,7 +15,7 @@ namespace YAML
virtual Content *Clone() const; virtual Content *Clone() const;
virtual void Parse(Scanner* pScanner, const ParserState& state); virtual void Parse(Scanner* pScanner, ParserState& state);
virtual void Write(Emitter&) const; virtual void Write(Emitter&) const;
virtual bool GetBegin(std::vector <Node *>::const_iterator&) const; virtual bool GetBegin(std::vector <Node *>::const_iterator&) const;

View File

@@ -1,13 +0,0 @@
#include "crt.h"
#include "content.h"
namespace YAML
{
Content::Content()
{
}
Content::~Content()
{
}
}

View File

@@ -23,12 +23,12 @@ namespace YAML
class Content class Content
{ {
public: public:
Content(); Content() {}
virtual ~Content(); virtual ~Content() {}
virtual Content *Clone() const = 0; virtual Content *Clone() const = 0;
virtual void Parse(Scanner *pScanner, const ParserState& state) = 0; virtual void Parse(Scanner *pScanner, ParserState& state) = 0;
virtual void Write(Emitter& out) const = 0; virtual void Write(Emitter& out) const = 0;
virtual bool GetBegin(std::vector <Node *>::const_iterator&) const { return false; } virtual bool GetBegin(std::vector <Node *>::const_iterator&) const { return false; }

View File

@@ -146,6 +146,8 @@ namespace YAML
switch(curState) { switch(curState) {
// document-level // document-level
case ES_WAITING_FOR_DOC: case ES_WAITING_FOR_DOC:
m_stream << "---";
m_pState->RequireSeparation();
m_pState->SwitchState(ES_WRITING_DOC); m_pState->SwitchState(ES_WRITING_DOC);
return true; return true;
case ES_WRITING_DOC: case ES_WRITING_DOC:
@@ -323,7 +325,10 @@ namespace YAML
EMITTER_STATE curState = m_pState->GetCurState(); EMITTER_STATE curState = m_pState->GetCurState();
EMITTER_MANIP flowType = m_pState->GetFlowType(GT_SEQ); EMITTER_MANIP flowType = m_pState->GetFlowType(GT_SEQ);
if(flowType == Block) { if(flowType == Block) {
if(curState == ES_WRITING_BLOCK_SEQ_ENTRY || curState == ES_WRITING_BLOCK_MAP_KEY || curState == ES_WRITING_BLOCK_MAP_VALUE) { if(curState == ES_WRITING_BLOCK_SEQ_ENTRY ||
curState == ES_WRITING_BLOCK_MAP_KEY || curState == ES_WRITING_BLOCK_MAP_VALUE ||
curState == ES_WRITING_DOC
) {
m_stream << "\n"; m_stream << "\n";
m_pState->UnsetSeparation(); m_pState->UnsetSeparation();
} }
@@ -354,8 +359,12 @@ namespace YAML
// to a flow sequence if it is // to a flow sequence if it is
assert(curState == ES_DONE_WITH_BLOCK_SEQ_ENTRY || curState == ES_WAITING_FOR_BLOCK_SEQ_ENTRY); assert(curState == ES_DONE_WITH_BLOCK_SEQ_ENTRY || curState == ES_WAITING_FOR_BLOCK_SEQ_ENTRY);
if(curState == ES_WAITING_FOR_BLOCK_SEQ_ENTRY) { if(curState == ES_WAITING_FOR_BLOCK_SEQ_ENTRY) {
// Note: only one of these will actually output anything for a given situation
EmitSeparationIfNecessary();
unsigned curIndent = m_pState->GetCurIndent(); unsigned curIndent = m_pState->GetCurIndent();
m_stream << IndentTo(curIndent) << "[]"; m_stream << IndentTo(curIndent);
m_stream << "[]";
} }
} else if(flowType == FT_FLOW) { } else if(flowType == FT_FLOW) {
// Note: flow sequences are allowed to be empty // Note: flow sequences are allowed to be empty
@@ -384,7 +393,10 @@ namespace YAML
EMITTER_STATE curState = m_pState->GetCurState(); EMITTER_STATE curState = m_pState->GetCurState();
EMITTER_MANIP flowType = m_pState->GetFlowType(GT_MAP); EMITTER_MANIP flowType = m_pState->GetFlowType(GT_MAP);
if(flowType == Block) { if(flowType == Block) {
if(curState == ES_WRITING_BLOCK_SEQ_ENTRY || curState == ES_WRITING_BLOCK_MAP_KEY || curState == ES_WRITING_BLOCK_MAP_VALUE) { if(curState == ES_WRITING_BLOCK_SEQ_ENTRY ||
curState == ES_WRITING_BLOCK_MAP_KEY || curState == ES_WRITING_BLOCK_MAP_VALUE ||
curState == ES_WRITING_DOC
) {
m_stream << "\n"; m_stream << "\n";
m_pState->UnsetSeparation(); m_pState->UnsetSeparation();
} }
@@ -415,8 +427,11 @@ namespace YAML
// to a flow sequence if it is // to a flow sequence if it is
assert(curState == ES_DONE_WITH_BLOCK_MAP_VALUE || curState == ES_WAITING_FOR_BLOCK_MAP_ENTRY); assert(curState == ES_DONE_WITH_BLOCK_MAP_VALUE || curState == ES_WAITING_FOR_BLOCK_MAP_ENTRY);
if(curState == ES_WAITING_FOR_BLOCK_MAP_ENTRY) { if(curState == ES_WAITING_FOR_BLOCK_MAP_ENTRY) {
// Note: only one of these will actually output anything for a given situation
EmitSeparationIfNecessary();
unsigned curIndent = m_pState->GetCurIndent(); unsigned curIndent = m_pState->GetCurIndent();
m_stream << IndentTo(curIndent) << "{}"; m_stream << IndentTo(curIndent);
m_stream << "{}";
} }
} else if(flowType == FT_FLOW) { } else if(flowType == FT_FLOW) {
// Note: flow maps are allowed to be empty // Note: flow maps are allowed to be empty
@@ -534,24 +549,12 @@ namespace YAML
return *this; return *this;
} }
Emitter& Emitter::Write(const char *str) void Emitter::PreWriteIntegralType(std::stringstream& str)
{ {
if(!good())
return *this;
return Write(std::string(str));
}
Emitter& Emitter::Write(int i)
{
if(!good())
return *this;
PreAtomicWrite(); PreAtomicWrite();
EmitSeparationIfNecessary(); EmitSeparationIfNecessary();
EMITTER_MANIP intFmt = m_pState->GetIntFormat(); EMITTER_MANIP intFmt = m_pState->GetIntFormat();
std::stringstream str;
switch(intFmt) { switch(intFmt) {
case Dec: case Dec:
str << std::dec; str << std::dec;
@@ -565,12 +568,12 @@ namespace YAML
default: default:
assert(false); assert(false);
} }
}
str << i; void Emitter::PostWriteIntegralType(const std::stringstream& str)
{
m_stream << str.str(); m_stream << str.str();
PostAtomicWrite(); PostAtomicWrite();
return *this;
} }
Emitter& Emitter::Write(bool b) Emitter& Emitter::Write(bool b)
@@ -612,38 +615,6 @@ namespace YAML
return *this; return *this;
} }
Emitter& Emitter::Write(float f)
{
if(!good())
return *this;
PreAtomicWrite();
EmitSeparationIfNecessary();
std::stringstream str;
str << f;
m_stream << str.str();
PostAtomicWrite();
return *this;
}
Emitter& Emitter::Write(double d)
{
if(!good())
return *this;
PreAtomicWrite();
EmitSeparationIfNecessary();
std::stringstream str;
str << d;
m_stream << str.str();
PostAtomicWrite();
return *this;
}
Emitter& Emitter::Write(const _Alias& alias) Emitter& Emitter::Write(const _Alias& alias)
{ {
if(!good()) if(!good())
@@ -675,6 +646,22 @@ namespace YAML
return *this; return *this;
} }
Emitter& Emitter::Write(const _Tag& tag)
{
if(!good())
return *this;
PreAtomicWrite();
EmitSeparationIfNecessary();
if(!Utils::WriteTag(m_stream, tag.content)) {
m_pState->SetError(ErrorMsg::INVALID_TAG);
return *this;
}
m_pState->RequireSeparation();
// Note: no PostAtomicWrite() because we need another value for this node
return *this;
}
Emitter& Emitter::Write(const _Comment& comment) Emitter& Emitter::Write(const _Comment& comment)
{ {
if(!good()) if(!good())

View File

@@ -129,7 +129,7 @@ namespace YAML
bool IsValidPlainScalar(const std::string& str, bool inFlow, bool allowOnlyAscii) { bool IsValidPlainScalar(const std::string& str, bool inFlow, bool allowOnlyAscii) {
// first check the start // first check the start
const RegEx& start = (inFlow ? Exp::PlainScalarInFlow : Exp::PlainScalar); const RegEx& start = (inFlow ? Exp::PlainScalarInFlow() : Exp::PlainScalar());
if(!start.Matches(str)) if(!start.Matches(str))
return false; return false;
@@ -138,12 +138,12 @@ namespace YAML
return false; return false;
// then check until something is disallowed // then check until something is disallowed
const RegEx& disallowed = (inFlow ? Exp::EndScalarInFlow : Exp::EndScalar) const RegEx& disallowed = (inFlow ? Exp::EndScalarInFlow() : Exp::EndScalar())
|| (Exp::BlankOrBreak + Exp::Comment) || (Exp::BlankOrBreak() + Exp::Comment())
|| Exp::NotPrintable || Exp::NotPrintable()
|| Exp::Utf8_ByteOrderMark || Exp::Utf8_ByteOrderMark()
|| Exp::Break || Exp::Break()
|| Exp::Tab; || Exp::Tab();
StringCharSource buffer(str.c_str(), str.size()); StringCharSource buffer(str.c_str(), str.size());
while(buffer) { while(buffer) {
if(disallowed.Matches(buffer)) if(disallowed.Matches(buffer))
@@ -293,6 +293,24 @@ namespace YAML
out << "&"; out << "&";
return WriteAliasName(out, str); return WriteAliasName(out, str);
} }
bool WriteTag(ostream& out, const std::string& str)
{
out << "!<";
StringCharSource buffer(str.c_str(), str.size());
while(buffer) {
int n = Exp::URI().Match(buffer);
if(n <= 0)
return false;
while(--n >= 0) {
out << buffer[0];
++buffer;
}
}
out << ">";
return true;
}
} }
} }

View File

@@ -18,6 +18,7 @@ namespace YAML
bool WriteComment(ostream& out, const std::string& str, int postCommentIndent); bool WriteComment(ostream& out, const std::string& str, int postCommentIndent);
bool WriteAlias(ostream& out, const std::string& str); bool WriteAlias(ostream& out, const std::string& str);
bool WriteAnchor(ostream& out, const std::string& str); bool WriteAnchor(ostream& out, const std::string& str);
bool WriteTag(ostream& out, const std::string& str);
} }
} }

View File

@@ -1,4 +1,3 @@
#include "crt.h"
#include "exp.h" #include "exp.h"
#include "exceptions.h" #include "exceptions.h"
#include <sstream> #include <sstream>

163
src/exp.h
View File

@@ -17,50 +17,153 @@ namespace YAML
namespace Exp namespace Exp
{ {
// misc // misc
const RegEx Space = RegEx(' '); inline const RegEx& Space() {
const RegEx Tab = RegEx('\t'); static const RegEx e = RegEx(' ');
const RegEx Blank = Space || Tab; return e;
const RegEx Break = RegEx('\n') || RegEx("\r\n"); }
const RegEx BlankOrBreak = Blank || Break; inline const RegEx& Tab() {
const RegEx Digit = RegEx('0', '9'); static const RegEx e = RegEx('\t');
const RegEx Alpha = RegEx('a', 'z') || RegEx('A', 'Z'); return e;
const RegEx AlphaNumeric = Alpha || Digit; }
const RegEx Hex = Digit || RegEx('A', 'F') || RegEx('a', 'f'); inline const RegEx& Blank() {
static const RegEx e = Space() || Tab();
return e;
}
inline const RegEx& Break() {
static const RegEx e = RegEx('\n') || RegEx("\r\n");
return e;
}
inline const RegEx& BlankOrBreak() {
static const RegEx e = Blank() || Break();
return e;
}
inline const RegEx& Digit() {
static const RegEx e = RegEx('0', '9');
return e;
}
inline const RegEx& Alpha() {
static const RegEx e = RegEx('a', 'z') || RegEx('A', 'Z');
return e;
}
inline const RegEx& AlphaNumeric() {
static const RegEx e = Alpha() || Digit();
return e;
}
inline const RegEx& Word() {
static const RegEx e = AlphaNumeric() || RegEx('-');
return e;
}
inline const RegEx& Hex() {
static const RegEx e = Digit() || RegEx('A', 'F') || RegEx('a', 'f');
return e;
}
// Valid Unicode code points that are not part of c-printable (YAML 1.2, sec. 5.1) // Valid Unicode code points that are not part of c-printable (YAML 1.2, sec. 5.1)
const RegEx NotPrintable = RegEx(0) || inline const RegEx& NotPrintable() {
static const RegEx e = RegEx(0) ||
RegEx("\x01\x02\x03\x04\x05\x06\x07\x08\x0B\x0C\x7F", REGEX_OR) || RegEx("\x01\x02\x03\x04\x05\x06\x07\x08\x0B\x0C\x7F", REGEX_OR) ||
RegEx(0x0E, 0x1F) || RegEx(0x0E, 0x1F) ||
(RegEx('\xC2') + (RegEx('\x80', '\x84') || RegEx('\x86', '\x9F'))); (RegEx('\xC2') + (RegEx('\x80', '\x84') || RegEx('\x86', '\x9F')));
const RegEx Utf8_ByteOrderMark = RegEx("\xEF\xBB\xBF"); return e;
}
inline const RegEx& Utf8_ByteOrderMark() {
static const RegEx e = RegEx("\xEF\xBB\xBF");
return e;
}
// actual tags // actual tags
const RegEx DocStart = RegEx("---") + (BlankOrBreak || RegEx()); inline const RegEx& DocStart() {
const RegEx DocEnd = RegEx("...") + (BlankOrBreak || RegEx()); static const RegEx e = RegEx("---") + (BlankOrBreak() || RegEx());
const RegEx DocIndicator = DocStart || DocEnd; return e;
const RegEx BlockEntry = RegEx('-') + (BlankOrBreak || RegEx()); }
const RegEx Key = RegEx('?'), inline const RegEx& DocEnd() {
KeyInFlow = RegEx('?') + BlankOrBreak; static const RegEx e = RegEx("...") + (BlankOrBreak() || RegEx());
const RegEx Value = RegEx(':') + (BlankOrBreak || RegEx()), return e;
ValueInFlow = RegEx(':') + (BlankOrBreak || RegEx(",}", REGEX_OR)); }
const RegEx Comment = RegEx('#'); inline const RegEx& DocIndicator() {
const RegEx AnchorEnd = RegEx("?:,]}%@`", REGEX_OR) || BlankOrBreak; static const RegEx e = DocStart() || DocEnd();
return e;
}
inline const RegEx& BlockEntry() {
static const RegEx e = RegEx('-') + (BlankOrBreak() || RegEx());
return e;
}
inline const RegEx& Key() {
static const RegEx e = RegEx('?');
return e;
}
inline const RegEx& KeyInFlow() {
static const RegEx e = RegEx('?') + BlankOrBreak();
return e;
}
inline const RegEx& Value() {
static const RegEx e = RegEx(':') + (BlankOrBreak() || RegEx());
return e;
}
inline const RegEx& ValueInFlow() {
static const RegEx e = RegEx(':') + (BlankOrBreak() || RegEx(",}", REGEX_OR));
return e;
}
inline const RegEx& ValueInJSONFlow() {
static const RegEx e = RegEx(':');
return e;
}
inline const RegEx Comment() {
static const RegEx e = RegEx('#');
return e;
}
inline const RegEx& AnchorEnd() {
static const RegEx e = RegEx("?:,]}%@`", REGEX_OR) || BlankOrBreak();
return e;
}
inline const RegEx& URI() {
static const RegEx e = Word() || RegEx("#;/?:@&=+$,_.!~*'()[]", REGEX_OR) || (RegEx('%') + Hex() + Hex());
return e;
}
inline const RegEx& Tag() {
static const RegEx e = Word() || RegEx("#;/?:@&=+$_.~*'", REGEX_OR) || (RegEx('%') + Hex() + Hex());
return e;
}
// Plain scalar rules: // Plain scalar rules:
// . Cannot start with a blank. // . Cannot start with a blank.
// . Can never start with any of , [ ] { } # & * ! | > \' \" % @ ` // . Can never start with any of , [ ] { } # & * ! | > \' \" % @ `
// . In the block context - ? : must be not be followed with a space. // . In the block context - ? : must be not be followed with a space.
// . In the flow context ? is illegal and : and - must not be followed with a space. // . In the flow context ? is illegal and : and - must not be followed with a space.
const RegEx PlainScalar = !(BlankOrBreak || RegEx(",[]{}#&*!|>\'\"%@`", REGEX_OR) || (RegEx("-?:", REGEX_OR) + Blank)), inline const RegEx& PlainScalar() {
PlainScalarInFlow = !(BlankOrBreak || RegEx("?,[]{}#&*!|>\'\"%@`", REGEX_OR) || (RegEx("-:", REGEX_OR) + Blank)); static const RegEx e = !(BlankOrBreak() || RegEx(",[]{}#&*!|>\'\"%@`", REGEX_OR) || (RegEx("-?:", REGEX_OR) + Blank()));
const RegEx EndScalar = RegEx(':') + (BlankOrBreak || RegEx()), return e;
EndScalarInFlow = (RegEx(':') + (BlankOrBreak || RegEx(",]}", REGEX_OR))) || RegEx(",?[]{}", REGEX_OR); }
inline const RegEx& PlainScalarInFlow() {
static const RegEx e = !(BlankOrBreak() || RegEx("?,[]{}#&*!|>\'\"%@`", REGEX_OR) || (RegEx("-:", REGEX_OR) + Blank()));
return e;
}
inline const RegEx& EndScalar() {
static const RegEx e = RegEx(':') + (BlankOrBreak() || RegEx());
return e;
}
inline const RegEx& EndScalarInFlow() {
static const RegEx e = (RegEx(':') + (BlankOrBreak() || RegEx(",]}", REGEX_OR))) || RegEx(",?[]{}", REGEX_OR);
return e;
}
const RegEx EscSingleQuote = RegEx("\'\'"); inline const RegEx& EscSingleQuote() {
const RegEx EscBreak = RegEx('\\') + Break; static const RegEx e = RegEx("\'\'");
return e;
}
inline const RegEx& EscBreak() {
static const RegEx e = RegEx('\\') + Break();
return e;
}
const RegEx ChompIndicator = RegEx("+-", REGEX_OR); inline const RegEx& ChompIndicator() {
const RegEx Chomp = (ChompIndicator + Digit) || (Digit + ChompIndicator) || ChompIndicator || Digit; static const RegEx e = RegEx("+-", REGEX_OR);
return e;
}
inline const RegEx& Chomp() {
static const RegEx e = (ChompIndicator() + Digit()) || (Digit() + ChompIndicator()) || ChompIndicator() || Digit();
return e;
}
// and some functions // and some functions
std::string Escape(Stream& in); std::string Escape(Stream& in);
@@ -79,6 +182,8 @@ namespace YAML
const char Tag = '!'; const char Tag = '!';
const char LiteralScalar = '|'; const char LiteralScalar = '|';
const char FoldedScalar = '>'; const char FoldedScalar = '>';
const char VerbatimTagStart = '<';
const char VerbatimTagEnd = '>';
} }
} }

View File

@@ -1,4 +1,3 @@
#include "crt.h"
#include "node.h" #include "node.h"
#include "exceptions.h" #include "exceptions.h"
#include "iterpriv.h" #include "iterpriv.h"

View File

@@ -1,11 +1,9 @@
#include "crt.h"
#include "map.h" #include "map.h"
#include "node.h" #include "node.h"
#include "scanner.h" #include "scanner.h"
#include "token.h" #include "token.h"
#include "exceptions.h" #include "exceptions.h"
#include "emitter.h" #include "emitter.h"
#include <memory>
namespace YAML namespace YAML
{ {
@@ -18,7 +16,7 @@ namespace YAML
for(node_map::const_iterator it=data.begin();it!=data.end();++it) { for(node_map::const_iterator it=data.begin();it!=data.end();++it) {
std::auto_ptr<Node> pKey = it->first->Clone(); std::auto_ptr<Node> pKey = it->first->Clone();
std::auto_ptr<Node> pValue = it->second->Clone(); std::auto_ptr<Node> pValue = it->second->Clone();
m_data[pKey.release()] = pValue.release(); AddEntry(pKey, pValue);
} }
} }
@@ -58,7 +56,7 @@ namespace YAML
return m_data.size(); return m_data.size();
} }
void Map::Parse(Scanner *pScanner, const ParserState& state) void Map::Parse(Scanner *pScanner, ParserState& state)
{ {
Clear(); Clear();
@@ -66,14 +64,17 @@ namespace YAML
switch(pScanner->peek().type) { switch(pScanner->peek().type) {
case Token::BLOCK_MAP_START: ParseBlock(pScanner, state); break; case Token::BLOCK_MAP_START: ParseBlock(pScanner, state); break;
case Token::FLOW_MAP_START: ParseFlow(pScanner, state); break; case Token::FLOW_MAP_START: ParseFlow(pScanner, state); break;
case Token::KEY: ParseCompact(pScanner, state); break;
case Token::VALUE: ParseCompactWithNoKey(pScanner, state); break;
default: break; default: break;
} }
} }
void Map::ParseBlock(Scanner *pScanner, const ParserState& state) void Map::ParseBlock(Scanner *pScanner, ParserState& state)
{ {
// eat start token // eat start token
pScanner->pop(); pScanner->pop();
state.PushCollectionType(ParserState::BLOCK_MAP);
while(1) { while(1) {
if(pScanner->empty()) if(pScanner->empty())
@@ -102,15 +103,17 @@ namespace YAML
pValue->Parse(pScanner, state); pValue->Parse(pScanner, state);
} }
// assign the map with the actual pointers AddEntry(pKey, pValue);
m_data[pKey.release()] = pValue.release();
}
} }
void Map::ParseFlow(Scanner *pScanner, const ParserState& state) state.PopCollectionType(ParserState::BLOCK_MAP);
}
void Map::ParseFlow(Scanner *pScanner, ParserState& state)
{ {
// eat start token // eat start token
pScanner->pop(); pScanner->pop();
state.PushCollectionType(ParserState::FLOW_MAP);
while(1) { while(1) {
if(pScanner->empty()) if(pScanner->empty())
@@ -144,9 +147,55 @@ namespace YAML
else if(nextToken.type != Token::FLOW_MAP_END) else if(nextToken.type != Token::FLOW_MAP_END)
throw ParserException(nextToken.mark, ErrorMsg::END_OF_MAP_FLOW); throw ParserException(nextToken.mark, ErrorMsg::END_OF_MAP_FLOW);
// assign the map with the actual pointers AddEntry(pKey, pValue);
m_data[pKey.release()] = pValue.release();
} }
state.PopCollectionType(ParserState::FLOW_MAP);
}
// ParseCompact
// . Single "key: value" pair in a flow sequence
void Map::ParseCompact(Scanner *pScanner, ParserState& state)
{
state.PushCollectionType(ParserState::COMPACT_MAP);
std::auto_ptr <Node> pKey(new Node), pValue(new Node);
// grab 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);
}
AddEntry(pKey, pValue);
state.PopCollectionType(ParserState::COMPACT_MAP);
}
// ParseCompactWithNoKey
// . Single ": value" pair in a flow sequence
void Map::ParseCompactWithNoKey(Scanner *pScanner, ParserState& state)
{
state.PushCollectionType(ParserState::COMPACT_MAP);
std::auto_ptr <Node> pKey(new Node), pValue(new Node);
// grab value
pScanner->pop();
pValue->Parse(pScanner, state);
AddEntry(pKey, pValue);
state.PopCollectionType(ParserState::COMPACT_MAP);
}
void Map::AddEntry(std::auto_ptr<Node> pKey, std::auto_ptr<Node> pValue)
{
node_map::const_iterator it = m_data.find(pKey.get());
if(it != m_data.end())
return;
m_data[pKey.release()] = pValue.release();
} }
void Map::Write(Emitter& out) const void Map::Write(Emitter& out) const

View File

@@ -6,6 +6,7 @@
#include "content.h" #include "content.h"
#include <map> #include <map>
#include <memory>
namespace YAML namespace YAML
{ {
@@ -27,7 +28,7 @@ namespace YAML
virtual bool GetBegin(std::map <Node *, Node *, ltnode>::const_iterator& it) const; 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 bool GetEnd(std::map <Node *, Node *, ltnode>::const_iterator& it) const;
virtual std::size_t GetSize() const; virtual std::size_t GetSize() const;
virtual void Parse(Scanner *pScanner, const ParserState& state); virtual void Parse(Scanner *pScanner, ParserState& state);
virtual void Write(Emitter& out) const; virtual void Write(Emitter& out) const;
virtual bool IsMap() const { return true; } virtual bool IsMap() const { return true; }
@@ -39,8 +40,12 @@ namespace YAML
virtual int Compare(Map *pMap); virtual int Compare(Map *pMap);
private: private:
void ParseBlock(Scanner *pScanner, const ParserState& state); void ParseBlock(Scanner *pScanner, ParserState& state);
void ParseFlow(Scanner *pScanner, const ParserState& state); void ParseFlow(Scanner *pScanner, ParserState& state);
void ParseCompact(Scanner *pScanner, ParserState& state);
void ParseCompactWithNoKey(Scanner *pScanner, ParserState& state);
void AddEntry(std::auto_ptr<Node> pKey, std::auto_ptr<Node> pValue);
private: private:
node_map m_data; node_map m_data;

View File

@@ -1,4 +1,3 @@
#include "crt.h"
#include "node.h" #include "node.h"
#include "token.h" #include "token.h"
#include "scanner.h" #include "scanner.h"
@@ -10,6 +9,7 @@
#include "aliascontent.h" #include "aliascontent.h"
#include "iterpriv.h" #include "iterpriv.h"
#include "emitter.h" #include "emitter.h"
#include "tag.h"
#include <stdexcept> #include <stdexcept>
namespace YAML namespace YAML
@@ -27,7 +27,7 @@ namespace YAML
Node::Node(const Mark& mark, const std::string& anchor, const std::string& tag, const Content *pContent) Node::Node(const Mark& mark, const std::string& anchor, const std::string& tag, const Content *pContent)
: m_mark(mark), m_anchor(anchor), m_tag(tag), m_pContent(0), m_alias(false), m_pIdentity(this), m_referenced(false) : m_mark(mark), m_anchor(anchor), m_tag(tag), m_pContent(0), m_alias(false), m_pIdentity(this), m_referenced(false)
{ {
if(m_pContent) if(pContent)
m_pContent = pContent->Clone(); m_pContent = pContent->Clone();
} }
@@ -54,7 +54,7 @@ namespace YAML
return std::auto_ptr<Node> (new Node(m_mark, m_anchor, m_tag, m_pContent)); return std::auto_ptr<Node> (new Node(m_mark, m_anchor, m_tag, m_pContent));
} }
void Node::Parse(Scanner *pScanner, const ParserState& state) void Node::Parse(Scanner *pScanner, ParserState& state)
{ {
Clear(); Clear();
@@ -65,6 +65,13 @@ namespace YAML
// save location // save location
m_mark = pScanner->peek().mark; m_mark = pScanner->peek().mark;
// special case: a value node by itself must be a map, with no header
if(pScanner->peek().type == Token::VALUE) {
m_pContent = new Map;
m_pContent->Parse(pScanner, state);
return;
}
ParseHeader(pScanner, state); ParseHeader(pScanner, state);
// is this an alias? if so, its contents are an alias to // is this an alias? if so, its contents are an alias to
@@ -99,10 +106,12 @@ namespace YAML
case Token::BLOCK_MAP_START: case Token::BLOCK_MAP_START:
m_pContent = new Map; m_pContent = new Map;
break; break;
case Token::KEY:
// compact maps can only go in a flow sequence
if(state.GetCurCollectionType() == ParserState::FLOW_SEQ)
m_pContent = new Map;
break;
default: default:
// std::stringstream str;
// str << TokenNames[pScanner->peek().type];
// throw std::runtime_error(str.str());
break; break;
} }
@@ -117,7 +126,7 @@ namespace YAML
// ParseHeader // ParseHeader
// . Grabs any tag, alias, or anchor tokens and deals with them. // . Grabs any tag, alias, or anchor tokens and deals with them.
void Node::ParseHeader(Scanner *pScanner, const ParserState& state) void Node::ParseHeader(Scanner *pScanner, ParserState& state)
{ {
while(1) { while(1) {
if(pScanner->empty()) if(pScanner->empty())
@@ -132,20 +141,18 @@ namespace YAML
} }
} }
void Node::ParseTag(Scanner *pScanner, const ParserState& state) void Node::ParseTag(Scanner *pScanner, ParserState& state)
{ {
Token& token = pScanner->peek(); Token& token = pScanner->peek();
if(m_tag != "") if(m_tag != "")
throw ParserException(token.mark, ErrorMsg::MULTIPLE_TAGS); throw ParserException(token.mark, ErrorMsg::MULTIPLE_TAGS);
m_tag = state.TranslateTag(token.value); Tag tag(token);
m_tag = tag.Translate(state);
for(std::size_t i=0;i<token.params.size();i++)
m_tag += token.params[i];
pScanner->pop(); pScanner->pop();
} }
void Node::ParseAnchor(Scanner *pScanner, const ParserState& /*state*/) void Node::ParseAnchor(Scanner *pScanner, ParserState& /*state*/)
{ {
Token& token = pScanner->peek(); Token& token = pScanner->peek();
if(m_anchor != "") if(m_anchor != "")
@@ -156,7 +163,7 @@ namespace YAML
pScanner->pop(); pScanner->pop();
} }
void Node::ParseAlias(Scanner *pScanner, const ParserState& /*state*/) void Node::ParseAlias(Scanner *pScanner, ParserState& /*state*/)
{ {
Token& token = pScanner->peek(); Token& token = pScanner->peek();
if(m_anchor != "") if(m_anchor != "")
@@ -242,7 +249,10 @@ namespace YAML
bool Node::GetScalar(std::string& s) const bool Node::GetScalar(std::string& s) const
{ {
if(!m_pContent) { if(!m_pContent) {
if(m_tag.empty())
s = "~"; s = "~";
else
s = "";
return true; return true;
} }
@@ -259,7 +269,8 @@ namespace YAML
out << Anchor(node.m_anchor); out << Anchor(node.m_anchor);
} }
// TODO: write tag if(node.m_tag != "")
out << VerbatimTag(node.m_tag);
// write content // write content
if(node.m_pContent) if(node.m_pContent)

View File

@@ -1,8 +1,8 @@
#include "crt.h"
#include "parser.h" #include "parser.h"
#include "scanner.h" #include "scanner.h"
#include "token.h" #include "token.h"
#include "exceptions.h" #include "exceptions.h"
#include "parserstate.h"
#include <sstream> #include <sstream>
#include <cstdio> #include <cstdio>
@@ -29,7 +29,7 @@ namespace YAML
void Parser::Load(std::istream& in) void Parser::Load(std::istream& in)
{ {
m_pScanner.reset(new Scanner(in)); m_pScanner.reset(new Scanner(in));
m_state.Reset(); m_pState.reset(new ParserState);
} }
// GetNextDocument // GetNextDocument
@@ -55,7 +55,7 @@ namespace YAML
m_pScanner->pop(); m_pScanner->pop();
// now parse our root node // now parse our root node
document.Parse(m_pScanner.get(), m_state); document.Parse(m_pScanner.get(), *m_pState);
// and finally eat any doc ends we see // and finally eat any doc ends we see
while(!m_pScanner->empty() && m_pScanner->peek().type == Token::DOC_END) while(!m_pScanner->empty() && m_pScanner->peek().type == Token::DOC_END)
@@ -84,51 +84,59 @@ namespace YAML
// we keep the directives from the last document if none are specified; // we keep the directives from the last document if none are specified;
// but if any directives are specific, then we reset them // but if any directives are specific, then we reset them
if(!readDirective) if(!readDirective)
m_state.Reset(); m_pState.reset(new ParserState);
readDirective = true; readDirective = true;
HandleDirective(&token); HandleDirective(token);
m_pScanner->pop(); m_pScanner->pop();
} }
} }
void Parser::HandleDirective(Token *pToken) void Parser::HandleDirective(const Token& token)
{ {
if(pToken->value == "YAML") if(token.value == "YAML")
HandleYamlDirective(pToken); HandleYamlDirective(token);
else if(pToken->value == "TAG") else if(token.value == "TAG")
HandleTagDirective(pToken); HandleTagDirective(token);
} }
// HandleYamlDirective // HandleYamlDirective
// . Should be of the form 'major.minor' (like a version number) // . Should be of the form 'major.minor' (like a version number)
void Parser::HandleYamlDirective(Token *pToken) void Parser::HandleYamlDirective(const Token& token)
{ {
if(pToken->params.size() != 1) if(token.params.size() != 1)
throw ParserException(pToken->mark, ErrorMsg::YAML_DIRECTIVE_ARGS); throw ParserException(token.mark, ErrorMsg::YAML_DIRECTIVE_ARGS);
std::stringstream str(pToken->params[0]); if(!m_pState->version.isDefault)
str >> m_state.version.major; throw ParserException(token.mark, ErrorMsg::REPEATED_YAML_DIRECTIVE);
std::stringstream str(token.params[0]);
str >> m_pState->version.major;
str.get(); str.get();
str >> m_state.version.minor; str >> m_pState->version.minor;
if(!str || str.peek() != EOF) if(!str || str.peek() != EOF)
throw ParserException(pToken->mark, ErrorMsg::YAML_VERSION + pToken->params[0]); throw ParserException(token.mark, ErrorMsg::YAML_VERSION + token.params[0]);
if(m_state.version.major > 1) if(m_pState->version.major > 1)
throw ParserException(pToken->mark, ErrorMsg::YAML_MAJOR_VERSION); throw ParserException(token.mark, ErrorMsg::YAML_MAJOR_VERSION);
m_pState->version.isDefault = false;
// TODO: warning on major == 1, minor > 2? // TODO: warning on major == 1, minor > 2?
} }
// HandleTagDirective // HandleTagDirective
// . Should be of the form 'handle prefix', where 'handle' is converted to 'prefix' in the file. // . Should be of the form 'handle prefix', where 'handle' is converted to 'prefix' in the file.
void Parser::HandleTagDirective(Token *pToken) void Parser::HandleTagDirective(const Token& token)
{ {
if(pToken->params.size() != 2) if(token.params.size() != 2)
throw ParserException(pToken->mark, ErrorMsg::TAG_DIRECTIVE_ARGS); throw ParserException(token.mark, ErrorMsg::TAG_DIRECTIVE_ARGS);
std::string handle = pToken->params[0], prefix = pToken->params[1]; const std::string& handle = token.params[0];
m_state.tags[handle] = prefix; const std::string& prefix = token.params[1];
if(m_pState->tags.find(handle) != m_pState->tags.end())
throw ParserException(token.mark, ErrorMsg::REPEATED_TAG_DIRECTIVE);
m_pState->tags[handle] = prefix;
} }
void Parser::PrintTokens(std::ostream& out) void Parser::PrintTokens(std::ostream& out)

View File

@@ -1,25 +1,23 @@
#include "crt.h"
#include "parserstate.h" #include "parserstate.h"
namespace YAML namespace YAML
{ {
void ParserState::Reset() ParserState::ParserState()
{ {
// version // version
version.isDefault = true;
version.major = 1; version.major = 1;
version.minor = 2; version.minor = 2;
// and tags
tags.clear();
tags["!"] = "!";
tags["!!"] = "tag:yaml.org,2002:";
} }
std::string ParserState::TranslateTag(const std::string& handle) const const std::string ParserState::TranslateTagHandle(const std::string& handle) const
{ {
std::map <std::string, std::string>::const_iterator it = tags.find(handle); std::map <std::string, std::string>::const_iterator it = tags.find(handle);
if(it == tags.end()) if(it == tags.end()) {
if(handle == "!!")
return "tag:yaml.org,2002:";
return handle; return handle;
}
return it->second; return it->second;
} }

37
src/parserstate.h Normal file
View File

@@ -0,0 +1,37 @@
#pragma once
#ifndef PARSERSTATE_H_62B23520_7C8E_11DE_8A39_0800200C9A66
#define PARSERSTATE_H_62B23520_7C8E_11DE_8A39_0800200C9A66
#include <string>
#include <map>
#include <stack>
#include <cassert>
namespace YAML
{
struct Version {
bool isDefault;
int major, minor;
};
struct ParserState
{
enum COLLECTION_TYPE { NONE, BLOCK_MAP, BLOCK_SEQ, FLOW_MAP, FLOW_SEQ, COMPACT_MAP };
ParserState();
const std::string TranslateTagHandle(const std::string& handle) const;
COLLECTION_TYPE GetCurCollectionType() const { if(collectionStack.empty()) return NONE; return collectionStack.top(); }
void PushCollectionType(COLLECTION_TYPE type) { collectionStack.push(type); }
void PopCollectionType(COLLECTION_TYPE type) { assert(type == GetCurCollectionType()); collectionStack.pop(); }
Version version;
std::map <std::string, std::string> tags;
std::stack <COLLECTION_TYPE> collectionStack;
};
}
#endif // PARSERSTATE_H_62B23520_7C8E_11DE_8A39_0800200C9A66

View File

@@ -1,4 +1,3 @@
#include "crt.h"
#include "regex.h" #include "regex.h"
namespace YAML namespace YAML

View File

@@ -37,12 +37,12 @@ namespace YAML
int Match(const std::string& str) const; int Match(const std::string& str) const;
int Match(const Stream& in) const; int Match(const Stream& in) const;
template <typename Source> int Match(const Source& source) const;
private: private:
RegEx(REGEX_OP op); RegEx(REGEX_OP op);
template <typename Source> bool IsValidSource(const Source& source) const; template <typename Source> bool IsValidSource(const Source& source) const;
template <typename Source> int Match(const Source& source) const;
template <typename Source> int MatchUnchecked(const Source& source) const; template <typename Source> int MatchUnchecked(const Source& source) const;
template <typename Source> int MatchOpEmpty(const Source& source) const; template <typename Source> int MatchOpEmpty(const Source& source) const;

View File

@@ -1,4 +1,3 @@
#include "crt.h"
#include "scalar.h" #include "scalar.h"
#include "scanner.h" #include "scanner.h"
#include "token.h" #include "token.h"
@@ -25,7 +24,7 @@ namespace YAML
return new Scalar(m_data); return new Scalar(m_data);
} }
void Scalar::Parse(Scanner *pScanner, const ParserState& /*state*/) void Scalar::Parse(Scanner *pScanner, ParserState& /*state*/)
{ {
Token& token = pScanner->peek(); Token& token = pScanner->peek();
m_data = token.value; m_data = token.value;

View File

@@ -18,7 +18,7 @@ namespace YAML
virtual Content *Clone() const; virtual Content *Clone() const;
virtual void Parse(Scanner *pScanner, const ParserState& state); virtual void Parse(Scanner *pScanner, ParserState& state);
virtual void Write(Emitter& out) const; virtual void Write(Emitter& out) const;
virtual bool IsScalar() const { return true; } virtual bool IsScalar() const { return true; }

View File

@@ -1,19 +1,22 @@
#include "crt.h"
#include "scanner.h" #include "scanner.h"
#include "token.h" #include "token.h"
#include "exceptions.h" #include "exceptions.h"
#include "exp.h" #include "exp.h"
#include <cassert> #include <cassert>
#include <memory>
namespace YAML namespace YAML
{ {
Scanner::Scanner(std::istream& in) Scanner::Scanner(std::istream& in)
: INPUT(in), m_startedStream(false), m_endedStream(false), m_simpleKeyAllowed(false) : INPUT(in), m_startedStream(false), m_endedStream(false), m_simpleKeyAllowed(false), m_canBeJSONFlow(false)
{ {
} }
Scanner::~Scanner() Scanner::~Scanner()
{ {
for(unsigned i=0;i<m_indentRefs.size();i++)
delete m_indentRefs[i];
m_indentRefs.clear();
} }
// empty // empty
@@ -116,10 +119,10 @@ namespace YAML
return ScanDirective(); return ScanDirective();
// document token // document token
if(INPUT.column() == 0 && Exp::DocStart.Matches(INPUT)) if(INPUT.column() == 0 && Exp::DocStart().Matches(INPUT))
return ScanDocStart(); return ScanDocStart();
if(INPUT.column() == 0 && Exp::DocEnd.Matches(INPUT)) if(INPUT.column() == 0 && Exp::DocEnd().Matches(INPUT))
return ScanDocEnd(); return ScanDocEnd();
// flow start/end/entry // flow start/end/entry
@@ -133,13 +136,13 @@ namespace YAML
return ScanFlowEntry(); return ScanFlowEntry();
// block/map stuff // block/map stuff
if(Exp::BlockEntry.Matches(INPUT)) if(Exp::BlockEntry().Matches(INPUT))
return ScanBlockEntry(); return ScanBlockEntry();
if((InBlockContext() ? Exp::Key : Exp::KeyInFlow).Matches(INPUT)) if((InBlockContext() ? Exp::Key() : Exp::KeyInFlow()).Matches(INPUT))
return ScanKey(); return ScanKey();
if((InBlockContext() ? Exp::Value : Exp::ValueInFlow).Matches(INPUT)) if(GetValueRegex().Matches(INPUT))
return ScanValue(); return ScanValue();
// alias/anchor // alias/anchor
@@ -158,7 +161,7 @@ namespace YAML
return ScanQuotedScalar(); return ScanQuotedScalar();
// plain scalars // plain scalars
if((InBlockContext() ? Exp::PlainScalar : Exp::PlainScalarInFlow).Matches(INPUT)) if((InBlockContext() ? Exp::PlainScalar() : Exp::PlainScalarInFlow()).Matches(INPUT))
return ScanPlainScalar(); return ScanPlainScalar();
// don't know what it is! // don't know what it is!
@@ -172,24 +175,24 @@ namespace YAML
while(1) { while(1) {
// first eat whitespace // first eat whitespace
while(INPUT && IsWhitespaceToBeEaten(INPUT.peek())) { while(INPUT && IsWhitespaceToBeEaten(INPUT.peek())) {
if(InBlockContext() && Exp::Tab.Matches(INPUT)) if(InBlockContext() && Exp::Tab().Matches(INPUT))
m_simpleKeyAllowed = false; m_simpleKeyAllowed = false;
INPUT.eat(1); INPUT.eat(1);
} }
// then eat a comment // then eat a comment
if(Exp::Comment.Matches(INPUT)) { if(Exp::Comment().Matches(INPUT)) {
// eat until line break // eat until line break
while(INPUT && !Exp::Break.Matches(INPUT)) while(INPUT && !Exp::Break().Matches(INPUT))
INPUT.eat(1); INPUT.eat(1);
} }
// if it's NOT a line break, then we're done! // if it's NOT a line break, then we're done!
if(!Exp::Break.Matches(INPUT)) if(!Exp::Break().Matches(INPUT))
break; break;
// otherwise, let's eat the line break and keep going // otherwise, let's eat the line break and keep going
int n = Exp::Break.Match(INPUT); int n = Exp::Break().Match(INPUT);
INPUT.eat(n); INPUT.eat(n);
// oh yeah, and let's get rid of that simple key // oh yeah, and let's get rid of that simple key
@@ -223,13 +226,25 @@ namespace YAML
return false; return false;
} }
// GetValueRegex
// . Get the appropriate regex to check if it's a value token
const RegEx& Scanner::GetValueRegex() const
{
if(InBlockContext())
return Exp::Value();
return m_canBeJSONFlow ? Exp::ValueInJSONFlow() : Exp::ValueInFlow();
}
// StartStream // StartStream
// . Set the initial conditions for starting a stream. // . Set the initial conditions for starting a stream.
void Scanner::StartStream() void Scanner::StartStream()
{ {
m_startedStream = true; m_startedStream = true;
m_simpleKeyAllowed = true; m_simpleKeyAllowed = true;
m_indents.push(IndentMarker(-1, IndentMarker::NONE)); IndentMarker *pIndent = new IndentMarker(-1, IndentMarker::NONE);
m_indentRefs.push_back(pIndent);
m_indents.push(pIndent);
m_anchors.clear(); m_anchors.clear();
} }
@@ -248,6 +263,22 @@ namespace YAML
m_endedStream = true; m_endedStream = true;
} }
Token *Scanner::PushToken(Token::TYPE type)
{
m_tokens.push(Token(type, INPUT.mark()));
return &m_tokens.back();
}
Token::TYPE Scanner::GetStartTokenFor(IndentMarker::INDENT_TYPE type) const
{
switch(type) {
case IndentMarker::SEQ: return Token::BLOCK_SEQ_START;
case IndentMarker::MAP: return Token::BLOCK_MAP_START;
case IndentMarker::NONE: assert(false); break;
}
assert(false);
}
// PushIndentTo // PushIndentTo
// . Pushes an indentation onto the stack, and enqueues the // . Pushes an indentation onto the stack, and enqueues the
// proper token (sequence start or mapping start). // proper token (sequence start or mapping start).
@@ -258,8 +289,9 @@ namespace YAML
if(InFlowContext()) if(InFlowContext())
return 0; return 0;
IndentMarker indent(column, type); std::auto_ptr<IndentMarker> pIndent(new IndentMarker(column, type));
const IndentMarker& lastIndent = m_indents.top(); IndentMarker& indent = *pIndent;
const IndentMarker& lastIndent = *m_indents.top();
// is this actually an indentation? // is this actually an indentation?
if(indent.column < lastIndent.column) if(indent.column < lastIndent.column)
@@ -268,22 +300,18 @@ namespace YAML
return 0; return 0;
// push a start token // push a start token
if(type == IndentMarker::SEQ) indent.pStartToken = PushToken(GetStartTokenFor(type));
m_tokens.push(Token(Token::BLOCK_SEQ_START, INPUT.mark()));
else if(type == IndentMarker::MAP)
m_tokens.push(Token(Token::BLOCK_MAP_START, INPUT.mark()));
else
assert(false);
indent.pStartToken = &m_tokens.back();
// and then the indent // and then the indent
m_indents.push(indent); m_indents.push(&indent);
return &m_indents.top(); m_indentRefs.push_back(pIndent.release());
return m_indentRefs.back();
} }
// PopIndentToHere // PopIndentToHere
// . Pops indentations off the stack until we reach the current indentation level, // . Pops indentations off the stack until we reach the current indentation level,
// and enqueues the proper token each time. // and enqueues the proper token each time.
// . Then pops all invalid indentations off.
void Scanner::PopIndentToHere() void Scanner::PopIndentToHere()
{ {
// are we in flow? // are we in flow?
@@ -292,14 +320,17 @@ namespace YAML
// now pop away // now pop away
while(!m_indents.empty()) { while(!m_indents.empty()) {
const IndentMarker& indent = m_indents.top(); const IndentMarker& indent = *m_indents.top();
if(indent.column < INPUT.column()) if(indent.column < INPUT.column())
break; break;
if(indent.column == INPUT.column() && !(indent.type == IndentMarker::SEQ && !Exp::BlockEntry.Matches(INPUT))) if(indent.column == INPUT.column() && !(indent.type == IndentMarker::SEQ && !Exp::BlockEntry().Matches(INPUT)))
break; break;
PopIndent(); PopIndent();
} }
while(!m_indents.empty() && m_indents.top()->status == IndentMarker::INVALID)
PopIndent();
} }
// PopAllIndents // PopAllIndents
@@ -313,7 +344,7 @@ namespace YAML
// now pop away // now pop away
while(!m_indents.empty()) { while(!m_indents.empty()) {
const IndentMarker& indent = m_indents.top(); const IndentMarker& indent = *m_indents.top();
if(indent.type == IndentMarker::NONE) if(indent.type == IndentMarker::NONE)
break; break;
@@ -325,17 +356,17 @@ namespace YAML
// . Pops a single indent, pushing the proper token // . Pops a single indent, pushing the proper token
void Scanner::PopIndent() void Scanner::PopIndent()
{ {
IndentMarker indent = m_indents.top(); const IndentMarker& indent = *m_indents.top();
IndentMarker::INDENT_TYPE type = indent.type;
m_indents.pop(); m_indents.pop();
if(!indent.isValid) {
if(indent.status != IndentMarker::VALID) {
InvalidateSimpleKey(); InvalidateSimpleKey();
return; return;
} }
if(type == IndentMarker::SEQ) if(indent.type == IndentMarker::SEQ)
m_tokens.push(Token(Token::BLOCK_SEQ_END, INPUT.mark())); m_tokens.push(Token(Token::BLOCK_SEQ_END, INPUT.mark()));
else if(type == IndentMarker::MAP) else if(indent.type == IndentMarker::MAP)
m_tokens.push(Token(Token::BLOCK_MAP_END, INPUT.mark())); m_tokens.push(Token(Token::BLOCK_MAP_END, INPUT.mark()));
} }
@@ -344,7 +375,7 @@ namespace YAML
{ {
if(m_indents.empty()) if(m_indents.empty())
return 0; return 0;
return m_indents.top().column; return m_indents.top()->column;
} }
// Save // Save
@@ -389,3 +420,4 @@ namespace YAML
m_anchors.clear(); m_anchors.clear();
} }
} }

View File

@@ -16,6 +16,7 @@
namespace YAML namespace YAML
{ {
class Node; class Node;
class RegEx;
class Scanner class Scanner
{ {
@@ -36,11 +37,12 @@ namespace YAML
private: private:
struct IndentMarker { struct IndentMarker {
enum INDENT_TYPE { MAP, SEQ, NONE }; enum INDENT_TYPE { MAP, SEQ, NONE };
IndentMarker(int column_, INDENT_TYPE type_): column(column_), type(type_), isValid(true), pStartToken(0) {} enum STATUS { VALID, INVALID, UNKNOWN };
IndentMarker(int column_, INDENT_TYPE type_): column(column_), type(type_), status(VALID), pStartToken(0) {}
int column; int column;
INDENT_TYPE type; INDENT_TYPE type;
bool isValid; STATUS status;
Token *pStartToken; Token *pStartToken;
}; };
@@ -53,11 +55,13 @@ namespace YAML
void ScanToNextToken(); void ScanToNextToken();
void StartStream(); void StartStream();
void EndStream(); void EndStream();
Token *PushToken(Token::TYPE type);
bool InFlowContext() const { return !m_flows.empty(); } bool InFlowContext() const { return !m_flows.empty(); }
bool InBlockContext() const { return m_flows.empty(); } bool InBlockContext() const { return m_flows.empty(); }
int GetFlowLevel() const { return m_flows.size(); } int GetFlowLevel() const { return m_flows.size(); }
Token::TYPE GetStartTokenFor(IndentMarker::INDENT_TYPE type) const;
IndentMarker *PushIndentTo(int column, IndentMarker::INDENT_TYPE type); IndentMarker *PushIndentTo(int column, IndentMarker::INDENT_TYPE type);
void PopIndentToHere(); void PopIndentToHere();
void PopAllIndents(); void PopAllIndents();
@@ -75,6 +79,7 @@ namespace YAML
void ThrowParserException(const std::string& msg) const; void ThrowParserException(const std::string& msg) const;
bool IsWhitespaceToBeEaten(char ch); bool IsWhitespaceToBeEaten(char ch);
const RegEx& GetValueRegex() const;
struct SimpleKey { struct SimpleKey {
SimpleKey(const Mark& mark_, int flowLevel_); SimpleKey(const Mark& mark_, int flowLevel_);
@@ -117,11 +122,14 @@ namespace YAML
// state info // state info
bool m_startedStream, m_endedStream; bool m_startedStream, m_endedStream;
bool m_simpleKeyAllowed; bool m_simpleKeyAllowed;
bool m_canBeJSONFlow;
std::stack <SimpleKey> m_simpleKeys; std::stack <SimpleKey> m_simpleKeys;
std::stack <IndentMarker> m_indents; std::stack <IndentMarker *> m_indents;
std::vector <IndentMarker *> m_indentRefs; // for "garbage collection"
std::stack <FLOW_MARKER> m_flows; std::stack <FLOW_MARKER> m_flows;
std::map <std::string, const Node *> m_anchors; std::map <std::string, const Node *> m_anchors;
}; };
} }
#endif // SCANNER_H_62B23520_7C8E_11DE_8A39_0800200C9A66 #endif // SCANNER_H_62B23520_7C8E_11DE_8A39_0800200C9A66

View File

@@ -1,4 +1,3 @@
#include "crt.h"
#include "scanscalar.h" #include "scanscalar.h"
#include "scanner.h" #include "scanner.h"
#include "exp.h" #include "exp.h"
@@ -32,12 +31,13 @@ namespace YAML
// Phase #1: scan until line ending // Phase #1: scan until line ending
std::size_t lastNonWhitespaceChar = scalar.size(); std::size_t lastNonWhitespaceChar = scalar.size();
while(!params.end.Matches(INPUT) && !Exp::Break.Matches(INPUT)) { bool escapedNewline = false;
while(!params.end.Matches(INPUT) && !Exp::Break().Matches(INPUT)) {
if(!INPUT) if(!INPUT)
break; break;
// document indicator? // document indicator?
if(INPUT.column() == 0 && Exp::DocIndicator.Matches(INPUT)) { if(INPUT.column() == 0 && Exp::DocIndicator().Matches(INPUT)) {
if(params.onDocIndicator == BREAK) if(params.onDocIndicator == BREAK)
break; break;
else if(params.onDocIndicator == THROW) else if(params.onDocIndicator == THROW)
@@ -48,11 +48,12 @@ namespace YAML
pastOpeningBreak = true; pastOpeningBreak = true;
// escaped newline? (only if we're escaping on slash) // escaped newline? (only if we're escaping on slash)
if(params.escape == '\\' && Exp::EscBreak.Matches(INPUT)) { if(params.escape == '\\' && Exp::EscBreak().Matches(INPUT)) {
int n = Exp::EscBreak.Match(INPUT); // eat escape character and get out (but preserve trailing whitespace!)
INPUT.eat(n); INPUT.get();
lastNonWhitespaceChar = scalar.size(); lastNonWhitespaceChar = scalar.size();
continue; escapedNewline = true;
break;
} }
// escape this? // escape this?
@@ -77,7 +78,7 @@ namespace YAML
} }
// doc indicator? // doc indicator?
if(params.onDocIndicator == BREAK && INPUT.column() == 0 && Exp::DocIndicator.Matches(INPUT)) if(params.onDocIndicator == BREAK && INPUT.column() == 0 && Exp::DocIndicator().Matches(INPUT))
break; break;
// are we done via character match? // are we done via character match?
@@ -94,7 +95,7 @@ namespace YAML
// ******************************** // ********************************
// Phase #2: eat line ending // Phase #2: eat line ending
n = Exp::Break.Match(INPUT); n = Exp::Break().Match(INPUT);
INPUT.eat(n); INPUT.eat(n);
// ******************************** // ********************************
@@ -109,7 +110,7 @@ namespace YAML
params.indent = std::max(params.indent, INPUT.column()); params.indent = std::max(params.indent, INPUT.column());
// and then the rest of the whitespace // and then the rest of the whitespace
while(Exp::Blank.Matches(INPUT)) { while(Exp::Blank().Matches(INPUT)) {
// we check for tabs that masquerade as indentation // we check for tabs that masquerade as indentation
if(INPUT.peek() == '\t'&& INPUT.column() < params.indent && params.onTabInIndentation == THROW) if(INPUT.peek() == '\t'&& INPUT.column() < params.indent && params.onTabInIndentation == THROW)
throw ParserException(INPUT.mark(), ErrorMsg::TAB_IN_INDENTATION); throw ParserException(INPUT.mark(), ErrorMsg::TAB_IN_INDENTATION);
@@ -121,8 +122,8 @@ namespace YAML
} }
// was this an empty line? // was this an empty line?
bool nextEmptyLine = Exp::Break.Matches(INPUT); bool nextEmptyLine = Exp::Break().Matches(INPUT);
bool nextMoreIndented = Exp::Blank.Matches(INPUT); bool nextMoreIndented = Exp::Blank().Matches(INPUT);
if(params.fold == FOLD_BLOCK && foldedNewlineCount == 0 && nextEmptyLine) if(params.fold == FOLD_BLOCK && foldedNewlineCount == 0 && nextEmptyLine)
foldedNewlineStartedMoreIndented = moreIndented; foldedNewlineStartedMoreIndented = moreIndented;
@@ -150,7 +151,7 @@ namespace YAML
case FOLD_FLOW: case FOLD_FLOW:
if(nextEmptyLine) if(nextEmptyLine)
scalar += "\n"; scalar += "\n";
else if(!emptyLine && !nextEmptyLine) else if(!emptyLine && !nextEmptyLine && !escapedNewline)
scalar += " "; scalar += " ";
break; break;
} }

View File

@@ -40,3 +40,4 @@ namespace YAML
} }
#endif // SCANSCALAR_H_62B23520_7C8E_11DE_8A39_0800200C9A66 #endif // SCANSCALAR_H_62B23520_7C8E_11DE_8A39_0800200C9A66

84
src/scantag.cpp Normal file
View File

@@ -0,0 +1,84 @@
#include "scanner.h"
#include "regex.h"
#include "exp.h"
#include "exceptions.h"
namespace YAML
{
const std::string ScanVerbatimTag(Stream& INPUT)
{
std::string tag;
// eat the start character
INPUT.get();
while(INPUT) {
if(INPUT.peek() == Keys::VerbatimTagEnd) {
// eat the end character
INPUT.get();
return tag;
}
int n = Exp::URI().Match(INPUT);
if(n <= 0)
break;
tag += INPUT.get(n);
}
throw ParserException(INPUT.mark(), ErrorMsg::END_OF_VERBATIM_TAG);
}
const std::string ScanTagHandle(Stream& INPUT, bool& canBeHandle)
{
std::string tag;
canBeHandle = true;
Mark firstNonWordChar;
while(INPUT) {
if(INPUT.peek() == Keys::Tag) {
if(!canBeHandle)
throw ParserException(firstNonWordChar, ErrorMsg::CHAR_IN_TAG_HANDLE);
break;
}
int n = 0;
if(canBeHandle) {
n = Exp::Word().Match(INPUT);
if(n <= 0) {
canBeHandle = false;
firstNonWordChar = INPUT.mark();
}
}
if(!canBeHandle)
n = Exp::Tag().Match(INPUT);
if(n <= 0)
break;
tag += INPUT.get(n);
}
return tag;
}
const std::string ScanTagSuffix(Stream& INPUT)
{
std::string tag;
while(INPUT) {
int n = Exp::Tag().Match(INPUT);
if(n <= 0)
break;
tag += INPUT.get(n);
}
if(tag.empty())
throw ParserException(INPUT.mark(), ErrorMsg::TAG_WITH_NO_SUFFIX);
return tag;
}
}

18
src/scantag.h Normal file
View File

@@ -0,0 +1,18 @@
#pragma once
#ifndef SCANTAG_H_62B23520_7C8E_11DE_8A39_0800200C9A66
#define SCANTAG_H_62B23520_7C8E_11DE_8A39_0800200C9A66
#include <string>
#include "stream.h"
namespace YAML
{
const std::string ScanVerbatimTag(Stream& INPUT);
const std::string ScanTagHandle(Stream& INPUT, bool& canBeHandle);
const std::string ScanTagSuffix(Stream& INPUT);
}
#endif // SCANTAG_H_62B23520_7C8E_11DE_8A39_0800200C9A66

View File

@@ -1,9 +1,10 @@
#include "crt.h"
#include "scanner.h" #include "scanner.h"
#include "token.h" #include "token.h"
#include "exceptions.h" #include "exceptions.h"
#include "exp.h" #include "exp.h"
#include "scanscalar.h" #include "scanscalar.h"
#include "scantag.h"
#include "tag.h"
#include <sstream> #include <sstream>
namespace YAML namespace YAML
@@ -23,36 +24,34 @@ namespace YAML
PopAllSimpleKeys(); PopAllSimpleKeys();
m_simpleKeyAllowed = false; m_simpleKeyAllowed = false;
m_canBeJSONFlow = false;
// store pos and eat indicator // store pos and eat indicator
Mark mark = INPUT.mark(); Token token(Token::DIRECTIVE, INPUT.mark());
INPUT.eat(1); INPUT.eat(1);
// read name // read name
while(INPUT && !Exp::BlankOrBreak.Matches(INPUT)) while(INPUT && !Exp::BlankOrBreak().Matches(INPUT))
name += INPUT.get(); token.value += INPUT.get();
// read parameters // read parameters
while(1) { while(1) {
// first get rid of whitespace // first get rid of whitespace
while(Exp::Blank.Matches(INPUT)) while(Exp::Blank().Matches(INPUT))
INPUT.eat(1); INPUT.eat(1);
// break on newline or comment // break on newline or comment
if(!INPUT || Exp::Break.Matches(INPUT) || Exp::Comment.Matches(INPUT)) if(!INPUT || Exp::Break().Matches(INPUT) || Exp::Comment().Matches(INPUT))
break; break;
// now read parameter // now read parameter
std::string param; std::string param;
while(INPUT && !Exp::BlankOrBreak.Matches(INPUT)) while(INPUT && !Exp::BlankOrBreak().Matches(INPUT))
param += INPUT.get(); param += INPUT.get();
params.push_back(param); token.params.push_back(param);
} }
Token token(Token::DIRECTIVE, mark);
token.value = name;
token.params = params;
m_tokens.push(token); m_tokens.push(token);
} }
@@ -62,6 +61,7 @@ namespace YAML
PopAllIndents(); PopAllIndents();
PopAllSimpleKeys(); PopAllSimpleKeys();
m_simpleKeyAllowed = false; m_simpleKeyAllowed = false;
m_canBeJSONFlow = false;
// eat // eat
Mark mark = INPUT.mark(); Mark mark = INPUT.mark();
@@ -75,6 +75,7 @@ namespace YAML
PopAllIndents(); PopAllIndents();
PopAllSimpleKeys(); PopAllSimpleKeys();
m_simpleKeyAllowed = false; m_simpleKeyAllowed = false;
m_canBeJSONFlow = false;
// eat // eat
Mark mark = INPUT.mark(); Mark mark = INPUT.mark();
@@ -88,6 +89,7 @@ namespace YAML
// flows can be simple keys // flows can be simple keys
InsertPotentialSimpleKey(); InsertPotentialSimpleKey();
m_simpleKeyAllowed = true; m_simpleKeyAllowed = true;
m_canBeJSONFlow = false;
// eat // eat
Mark mark = INPUT.mark(); Mark mark = INPUT.mark();
@@ -105,10 +107,15 @@ namespace YAML
throw ParserException(INPUT.mark(), ErrorMsg::FLOW_END); throw ParserException(INPUT.mark(), ErrorMsg::FLOW_END);
// we might have a solo entry in the flow context // we might have a solo entry in the flow context
if(VerifySimpleKey()) if(InFlowContext()) {
if(m_flows.top() == FLOW_MAP && VerifySimpleKey())
m_tokens.push(Token(Token::VALUE, INPUT.mark())); m_tokens.push(Token(Token::VALUE, INPUT.mark()));
else if(m_flows.top() == FLOW_SEQ)
InvalidateSimpleKey();
}
m_simpleKeyAllowed = false; m_simpleKeyAllowed = false;
m_canBeJSONFlow = true;
// eat // eat
Mark mark = INPUT.mark(); Mark mark = INPUT.mark();
@@ -128,10 +135,15 @@ namespace YAML
void Scanner::ScanFlowEntry() void Scanner::ScanFlowEntry()
{ {
// we might have a solo entry in the flow context // we might have a solo entry in the flow context
if(VerifySimpleKey()) if(InFlowContext()) {
if(m_flows.top() == FLOW_MAP && VerifySimpleKey())
m_tokens.push(Token(Token::VALUE, INPUT.mark())); m_tokens.push(Token(Token::VALUE, INPUT.mark()));
else if(m_flows.top() == FLOW_SEQ)
InvalidateSimpleKey();
}
m_simpleKeyAllowed = true; m_simpleKeyAllowed = true;
m_canBeJSONFlow = false;
// eat // eat
Mark mark = INPUT.mark(); Mark mark = INPUT.mark();
@@ -152,6 +164,7 @@ namespace YAML
PushIndentTo(INPUT.column(), IndentMarker::SEQ); PushIndentTo(INPUT.column(), IndentMarker::SEQ);
m_simpleKeyAllowed = true; m_simpleKeyAllowed = true;
m_canBeJSONFlow = false;
// eat // eat
Mark mark = INPUT.mark(); Mark mark = INPUT.mark();
@@ -184,6 +197,7 @@ namespace YAML
{ {
// and check that simple key // and check that simple key
bool isSimpleKey = VerifySimpleKey(); bool isSimpleKey = VerifySimpleKey();
m_canBeJSONFlow = false;
if(isSimpleKey) { if(isSimpleKey) {
// can't follow a simple key with another simple key (dunno why, though - it seems fine) // can't follow a simple key with another simple key (dunno why, though - it seems fine)
@@ -216,6 +230,7 @@ namespace YAML
// insert a potential simple key // insert a potential simple key
InsertPotentialSimpleKey(); InsertPotentialSimpleKey();
m_simpleKeyAllowed = false; m_simpleKeyAllowed = false;
m_canBeJSONFlow = false;
// eat the indicator // eat the indicator
Mark mark = INPUT.mark(); Mark mark = INPUT.mark();
@@ -223,7 +238,7 @@ namespace YAML
alias = (indicator == Keys::Alias); alias = (indicator == Keys::Alias);
// now eat the content // now eat the content
while(Exp::AlphaNumeric.Matches(INPUT)) while(Exp::AlphaNumeric().Matches(INPUT))
name += INPUT.get(); name += INPUT.get();
// we need to have read SOMETHING! // we need to have read SOMETHING!
@@ -231,7 +246,7 @@ namespace YAML
throw ParserException(INPUT.mark(), alias ? ErrorMsg::ALIAS_NOT_FOUND : ErrorMsg::ANCHOR_NOT_FOUND); throw ParserException(INPUT.mark(), alias ? ErrorMsg::ALIAS_NOT_FOUND : ErrorMsg::ANCHOR_NOT_FOUND);
// and needs to end correctly // and needs to end correctly
if(INPUT && !Exp::AnchorEnd.Matches(INPUT)) if(INPUT && !Exp::AnchorEnd().Matches(INPUT))
throw ParserException(INPUT.mark(), alias ? ErrorMsg::CHAR_IN_ALIAS : ErrorMsg::CHAR_IN_ANCHOR); throw ParserException(INPUT.mark(), alias ? ErrorMsg::CHAR_IN_ALIAS : ErrorMsg::CHAR_IN_ANCHOR);
// and we're done // and we're done
@@ -243,37 +258,35 @@ namespace YAML
// Tag // Tag
void Scanner::ScanTag() void Scanner::ScanTag()
{ {
std::string handle, suffix;
// insert a potential simple key // insert a potential simple key
InsertPotentialSimpleKey(); InsertPotentialSimpleKey();
m_simpleKeyAllowed = false; m_simpleKeyAllowed = false;
m_canBeJSONFlow = false;
Token token(Token::TAG, INPUT.mark());
// eat the indicator // eat the indicator
Mark mark = INPUT.mark(); INPUT.get();
handle += INPUT.get();
// read the handle if(INPUT && INPUT.peek() == Keys::VerbatimTagStart){
while(INPUT && INPUT.peek() != Keys::Tag && !Exp::BlankOrBreak.Matches(INPUT)) std::string tag = ScanVerbatimTag(INPUT);
handle += INPUT.get();
token.value = tag;
token.data = Tag::VERBATIM;
} else {
bool canBeHandle;
token.value = ScanTagHandle(INPUT, canBeHandle);
token.data = (token.value.empty() ? Tag::SECONDARY_HANDLE : Tag::PRIMARY_HANDLE);
// is there a suffix? // is there a suffix?
if(INPUT.peek() == Keys::Tag) { if(canBeHandle && INPUT.peek() == Keys::Tag) {
// eat the indicator // eat the indicator
handle += INPUT.get(); INPUT.get();
token.params.push_back(ScanTagSuffix(INPUT));
// then read it token.data = Tag::NAMED_HANDLE;
while(INPUT && !Exp::BlankOrBreak.Matches(INPUT)) }
suffix += INPUT.get();
} else {
// this is a bit weird: we keep just the '!' as the handle and move the rest to the suffix
suffix = handle.substr(1);
handle = "!";
} }
Token token(Token::TAG, mark);
token.value = handle;
token.params.push_back(suffix);
m_tokens.push(token); m_tokens.push(token);
} }
@@ -284,7 +297,7 @@ namespace YAML
// set up the scanning parameters // set up the scanning parameters
ScanScalarParams params; ScanScalarParams params;
params.end = (InFlowContext() ? Exp::EndScalarInFlow : Exp::EndScalar) || (Exp::BlankOrBreak + Exp::Comment); params.end = (InFlowContext() ? Exp::EndScalarInFlow() : Exp::EndScalar()) || (Exp::BlankOrBreak() + Exp::Comment());
params.eatEnd = false; params.eatEnd = false;
params.indent = (InFlowContext() ? 0 : GetTopIndent() + 1); params.indent = (InFlowContext() ? 0 : GetTopIndent() + 1);
params.fold = FOLD_FLOW; params.fold = FOLD_FLOW;
@@ -302,6 +315,7 @@ namespace YAML
// can have a simple key only if we ended the scalar by starting a new line // can have a simple key only if we ended the scalar by starting a new line
m_simpleKeyAllowed = params.leadingSpaces; m_simpleKeyAllowed = params.leadingSpaces;
m_canBeJSONFlow = false;
// finally, check and see if we ended on an illegal character // finally, check and see if we ended on an illegal character
//if(Exp::IllegalCharInScalar.Matches(INPUT)) //if(Exp::IllegalCharInScalar.Matches(INPUT))
@@ -323,7 +337,7 @@ namespace YAML
// setup the scanning parameters // setup the scanning parameters
ScanScalarParams params; ScanScalarParams params;
params.end = (single ? RegEx(quote) && !Exp::EscSingleQuote : RegEx(quote)); params.end = (single ? RegEx(quote) && !Exp::EscSingleQuote() : RegEx(quote));
params.eatEnd = true; params.eatEnd = true;
params.escape = (single ? '\'' : '\\'); params.escape = (single ? '\'' : '\\');
params.indent = 0; params.indent = 0;
@@ -344,6 +358,7 @@ namespace YAML
// and scan // and scan
scalar = ScanScalar(INPUT, params); scalar = ScanScalar(INPUT, params);
m_simpleKeyAllowed = false; m_simpleKeyAllowed = false;
m_canBeJSONFlow = true;
Token token(Token::SCALAR, mark); Token token(Token::SCALAR, mark);
token.value = scalar; token.value = scalar;
@@ -369,14 +384,14 @@ namespace YAML
// eat chomping/indentation indicators // eat chomping/indentation indicators
params.chomp = CLIP; params.chomp = CLIP;
int n = Exp::Chomp.Match(INPUT); int n = Exp::Chomp().Match(INPUT);
for(int i=0;i<n;i++) { for(int i=0;i<n;i++) {
char ch = INPUT.get(); char ch = INPUT.get();
if(ch == '+') if(ch == '+')
params.chomp = KEEP; params.chomp = KEEP;
else if(ch == '-') else if(ch == '-')
params.chomp = STRIP; params.chomp = STRIP;
else if(Exp::Digit.Matches(ch)) { else if(Exp::Digit().Matches(ch)) {
if(ch == '0') if(ch == '0')
throw ParserException(INPUT.mark(), ErrorMsg::ZERO_INDENT_IN_BLOCK); throw ParserException(INPUT.mark(), ErrorMsg::ZERO_INDENT_IN_BLOCK);
@@ -386,16 +401,16 @@ namespace YAML
} }
// now eat whitespace // now eat whitespace
while(Exp::Blank.Matches(INPUT)) while(Exp::Blank().Matches(INPUT))
INPUT.eat(1); INPUT.eat(1);
// and comments to the end of the line // and comments to the end of the line
if(Exp::Comment.Matches(INPUT)) if(Exp::Comment().Matches(INPUT))
while(INPUT && !Exp::Break.Matches(INPUT)) while(INPUT && !Exp::Break().Matches(INPUT))
INPUT.eat(1); INPUT.eat(1);
// if it's not a line break, then we ran into a bad character inline // if it's not a line break, then we ran into a bad character inline
if(INPUT && !Exp::Break.Matches(INPUT)) if(INPUT && !Exp::Break().Matches(INPUT))
throw ParserException(INPUT.mark(), ErrorMsg::CHAR_IN_BLOCK); throw ParserException(INPUT.mark(), ErrorMsg::CHAR_IN_BLOCK);
// set the initial indentation // set the initial indentation
@@ -410,6 +425,7 @@ namespace YAML
// simple keys always ok after block scalars (since we're gonna start a new line anyways) // simple keys always ok after block scalars (since we're gonna start a new line anyways)
m_simpleKeyAllowed = true; m_simpleKeyAllowed = true;
m_canBeJSONFlow = false;
Token token(Token::SCALAR, mark); Token token(Token::SCALAR, mark);
token.value = scalar; token.value = scalar;

View File

@@ -1,4 +1,3 @@
#include "crt.h"
#include "sequence.h" #include "sequence.h"
#include "node.h" #include "node.h"
#include "scanner.h" #include "scanner.h"
@@ -60,7 +59,7 @@ namespace YAML
return m_data.size(); return m_data.size();
} }
void Sequence::Parse(Scanner *pScanner, const ParserState& state) void Sequence::Parse(Scanner *pScanner, ParserState& state)
{ {
Clear(); Clear();
@@ -72,10 +71,11 @@ namespace YAML
} }
} }
void Sequence::ParseBlock(Scanner *pScanner, const ParserState& state) void Sequence::ParseBlock(Scanner *pScanner, ParserState& state)
{ {
// eat start token // eat start token
pScanner->pop(); pScanner->pop();
state.PushCollectionType(ParserState::BLOCK_SEQ);
while(1) { while(1) {
if(pScanner->empty()) if(pScanner->empty())
@@ -101,12 +101,15 @@ namespace YAML
pNode->Parse(pScanner, state); pNode->Parse(pScanner, state);
} }
state.PopCollectionType(ParserState::BLOCK_SEQ);
} }
void Sequence::ParseFlow(Scanner *pScanner, const ParserState& state) void Sequence::ParseFlow(Scanner *pScanner, ParserState& state)
{ {
// eat start token // eat start token
pScanner->pop(); pScanner->pop();
state.PushCollectionType(ParserState::FLOW_SEQ);
while(1) { while(1) {
if(pScanner->empty()) if(pScanner->empty())
@@ -130,6 +133,8 @@ namespace YAML
else if(token.type != Token::FLOW_SEQ_END) else if(token.type != Token::FLOW_SEQ_END)
throw ParserException(token.mark, ErrorMsg::END_OF_SEQ_FLOW); throw ParserException(token.mark, ErrorMsg::END_OF_SEQ_FLOW);
} }
state.PopCollectionType(ParserState::FLOW_SEQ);
} }
void Sequence::Write(Emitter& out) const void Sequence::Write(Emitter& out) const

View File

@@ -26,7 +26,7 @@ namespace YAML
virtual Node *GetNode(std::size_t i) const; virtual Node *GetNode(std::size_t i) const;
virtual std::size_t GetSize() const; virtual std::size_t GetSize() const;
virtual void Parse(Scanner *pScanner, const ParserState& state); virtual void Parse(Scanner *pScanner, ParserState& state);
virtual void Write(Emitter& out) const; virtual void Write(Emitter& out) const;
virtual bool IsSequence() const { return true; } virtual bool IsSequence() const { return true; }
@@ -38,8 +38,8 @@ namespace YAML
virtual int Compare(Map *) { return -1; } virtual int Compare(Map *) { return -1; }
private: private:
void ParseBlock(Scanner *pScanner, const ParserState& state); void ParseBlock(Scanner *pScanner, ParserState& state);
void ParseFlow(Scanner *pScanner, const ParserState& state); void ParseFlow(Scanner *pScanner, ParserState& state);
protected: protected:
std::vector <Node *> m_data; std::vector <Node *> m_data;

View File

@@ -1,4 +1,3 @@
#include "crt.h"
#include "scanner.h" #include "scanner.h"
#include "token.h" #include "token.h"
#include "exceptions.h" #include "exceptions.h"
@@ -13,9 +12,11 @@ namespace YAML
void Scanner::SimpleKey::Validate() void Scanner::SimpleKey::Validate()
{ {
// Note: pIndent will *not* be garbage here; see below // Note: pIndent will *not* be garbage here;
// we "garbage collect" them so we can
// always refer to them
if(pIndent) if(pIndent)
pIndent->isValid = true; pIndent->status = IndentMarker::VALID;
if(pMapStart) if(pMapStart)
pMapStart->status = Token::VALID; pMapStart->status = Token::VALID;
if(pKey) if(pKey)
@@ -24,8 +25,8 @@ namespace YAML
void Scanner::SimpleKey::Invalidate() void Scanner::SimpleKey::Invalidate()
{ {
// Note: pIndent might be a garbage pointer here, but that's ok if(pIndent)
// An indent will only be popped if the simple key is invalid pIndent->status = IndentMarker::INVALID;
if(pMapStart) if(pMapStart)
pMapStart->status = Token::INVALID; pMapStart->status = Token::INVALID;
if(pKey) if(pKey)
@@ -38,9 +39,6 @@ namespace YAML
if(!m_simpleKeyAllowed) if(!m_simpleKeyAllowed)
return false; return false;
if(InFlowContext() && m_flows.top() != FLOW_MAP)
return false;
return !ExistsActiveSimpleKey(); return !ExistsActiveSimpleKey();
} }
@@ -67,12 +65,14 @@ namespace YAML
SimpleKey key(INPUT.mark(), GetFlowLevel()); SimpleKey key(INPUT.mark(), GetFlowLevel());
// first add a map start, if necessary // first add a map start, if necessary
if(InBlockContext()) {
key.pIndent = PushIndentTo(INPUT.column(), IndentMarker::MAP); key.pIndent = PushIndentTo(INPUT.column(), IndentMarker::MAP);
if(key.pIndent) { if(key.pIndent) {
key.pIndent->isValid = false; key.pIndent->status = IndentMarker::UNKNOWN;
key.pMapStart = key.pIndent->pStartToken; key.pMapStart = key.pIndent->pStartToken;
key.pMapStart->status = Token::UNVERIFIED; key.pMapStart->status = Token::UNVERIFIED;
} }
}
// then add the (now unverified) key // then add the (now unverified) key
m_tokens.push(Token(Token::KEY, INPUT.mark())); m_tokens.push(Token(Token::KEY, INPUT.mark()));
@@ -136,3 +136,4 @@ namespace YAML
m_simpleKeys.pop(); m_simpleKeys.pop();
} }
} }

View File

@@ -1,4 +1,3 @@
#include "crt.h"
#include "stream.h" #include "stream.h"
#include <iostream> #include <iostream>
#include "exp.h" #include "exp.h"

View File

@@ -30,6 +30,11 @@ namespace YAML
++m_offset; ++m_offset;
return *this; return *this;
} }
StringCharSource& operator += (std::size_t offset) {
m_offset += offset;
return *this;
}
private: private:
const char *m_str; const char *m_str;
std::size_t m_size; std::size_t m_size;

50
src/tag.cpp Normal file
View File

@@ -0,0 +1,50 @@
#include "tag.h"
#include "token.h"
#include "parserstate.h"
#include <cassert>
namespace YAML
{
Tag::Tag(const Token& token): type(static_cast<TYPE>(token.data))
{
switch(type) {
case VERBATIM:
value = token.value;
break;
case PRIMARY_HANDLE:
value = token.value;
break;
case SECONDARY_HANDLE:
value = token.value;
break;
case NAMED_HANDLE:
handle = token.value;
value = token.params[0];
break;
case NON_SPECIFIC:
break;
default:
assert(false);
}
}
const std::string Tag::Translate(const ParserState& state)
{
switch(type) {
case VERBATIM:
return value;
case PRIMARY_HANDLE:
return state.TranslateTagHandle("!") + value;
case SECONDARY_HANDLE:
return state.TranslateTagHandle("!!") + value;
case NAMED_HANDLE:
return state.TranslateTagHandle("!" + handle + "!") + value;
case NON_SPECIFIC:
// TODO:
return "!";
default:
assert(false);
}
}
}

26
src/tag.h Normal file
View File

@@ -0,0 +1,26 @@
#pragma once
#ifndef TAG_H_62B23520_7C8E_11DE_8A39_0800200C9A66
#define TAG_H_62B23520_7C8E_11DE_8A39_0800200C9A66
#include <string>
namespace YAML
{
struct Token;
struct ParserState;
struct Tag {
enum TYPE {
VERBATIM, PRIMARY_HANDLE, SECONDARY_HANDLE, NAMED_HANDLE, NON_SPECIFIC
};
Tag(const Token& token);
const std::string Translate(const ParserState& state);
TYPE type;
std::string handle, value;
};
}
#endif // TAG_H_62B23520_7C8E_11DE_8A39_0800200C9A66

View File

@@ -24,6 +24,7 @@ namespace YAML
"FLOW_MAP_START", "FLOW_MAP_START",
"FLOW_SEQ_END", "FLOW_SEQ_END",
"FLOW_MAP_END", "FLOW_MAP_END",
"FLOW_MAP_COMPACT",
"FLOW_ENTRY", "FLOW_ENTRY",
"KEY", "KEY",
"VALUE", "VALUE",
@@ -49,6 +50,7 @@ namespace YAML
FLOW_MAP_START, FLOW_MAP_START,
FLOW_SEQ_END, FLOW_SEQ_END,
FLOW_MAP_END, FLOW_MAP_END,
FLOW_MAP_COMPACT,
FLOW_ENTRY, FLOW_ENTRY,
KEY, KEY,
VALUE, VALUE,
@@ -59,7 +61,7 @@ namespace YAML
}; };
// data // data
Token(TYPE type_, const Mark& mark_): status(VALID), type(type_), mark(mark_) {} Token(TYPE type_, const Mark& mark_): status(VALID), type(type_), mark(mark_), data(0) {}
friend std::ostream& operator << (std::ostream& out, const Token& token) { friend std::ostream& operator << (std::ostream& out, const Token& token) {
out << TokenNames[token.type] << std::string(": ") << token.value; out << TokenNames[token.type] << std::string(": ") << token.value;
@@ -73,6 +75,7 @@ namespace YAML
Mark mark; Mark mark;
std::string value; std::string value;
std::vector <std::string> params; std::vector <std::string> params;
int data;
}; };
} }

226
test.vcproj Normal file
View File

@@ -0,0 +1,226 @@
<?xml version="1.0" encoding="Windows-1252"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="9.00"
Name="test"
ProjectGUID="{D1108F40-6ADF-467E-A95A-236C39A515C5}"
RootNamespace="test"
TargetFrameworkVersion="196613"
>
<Platforms>
<Platform
Name="Win32"
/>
</Platforms>
<ToolFiles>
</ToolFiles>
<Configurations>
<Configuration
Name="Debug|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="1"
CharacterSet="2"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
AdditionalOptions="/D_SCL_SECURE_NO_WARNINGS"
Optimization="0"
AdditionalIncludeDirectories="include"
MinimalRebuild="true"
BasicRuntimeChecks="3"
RuntimeLibrary="3"
WarningLevel="3"
DebugInformationFormat="4"
DisableSpecificWarnings="4127;4355"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
AdditionalDependencies="yamlcppd.lib"
AdditionalLibraryDirectories="lib"
GenerateDebugInformation="true"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
Name="Release|Win32"
OutputDirectory="$(SolutionDir)$(ConfigurationName)"
IntermediateDirectory="$(ConfigurationName)"
ConfigurationType="1"
CharacterSet="2"
WholeProgramOptimization="1"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
AdditionalOptions="/D_SCL_SECURE_NO_WARNINGS"
Optimization="2"
EnableIntrinsicFunctions="true"
AdditionalIncludeDirectories="include"
RuntimeLibrary="2"
EnableFunctionLevelLinking="true"
WarningLevel="3"
DebugInformationFormat="3"
DisableSpecificWarnings="4127;4355"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
AdditionalDependencies="yamlcpp.lib"
AdditionalLibraryDirectories="lib"
GenerateDebugInformation="true"
OptimizeReferences="2"
EnableCOMDATFolding="2"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<Filter
Name="Source Files"
Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
>
<File
RelativePath=".\test\emittertests.cpp"
>
</File>
<File
RelativePath=".\test\main.cpp"
>
</File>
<File
RelativePath=".\test\parsertests.cpp"
>
</File>
<File
RelativePath=".\test\spectests.cpp"
>
</File>
<File
RelativePath=".\test\tests.cpp"
>
</File>
</Filter>
<Filter
Name="Header Files"
Filter="h;hpp;hxx;hm;inl;inc;xsd"
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
>
<File
RelativePath=".\test\emittertests.h"
>
</File>
<File
RelativePath=".\test\parsertests.h"
>
</File>
<File
RelativePath=".\test\spectests.h"
>
</File>
<File
RelativePath=".\test\tests.h"
>
</File>
</Filter>
<Filter
Name="Resource Files"
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
>
</Filter>
</Files>
<Globals>
</Globals>
</VisualStudioProject>

10
test/CMakeLists.txt Normal file
View File

@@ -0,0 +1,10 @@
file(GLOB test_headers [a-z]*.h)
file(GLOB test_sources [a-z]*.cpp)
add_executable(run-tests
${test_sources}
${test_headers}
)
target_link_libraries(run-tests yaml-cpp)
add_test(yaml-reader-test run-tests)

View File

@@ -9,7 +9,7 @@ namespace Test
void SimpleScalar(YAML::Emitter& out, std::string& desiredOutput) { void SimpleScalar(YAML::Emitter& out, std::string& desiredOutput) {
out << "Hello, World!"; out << "Hello, World!";
desiredOutput = "Hello, World!"; desiredOutput = "--- Hello, World!";
} }
void SimpleSeq(YAML::Emitter& out, std::string& desiredOutput) { void SimpleSeq(YAML::Emitter& out, std::string& desiredOutput) {
@@ -19,7 +19,7 @@ namespace Test
out << "milk"; out << "milk";
out << YAML::EndSeq; out << YAML::EndSeq;
desiredOutput = "- eggs\n- bread\n- milk"; desiredOutput = "---\n- eggs\n- bread\n- milk";
} }
void SimpleFlowSeq(YAML::Emitter& out, std::string& desiredOutput) { void SimpleFlowSeq(YAML::Emitter& out, std::string& desiredOutput) {
@@ -30,7 +30,7 @@ namespace Test
out << "Moe"; out << "Moe";
out << YAML::EndSeq; out << YAML::EndSeq;
desiredOutput = "[Larry, Curly, Moe]"; desiredOutput = "--- [Larry, Curly, Moe]";
} }
void EmptyFlowSeq(YAML::Emitter& out, std::string& desiredOutput) { void EmptyFlowSeq(YAML::Emitter& out, std::string& desiredOutput) {
@@ -38,7 +38,7 @@ namespace Test
out << YAML::BeginSeq; out << YAML::BeginSeq;
out << YAML::EndSeq; out << YAML::EndSeq;
desiredOutput = "[]"; desiredOutput = "--- []";
} }
void NestedBlockSeq(YAML::Emitter& out, std::string& desiredOutput) { void NestedBlockSeq(YAML::Emitter& out, std::string& desiredOutput) {
@@ -47,7 +47,7 @@ namespace Test
out << YAML::BeginSeq << "subitem 1" << "subitem 2" << YAML::EndSeq; out << YAML::BeginSeq << "subitem 1" << "subitem 2" << YAML::EndSeq;
out << YAML::EndSeq; out << YAML::EndSeq;
desiredOutput = "- item 1\n-\n - subitem 1\n - subitem 2"; desiredOutput = "---\n- item 1\n-\n - subitem 1\n - subitem 2";
} }
void NestedFlowSeq(YAML::Emitter& out, std::string& desiredOutput) { void NestedFlowSeq(YAML::Emitter& out, std::string& desiredOutput) {
@@ -56,7 +56,7 @@ namespace Test
out << YAML::Flow << YAML::BeginSeq << "two" << "three" << YAML::EndSeq; out << YAML::Flow << YAML::BeginSeq << "two" << "three" << YAML::EndSeq;
out << YAML::EndSeq; out << YAML::EndSeq;
desiredOutput = "- one\n- [two, three]"; desiredOutput = "---\n- one\n- [two, three]";
} }
void SimpleMap(YAML::Emitter& out, std::string& desiredOutput) { void SimpleMap(YAML::Emitter& out, std::string& desiredOutput) {
@@ -67,7 +67,7 @@ namespace Test
out << YAML::Value << "3B"; out << YAML::Value << "3B";
out << YAML::EndMap; out << YAML::EndMap;
desiredOutput = "name: Ryan Braun\nposition: 3B"; desiredOutput = "---\nname: Ryan Braun\nposition: 3B";
} }
void SimpleFlowMap(YAML::Emitter& out, std::string& desiredOutput) { void SimpleFlowMap(YAML::Emitter& out, std::string& desiredOutput) {
@@ -79,7 +79,7 @@ namespace Test
out << YAML::Value << "blue"; out << YAML::Value << "blue";
out << YAML::EndMap; out << YAML::EndMap;
desiredOutput = "{shape: square, color: blue}"; desiredOutput = "--- {shape: square, color: blue}";
} }
void MapAndList(YAML::Emitter& out, std::string& desiredOutput) { void MapAndList(YAML::Emitter& out, std::string& desiredOutput) {
@@ -90,7 +90,7 @@ namespace Test
out << YAML::Value << YAML::BeginSeq << "Sasha" << "Malia" << YAML::EndSeq; out << YAML::Value << YAML::BeginSeq << "Sasha" << "Malia" << YAML::EndSeq;
out << YAML::EndMap; out << YAML::EndMap;
desiredOutput = "name: Barack Obama\nchildren:\n - Sasha\n - Malia"; desiredOutput = "---\nname: Barack Obama\nchildren:\n - Sasha\n - Malia";
} }
void ListAndMap(YAML::Emitter& out, std::string& desiredOutput) { void ListAndMap(YAML::Emitter& out, std::string& desiredOutput) {
@@ -103,7 +103,7 @@ namespace Test
out << "item 2"; out << "item 2";
out << YAML::EndSeq; out << YAML::EndSeq;
desiredOutput = "- item 1\n-\n pens: 8\n pencils: 14\n- item 2"; desiredOutput = "---\n- item 1\n-\n pens: 8\n pencils: 14\n- item 2";
} }
void NestedBlockMap(YAML::Emitter& out, std::string& desiredOutput) { void NestedBlockMap(YAML::Emitter& out, std::string& desiredOutput) {
@@ -119,7 +119,7 @@ namespace Test
out << YAML::EndMap; out << YAML::EndMap;
out << YAML::EndMap; out << YAML::EndMap;
desiredOutput = "name: Fred\ngrades:\n algebra: A\n physics: C+\n literature: B"; desiredOutput = "---\nname: Fred\ngrades:\n algebra: A\n physics: C+\n literature: B";
} }
void NestedFlowMap(YAML::Emitter& out, std::string& desiredOutput) { void NestedFlowMap(YAML::Emitter& out, std::string& desiredOutput) {
@@ -136,7 +136,7 @@ namespace Test
out << YAML::EndMap; out << YAML::EndMap;
out << YAML::EndMap; out << YAML::EndMap;
desiredOutput = "{name: Fred, grades: {algebra: A, physics: C+, literature: B}}"; desiredOutput = "--- {name: Fred, grades: {algebra: A, physics: C+, literature: B}}";
} }
void MapListMix(YAML::Emitter& out, std::string& desiredOutput) { void MapListMix(YAML::Emitter& out, std::string& desiredOutput) {
@@ -149,7 +149,7 @@ namespace Test
out << YAML::Key << "invincible" << YAML::Value << YAML::OnOffBool << false; out << YAML::Key << "invincible" << YAML::Value << YAML::OnOffBool << false;
out << YAML::EndMap; out << YAML::EndMap;
desiredOutput = "name: Bob\nposition: [2, 4]\ninvincible: off"; desiredOutput = "---\nname: Bob\nposition: [2, 4]\ninvincible: off";
} }
void SimpleLongKey(YAML::Emitter& out, std::string& desiredOutput) void SimpleLongKey(YAML::Emitter& out, std::string& desiredOutput)
@@ -162,7 +162,7 @@ namespace Test
out << YAML::Value << 145; out << YAML::Value << 145;
out << YAML::EndMap; out << YAML::EndMap;
desiredOutput = "? height\n: 5'9\"\n? weight\n: 145"; desiredOutput = "---\n? height\n: 5'9\"\n? weight\n: 145";
} }
void SingleLongKey(YAML::Emitter& out, std::string& desiredOutput) void SingleLongKey(YAML::Emitter& out, std::string& desiredOutput)
@@ -176,7 +176,7 @@ namespace Test
out << YAML::Value << 145; out << YAML::Value << 145;
out << YAML::EndMap; out << YAML::EndMap;
desiredOutput = "age: 24\n? height\n: 5'9\"\nweight: 145"; desiredOutput = "---\nage: 24\n? height\n: 5'9\"\nweight: 145";
} }
void ComplexLongKey(YAML::Emitter& out, std::string& desiredOutput) void ComplexLongKey(YAML::Emitter& out, std::string& desiredOutput)
@@ -189,7 +189,7 @@ namespace Test
out << YAML::Value << "demon"; out << YAML::Value << "demon";
out << YAML::EndMap; out << YAML::EndMap;
desiredOutput = "?\n - 1\n - 3\n: monster\n? [2, 0]\n: demon"; desiredOutput = "---\n?\n - 1\n - 3\n: monster\n? [2, 0]\n: demon";
} }
void AutoLongKey(YAML::Emitter& out, std::string& desiredOutput) void AutoLongKey(YAML::Emitter& out, std::string& desiredOutput)
@@ -203,7 +203,7 @@ namespace Test
out << YAML::Value << "angel"; out << YAML::Value << "angel";
out << YAML::EndMap; out << YAML::EndMap;
desiredOutput = "?\n - 1\n - 3\n: monster\n? [2, 0]\n: demon\nthe origin: angel"; desiredOutput = "---\n?\n - 1\n - 3\n: monster\n? [2, 0]\n: demon\nthe origin: angel";
} }
void ScalarFormat(YAML::Emitter& out, std::string& desiredOutput) void ScalarFormat(YAML::Emitter& out, std::string& desiredOutput)
@@ -217,7 +217,7 @@ namespace Test
out << YAML::Literal << "literal scalar\nthat may span\nmany, many\nlines and have \"whatever\" crazy\tsymbols that we like"; out << YAML::Literal << "literal scalar\nthat may span\nmany, many\nlines and have \"whatever\" crazy\tsymbols that we like";
out << YAML::EndSeq; out << YAML::EndSeq;
desiredOutput = "- simple scalar\n- 'explicit single-quoted scalar'\n- \"explicit double-quoted scalar\"\n- \"auto-detected\\x0adouble-quoted scalar\"\n- a non-\"auto-detected\" double-quoted scalar\n- |\n literal scalar\n that may span\n many, many\n lines and have \"whatever\" crazy\tsymbols that we like"; desiredOutput = "---\n- simple scalar\n- 'explicit single-quoted scalar'\n- \"explicit double-quoted scalar\"\n- \"auto-detected\\x0adouble-quoted scalar\"\n- a non-\"auto-detected\" double-quoted scalar\n- |\n literal scalar\n that may span\n many, many\n lines and have \"whatever\" crazy\tsymbols that we like";
} }
void AutoLongKeyScalar(YAML::Emitter& out, std::string& desiredOutput) void AutoLongKeyScalar(YAML::Emitter& out, std::string& desiredOutput)
@@ -227,7 +227,7 @@ namespace Test
out << YAML::Value << "and its value"; out << YAML::Value << "and its value";
out << YAML::EndMap; out << YAML::EndMap;
desiredOutput = "? |\n multi-line\n scalar\n: and its value"; desiredOutput = "---\n? |\n multi-line\n scalar\n: and its value";
} }
void LongKeyFlowMap(YAML::Emitter& out, std::string& desiredOutput) void LongKeyFlowMap(YAML::Emitter& out, std::string& desiredOutput)
@@ -240,7 +240,7 @@ namespace Test
out << YAML::Value << "and its value"; out << YAML::Value << "and its value";
out << YAML::EndMap; out << YAML::EndMap;
desiredOutput = "{simple key: and value, ? long key: and its value}"; desiredOutput = "--- {simple key: and value, ? long key: and its value}";
} }
void BlockMapAsKey(YAML::Emitter& out, std::string& desiredOutput) void BlockMapAsKey(YAML::Emitter& out, std::string& desiredOutput)
@@ -255,7 +255,7 @@ namespace Test
out << "total value"; out << "total value";
out << YAML::EndMap; out << YAML::EndMap;
desiredOutput = "?\n key: value\n next key: next value\n: total value"; desiredOutput = "---\n?\n key: value\n next key: next value\n: total value";
} }
void AliasAndAnchor(YAML::Emitter& out, std::string& desiredOutput) void AliasAndAnchor(YAML::Emitter& out, std::string& desiredOutput)
@@ -269,7 +269,7 @@ namespace Test
out << YAML::Alias("fred"); out << YAML::Alias("fred");
out << YAML::EndSeq; out << YAML::EndSeq;
desiredOutput = "- &fred\n name: Fred\n age: 42\n- *fred"; desiredOutput = "---\n- &fred\n name: Fred\n age: 42\n- *fred";
} }
void AliasAndAnchorWithNull(YAML::Emitter& out, std::string& desiredOutput) void AliasAndAnchorWithNull(YAML::Emitter& out, std::string& desiredOutput)
@@ -279,7 +279,98 @@ namespace Test
out << YAML::Alias("fred"); out << YAML::Alias("fred");
out << YAML::EndSeq; out << YAML::EndSeq;
desiredOutput = "- &fred ~\n- *fred"; desiredOutput = "---\n- &fred ~\n- *fred";
}
void SimpleVerbatimTag(YAML::Emitter& out, std::string& desiredOutput)
{
out << YAML::VerbatimTag("!foo") << "bar";
desiredOutput = "--- !<!foo> bar";
}
void VerbatimTagInBlockSeq(YAML::Emitter& out, std::string& desiredOutput)
{
out << YAML::BeginSeq;
out << YAML::VerbatimTag("!foo") << "bar";
out << "baz";
out << YAML::EndSeq;
desiredOutput = "---\n- !<!foo> bar\n- baz";
}
void VerbatimTagInFlowSeq(YAML::Emitter& out, std::string& desiredOutput)
{
out << YAML::Flow << YAML::BeginSeq;
out << YAML::VerbatimTag("!foo") << "bar";
out << "baz";
out << YAML::EndSeq;
desiredOutput = "--- [!<!foo> bar, baz]";
}
void VerbatimTagInFlowSeqWithNull(YAML::Emitter& out, std::string& desiredOutput)
{
out << YAML::Flow << YAML::BeginSeq;
out << YAML::VerbatimTag("!foo") << YAML::Null;
out << "baz";
out << YAML::EndSeq;
desiredOutput = "--- [!<!foo> ~, baz]";
}
void VerbatimTagInBlockMap(YAML::Emitter& out, std::string& desiredOutput)
{
out << YAML::BeginMap;
out << YAML::Key << YAML::VerbatimTag("!foo") << "bar";
out << YAML::Value << YAML::VerbatimTag("!waz") << "baz";
out << YAML::EndMap;
desiredOutput = "---\n!<!foo> bar: !<!waz> baz";
}
void VerbatimTagInFlowMap(YAML::Emitter& out, std::string& desiredOutput)
{
out << YAML::Flow << YAML::BeginMap;
out << YAML::Key << YAML::VerbatimTag("!foo") << "bar";
out << YAML::Value << "baz";
out << YAML::EndMap;
desiredOutput = "--- {!<!foo> bar: baz}";
}
void VerbatimTagInFlowMapWithNull(YAML::Emitter& out, std::string& desiredOutput)
{
out << YAML::Flow << YAML::BeginMap;
out << YAML::Key << YAML::VerbatimTag("!foo") << YAML::Null;
out << YAML::Value << "baz";
out << YAML::EndMap;
desiredOutput = "--- {!<!foo> ~: baz}";
}
void VerbatimTagWithEmptySeq(YAML::Emitter& out, std::string& desiredOutput)
{
out << YAML::VerbatimTag("!foo") << YAML::BeginSeq << YAML::EndSeq;
desiredOutput = "--- !<!foo>\n[]";
}
void VerbatimTagWithEmptyMap(YAML::Emitter& out, std::string& desiredOutput)
{
out << YAML::VerbatimTag("!bar") << YAML::BeginMap << YAML::EndMap;
desiredOutput = "--- !<!bar>\n{}";
}
void VerbatimTagWithEmptySeqAndMap(YAML::Emitter& out, std::string& desiredOutput)
{
out << YAML::BeginSeq;
out << YAML::VerbatimTag("!foo") << YAML::BeginSeq << YAML::EndSeq;
out << YAML::VerbatimTag("!bar") << YAML::BeginMap << YAML::EndMap;
out << YAML::EndSeq;
desiredOutput = "---\n- !<!foo>\n []\n- !<!bar>\n {}";
} }
void ComplexDoc(YAML::Emitter& out, std::string& desiredOutput) void ComplexDoc(YAML::Emitter& out, std::string& desiredOutput)
@@ -335,7 +426,7 @@ namespace Test
out << YAML::Value << YAML::Alias("id001"); out << YAML::Value << YAML::Alias("id001");
out << YAML::EndMap; out << YAML::EndMap;
desiredOutput = "receipt: Oz-Ware Purchase Invoice\ndate: 2007-08-06\ncustomer:\n given: Dorothy\n family: Gale\nitems:\n -\n part_no: A4786\n descrip: Water Bucket (Filled)\n price: 1.47\n quantity: 4\n -\n part_no: E1628\n descrip: High Heeled \"Ruby\" Slippers\n price: 100.27\n quantity: 1\nbill-to: &id001\n street: |\n 123 Tornado Alley\n Suite 16\n city: East Westville\n state: KS\nship-to: *id001"; desiredOutput = "---\nreceipt: Oz-Ware Purchase Invoice\ndate: 2007-08-06\ncustomer:\n given: Dorothy\n family: Gale\nitems:\n -\n part_no: A4786\n descrip: Water Bucket (Filled)\n price: 1.47\n quantity: 4\n -\n part_no: E1628\n descrip: High Heeled \"Ruby\" Slippers\n price: 100.27\n quantity: 1\nbill-to: &id001\n street: |\n 123 Tornado Alley\n Suite 16\n city: East Westville\n state: KS\nship-to: *id001";
} }
void STLContainers(YAML::Emitter& out, std::string& desiredOutput) void STLContainers(YAML::Emitter& out, std::string& desiredOutput)
@@ -355,7 +446,7 @@ namespace Test
out << ages; out << ages;
out << YAML::EndSeq; out << YAML::EndSeq;
desiredOutput = "- [2, 3, 5, 7, 11, 13]\n-\n Daniel: 26\n Jesse: 24"; desiredOutput = "---\n- [2, 3, 5, 7, 11, 13]\n-\n Daniel: 26\n Jesse: 24";
} }
void SimpleComment(YAML::Emitter& out, std::string& desiredOutput) void SimpleComment(YAML::Emitter& out, std::string& desiredOutput)
@@ -365,7 +456,7 @@ namespace Test
out << YAML::Value << "least squares" << YAML::Comment("should we change this method?"); out << YAML::Value << "least squares" << YAML::Comment("should we change this method?");
out << YAML::EndMap; out << YAML::EndMap;
desiredOutput = "method: least squares # should we change this method?"; desiredOutput = "---\nmethod: least squares # should we change this method?";
} }
void MultiLineComment(YAML::Emitter& out, std::string& desiredOutput) void MultiLineComment(YAML::Emitter& out, std::string& desiredOutput)
@@ -375,7 +466,7 @@ namespace Test
out << "item 2"; out << "item 2";
out << YAML::EndSeq; out << YAML::EndSeq;
desiredOutput = "- item 1 # really really long\n # comment that couldn't possibly\n # fit on one line\n- item 2"; desiredOutput = "---\n- item 1 # really really long\n # comment that couldn't possibly\n # fit on one line\n- item 2";
} }
void ComplexComments(YAML::Emitter& out, std::string& desiredOutput) void ComplexComments(YAML::Emitter& out, std::string& desiredOutput)
@@ -385,7 +476,7 @@ namespace Test
out << YAML::Value << "value"; out << YAML::Value << "value";
out << YAML::EndMap; out << YAML::EndMap;
desiredOutput = "? long key # long key\n: value"; desiredOutput = "---\n? long key # long key\n: value";
} }
void Indentation(YAML::Emitter& out, std::string& desiredOutput) void Indentation(YAML::Emitter& out, std::string& desiredOutput)
@@ -398,7 +489,7 @@ namespace Test
out << YAML::EndMap; out << YAML::EndMap;
out << YAML::EndSeq; out << YAML::EndSeq;
desiredOutput = "-\n key 1: value 1\n key 2:\n - a\n - b\n - c"; desiredOutput = "---\n-\n key 1: value 1\n key 2:\n - a\n - b\n - c";
} }
void SimpleGlobalSettings(YAML::Emitter& out, std::string& desiredOutput) void SimpleGlobalSettings(YAML::Emitter& out, std::string& desiredOutput)
@@ -413,7 +504,7 @@ namespace Test
out << YAML::EndMap; out << YAML::EndMap;
out << YAML::EndSeq; out << YAML::EndSeq;
desiredOutput = "-\n ? key 1\n : value 1\n ? key 2\n : [a, b, c]"; desiredOutput = "---\n-\n ? key 1\n : value 1\n ? key 2\n : [a, b, c]";
} }
void ComplexGlobalSettings(YAML::Emitter& out, std::string& desiredOutput) void ComplexGlobalSettings(YAML::Emitter& out, std::string& desiredOutput)
@@ -432,7 +523,7 @@ namespace Test
out << YAML::EndMap; out << YAML::EndMap;
out << YAML::EndSeq; out << YAML::EndSeq;
desiredOutput = "-\n key 1: value 1\n key 2: [a, b, c]\n-\n ? [1, 2]\n :\n a: b"; desiredOutput = "---\n-\n key 1: value 1\n key 2: [a, b, c]\n-\n ? [1, 2]\n :\n a: b";
} }
void Null(YAML::Emitter& out, std::string& desiredOutput) void Null(YAML::Emitter& out, std::string& desiredOutput)
@@ -445,28 +536,96 @@ namespace Test
out << YAML::EndMap; out << YAML::EndMap;
out << YAML::EndSeq; out << YAML::EndSeq;
desiredOutput = "- ~\n-\n null value: ~\n ~: null key"; desiredOutput = "---\n- ~\n-\n null value: ~\n ~: null key";
} }
void EscapedUnicode(YAML::Emitter& out, std::string& desiredOutput) void EscapedUnicode(YAML::Emitter& out, std::string& desiredOutput)
{ {
out << YAML::EscapeNonAscii << "\x24 \xC2\xA2 \xE2\x82\xAC \xF0\xA4\xAD\xA2"; out << YAML::EscapeNonAscii << "\x24 \xC2\xA2 \xE2\x82\xAC \xF0\xA4\xAD\xA2";
desiredOutput = "\"$ \\xa2 \\u20ac \\U00024b62\""; desiredOutput = "--- \"$ \\xa2 \\u20ac \\U00024b62\"";
} }
void Unicode(YAML::Emitter& out, std::string& desiredOutput) void Unicode(YAML::Emitter& out, std::string& desiredOutput)
{ {
out << "\x24 \xC2\xA2 \xE2\x82\xAC \xF0\xA4\xAD\xA2"; out << "\x24 \xC2\xA2 \xE2\x82\xAC \xF0\xA4\xAD\xA2";
desiredOutput = "\x24 \xC2\xA2 \xE2\x82\xAC \xF0\xA4\xAD\xA2"; desiredOutput = "--- \x24 \xC2\xA2 \xE2\x82\xAC \xF0\xA4\xAD\xA2";
} }
void DoubleQuotedUnicode(YAML::Emitter& out, std::string& desiredOutput) void DoubleQuotedUnicode(YAML::Emitter& out, std::string& desiredOutput)
{ {
out << YAML::DoubleQuoted << "\x24 \xC2\xA2 \xE2\x82\xAC \xF0\xA4\xAD\xA2"; out << YAML::DoubleQuoted << "\x24 \xC2\xA2 \xE2\x82\xAC \xF0\xA4\xAD\xA2";
desiredOutput = "\"\x24 \xC2\xA2 \xE2\x82\xAC \xF0\xA4\xAD\xA2\""; desiredOutput = "--- \"\x24 \xC2\xA2 \xE2\x82\xAC \xF0\xA4\xAD\xA2\"";
} }
struct Foo {
Foo(): x(0) {}
Foo(int x_, const std::string& bar_): x(x_), bar(bar_) {}
int x;
std::string bar;
};
YAML::Emitter& operator << (YAML::Emitter& out, const Foo& foo) {
out << YAML::BeginMap;
out << YAML::Key << "x" << YAML::Value << foo.x;
out << YAML::Key << "bar" << YAML::Value << foo.bar;
out << YAML::EndMap;
return out;
}
void UserType(YAML::Emitter& out, std::string& desiredOutput)
{
out << YAML::BeginSeq;
out << Foo(5, "hello");
out << Foo(3, "goodbye");
out << YAML::EndSeq;
desiredOutput = "---\n-\n x: 5\n bar: hello\n-\n x: 3\n bar: goodbye";
}
void UserTypeInContainer(YAML::Emitter& out, std::string& desiredOutput)
{
std::vector<Foo> fv;
fv.push_back(Foo(5, "hello"));
fv.push_back(Foo(3, "goodbye"));
out << fv;
desiredOutput = "---\n-\n x: 5\n bar: hello\n-\n x: 3\n bar: goodbye";
}
template <typename T>
YAML::Emitter& operator << (YAML::Emitter& out, const T *v) {
if(v)
out << *v;
else
out << YAML::Null;
return out;
}
void PointerToInt(YAML::Emitter& out, std::string& desiredOutput)
{
int foo = 5;
int *bar = &foo;
int *baz = 0;
out << YAML::BeginSeq;
out << bar << baz;
out << YAML::EndSeq;
desiredOutput = "---\n- 5\n- ~";
}
void PointerToUserType(YAML::Emitter& out, std::string& desiredOutput)
{
Foo foo(5, "hello");
Foo *bar = &foo;
Foo *baz = 0;
out << YAML::BeginSeq;
out << bar << baz;
out << YAML::EndSeq;
desiredOutput = "---\n-\n x: 5\n bar: hello\n- ~";
}
//////////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////////
// incorrect emitting // incorrect emitting
@@ -620,6 +779,16 @@ namespace Test
RunEmitterTest(&Emitter::BlockMapAsKey, "block map as key", passed, total); RunEmitterTest(&Emitter::BlockMapAsKey, "block map as key", passed, total);
RunEmitterTest(&Emitter::AliasAndAnchor, "alias and anchor", passed, total); RunEmitterTest(&Emitter::AliasAndAnchor, "alias and anchor", passed, total);
RunEmitterTest(&Emitter::AliasAndAnchorWithNull, "alias and anchor with null", passed, total); RunEmitterTest(&Emitter::AliasAndAnchorWithNull, "alias and anchor with null", passed, total);
RunEmitterTest(&Emitter::SimpleVerbatimTag, "simple verbatim tag", passed, total);
RunEmitterTest(&Emitter::VerbatimTagInBlockSeq, "verbatim tag in block seq", passed, total);
RunEmitterTest(&Emitter::VerbatimTagInFlowSeq, "verbatim tag in flow seq", passed, total);
RunEmitterTest(&Emitter::VerbatimTagInFlowSeqWithNull, "verbatim tag in flow seq with null", passed, total);
RunEmitterTest(&Emitter::VerbatimTagInBlockMap, "verbatim tag in block map", passed, total);
RunEmitterTest(&Emitter::VerbatimTagInFlowMap, "verbatim tag in flow map", passed, total);
RunEmitterTest(&Emitter::VerbatimTagInFlowMapWithNull, "verbatim tag in flow map with null", passed, total);
RunEmitterTest(&Emitter::VerbatimTagWithEmptySeq, "verbatim tag with empty seq", passed, total);
RunEmitterTest(&Emitter::VerbatimTagWithEmptyMap, "verbatim tag with empty map", passed, total);
RunEmitterTest(&Emitter::VerbatimTagWithEmptySeqAndMap, "verbatim tag with empty seq and map", passed, total);
RunEmitterTest(&Emitter::ComplexDoc, "complex doc", passed, total); RunEmitterTest(&Emitter::ComplexDoc, "complex doc", passed, total);
RunEmitterTest(&Emitter::STLContainers, "STL containers", passed, total); RunEmitterTest(&Emitter::STLContainers, "STL containers", passed, total);
RunEmitterTest(&Emitter::SimpleComment, "simple comment", passed, total); RunEmitterTest(&Emitter::SimpleComment, "simple comment", passed, total);
@@ -632,6 +801,10 @@ namespace Test
RunEmitterTest(&Emitter::EscapedUnicode, "escaped unicode", passed, total); RunEmitterTest(&Emitter::EscapedUnicode, "escaped unicode", passed, total);
RunEmitterTest(&Emitter::Unicode, "unicode", passed, total); RunEmitterTest(&Emitter::Unicode, "unicode", passed, total);
RunEmitterTest(&Emitter::DoubleQuotedUnicode, "double quoted unicode", passed, total); RunEmitterTest(&Emitter::DoubleQuotedUnicode, "double quoted unicode", passed, total);
RunEmitterTest(&Emitter::UserType, "user type", passed, total);
RunEmitterTest(&Emitter::UserTypeInContainer, "user type in container", passed, total);
RunEmitterTest(&Emitter::PointerToInt, "pointer to int", passed, total);
RunEmitterTest(&Emitter::PointerToUserType, "pointer to user type", passed, total);
RunEmitterErrorTest(&Emitter::ExtraEndSeq, "extra EndSeq", passed, total); RunEmitterErrorTest(&Emitter::ExtraEndSeq, "extra EndSeq", passed, total);
RunEmitterErrorTest(&Emitter::ExtraEndMap, "extra EndMap", passed, total); RunEmitterErrorTest(&Emitter::ExtraEndMap, "extra EndMap", passed, total);

7
test/main.cpp Normal file
View File

@@ -0,0 +1,7 @@
#include "tests.h"
int main()
{
Test::RunAll();
return 0;
}

View File

@@ -610,6 +610,102 @@ namespace Test
return true; return true;
} }
bool BlockKeyWithNullValue()
{
std::string input =
"key:\n"
"just a key: value";
std::stringstream stream(input);
YAML::Parser parser(stream);
YAML::Node doc;
parser.GetNextDocument(doc);
if(doc.size() != 2)
return false;
if(!IsNull(doc["key"]))
return false;
if(doc["just a key"] != "value")
return false;
return true;
}
bool Bases()
{
std::string input =
"- 15\n"
"- 0x10\n"
"- 030\n"
"- 0xffffffff\n";
std::stringstream stream(input);
YAML::Parser parser(stream);
YAML::Node doc;
parser.GetNextDocument(doc);
if(doc.size() != 4)
return false;
if(doc[0] != 15)
return false;
if(doc[1] != 0x10)
return false;
if(doc[2] != 030)
return false;
if(doc[3] != 0xffffffff)
return false;
return true;
}
bool KeyNotFound()
{
std::string input = "key: value";
std::stringstream stream(input);
YAML::Parser parser(stream);
YAML::Node doc;
parser.GetNextDocument(doc);
try {
doc["bad key"];
} catch(const YAML::Exception& e) {
if(e.msg != YAML::ErrorMsg::KEY_NOT_FOUND + ": bad key")
throw;
}
try {
doc[5];
} catch(const YAML::Exception& e) {
if(e.msg != YAML::ErrorMsg::KEY_NOT_FOUND + ": 5")
throw;
}
try {
doc[2.5];
} catch(const YAML::Exception& e) {
if(e.msg != YAML::ErrorMsg::KEY_NOT_FOUND + ": 2.5")
throw;
}
return true;
}
bool DuplicateKey()
{
std::string input = "{a: 1, b: 2, c: 3, a: 4}";
std::stringstream stream(input);
YAML::Parser parser(stream);
YAML::Node doc;
parser.GetNextDocument(doc);
if(doc["a"] != 1)
return false;
if(doc["b"] != 2)
return false;
if(doc["c"] != 3)
return false;
return true;
}
} }
namespace { namespace {
@@ -627,7 +723,7 @@ namespace Test
doc >> output; doc >> output;
} catch(const YAML::Exception& e) { } catch(const YAML::Exception& e) {
ok = false; ok = false;
error = e.msg; error = e.what();
} }
if(ok && output == desiredOutput) { if(ok && output == desiredOutput) {
passed++; passed++;
@@ -869,6 +965,10 @@ namespace Test
RunParserTest(&Parser::MultipleDocs, "multiple docs", passed, total); RunParserTest(&Parser::MultipleDocs, "multiple docs", passed, total);
RunParserTest(&Parser::ExplicitEndDoc, "explicit end doc", passed, total); RunParserTest(&Parser::ExplicitEndDoc, "explicit end doc", passed, total);
RunParserTest(&Parser::MultipleDocsWithSomeExplicitIndicators, "multiple docs with some explicit indicators", passed, total); RunParserTest(&Parser::MultipleDocsWithSomeExplicitIndicators, "multiple docs with some explicit indicators", passed, total);
RunParserTest(&Parser::BlockKeyWithNullValue, "block key with null value", passed, total);
RunParserTest(&Parser::Bases, "bases", passed, total);
RunParserTest(&Parser::KeyNotFound, "key not found", passed, total);
RunParserTest(&Parser::DuplicateKey, "duplicate key", passed, total);
RunEncodingTest(&EncodeToUtf8, false, "UTF-8, no BOM", passed, total); RunEncodingTest(&EncodeToUtf8, false, "UTF-8, no BOM", passed, total);
RunEncodingTest(&EncodeToUtf8, true, "UTF-8 with BOM", passed, total); RunEncodingTest(&EncodeToUtf8, true, "UTF-8 with BOM", passed, total);

View File

@@ -32,7 +32,7 @@ namespace Test {
ret = test(); ret = test();
} catch(const YAML::Exception& e) { } catch(const YAML::Exception& e) {
ret.ok = false; ret.ok = false;
ret.error = " Exception caught: " + e.msg; ret.error = std::string(" Exception caught: ") + e.what();
} }
if(!ret.ok) { if(!ret.ok) {
@@ -459,7 +459,136 @@ namespace Test {
return true; return true;
} }
// TODO: 2.19 - 2.26 tags // TODO: 2.19 - 2.22 schema tags
// 2.23
TEST VariousExplicitTags()
{
std::string input =
"---\n"
"not-date: !!str 2002-04-28\n"
"\n"
"picture: !!binary |\n"
" R0lGODlhDAAMAIQAAP//9/X\n"
" 17unp5WZmZgAAAOfn515eXv\n"
" Pz7Y6OjuDg4J+fn5OTk6enp\n"
" 56enmleECcgggoBADs=\n"
"\n"
"application specific tag: !something |\n"
" The semantics of the tag\n"
" above may be different for\n"
" different documents.";
PARSE(doc, input);
YAML_ASSERT(doc.size() == 3);
YAML_ASSERT(doc["not-date"].GetTag() == "tag:yaml.org,2002:str");
YAML_ASSERT(doc["not-date"] == "2002-04-28");
YAML_ASSERT(doc["picture"].GetTag() == "tag:yaml.org,2002:binary");
YAML_ASSERT(doc["picture"] ==
"R0lGODlhDAAMAIQAAP//9/X\n"
"17unp5WZmZgAAAOfn515eXv\n"
"Pz7Y6OjuDg4J+fn5OTk6enp\n"
"56enmleECcgggoBADs=\n"
);
YAML_ASSERT(doc["application specific tag"].GetTag() == "!something");
YAML_ASSERT(doc["application specific tag"] ==
"The semantics of the tag\n"
"above may be different for\n"
"different documents."
);
return true;
}
// 2.24
TEST GlobalTags()
{
std::string input =
"%TAG ! tag:clarkevans.com,2002:\n"
"--- !shape\n"
" # Use the ! handle for presenting\n"
" # tag:clarkevans.com,2002:circle\n"
"- !circle\n"
" center: &ORIGIN {x: 73, y: 129}\n"
" radius: 7\n"
"- !line\n"
" start: *ORIGIN\n"
" finish: { x: 89, y: 102 }\n"
"- !label\n"
" start: *ORIGIN\n"
" color: 0xFFEEBB\n"
" text: Pretty vector drawing.";
PARSE(doc, input);
YAML_ASSERT(doc.GetTag() == "tag:clarkevans.com,2002:shape");
YAML_ASSERT(doc.size() == 3);
YAML_ASSERT(doc[0].GetTag() == "tag:clarkevans.com,2002:circle");
YAML_ASSERT(doc[0].size() == 2);
YAML_ASSERT(doc[0]["center"].size() == 2);
YAML_ASSERT(doc[0]["center"]["x"] == 73);
YAML_ASSERT(doc[0]["center"]["y"] == 129);
YAML_ASSERT(doc[0]["radius"] == 7);
YAML_ASSERT(doc[1].GetTag() == "tag:clarkevans.com,2002:line");
YAML_ASSERT(doc[1].size() == 2);
YAML_ASSERT(doc[1]["start"].size() == 2);
YAML_ASSERT(doc[1]["start"]["x"] == 73);
YAML_ASSERT(doc[1]["start"]["y"] == 129);
YAML_ASSERT(doc[1]["finish"].size() == 2);
YAML_ASSERT(doc[1]["finish"]["x"] == 89);
YAML_ASSERT(doc[1]["finish"]["y"] == 102);
YAML_ASSERT(doc[2].GetTag() == "tag:clarkevans.com,2002:label");
YAML_ASSERT(doc[2].size() == 3);
YAML_ASSERT(doc[2]["start"].size() == 2);
YAML_ASSERT(doc[2]["start"]["x"] == 73);
YAML_ASSERT(doc[2]["start"]["y"] == 129);
YAML_ASSERT(doc[2]["color"] == "0xFFEEBB");
YAML_ASSERT(doc[2]["text"] == "Pretty vector drawing.");
return true;
}
// 2.25
TEST UnorderedSets()
{
std::string input =
"# Sets are represented as a\n"
"# Mapping where each key is\n"
"# associated with a null value\n"
"--- !!set\n"
"? Mark McGwire\n"
"? Sammy Sosa\n"
"? Ken Griffey";
PARSE(doc, input);
YAML_ASSERT(doc.GetTag() == "tag:yaml.org,2002:set");
YAML_ASSERT(doc.size() == 3);
YAML_ASSERT(IsNull(doc["Mark McGwire"]));
YAML_ASSERT(IsNull(doc["Sammy Sosa"]));
YAML_ASSERT(IsNull(doc["Ken Griffey"]));
return true;
}
// 2.26
TEST OrderedMappings()
{
std::string input =
"# Ordered maps are represented as\n"
"# A sequence of mappings, with\n"
"# each mapping having one key\n"
"--- !!omap\n"
"- Mark McGwire: 65\n"
"- Sammy Sosa: 63\n"
"- Ken Griffey: 58";
PARSE(doc, input);
YAML_ASSERT(doc.GetTag() == "tag:yaml.org,2002:omap");
YAML_ASSERT(doc.size() == 3);
YAML_ASSERT(doc[0].size() == 1);
YAML_ASSERT(doc[0]["Mark McGwire"] == 65);
YAML_ASSERT(doc[1].size() == 1);
YAML_ASSERT(doc[1]["Sammy Sosa"] == 63);
YAML_ASSERT(doc[2].size() == 1);
YAML_ASSERT(doc[2]["Ken Griffey"] == 58);
return true;
}
// 2.27 // 2.27
TEST Invoice() TEST Invoice()
@@ -496,6 +625,7 @@ namespace Test {
" Billsmer @ 338-4338."; " Billsmer @ 338-4338.";
PARSE(doc, input); PARSE(doc, input);
YAML_ASSERT(doc.GetTag() == "tag:clarkevans.com,2002:invoice");
YAML_ASSERT(doc.size() == 8); YAML_ASSERT(doc.size() == 8);
YAML_ASSERT(doc["invoice"] == 34843); YAML_ASSERT(doc["invoice"] == 34843);
YAML_ASSERT(doc["date"] == "2001-01-23"); YAML_ASSERT(doc["date"] == "2001-01-23");
@@ -635,7 +765,16 @@ namespace Test {
return true; return true;
} }
// TODO: 5.5 comment only // 5.5
TEST CommentIndicator()
{
std::string input =
"# Comment only.";
PARSE(doc, input);
YAML_ASSERT(doc.size() == 0);
return true;
}
// 5.6 // 5.6
TEST NodePropertyIndicators() TEST NodePropertyIndicators()
@@ -930,10 +1069,9 @@ namespace Test {
" # Comment\n" " # Comment\n"
" \n" " \n"
"\n"; "\n";
std::stringstream stream(input);
YAML::Parser parser(stream);
YAML_ASSERT(!parser); PARSE(doc, input);
YAML_ASSERT(doc.size() == 0);
return true; return true;
} }
@@ -983,9 +1121,9 @@ namespace Test {
" 0.278"; " 0.278";
PARSE(doc, input); PARSE(doc, input);
StringMap key; std::map<std::string, std::string> key;
key._["first"] = "Sammy"; key["first"] = "Sammy";
key._["last"] = "Sosa"; key["last"] = "Sosa";
YAML_ASSERT(doc.size() == 1); YAML_ASSERT(doc.size() == 1);
YAML_ASSERT(doc[key].size() == 2); YAML_ASSERT(doc[key].size() == 2);
YAML_ASSERT(doc[key]["hr"] == 65); YAML_ASSERT(doc[key]["hr"] == 65);
@@ -993,8 +1131,291 @@ namespace Test {
return true; return true;
} }
// TODO: 6.13 - 6.17 directives // 6.13
// TODO: 6.18 - 6.28 tags TEST ReservedDirectives()
{
std::string input =
"%FOO bar baz # Should be ignored\n"
" # with a warning.\n"
"--- \"foo\"";
PARSE(doc, input);
return true;
}
// 6.14
TEST YAMLDirective()
{
std::string input =
"%YAML 1.3 # Attempt parsing\n"
" # with a warning\n"
"---\n"
"\"foo\"";
PARSE(doc, input);
return true;
}
// 6.15
TEST InvalidRepeatedYAMLDirective()
{
std::string input =
"%YAML 1.2\n"
"%YAML 1.1\n"
"foo";
try {
PARSE(doc, input);
} catch(const YAML::ParserException& e) {
if(e.msg == YAML::ErrorMsg::REPEATED_YAML_DIRECTIVE)
return true;
throw;
}
return " No exception was thrown";
}
// 6.16
TEST TagDirective()
{
std::string input =
"%TAG !yaml! tag:yaml.org,2002:\n"
"---\n"
"!yaml!str \"foo\"";
PARSE(doc, input);
YAML_ASSERT(doc.GetTag() == "tag:yaml.org,2002:str");
YAML_ASSERT(doc == "foo");
return true;
}
// 6.17
TEST InvalidRepeatedTagDirective()
{
std::string input =
"%TAG ! !foo\n"
"%TAG ! !foo\n"
"bar";
try {
PARSE(doc, input);
} catch(const YAML::ParserException& e) {
if(e.msg == YAML::ErrorMsg::REPEATED_TAG_DIRECTIVE)
return true;
throw;
}
return " No exception was thrown";
}
// 6.18
TEST PrimaryTagHandle()
{
std::string input =
"# Private\n"
"!foo \"bar\"\n"
"...\n"
"# Global\n"
"%TAG ! tag:example.com,2000:app/\n"
"---\n"
"!foo \"bar\"";
PARSE(doc, input);
YAML_ASSERT(doc.GetTag() == "!foo");
YAML_ASSERT(doc == "bar");
PARSE_NEXT(doc);
YAML_ASSERT(doc.GetTag() == "tag:example.com,2000:app/foo");
YAML_ASSERT(doc == "bar");
return true;
}
// 6.19
TEST SecondaryTagHandle()
{
std::string input =
"%TAG !! tag:example.com,2000:app/\n"
"---\n"
"!!int 1 - 3 # Interval, not integer";
PARSE(doc, input);
YAML_ASSERT(doc.GetTag() == "tag:example.com,2000:app/int");
YAML_ASSERT(doc == "1 - 3");
return true;
}
// 6.20
TEST TagHandles()
{
std::string input =
"%TAG !e! tag:example.com,2000:app/\n"
"---\n"
"!e!foo \"bar\"";
PARSE(doc, input);
YAML_ASSERT(doc.GetTag() == "tag:example.com,2000:app/foo");
YAML_ASSERT(doc == "bar");
return true;
}
// 6.21
TEST LocalTagPrefix()
{
std::string input =
"%TAG !m! !my-\n"
"--- # Bulb here\n"
"!m!light fluorescent\n"
"...\n"
"%TAG !m! !my-\n"
"--- # Color here\n"
"!m!light green";
PARSE(doc, input);
YAML_ASSERT(doc.GetTag() == "!my-light");
YAML_ASSERT(doc == "fluorescent");
PARSE_NEXT(doc);
YAML_ASSERT(doc.GetTag() == "!my-light");
YAML_ASSERT(doc == "green");
return true;
}
// 6.22
TEST GlobalTagPrefix()
{
std::string input =
"%TAG !e! tag:example.com,2000:app/\n"
"---\n"
"- !e!foo \"bar\"";
PARSE(doc, input);
YAML_ASSERT(doc.size() == 1);
YAML_ASSERT(doc[0].GetTag() == "tag:example.com,2000:app/foo");
YAML_ASSERT(doc[0] == "bar");
return true;
}
// 6.23
TEST NodeProperties()
{
std::string input =
"!!str &a1 \"foo\":\n"
" !!str bar\n"
"&a2 baz : *a1";
PARSE(doc, input);
YAML_ASSERT(doc.size() == 2);
for(YAML::Iterator it=doc.begin();it!=doc.end();++it) {
if(it.first() == "foo") {
YAML_ASSERT(it.first().GetTag() == "tag:yaml.org,2002:str");
YAML_ASSERT(it.second().GetTag() == "tag:yaml.org,2002:str");
YAML_ASSERT(it.second() == "bar");
} else if(it.first() == "baz") {
YAML_ASSERT(it.second() == "foo");
} else
return " unknown key";
}
return true;
}
// 6.24
TEST VerbatimTags()
{
std::string input =
"!<tag:yaml.org,2002:str> foo :\n"
" !<!bar> baz";
PARSE(doc, input);
YAML_ASSERT(doc.size() == 1);
for(YAML::Iterator it=doc.begin();it!=doc.end();++it) {
YAML_ASSERT(it.first().GetTag() == "tag:yaml.org,2002:str");
YAML_ASSERT(it.first() == "foo");
YAML_ASSERT(it.second().GetTag() == "!bar");
YAML_ASSERT(it.second() == "baz");
}
return true;
}
// 6.25
TEST InvalidVerbatimTags()
{
std::string input =
"- !<!> foo\n"
"- !<$:?> bar\n";
PARSE(doc, input);
return " not implemented yet"; // TODO: check tags (but we probably will say these are valid, I think)
}
// 6.26
TEST TagShorthands()
{
std::string input =
"%TAG !e! tag:example.com,2000:app/\n"
"---\n"
"- !local foo\n"
"- !!str bar\n"
"- !e!tag%21 baz\n";
PARSE(doc, input);
YAML_ASSERT(doc.size() == 3);
YAML_ASSERT(doc[0].GetTag() == "!local");
YAML_ASSERT(doc[0] == "foo");
YAML_ASSERT(doc[1].GetTag() == "tag:yaml.org,2002:str");
YAML_ASSERT(doc[1] == "bar");
YAML_ASSERT(doc[2].GetTag() == "tag:example.com,2000:app/tag%21");
YAML_ASSERT(doc[2] == "baz");
return true;
}
// 6.27
TEST InvalidTagShorthands()
{
std::string input1 =
"%TAG !e! tag:example,2000:app/\n"
"---\n"
"- !e! foo";
bool threw = false;
try {
PARSE(doc, input1);
} catch(const YAML::ParserException& e) {
threw = true;
if(e.msg != YAML::ErrorMsg::TAG_WITH_NO_SUFFIX)
throw;
}
if(!threw)
return " No exception was thrown for a tag with no suffix";
std::string input2 =
"%TAG !e! tag:example,2000:app/\n"
"---\n"
"- !h!bar baz";
PARSE(doc, input2); // TODO: should we reject this one (since !h! is not declared)?
return " not implemented yet";
}
// 6.28
TEST NonSpecificTags()
{
std::string input =
"# Assuming conventional resolution:\n"
"- \"12\"\n"
"- 12\n"
"- ! 12";
PARSE(doc, input);
YAML_ASSERT(doc.size() == 3);
YAML_ASSERT(doc[0] == "12"); // TODO: check tags. How?
YAML_ASSERT(doc[1] == 12);
YAML_ASSERT(doc[2] == "12");
return true;
}
// 6.29 // 6.29
TEST NodeAnchors() TEST NodeAnchors()
@@ -1039,8 +1460,16 @@ namespace Test {
PARSE(doc, input); PARSE(doc, input);
YAML_ASSERT(doc.size() == 2); YAML_ASSERT(doc.size() == 2);
YAML_ASSERT(doc["foo"] == ""); // TODO: check tag for(YAML::Iterator it=doc.begin();it!=doc.end();++it) {
YAML_ASSERT(doc[""] == "bar"); if(it.first() == "foo") {
YAML_ASSERT(it.second().GetTag() == "tag:yaml.org,2002:str");
YAML_ASSERT(it.second() == "");
} else if(it.first() == "") {
YAML_ASSERT(it.first().GetTag() == "tag:yaml.org,2002:str");
YAML_ASSERT(it.second() == "bar");
} else
return " unexpected key";
}
return true; return true;
} }
@@ -1207,6 +1636,424 @@ namespace Test {
YAML_ASSERT(doc == "1st non-empty\n2nd non-empty 3rd non-empty"); YAML_ASSERT(doc == "1st non-empty\n2nd non-empty 3rd non-empty");
return true; return true;
} }
// 7.13
TEST FlowSequence()
{
std::string input =
"- [ one, two, ]\n"
"- [three ,four]";
PARSE(doc, input);
YAML_ASSERT(doc.size() == 2);
YAML_ASSERT(doc[0].size() == 2);
YAML_ASSERT(doc[0][0] == "one");
YAML_ASSERT(doc[0][1] == "two");
YAML_ASSERT(doc[1].size() == 2);
YAML_ASSERT(doc[1][0] == "three");
YAML_ASSERT(doc[1][1] == "four");
return true;
}
// 7.14
TEST FlowSequenceEntries()
{
std::string input =
"[\n"
"\"double\n"
" quoted\", 'single\n"
" quoted',\n"
"plain\n"
" text, [ nested ],\n"
"single: pair,\n"
"]";
PARSE(doc, input);
YAML_ASSERT(doc.size() == 5);
YAML_ASSERT(doc[0] == "double quoted");
YAML_ASSERT(doc[1] == "single quoted");
YAML_ASSERT(doc[2] == "plain text");
YAML_ASSERT(doc[3].size() == 1);
YAML_ASSERT(doc[3][0] == "nested");
YAML_ASSERT(doc[4].size() == 1);
YAML_ASSERT(doc[4]["single"] == "pair");
return true;
}
// 7.15
TEST FlowMappings()
{
std::string input =
"- { one : two , three: four , }\n"
"- {five: six,seven : eight}";
PARSE(doc, input);
YAML_ASSERT(doc.size() == 2);
YAML_ASSERT(doc[0].size() == 2);
YAML_ASSERT(doc[0]["one"] == "two");
YAML_ASSERT(doc[0]["three"] == "four");
YAML_ASSERT(doc[1].size() == 2);
YAML_ASSERT(doc[1]["five"] == "six");
YAML_ASSERT(doc[1]["seven"] == "eight");
return true;
}
// 7.16
TEST FlowMappingEntries()
{
std::string input =
"{\n"
"? explicit: entry,\n"
"implicit: entry,\n"
"?\n"
"}";
PARSE(doc, input);
YAML_ASSERT(doc.size() == 3);
YAML_ASSERT(doc["explicit"] == "entry");
YAML_ASSERT(doc["implicit"] == "entry");
YAML_ASSERT(IsNull(doc[YAML::Null]));
return true;
}
// 7.17
TEST FlowMappingSeparateValues()
{
std::string input =
"{\n"
"unquoted : \"separate\",\n"
"http://foo.com,\n"
"omitted value:,\n"
": omitted key,\n"
"}";
PARSE(doc, input);
YAML_ASSERT(doc.size() == 4);
YAML_ASSERT(doc["unquoted"] == "separate");
YAML_ASSERT(IsNull(doc["http://foo.com"]));
YAML_ASSERT(IsNull(doc["omitted value"]));
YAML_ASSERT(doc[YAML::Null] == "omitted key");
return true;
}
// 7.18
TEST FlowMappingAdjacentValues()
{
std::string input =
"{\n"
"\"adjacent\":value,\n"
"\"readable\":value,\n"
"\"empty\":\n"
"}";
PARSE(doc, input);
YAML_ASSERT(doc.size() == 3);
YAML_ASSERT(doc["adjacent"] == "value");
YAML_ASSERT(doc["readable"] == "value");
YAML_ASSERT(IsNull(doc["empty"]));
return true;
}
// 7.19
TEST SinglePairFlowMappings()
{
std::string input =
"[\n"
"foo: bar\n"
"]";
PARSE(doc, input);
YAML_ASSERT(doc.size() == 1);
YAML_ASSERT(doc[0].size() == 1);
YAML_ASSERT(doc[0]["foo"] == "bar");
return true;
}
// 7.20
TEST SinglePairExplicitEntry()
{
std::string input =
"[\n"
"? foo\n"
" bar : baz\n"
"]";
PARSE(doc, input);
YAML_ASSERT(doc.size() == 1);
YAML_ASSERT(doc[0].size() == 1);
YAML_ASSERT(doc[0]["foo bar"] == "baz");
return true;
}
// 7.21
TEST SinglePairImplicitEntries()
{
std::string input =
"- [ YAML : separate ]\n"
"- [ : empty key entry ]\n"
"- [ {JSON: like}:adjacent ]";
PARSE(doc, input);
YAML_ASSERT(doc.size() == 3);
YAML_ASSERT(doc[0].size() == 1);
YAML_ASSERT(doc[0][0].size() == 1);
YAML_ASSERT(doc[0][0]["YAML"] == "separate");
YAML_ASSERT(doc[1].size() == 1);
YAML_ASSERT(doc[1][0].size() == 1);
YAML_ASSERT(doc[1][0][YAML::Null] == "empty key entry");
YAML_ASSERT(doc[2].size() == 1);
YAML_ASSERT(doc[2][0].size() == 1);
StringMap key;
key._["JSON"] = "like";
YAML_ASSERT(doc[2][0][key] == "adjacent");
return true;
}
// 7.22
TEST InvalidImplicitKeys()
{
std::string input =
"[ foo\n"
" bar: invalid,"; // Note: we don't check (on purpose) the >1K chars for an implicit key
try {
PARSE(doc, input);
} catch(const YAML::Exception& e) {
if(e.msg == YAML::ErrorMsg::END_OF_SEQ_FLOW)
return true;
throw;
}
return " no exception thrown";
}
// 7.23
TEST FlowContent()
{
std::string input =
"- [ a, b ]\n"
"- { a: b }\n"
"- \"a\"\n"
"- 'b'\n"
"- c";
PARSE(doc, input);
YAML_ASSERT(doc.size() == 5);
YAML_ASSERT(doc[0].size() == 2);
YAML_ASSERT(doc[0][0] == "a");
YAML_ASSERT(doc[0][1] == "b");
YAML_ASSERT(doc[1].size() == 1);
YAML_ASSERT(doc[1]["a"] == "b");
YAML_ASSERT(doc[2] == "a");
YAML_ASSERT(doc[3] == 'b');
YAML_ASSERT(doc[4] == "c");
return true;
}
// 7.24
TEST FlowNodes()
{
std::string input =
"- !!str \"a\"\n"
"- 'b'\n"
"- &anchor \"c\"\n"
"- *anchor\n"
"- !!str";
PARSE(doc, input);
YAML_ASSERT(doc.size() == 5);
YAML_ASSERT(doc[0].GetTag() == "tag:yaml.org,2002:str");
YAML_ASSERT(doc[0] == "a");
YAML_ASSERT(doc[1] == 'b');
YAML_ASSERT(doc[2] == "c");
YAML_ASSERT(doc[3] == "c");
YAML_ASSERT(doc[4].GetTag() == "tag:yaml.org,2002:str");
YAML_ASSERT(doc[4] == "");
return true;
}
// 8.1
TEST BlockScalarHeader()
{
std::string input =
"- | # Empty header\n"
" literal\n"
"- >1 # Indentation indicator\n"
" folded\n"
"- |+ # Chomping indicator\n"
" keep\n"
"\n"
"- >1- # Both indicators\n"
" strip\n";
PARSE(doc, input);
YAML_ASSERT(doc.size() == 4);
YAML_ASSERT(doc[0] == "literal\n");
YAML_ASSERT(doc[1] == " folded\n");
YAML_ASSERT(doc[2] == "keep\n\n");
YAML_ASSERT(doc[3] == " strip");
return true;
}
// 8.2
TEST BlockIndentationHeader()
{
std::string input =
"- |\n"
" detected\n"
"- >\n"
" \n"
" \n"
" # detected\n"
"- |1\n"
" explicit\n"
"- >\n"
" \t\n"
" detected\n";
PARSE(doc, input);
YAML_ASSERT(doc.size() == 4);
YAML_ASSERT(doc[0] == "detected\n");
YAML_ASSERT(doc[1] == "\n\n# detected\n");
YAML_ASSERT(doc[2] == " explicit\n");
YAML_ASSERT(doc[3] == "\t detected\n");
return true;
}
// 8.3
TEST InvalidBlockScalarIndentationIndicators()
{
{
std::string input =
"- |\n"
" \n"
" text";
bool threw = false;
try {
PARSE(doc, input);
} catch(const YAML::Exception& e) {
if(e.msg != YAML::ErrorMsg::END_OF_SEQ)
throw;
threw = true;
}
if(!threw)
return " no exception thrown for less indented auto-detecting indentation for a literal block scalar";
}
{
std::string input =
"- >\n"
" text\n"
" text";
bool threw = false;
try {
PARSE(doc, input);
} catch(const YAML::Exception& e) {
if(e.msg != YAML::ErrorMsg::END_OF_SEQ)
throw;
threw = true;
}
if(!threw)
return " no exception thrown for less indented auto-detecting indentation for a folded block scalar";
}
{
std::string input =
"- |2\n"
" text";
bool threw = false;
try {
PARSE(doc, input);
} catch(const YAML::Exception& e) {
if(e.msg != YAML::ErrorMsg::END_OF_SEQ)
throw;
threw = true;
}
if(!threw)
return " no exception thrown for less indented explicit indentation for a literal block scalar";
}
return true;
}
// 8.4
TEST ChompingFinalLineBreak()
{
std::string input =
"strip: |-\n"
" text\n"
"clip: |\n"
" text\n"
"keep: |+\n"
" text\n";
PARSE(doc, input);
YAML_ASSERT(doc.size() == 3);
YAML_ASSERT(doc["strip"] == "text");
YAML_ASSERT(doc["clip"] == "text\n");
YAML_ASSERT(doc["keep"] == "text\n");
return true;
}
// 8.5
TEST ChompingTrailingLines()
{
std::string input =
" # Strip\n"
" # Comments:\n"
"strip: |-\n"
" # text\n"
" \n"
" # Clip\n"
" # comments:\n"
"\n"
"clip: |\n"
" # text\n"
" \n"
" # Keep\n"
" # comments:\n"
"\n"
"keep: |+\n"
" # text\n"
"\n"
" # Trail\n"
" # Comments\n";
PARSE(doc, input);
YAML_ASSERT(doc.size() == 3);
YAML_ASSERT(doc["strip"] == "# text");
YAML_ASSERT(doc["clip"] == "# text\n");
YAML_ASSERT(doc["keep"] == "# text\n");
return true;
}
// 8.6
TEST EmptyScalarChomping()
{
std::string input =
"strip: >-\n"
"\n"
"clip: >\n"
"\n"
"keep: |+\n"
"\n";
PARSE(doc, input);
YAML_ASSERT(doc.size() == 3);
YAML_ASSERT(doc["strip"] == "");
YAML_ASSERT(doc["clip"] == "");
YAML_ASSERT(doc["keep"] == "\n");
return true;
}
} }
bool RunSpecTests() bool RunSpecTests()
@@ -1232,6 +2079,10 @@ namespace Test {
RunSpecTest(&Spec::QuotedScalars, "2.17", "Quoted scalars", passed, total); RunSpecTest(&Spec::QuotedScalars, "2.17", "Quoted scalars", passed, total);
RunSpecTest(&Spec::MultiLineFlowScalars, "2.18", "Multi-line flow scalars", passed, total); RunSpecTest(&Spec::MultiLineFlowScalars, "2.18", "Multi-line flow scalars", passed, total);
RunSpecTest(&Spec::VariousExplicitTags, "2.23", "Various Explicit Tags", passed, total);
RunSpecTest(&Spec::GlobalTags, "2.24", "Global Tags", passed, total);
RunSpecTest(&Spec::UnorderedSets, "2.25", "Unordered Sets", passed, total);
RunSpecTest(&Spec::OrderedMappings, "2.26", "Ordered Mappings", passed, total);
RunSpecTest(&Spec::Invoice, "2.27", "Invoice", passed, total); RunSpecTest(&Spec::Invoice, "2.27", "Invoice", passed, total);
RunSpecTest(&Spec::LogFile, "2.28", "Log File", passed, total); RunSpecTest(&Spec::LogFile, "2.28", "Log File", passed, total);
@@ -1255,8 +2106,24 @@ namespace Test {
RunSpecTest(&Spec::FlowFolding, "6.8", "Flow Folding", passed, total); RunSpecTest(&Spec::FlowFolding, "6.8", "Flow Folding", passed, total);
RunSpecTest(&Spec::SeparatedComment, "6.9", "Separated Comment", passed, total); RunSpecTest(&Spec::SeparatedComment, "6.9", "Separated Comment", passed, total);
RunSpecTest(&Spec::CommentLines, "6.10", "Comment Lines", passed, total); RunSpecTest(&Spec::CommentLines, "6.10", "Comment Lines", passed, total);
RunSpecTest(&Spec::SeparationSpacesII, "6.11", "Separation Spaces", passed, total); RunSpecTest(&Spec::MultiLineComments, "6.11", "Multi-Line Comments", passed, total);
RunSpecTest(&Spec::SeparationSpacesII, "6.12", "Separation Spaces", passed, total);
RunSpecTest(&Spec::ReservedDirectives, "6.13", "Reserved Directives", passed, total);
RunSpecTest(&Spec::YAMLDirective, "6.14", "YAML Directive", passed, total);
RunSpecTest(&Spec::InvalidRepeatedYAMLDirective, "6.15", "Invalid Repeated YAML Directive", passed, total);
RunSpecTest(&Spec::TagDirective, "6.16", "Tag Directive", passed, total);
RunSpecTest(&Spec::InvalidRepeatedTagDirective, "6.17", "Invalid Repeated Tag Directive", passed, total);
RunSpecTest(&Spec::PrimaryTagHandle, "6.18", "Primary Tag Handle", passed, total);
RunSpecTest(&Spec::SecondaryTagHandle, "6.19", "SecondaryTagHandle", passed, total);
RunSpecTest(&Spec::TagHandles, "6.20", "TagHandles", passed, total);
RunSpecTest(&Spec::LocalTagPrefix, "6.21", "LocalTagPrefix", passed, total);
RunSpecTest(&Spec::GlobalTagPrefix, "6.22", "GlobalTagPrefix", passed, total);
RunSpecTest(&Spec::NodeProperties, "6.23", "NodeProperties", passed, total);
RunSpecTest(&Spec::VerbatimTags, "6.24", "Verbatim Tags", passed, total);
RunSpecTest(&Spec::InvalidVerbatimTags, "6.25", "Invalid Verbatim Tags", passed, total);
RunSpecTest(&Spec::TagShorthands, "6.26", "Tag Shorthands", passed, total);
RunSpecTest(&Spec::InvalidTagShorthands, "6.27", "Invalid Tag Shorthands", passed, total);
RunSpecTest(&Spec::NonSpecificTags, "6.28", "Non Specific Tags", passed, total);
RunSpecTest(&Spec::NodeAnchors, "6.29", "Node Anchors", passed, total); RunSpecTest(&Spec::NodeAnchors, "6.29", "Node Anchors", passed, total);
RunSpecTest(&Spec::AliasNodes, "7.1", "Alias Nodes", passed, total); RunSpecTest(&Spec::AliasNodes, "7.1", "Alias Nodes", passed, total);
@@ -1271,6 +2138,25 @@ namespace Test {
RunSpecTest(&Spec::PlainCharacters, "7.10", "Plain Characters", passed, total); RunSpecTest(&Spec::PlainCharacters, "7.10", "Plain Characters", passed, total);
RunSpecTest(&Spec::PlainImplicitKeys, "7.11", "Plain Implicit Keys", passed, total); RunSpecTest(&Spec::PlainImplicitKeys, "7.11", "Plain Implicit Keys", passed, total);
RunSpecTest(&Spec::PlainLines, "7.12", "Plain Lines", passed, total); RunSpecTest(&Spec::PlainLines, "7.12", "Plain Lines", passed, total);
RunSpecTest(&Spec::FlowSequence, "7.13", "Flow Sequence", passed, total);
RunSpecTest(&Spec::FlowSequenceEntries, "7.14", "Flow Sequence Entries", passed, total);
RunSpecTest(&Spec::FlowMappings, "7.15", "Flow Mappings", passed, total);
RunSpecTest(&Spec::FlowMappingEntries, "7.16", "Flow Mapping Entries", passed, total);
RunSpecTest(&Spec::FlowMappingSeparateValues, "7.17", "Flow Mapping Separate Values", passed, total);
RunSpecTest(&Spec::FlowMappingAdjacentValues, "7.18", "Flow Mapping Adjacent Values", passed, total);
RunSpecTest(&Spec::SinglePairFlowMappings, "7.19", "Single Pair Flow Mappings", passed, total);
RunSpecTest(&Spec::SinglePairExplicitEntry, "7.20", "Single Pair Explicit Entry", passed, total);
RunSpecTest(&Spec::SinglePairImplicitEntries, "7.21", "Single Pair Implicit Entries", passed, total);
RunSpecTest(&Spec::InvalidImplicitKeys, "7.22", "Invalid Implicit Keys", passed, total);
RunSpecTest(&Spec::FlowContent, "7.23", "Flow Content", passed, total);
RunSpecTest(&Spec::FlowNodes, "7.24", "FlowNodes", passed, total);
RunSpecTest(&Spec::BlockScalarHeader, "8.1", "Block Scalar Header", passed, total);
RunSpecTest(&Spec::BlockIndentationHeader, "8.2", "Block Indentation Header", passed, total);
RunSpecTest(&Spec::InvalidBlockScalarIndentationIndicators, "8.3", "Invalid Block Scalar Indentation Indicators", passed, total);
RunSpecTest(&Spec::ChompingFinalLineBreak, "8.4", "Chomping Final Line Break", passed, total);
RunSpecTest(&Spec::ChompingTrailingLines, "8.4", "Chomping Trailing Lines", passed, total);
RunSpecTest(&Spec::EmptyScalarChomping, "8.4", "Empty Scalar Chomping", passed, total);
std::cout << "Spec tests: " << passed << "/" << total << " passed\n"; std::cout << "Spec tests: " << passed << "/" << total << " passed\n";
return passed == total; return passed == total;

View File

@@ -1,10 +0,0 @@
file(GLOB yaml-reader_headers [a-z]*.h)
file(GLOB yaml-reader_sources [a-z]*.cpp)
add_executable(yaml-reader
${yaml-reader_sources}
${yaml-reader_headers}
)
target_link_libraries(yaml-reader yaml-cpp)
add_test(yaml-reader-test yaml-reader)

View File

@@ -1,11 +0,0 @@
#include "tests.h"
int main()
{
#ifdef WINDOWS
_CrtSetDbgFlag(_CRTDBG_LEAK_CHECK_DF|_CRTDBG_ALLOC_MEM_DF);
#endif // WINDOWS
Test::RunAll();
return 0;
}

View File

@@ -1,4 +0,0 @@
--- &list
- This document contains a recursive list.
- *list
...

View File

@@ -1,12 +1,17 @@
 
Microsoft Visual Studio Solution File, Format Version 10.00 Microsoft Visual Studio Solution File, Format Version 10.00
# Visual Studio 2008 # Visual Studio 2008
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "yaml-reader", "yaml-reader.vcproj", "{E8CC0D8A-D784-4A6B-B78B-ACEA13F9FB0B}" Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "yamlcpp", "yamlcpp.vcproj", "{3104AB4E-CD31-4F47-95E9-0E8D9374E15D}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test", "test.vcproj", "{D1108F40-6ADF-467E-A95A-236C39A515C5}"
ProjectSection(ProjectDependencies) = postProject ProjectSection(ProjectDependencies) = postProject
{3104AB4E-CD31-4F47-95E9-0E8D9374E15D} = {3104AB4E-CD31-4F47-95E9-0E8D9374E15D} {3104AB4E-CD31-4F47-95E9-0E8D9374E15D} = {3104AB4E-CD31-4F47-95E9-0E8D9374E15D}
EndProjectSection EndProjectSection
EndProject EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "yamlcpp", "yamlcpp.vcproj", "{3104AB4E-CD31-4F47-95E9-0E8D9374E15D}" Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "parse", "parse.vcproj", "{CD007B57-7812-4930-A5E2-6E5E56338814}"
ProjectSection(ProjectDependencies) = postProject
{3104AB4E-CD31-4F47-95E9-0E8D9374E15D} = {3104AB4E-CD31-4F47-95E9-0E8D9374E15D}
EndProjectSection
EndProject EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -14,14 +19,18 @@ Global
Release|Win32 = Release|Win32 Release|Win32 = Release|Win32
EndGlobalSection EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution GlobalSection(ProjectConfigurationPlatforms) = postSolution
{E8CC0D8A-D784-4A6B-B78B-ACEA13F9FB0B}.Debug|Win32.ActiveCfg = Debug|Win32
{E8CC0D8A-D784-4A6B-B78B-ACEA13F9FB0B}.Debug|Win32.Build.0 = Debug|Win32
{E8CC0D8A-D784-4A6B-B78B-ACEA13F9FB0B}.Release|Win32.ActiveCfg = Release|Win32
{E8CC0D8A-D784-4A6B-B78B-ACEA13F9FB0B}.Release|Win32.Build.0 = Release|Win32
{3104AB4E-CD31-4F47-95E9-0E8D9374E15D}.Debug|Win32.ActiveCfg = Debug|Win32 {3104AB4E-CD31-4F47-95E9-0E8D9374E15D}.Debug|Win32.ActiveCfg = Debug|Win32
{3104AB4E-CD31-4F47-95E9-0E8D9374E15D}.Debug|Win32.Build.0 = Debug|Win32 {3104AB4E-CD31-4F47-95E9-0E8D9374E15D}.Debug|Win32.Build.0 = Debug|Win32
{3104AB4E-CD31-4F47-95E9-0E8D9374E15D}.Release|Win32.ActiveCfg = Release|Win32 {3104AB4E-CD31-4F47-95E9-0E8D9374E15D}.Release|Win32.ActiveCfg = Release|Win32
{3104AB4E-CD31-4F47-95E9-0E8D9374E15D}.Release|Win32.Build.0 = Release|Win32 {3104AB4E-CD31-4F47-95E9-0E8D9374E15D}.Release|Win32.Build.0 = Release|Win32
{D1108F40-6ADF-467E-A95A-236C39A515C5}.Debug|Win32.ActiveCfg = Debug|Win32
{D1108F40-6ADF-467E-A95A-236C39A515C5}.Debug|Win32.Build.0 = Debug|Win32
{D1108F40-6ADF-467E-A95A-236C39A515C5}.Release|Win32.ActiveCfg = Release|Win32
{D1108F40-6ADF-467E-A95A-236C39A515C5}.Release|Win32.Build.0 = Release|Win32
{CD007B57-7812-4930-A5E2-6E5E56338814}.Debug|Win32.ActiveCfg = Debug|Win32
{CD007B57-7812-4930-A5E2-6E5E56338814}.Debug|Win32.Build.0 = Debug|Win32
{CD007B57-7812-4930-A5E2-6E5E56338814}.Release|Win32.ActiveCfg = Release|Win32
{CD007B57-7812-4930-A5E2-6E5E56338814}.Release|Win32.Build.0 = Release|Win32
EndGlobalSection EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE

View File

@@ -40,6 +40,7 @@
/> />
<Tool <Tool
Name="VCCLCompilerTool" Name="VCCLCompilerTool"
AdditionalOptions="/D_SCL_SECURE_NO_WARNINGS"
Optimization="0" Optimization="0"
AdditionalIncludeDirectories="include" AdditionalIncludeDirectories="include"
PreprocessorDefinitions="WIN32;_DEBUG;_LIB" PreprocessorDefinitions="WIN32;_DEBUG;_LIB"
@@ -49,6 +50,7 @@
UsePrecompiledHeader="0" UsePrecompiledHeader="0"
WarningLevel="4" WarningLevel="4"
DebugInformationFormat="3" DebugInformationFormat="3"
DisableSpecificWarnings="4127;4355"
/> />
<Tool <Tool
Name="VCManagedResourceCompilerTool" Name="VCManagedResourceCompilerTool"
@@ -104,6 +106,7 @@
/> />
<Tool <Tool
Name="VCCLCompilerTool" Name="VCCLCompilerTool"
AdditionalOptions="/D_SCL_SECURE_NO_WARNINGS"
Optimization="2" Optimization="2"
EnableIntrinsicFunctions="true" EnableIntrinsicFunctions="true"
AdditionalIncludeDirectories="include" AdditionalIncludeDirectories="include"
@@ -113,6 +116,7 @@
UsePrecompiledHeader="0" UsePrecompiledHeader="0"
WarningLevel="4" WarningLevel="4"
DebugInformationFormat="3" DebugInformationFormat="3"
DisableSpecificWarnings="4127;4355"
/> />
<Tool <Tool
Name="VCManagedResourceCompilerTool" Name="VCManagedResourceCompilerTool"
@@ -171,10 +175,6 @@
RelativePath=".\src\aliascontent.cpp" RelativePath=".\src\aliascontent.cpp"
> >
</File> </File>
<File
RelativePath=".\src\content.cpp"
>
</File>
<File <File
RelativePath=".\src\conversion.cpp" RelativePath=".\src\conversion.cpp"
> >
@@ -203,6 +203,10 @@
RelativePath=".\src\sequence.cpp" RelativePath=".\src\sequence.cpp"
> >
</File> </File>
<File
RelativePath=".\src\tag.cpp"
>
</File>
</Filter> </Filter>
<Filter <Filter
Name="Scanner" Name="Scanner"
@@ -223,6 +227,10 @@
RelativePath=".\src\scanscalar.cpp" RelativePath=".\src\scanscalar.cpp"
> >
</File> </File>
<File
RelativePath=".\src\scantag.cpp"
>
</File>
<File <File
RelativePath=".\src\scantoken.cpp" RelativePath=".\src\scantoken.cpp"
> >
@@ -337,6 +345,10 @@
RelativePath=".\src\sequence.h" RelativePath=".\src\sequence.h"
> >
</File> </File>
<File
RelativePath=".\src\tag.h"
>
</File>
</Filter> </Filter>
<Filter <Filter
Name="Scanner" Name="Scanner"
@@ -361,6 +373,10 @@
RelativePath=".\src\scanscalar.h" RelativePath=".\src\scanscalar.h"
> >
</File> </File>
<File
RelativePath=".\src\scantag.h"
>
</File>
<File <File
RelativePath=".\src\stream.h" RelativePath=".\src\stream.h"
> >