Compare commits

...

53 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
Jesse Beder
22410f46f5 Updated the CMake globbing so it only compiles sources starting with a lowercase letter (apparently Mac OS auto-generates files looking like ._whatever and it was trying to compile those too) 2009-10-25 18:01:48 +00:00
Jesse Beder
9559a661aa Tagged version 0.2.3 2009-10-22 21:55:44 +00:00
Jesse Beder
beb524489c Small refactoring 2009-10-22 21:51:32 +00:00
Jesse Beder
4ffb93c12b Switch to flow map when emitting an empty block map 2009-10-22 14:21:12 +00:00
Jesse Beder
ae06a40fe6 Switch to flow sequence when emitting an empty sequence 2009-10-22 14:17:12 +00:00
Jesse Beder
315b00065b Fixed bug in plain scalar folding 2009-10-20 14:47:16 +00:00
Jesse Beder
6f02f7556e Added a bunch of tests, simplified the testing code 2009-10-20 14:43:24 +00:00
Jesse Beder
fa0af88dfe Merged r270:HEAD of the emitting-unicode branch 2009-10-19 23:31:11 +00:00
Jesse Beder
bce845bb1f Fixed little bug in parser commit 2009-10-19 22:42:30 +00:00
Jesse Beder
ed570b9f7c Added default constructor to Parser, and cleaned it up a bit 2009-10-19 22:40:46 +00:00
Jesse Beder
59b0e986bf Update CMakeLists.txt to append, not overwrite CMAKE_CXX_FLAGS 2009-10-19 22:32:26 +00:00
Jesse Beder
cffb98d15b Patched for optional building of tests and tools 2009-10-12 05:21:00 +00:00
Jesse Beder
3e1ba0f3b4 Refactored the UTF-8 emitting 2009-10-08 21:05:56 +00:00
Jesse Beder
d0b5bf4b7b Fixed the emitter unicode output 2009-10-07 06:46:05 +00:00
Jesse Beder
7db39e66b8 Updated signature of Parser::GetNextDocument (issue 45) 2009-09-29 18:25:11 +00:00
Jesse Beder
94eb7f1dbd Modified old gcc version patch so it still uses the new Node::Read in Visual Studio. Also broke up the \uNNNN characters in the spec tests into \xNN-type strings. 2009-09-16 05:31:28 +00:00
Jesse Beder
5733b77b84 Patched for gcc version <= 3.3 (just fall back to original version of Node::Read) 2009-09-16 04:01:40 +00:00
Jesse Beder
98bebfb628 Tagged version 0.2.2 2009-09-09 01:37:23 +00:00
71 changed files with 3044 additions and 829 deletions

View File

@@ -10,16 +10,23 @@ if(IPHONE)
endif(IPHONE) endif(IPHONE)
if(CMAKE_COMPILER_IS_GNUCC) if(CMAKE_COMPILER_IS_GNUCC)
set(CMAKE_CXX_FLAGS "-O2 -Wall -pedantic -Wextra") 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 "1") 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 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
else(WIN32) else(WIN32)
@@ -36,9 +43,9 @@ set(_INSTALL_DESTINATIONS
ARCHIVE DESTINATION lib${LIB_SUFFIX} ARCHIVE DESTINATION lib${LIB_SUFFIX}
) )
# #
file(GLOB public_headers include/*.h) file(GLOB public_headers include/[a-z]*.h)
file(GLOB private_headers src/*.h) file(GLOB private_headers src/[a-z]*.h)
file(GLOB sources src/*.cpp) file(GLOB sources src/[a-z]*.cpp)
include_directories(${YAML_CPP_SOURCE_DIR}/include) include_directories(${YAML_CPP_SOURCE_DIR}/include)
add_library(yaml-cpp add_library(yaml-cpp
@@ -64,5 +71,7 @@ if(UNIX)
install(FILES ${PC_FILE} DESTINATION ${LIB_INSTALL_DIR}/pkgconfig) install(FILES ${PC_FILE} DESTINATION ${LIB_INSTALL_DIR}/pkgconfig)
endif(UNIX) endif(UNIX)
add_subdirectory (yaml-reader) if(YAML_CPP_BUILD_TOOLS)
add_subdirectory (util) add_subdirectory (test)
add_subdirectory (util)
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
{ {
@@ -29,6 +30,7 @@ namespace YAML
const std::string GetLastError() const; const std::string GetLastError() const;
// global setters // global setters
bool SetOutputCharset(EMITTER_MANIP value);
bool SetStringFormat(EMITTER_MANIP value); bool SetStringFormat(EMITTER_MANIP value);
bool SetBoolFormat(EMITTER_MANIP value); bool SetBoolFormat(EMITTER_MANIP value);
bool SetIntBase(EMITTER_MANIP value); bool SetIntBase(EMITTER_MANIP value);
@@ -44,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 };
@@ -74,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

@@ -11,6 +11,10 @@ namespace YAML
enum EMITTER_MANIP { enum EMITTER_MANIP {
// general manipulators // general manipulators
Auto, Auto,
// output character set
EmitNonAscii,
EscapeNonAscii,
// string manipulators // string manipulators
// Auto, // duplicate // Auto, // duplicate
@@ -76,6 +80,16 @@ namespace YAML
inline _Anchor Anchor(const std::string content) { inline _Anchor Anchor(const std::string content) {
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_) {}

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;
@@ -75,6 +75,9 @@ namespace YAML
const Node *Identity() const { return m_pIdentity; } const Node *Identity() const { return m_pIdentity; }
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

@@ -79,22 +79,22 @@ namespace YAML
template <typename T> template <typename T>
inline bool operator == (const T& value, const Node& node) { inline bool operator == (const T& value, const Node& node) {
return value == node.Read<T>(); return value == node.operator T();
} }
template <typename T> template <typename T>
inline bool operator == (const Node& node, const T& value) { inline bool operator == (const Node& node, const T& value) {
return value == node.Read<T>(); return value == node.operator T();
} }
template <typename T> template <typename T>
inline bool operator != (const T& value, const Node& node) { inline bool operator != (const T& value, const Node& node) {
return value != node.Read<T>(); return value != node.operator T();
} }
template <typename T> template <typename T>
inline bool operator != (const Node& node, const T& value) { inline bool operator != (const Node& node, const T& value) {
return value != node.Read<T>(); return value != node.operator T();
} }
inline bool operator == (const char *value, const Node& node) { inline bool operator == (const char *value, const Node& node) {

View File

@@ -6,7 +6,18 @@ namespace YAML
// (the goal is to call ConvertScalar if we can, and fall back to operator >> if not) // (the goal is to call ConvertScalar if we can, and fall back to operator >> if not)
// thanks to litb from stackoverflow.com // thanks to litb from stackoverflow.com
// http://stackoverflow.com/questions/1386183/how-to-call-a-templated-function-if-it-exists-and-something-else-otherwise/1386390#1386390 // http://stackoverflow.com/questions/1386183/how-to-call-a-templated-function-if-it-exists-and-something-else-otherwise/1386390#1386390
// Note: this doesn't work on gcc 3.2, but does on gcc 3.4 and above. I'm not sure about 3.3.
#if __GNUC__ && (__GNUC__ < 3 || (__GNUC__ == 3 && __GNUC_MINOR__ <= 3))
// trick doesn't work? Just fall back to ConvertScalar.
// This means that we can't use any user-defined types as keys in a map
template <typename T>
inline bool Node::Read(T& value) const {
return ConvertScalar(*this, value);
}
#else
// usual case: the trick!
template<bool> template<bool>
struct read_impl; struct read_impl;
@@ -41,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>
@@ -52,6 +64,7 @@ namespace YAML
return read_impl<sizeof (fallback::flag(), Convert(std::string(), value), fallback::flag()) != 1>::read(*this, value); return read_impl<sizeof (fallback::flag(), Convert(std::string(), value), fallback::flag()) != 1>::read(*this, value);
} }
#endif // done with trick
// the main conversion function // the main conversion function
template <typename T> template <typename T>

View File

@@ -4,44 +4,42 @@
#define PARSER_H_62B23520_7C8E_11DE_8A39_0800200C9A66 #define PARSER_H_62B23520_7C8E_11DE_8A39_0800200C9A66
#include "node.h"
#include "noncopyable.h"
#include <ios> #include <ios>
#include <string> #include <string>
#include <vector> #include <vector>
#include <map> #include <map>
#include "node.h" #include <memory>
#include "parserstate.h"
namespace YAML namespace YAML
{ {
class Scanner; class Scanner;
struct ParserState;
struct Token; struct Token;
class Parser class Parser: private noncopyable
{ {
public: public:
Parser();
Parser(std::istream& in); Parser(std::istream& in);
~Parser(); ~Parser();
operator bool() const; operator bool() const;
void Load(std::istream& in); void Load(std::istream& in);
void GetNextDocument(Node& document); bool GetNextDocument(Node& document);
void PrintTokens(std::ostream& out); void PrintTokens(std::ostream& out);
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:
// can't copy this std::auto_ptr<Scanner> m_pScanner;
Parser(const Parser&) {} std::auto_ptr<ParserState> m_pState;
Parser& operator = (const Parser&) { return *this; }
private:
Scanner *m_pScanner;
ParserState m_state;
}; };
} }

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

@@ -21,4 +21,4 @@ make install
If you don't want to use CMake, just add all .cpp files to a makefile. yaml-cpp does not need any special build settings, so no 'configure' file is necessary. If you don't want to use CMake, just add all .cpp files to a makefile. yaml-cpp does not need any special build settings, so no 'configure' file is necessary.
(Note: this is pretty tedious. It's sooo much easier to use CMake.) (Note: this is pretty tedious. It's sooo much easier to use CMake.)

View File

@@ -16,4 +16,4 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE. THE SOFTWARE.

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"
</File> Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
<File UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
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

@@ -37,6 +37,11 @@ namespace YAML
} }
// global setters // global setters
bool Emitter::SetOutputCharset(EMITTER_MANIP value)
{
return m_pState->SetOutputCharset(value, GLOBAL);
}
bool Emitter::SetStringFormat(EMITTER_MANIP value) bool Emitter::SetStringFormat(EMITTER_MANIP value)
{ {
return m_pState->SetStringFormat(value, GLOBAL); return m_pState->SetStringFormat(value, GLOBAL);
@@ -141,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:
@@ -318,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();
} }
@@ -344,12 +354,22 @@ namespace YAML
EMITTER_STATE curState = m_pState->GetCurState(); EMITTER_STATE curState = m_pState->GetCurState();
FLOW_TYPE flowType = m_pState->GetCurGroupFlowType(); FLOW_TYPE flowType = m_pState->GetCurGroupFlowType();
if(flowType == FT_BLOCK) if(flowType == FT_BLOCK) {
assert(curState == ES_DONE_WITH_BLOCK_SEQ_ENTRY); // Note: block sequences are *not* allowed to be empty, but we convert it
else if(flowType == FT_FLOW) { // to a flow sequence if it is
m_stream << "]"; assert(curState == ES_DONE_WITH_BLOCK_SEQ_ENTRY || 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();
m_stream << IndentTo(curIndent);
m_stream << "[]";
}
} else if(flowType == FT_FLOW) {
// Note: flow sequences are allowed to be empty // Note: flow sequences are allowed to be empty
assert(curState == ES_DONE_WITH_FLOW_SEQ_ENTRY || curState == ES_WAITING_FOR_FLOW_SEQ_ENTRY); assert(curState == ES_DONE_WITH_FLOW_SEQ_ENTRY || curState == ES_WAITING_FOR_FLOW_SEQ_ENTRY);
m_stream << "]";
} else } else
assert(false); assert(false);
@@ -373,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();
} }
@@ -399,12 +422,21 @@ namespace YAML
EMITTER_STATE curState = m_pState->GetCurState(); EMITTER_STATE curState = m_pState->GetCurState();
FLOW_TYPE flowType = m_pState->GetCurGroupFlowType(); FLOW_TYPE flowType = m_pState->GetCurGroupFlowType();
if(flowType == FT_BLOCK) if(flowType == FT_BLOCK) {
assert(curState == ES_DONE_WITH_BLOCK_MAP_VALUE); // Note: block sequences are *not* allowed to be empty, but we convert it
else if(flowType == FT_FLOW) { // to a flow sequence if it is
m_stream << "}"; assert(curState == ES_DONE_WITH_BLOCK_MAP_VALUE || 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();
m_stream << IndentTo(curIndent);
m_stream << "{}";
}
} else if(flowType == FT_FLOW) {
// Note: flow maps are allowed to be empty // Note: flow maps are allowed to be empty
assert(curState == ES_DONE_WITH_FLOW_MAP_VALUE || curState == ES_WAITING_FOR_FLOW_MAP_ENTRY); assert(curState == ES_DONE_WITH_FLOW_MAP_VALUE || curState == ES_WAITING_FOR_FLOW_MAP_ENTRY);
m_stream << "}";
} else } else
assert(false); assert(false);
@@ -485,13 +517,14 @@ namespace YAML
PreAtomicWrite(); PreAtomicWrite();
EmitSeparationIfNecessary(); EmitSeparationIfNecessary();
bool escapeNonAscii = m_pState->GetOutputCharset() == EscapeNonAscii;
EMITTER_MANIP strFmt = m_pState->GetStringFormat(); EMITTER_MANIP strFmt = m_pState->GetStringFormat();
FLOW_TYPE flowType = m_pState->GetCurGroupFlowType(); FLOW_TYPE flowType = m_pState->GetCurGroupFlowType();
unsigned curIndent = m_pState->GetCurIndent(); unsigned curIndent = m_pState->GetCurIndent();
switch(strFmt) { switch(strFmt) {
case Auto: case Auto:
Utils::WriteString(m_stream, str, flowType == FT_FLOW); Utils::WriteString(m_stream, str, flowType == FT_FLOW, escapeNonAscii);
break; break;
case SingleQuoted: case SingleQuoted:
if(!Utils::WriteSingleQuotedString(m_stream, str)) { if(!Utils::WriteSingleQuotedString(m_stream, str)) {
@@ -500,11 +533,11 @@ namespace YAML
} }
break; break;
case DoubleQuoted: case DoubleQuoted:
Utils::WriteDoubleQuotedString(m_stream, str); Utils::WriteDoubleQuotedString(m_stream, str, escapeNonAscii);
break; break;
case Literal: case Literal:
if(flowType == FT_FLOW) if(flowType == FT_FLOW)
Utils::WriteString(m_stream, str, flowType == FT_FLOW); Utils::WriteString(m_stream, str, flowType == FT_FLOW, escapeNonAscii);
else else
Utils::WriteLiteralString(m_stream, str, curIndent + m_pState->GetIndent()); Utils::WriteLiteralString(m_stream, str, curIndent + m_pState->GetIndent());
break; break;
@@ -516,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;
@@ -541,18 +562,18 @@ namespace YAML
case Hex: case Hex:
str << std::hex; str << std::hex;
break; break;
case Oct: case Oct:
str << std::oct; str << std::oct;
break; break;
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)
@@ -594,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())
@@ -657,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())
@@ -679,3 +684,4 @@ namespace YAML
return *this; return *this;
} }
} }

View File

@@ -9,6 +9,7 @@ namespace YAML
m_stateStack.push(ES_WAITING_FOR_DOC); m_stateStack.push(ES_WAITING_FOR_DOC);
// set default global manipulators // set default global manipulators
m_charset.set(EmitNonAscii);
m_strFmt.set(Auto); m_strFmt.set(Auto);
m_boolFmt.set(TrueFalseBool); m_boolFmt.set(TrueFalseBool);
m_boolLengthFmt.set(LongBool); m_boolLengthFmt.set(LongBool);
@@ -43,6 +44,7 @@ namespace YAML
// . Only the ones that make sense will be accepted // . Only the ones that make sense will be accepted
void EmitterState::SetLocalValue(EMITTER_MANIP value) void EmitterState::SetLocalValue(EMITTER_MANIP value)
{ {
SetOutputCharset(value, LOCAL);
SetStringFormat(value, LOCAL); SetStringFormat(value, LOCAL);
SetBoolFormat(value, LOCAL); SetBoolFormat(value, LOCAL);
SetBoolCaseFormat(value, LOCAL); SetBoolCaseFormat(value, LOCAL);
@@ -132,6 +134,18 @@ namespace YAML
{ {
m_modifiedSettings.clear(); m_modifiedSettings.clear();
} }
bool EmitterState::SetOutputCharset(EMITTER_MANIP value, FMT_SCOPE scope)
{
switch(value) {
case EmitNonAscii:
case EscapeNonAscii:
_Set(m_charset, value, scope);
return true;
default:
return false;
}
}
bool EmitterState::SetStringFormat(EMITTER_MANIP value, FMT_SCOPE scope) bool EmitterState::SetStringFormat(EMITTER_MANIP value, FMT_SCOPE scope)
{ {

View File

@@ -108,6 +108,9 @@ namespace YAML
void ClearModifiedSettings(); void ClearModifiedSettings();
// formatters // formatters
bool SetOutputCharset(EMITTER_MANIP value, FMT_SCOPE scope);
EMITTER_MANIP GetOutputCharset() const { return m_charset.get(); }
bool SetStringFormat(EMITTER_MANIP value, FMT_SCOPE scope); bool SetStringFormat(EMITTER_MANIP value, FMT_SCOPE scope);
EMITTER_MANIP GetStringFormat() const { return m_strFmt.get(); } EMITTER_MANIP GetStringFormat() const { return m_strFmt.get(); }
@@ -149,6 +152,7 @@ namespace YAML
// other state // other state
std::stack <EMITTER_STATE> m_stateStack; std::stack <EMITTER_STATE> m_stateStack;
Setting <EMITTER_MANIP> m_charset;
Setting <EMITTER_MANIP> m_strFmt; Setting <EMITTER_MANIP> m_strFmt;
Setting <EMITTER_MANIP> m_boolFmt; Setting <EMITTER_MANIP> m_boolFmt;
Setting <EMITTER_MANIP> m_boolLengthFmt; Setting <EMITTER_MANIP> m_boolLengthFmt;

View File

@@ -11,13 +11,125 @@ namespace YAML
namespace Utils namespace Utils
{ {
namespace { namespace {
bool IsPrintable(char ch) { enum {REPLACEMENT_CHARACTER = 0xFFFD};
return (0x20 <= ch && ch <= 0x7E);
bool IsAnchorChar(int ch) { // test for ns-anchor-char
switch (ch) {
case ',': case '[': case ']': case '{': case '}': // c-flow-indicator
case ' ': case '\t': // s-white
case 0xFEFF: // c-byte-order-mark
case 0xA: case 0xD: // b-char
return false;
case 0x85:
return true;
}
if (ch < 0x20)
return false;
if (ch < 0x7E)
return true;
if (ch < 0xA0)
return false;
if (ch >= 0xD800 && ch <= 0xDFFF)
return false;
if ((ch & 0xFFFE) == 0xFFFE)
return false;
if ((ch >= 0xFDD0) && (ch <= 0xFDEF))
return false;
if (ch > 0x10FFFF)
return false;
return true;
} }
bool IsValidPlainScalar(const std::string& str, bool inFlow) { int Utf8BytesIndicated(char ch) {
int byteVal = static_cast<unsigned char>(ch);
switch (byteVal >> 4) {
case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7:
return 1;
case 12: case 13:
return 2;
case 14:
return 3;
case 15:
return 4;
default:
return -1;
}
}
bool IsTrailingByte(char ch) {
return (ch & 0xC0) == 0x80;
}
bool GetNextCodePointAndAdvance(int& codePoint, std::string::const_iterator& first, std::string::const_iterator last) {
if (first == last)
return false;
int nBytes = Utf8BytesIndicated(*first);
if (nBytes < 1) {
// Bad lead byte
++first;
codePoint = REPLACEMENT_CHARACTER;
return true;
}
if (nBytes == 1) {
codePoint = *first++;
return true;
}
// Gather bits from trailing bytes
codePoint = static_cast<unsigned char>(*first) & ~(0xFF << (7 - nBytes));
++first;
--nBytes;
for (; nBytes > 0; ++first, --nBytes) {
if ((first == last) || !IsTrailingByte(*first)) {
codePoint = REPLACEMENT_CHARACTER;
break;
}
codePoint <<= 6;
codePoint |= *first & 0x3F;
}
// Check for illegal code points
if (codePoint > 0x10FFFF)
codePoint = REPLACEMENT_CHARACTER;
else if (codePoint >= 0xD800 && codePoint <= 0xDFFF)
codePoint = REPLACEMENT_CHARACTER;
else if ((codePoint & 0xFFFE) == 0xFFFE)
codePoint = REPLACEMENT_CHARACTER;
else if (codePoint >= 0xFDD0 && codePoint <= 0xFDEF)
codePoint = REPLACEMENT_CHARACTER;
return true;
}
void WriteCodePoint(ostream& out, int codePoint) {
if (codePoint < 0 || codePoint > 0x10FFFF) {
codePoint = REPLACEMENT_CHARACTER;
}
if (codePoint < 0x7F) {
out << static_cast<char>(codePoint);
} else if (codePoint < 0x7FF) {
out << static_cast<char>(0xC0 | (codePoint >> 6))
<< static_cast<char>(0x80 | (codePoint & 0x3F));
} else if (codePoint < 0xFFFF) {
out << static_cast<char>(0xE0 | (codePoint >> 12))
<< static_cast<char>(0x80 | ((codePoint >> 6) & 0x3F))
<< static_cast<char>(0x80 | (codePoint & 0x3F));
} else {
out << static_cast<char>(0xF0 | (codePoint >> 18))
<< static_cast<char>(0x80 | ((codePoint >> 12) & 0x3F))
<< static_cast<char>(0x80 | ((codePoint >> 6) & 0x3F))
<< static_cast<char>(0x80 | (codePoint & 0x3F));
}
}
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;
@@ -26,66 +138,111 @@ 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::Printable) || Exp::NotPrintable()
|| Exp::Break || Exp::Utf8_ByteOrderMark()
|| Exp::Tab; || Exp::Break()
|| 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))
return false; return false;
if(allowOnlyAscii && (0x7F < static_cast<unsigned char>(buffer[0])))
return false;
++buffer; ++buffer;
} }
return true; return true;
} }
void WriteDoubleQuoteEscapeSequence(ostream& out, int codePoint) {
static const char hexDigits[] = "0123456789abcdef";
char escSeq[] = "\\U00000000";
int digits = 8;
if (codePoint < 0xFF) {
escSeq[1] = 'x';
digits = 2;
} else if (codePoint < 0xFFFF) {
escSeq[1] = 'u';
digits = 4;
}
// Write digits into the escape sequence
int i = 2;
for (; digits > 0; --digits, ++i) {
escSeq[i] = hexDigits[(codePoint >> (4 * (digits - 1))) & 0xF];
}
escSeq[i] = 0; // terminate with NUL character
out << escSeq;
}
bool WriteAliasName(ostream& out, const std::string& str) {
int codePoint;
for(std::string::const_iterator i = str.begin();
GetNextCodePointAndAdvance(codePoint, i, str.end());
)
{
if (!IsAnchorChar(codePoint))
return false;
WriteCodePoint(out, codePoint);
}
return true;
}
} }
bool WriteString(ostream& out, const std::string& str, bool inFlow) bool WriteString(ostream& out, const std::string& str, bool inFlow, bool escapeNonAscii)
{ {
if(IsValidPlainScalar(str, inFlow)) { if(IsValidPlainScalar(str, inFlow, escapeNonAscii)) {
out << str; out << str;
return true; return true;
} else } else
return WriteDoubleQuotedString(out, str); return WriteDoubleQuotedString(out, str, escapeNonAscii);
} }
bool WriteSingleQuotedString(ostream& out, const std::string& str) bool WriteSingleQuotedString(ostream& out, const std::string& str)
{ {
out << "'"; out << "'";
for(std::size_t i=0;i<str.size();i++) { int codePoint;
char ch = str[i]; for(std::string::const_iterator i = str.begin();
if(!IsPrintable(ch)) GetNextCodePointAndAdvance(codePoint, i, str.end());
return false; )
{
if(ch == '\'') if (codePoint == '\n')
return false; // We can't handle a new line and the attendant indentation yet
if (codePoint == '\'')
out << "''"; out << "''";
else else
out << ch; WriteCodePoint(out, codePoint);
} }
out << "'"; out << "'";
return true; return true;
} }
bool WriteDoubleQuotedString(ostream& out, const std::string& str) bool WriteDoubleQuotedString(ostream& out, const std::string& str, bool escapeNonAscii)
{ {
out << "\""; out << "\"";
for(std::size_t i=0;i<str.size();i++) { int codePoint;
char ch = str[i]; for(std::string::const_iterator i = str.begin();
if(IsPrintable(ch)) { GetNextCodePointAndAdvance(codePoint, i, str.end());
if(ch == '\"') )
out << "\\\""; {
else if(ch == '\\') if (codePoint == '\"')
out << "\\\\"; out << "\\\"";
else else if (codePoint == '\\')
out << ch; out << "\\\\";
} else { else if (codePoint < 0x20 || (codePoint >= 0x80 && codePoint <= 0xA0)) // Control characters and non-breaking space
// TODO: for the common escaped characters, give their usual symbol WriteDoubleQuoteEscapeSequence(out, codePoint);
std::stringstream str; else if (codePoint == 0xFEFF) // Byte order marks (ZWNS) should be escaped (YAML 1.2, sec. 5.2)
str << "\\x" << std::hex << std::setfill('0') << std::setw(2) << static_cast<unsigned int>(static_cast<unsigned char>(ch)); WriteDoubleQuoteEscapeSequence(out, codePoint);
out << str.str(); else if (escapeNonAscii && codePoint > 0x7E)
} WriteDoubleQuoteEscapeSequence(out, codePoint);
else
WriteCodePoint(out, codePoint);
} }
out << "\""; out << "\"";
return true; return true;
@@ -95,11 +252,15 @@ namespace YAML
{ {
out << "|\n"; out << "|\n";
out << IndentTo(indent); out << IndentTo(indent);
for(std::size_t i=0;i<str.size();i++) { int codePoint;
if(str[i] == '\n') for(std::string::const_iterator i = str.begin();
out << "\n" << IndentTo(indent); GetNextCodePointAndAdvance(codePoint, i, str.end());
)
{
if (codePoint == '\n')
out << "\n" << IndentTo(indent);
else else
out << str[i]; WriteCodePoint(out, codePoint);
} }
return true; return true;
} }
@@ -108,11 +269,15 @@ namespace YAML
{ {
unsigned curIndent = out.col(); unsigned curIndent = out.col();
out << "#" << Indentation(postCommentIndent); out << "#" << Indentation(postCommentIndent);
for(std::size_t i=0;i<str.size();i++) { int codePoint;
if(str[i] == '\n') for(std::string::const_iterator i = str.begin();
GetNextCodePointAndAdvance(codePoint, i, str.end());
)
{
if(codePoint == '\n')
out << "\n" << IndentTo(curIndent) << "#" << Indentation(postCommentIndent); out << "\n" << IndentTo(curIndent) << "#" << Indentation(postCommentIndent);
else else
out << str[i]; WriteCodePoint(out, codePoint);
} }
return true; return true;
} }
@@ -120,24 +285,30 @@ namespace YAML
bool WriteAlias(ostream& out, const std::string& str) bool WriteAlias(ostream& out, const std::string& str)
{ {
out << "*"; out << "*";
for(std::size_t i=0;i<str.size();i++) { return WriteAliasName(out, str);
if(!IsPrintable(str[i]) || str[i] == ' ' || str[i] == '\t' || str[i] == '\n' || str[i] == '\r')
return false;
out << str[i];
}
return true;
} }
bool WriteAnchor(ostream& out, const std::string& str) bool WriteAnchor(ostream& out, const std::string& str)
{ {
out << "&"; out << "&";
for(std::size_t i=0;i<str.size();i++) { return WriteAliasName(out, str);
if(!IsPrintable(str[i]) || str[i] == ' ' || str[i] == '\t' || str[i] == '\n' || str[i] == '\r') }
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; return false;
out << str[i]; while(--n >= 0) {
out << buffer[0];
++buffer;
}
} }
out << ">";
return true; return true;
} }
} }

View File

@@ -11,13 +11,14 @@ namespace YAML
{ {
namespace Utils namespace Utils
{ {
bool WriteString(ostream& out, const std::string& str, bool inFlow); bool WriteString(ostream& out, const std::string& str, bool inFlow, bool escapeNonAscii);
bool WriteSingleQuotedString(ostream& out, const std::string& str); bool WriteSingleQuotedString(ostream& out, const std::string& str);
bool WriteDoubleQuotedString(ostream& out, const std::string& str); bool WriteDoubleQuotedString(ostream& out, const std::string& str, bool escapeNonAscii);
bool WriteLiteralString(ostream& out, const std::string& str, int indent); bool WriteLiteralString(ostream& out, const std::string& str, int indent);
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>
@@ -28,9 +27,9 @@ namespace YAML
return value; return value;
} }
std::string Str(char ch) std::string Str(unsigned ch)
{ {
return std::string("") + ch; return std::string(1, static_cast<char>(ch));
} }
// Escape // Escape

166
src/exp.h
View File

@@ -17,45 +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() {
const RegEx Printable = RegEx(0x20, 0x7E); 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)
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(0x0E, 0x1F) ||
(RegEx('\xC2') + (RegEx('\x80', '\x84') || RegEx('\x86', '\x9F')));
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);
@@ -74,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();
} }
state.PopCollectionType(ParserState::BLOCK_MAP);
} }
void Map::ParseFlow(Scanner *pScanner, const ParserState& state) 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();
@@ -64,6 +64,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);
@@ -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) {
s = "~"; if(m_tag.empty())
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,40 +1,45 @@
#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>
namespace YAML namespace YAML
{ {
Parser::Parser(std::istream& in): m_pScanner(0) Parser::Parser()
{
}
Parser::Parser(std::istream& in)
{ {
Load(in); Load(in);
} }
Parser::~Parser() Parser::~Parser()
{ {
delete m_pScanner;
} }
Parser::operator bool() const Parser::operator bool() const
{ {
return !m_pScanner->empty(); return m_pScanner.get() && !m_pScanner->empty();
} }
void Parser::Load(std::istream& in) void Parser::Load(std::istream& in)
{ {
delete m_pScanner; m_pScanner.reset(new Scanner(in));
m_pScanner = new Scanner(in); m_pState.reset(new ParserState);
m_state.Reset();
} }
// GetNextDocument // GetNextDocument
// . Reads the next document in the queue (of tokens). // . Reads the next document in the queue (of tokens).
// . Throws a ParserException on error. // . Throws a ParserException on error.
void Parser::GetNextDocument(Node& document) bool Parser::GetNextDocument(Node& document)
{ {
if(!m_pScanner.get())
return false;
// clear node // clear node
document.Clear(); document.Clear();
@@ -43,14 +48,14 @@ namespace YAML
// we better have some tokens in the queue // we better have some tokens in the queue
if(m_pScanner->empty()) if(m_pScanner->empty())
return; return false;
// first eat doc start (optional) // first eat doc start (optional)
if(m_pScanner->peek().type == Token::DOC_START) if(m_pScanner->peek().type == Token::DOC_START)
m_pScanner->pop(); m_pScanner->pop();
// now parse our root node // now parse our root node
document.Parse(m_pScanner, 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)
@@ -58,6 +63,8 @@ namespace YAML
// clear anchors from the scanner, which are no longer relevant // clear anchors from the scanner, which are no longer relevant
m_pScanner->ClearAnchors(); m_pScanner->ClearAnchors();
return true;
} }
// ParseDirectives // ParseDirectives
@@ -77,55 +84,66 @@ 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);
if(!m_pState->version.isDefault)
throw ParserException(token.mark, ErrorMsg::REPEATED_YAML_DIRECTIVE);
std::stringstream str(pToken->params[0]); std::stringstream str(token.params[0]);
str >> m_state.version.major; 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)
{ {
if(!m_pScanner.get())
return;
while(1) { while(1) {
if(m_pScanner->empty()) if(m_pScanner->empty())
break; break;

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()) {
m_tokens.push(Token(Token::VALUE, INPUT.mark())); if(m_flows.top() == FLOW_MAP && VerifySimpleKey())
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();
@@ -127,11 +134,16 @@ namespace YAML
// FlowEntry // FlowEntry
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()) {
m_tokens.push(Token(Token::VALUE, INPUT.mark())); if(m_flows.top() == FLOW_MAP && VerifySimpleKey())
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();
if(INPUT && INPUT.peek() == Keys::VerbatimTagStart){
std::string tag = ScanVerbatimTag(INPUT);
// read the handle token.value = tag;
while(INPUT && INPUT.peek() != Keys::Tag && !Exp::BlankOrBreak.Matches(INPUT)) token.data = Tag::VERBATIM;
handle += INPUT.get();
// is there a suffix?
if(INPUT.peek() == Keys::Tag) {
// eat the indicator
handle += INPUT.get();
// then read it
while(INPUT && !Exp::BlankOrBreak.Matches(INPUT))
suffix += INPUT.get();
} else { } else {
// this is a bit weird: we keep just the '!' as the handle and move the rest to the suffix bool canBeHandle;
suffix = handle.substr(1); token.value = ScanTagHandle(INPUT, canBeHandle);
handle = "!"; token.data = (token.value.empty() ? Tag::SECONDARY_HANDLE : Tag::PRIMARY_HANDLE);
// is there a suffix?
if(canBeHandle && INPUT.peek() == Keys::Tag) {
// eat the indicator
INPUT.get();
token.params.push_back(ScanTagSuffix(INPUT));
token.data = Tag::NAMED_HANDLE;
}
} }
Token token(Token::TAG, mark);
token.value = handle;
token.params.push_back(suffix);
m_tokens.push(token); m_tokens.push(token);
} }
@@ -284,10 +297,10 @@ 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_BLOCK; params.fold = FOLD_FLOW;
params.eatLeadingWhitespace = true; params.eatLeadingWhitespace = true;
params.trimTrailingSpaces = true; params.trimTrailingSpaces = true;
params.chomp = STRIP; params.chomp = STRIP;
@@ -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)
@@ -37,9 +38,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,11 +65,13 @@ 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
key.pIndent = PushIndentTo(INPUT.column(), IndentMarker::MAP); if(InBlockContext()) {
if(key.pIndent) { key.pIndent = PushIndentTo(INPUT.column(), IndentMarker::MAP);
key.pIndent->isValid = false; if(key.pIndent) {
key.pMapStart = key.pIndent->pStartToken; key.pIndent->status = IndentMarker::UNKNOWN;
key.pMapStart->status = Token::UNVERIFIED; key.pMapStart = key.pIndent->pStartToken;
key.pMapStart->status = Token::UNVERIFIED;
}
} }
// then add the (now unverified) key // then add the (now unverified) key
@@ -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,7 +536,95 @@ 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)
{
out << YAML::EscapeNonAscii << "\x24 \xC2\xA2 \xE2\x82\xAC \xF0\xA4\xAD\xA2";
desiredOutput = "--- \"$ \\xa2 \\u20ac \\U00024b62\"";
}
void Unicode(YAML::Emitter& out, std::string& desiredOutput)
{
out << "\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)
{
out << YAML::DoubleQuoted << "\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- ~";
} }
//////////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -600,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);
@@ -609,6 +798,13 @@ namespace Test
RunEmitterTest(&Emitter::SimpleGlobalSettings, "simple global settings", passed, total); RunEmitterTest(&Emitter::SimpleGlobalSettings, "simple global settings", passed, total);
RunEmitterTest(&Emitter::ComplexGlobalSettings, "complex global settings", passed, total); RunEmitterTest(&Emitter::ComplexGlobalSettings, "complex global settings", passed, total);
RunEmitterTest(&Emitter::Null, "null", passed, total); RunEmitterTest(&Emitter::Null, "null", passed, total);
RunEmitterTest(&Emitter::EscapedUnicode, "escaped unicode", passed, total);
RunEmitterTest(&Emitter::Unicode, "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

@@ -118,7 +118,7 @@ namespace Test
inputScalar = "http://example.com/foo#bar"; inputScalar = "http://example.com/foo#bar";
desiredOutput = "http://example.com/foo#bar"; desiredOutput = "http://example.com/foo#bar";
} }
bool SimpleSeq() bool SimpleSeq()
{ {
std::string input = std::string input =
@@ -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);

File diff suppressed because it is too large Load Diff

View File

@@ -11,9 +11,8 @@ int main(int argc, char **argv)
std::istream& input = (argc > 1 ? fin : std::cin); std::istream& input = (argc > 1 ? fin : std::cin);
try { try {
YAML::Parser parser(input); YAML::Parser parser(input);
while(parser) { YAML::Node doc;
YAML::Node doc; while(parser.GetNextDocument(doc)) {
parser.GetNextDocument(doc);
YAML::Emitter emitter; YAML::Emitter emitter;
emitter << doc; emitter << doc;
std::cout << emitter.c_str() << "\n"; std::cout << emitter.c_str() << "\n";

View File

@@ -1,10 +0,0 @@
file(GLOB yaml-reader_headers *.h)
file(GLOB yaml-reader_sources *.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"
> >