mirror of
https://github.com/jbeder/yaml-cpp.git
synced 2025-09-08 20:31:17 +00:00
- Reintegrated the other-tags branch into my staging branch. Local edits were required to integrate with the changes from the event-api branch.
This commit is contained in:
@@ -77,6 +77,8 @@ namespace YAML
|
|||||||
void EmitEndMap();
|
void EmitEndMap();
|
||||||
void EmitKey();
|
void EmitKey();
|
||||||
void EmitValue();
|
void EmitValue();
|
||||||
|
void EmitKindTag();
|
||||||
|
void EmitTag(bool verbatim, const _Tag& tag);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ostream m_stream;
|
ostream m_stream;
|
||||||
|
@@ -11,6 +11,7 @@ namespace YAML
|
|||||||
enum EMITTER_MANIP {
|
enum EMITTER_MANIP {
|
||||||
// general manipulators
|
// general manipulators
|
||||||
Auto,
|
Auto,
|
||||||
|
TagByKind,
|
||||||
|
|
||||||
// output character set
|
// output character set
|
||||||
EmitNonAscii,
|
EmitNonAscii,
|
||||||
@@ -82,14 +83,24 @@ namespace YAML
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct _Tag {
|
struct _Tag {
|
||||||
_Tag(const std::string& content_): content(content_), verbatim(true) {}
|
explicit _Tag(const std::string& content_)
|
||||||
|
: content(content_), verbatim(true)
|
||||||
|
{
|
||||||
|
}
|
||||||
std::string content;
|
std::string content;
|
||||||
bool verbatim;
|
bool verbatim;
|
||||||
};
|
};
|
||||||
|
|
||||||
inline _Tag VerbatimTag(const std::string& content) {
|
typedef _Tag VerbatimTag;
|
||||||
return _Tag(content);
|
|
||||||
}
|
struct LocalTag : public _Tag
|
||||||
|
{
|
||||||
|
explicit LocalTag(const std::string& content_)
|
||||||
|
: _Tag(content_)
|
||||||
|
{
|
||||||
|
verbatim = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
struct _Comment {
|
struct _Comment {
|
||||||
_Comment(const std::string& content_): content(content_) {}
|
_Comment(const std::string& content_): content(content_) {}
|
||||||
|
@@ -120,6 +120,9 @@ namespace YAML
|
|||||||
case Value:
|
case Value:
|
||||||
EmitValue();
|
EmitValue();
|
||||||
break;
|
break;
|
||||||
|
case TagByKind:
|
||||||
|
EmitKindTag();
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
m_pState->SetLocalValue(value);
|
m_pState->SetLocalValue(value);
|
||||||
break;
|
break;
|
||||||
@@ -651,15 +654,26 @@ namespace YAML
|
|||||||
if(!good())
|
if(!good())
|
||||||
return *this;
|
return *this;
|
||||||
|
|
||||||
|
EmitTag(tag.verbatim, tag);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Emitter::EmitTag(bool verbatim, const _Tag& tag)
|
||||||
|
{
|
||||||
PreAtomicWrite();
|
PreAtomicWrite();
|
||||||
EmitSeparationIfNecessary();
|
EmitSeparationIfNecessary();
|
||||||
if(!Utils::WriteTag(m_stream, tag.content)) {
|
if(!Utils::WriteTag(m_stream, tag.content, verbatim)) {
|
||||||
m_pState->SetError(ErrorMsg::INVALID_TAG);
|
m_pState->SetError(ErrorMsg::INVALID_TAG);
|
||||||
return *this;
|
return;
|
||||||
}
|
}
|
||||||
m_pState->RequireSeparation();
|
m_pState->RequireSeparation();
|
||||||
// Note: no PostAtomicWrite() because we need another value for this node
|
// Note: no PostAtomicWrite() because we need another value for this node
|
||||||
return *this;
|
}
|
||||||
|
|
||||||
|
void Emitter::EmitKindTag()
|
||||||
|
{
|
||||||
|
_Tag tag("");
|
||||||
|
EmitTag(false, tag);
|
||||||
}
|
}
|
||||||
|
|
||||||
Emitter& Emitter::Write(const _Comment& comment)
|
Emitter& Emitter::Write(const _Comment& comment)
|
||||||
|
@@ -294,12 +294,13 @@ namespace YAML
|
|||||||
return WriteAliasName(out, str);
|
return WriteAliasName(out, str);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WriteTag(ostream& out, const std::string& str)
|
bool WriteTag(ostream& out, const std::string& str, bool verbatim)
|
||||||
{
|
{
|
||||||
out << "!<";
|
out << (verbatim ? "!<" : "!");
|
||||||
StringCharSource buffer(str.c_str(), str.size());
|
StringCharSource buffer(str.c_str(), str.size());
|
||||||
|
const RegEx& reValid = verbatim ? Exp::URI() : Exp::Tag();
|
||||||
while(buffer) {
|
while(buffer) {
|
||||||
int n = Exp::URI().Match(buffer);
|
int n = reValid.Match(buffer);
|
||||||
if(n <= 0)
|
if(n <= 0)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@@ -308,7 +309,8 @@ namespace YAML
|
|||||||
++buffer;
|
++buffer;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
out << ">";
|
if (verbatim)
|
||||||
|
out << ">";
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -18,7 +18,7 @@ namespace YAML
|
|||||||
bool WriteComment(ostream& out, const std::string& str, int postCommentIndent);
|
bool WriteComment(ostream& out, const std::string& str, int postCommentIndent);
|
||||||
bool WriteAlias(ostream& out, const std::string& str);
|
bool WriteAlias(ostream& out, const std::string& str);
|
||||||
bool WriteAnchor(ostream& out, const std::string& str);
|
bool WriteAnchor(ostream& out, const std::string& str);
|
||||||
bool WriteTag(ostream& out, const std::string& str);
|
bool WriteTag(ostream& out, const std::string& str, bool verbatim);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -276,7 +276,12 @@ namespace YAML
|
|||||||
} else {
|
} else {
|
||||||
bool canBeHandle;
|
bool canBeHandle;
|
||||||
token.value = ScanTagHandle(INPUT, canBeHandle);
|
token.value = ScanTagHandle(INPUT, canBeHandle);
|
||||||
token.data = (token.value.empty() ? Tag::SECONDARY_HANDLE : Tag::PRIMARY_HANDLE);
|
if(!canBeHandle && token.value.empty())
|
||||||
|
token.data = Tag::NON_SPECIFIC;
|
||||||
|
else if(token.value.empty())
|
||||||
|
token.data = Tag::SECONDARY_HANDLE;
|
||||||
|
else
|
||||||
|
token.data = Tag::PRIMARY_HANDLE;
|
||||||
|
|
||||||
// is there a suffix?
|
// is there a suffix?
|
||||||
if(canBeHandle && INPUT.peek() == Keys::Tag) {
|
if(canBeHandle && INPUT.peek() == Keys::Tag) {
|
||||||
@@ -323,6 +328,7 @@ namespace YAML
|
|||||||
|
|
||||||
Token token(Token::SCALAR, mark);
|
Token token(Token::SCALAR, mark);
|
||||||
token.value = scalar;
|
token.value = scalar;
|
||||||
|
token.params.push_back(Token::PLAIN_SCALAR);
|
||||||
m_tokens.push(token);
|
m_tokens.push(token);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -8,6 +8,7 @@
|
|||||||
#include "token.h"
|
#include "token.h"
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
namespace YAML
|
namespace YAML
|
||||||
{
|
{
|
||||||
@@ -73,6 +74,17 @@ namespace YAML
|
|||||||
anchor_t anchor;
|
anchor_t anchor;
|
||||||
ParseProperties(tag, anchor);
|
ParseProperties(tag, anchor);
|
||||||
|
|
||||||
|
if (tag.empty()) {
|
||||||
|
const Token& token = m_scanner.peek();
|
||||||
|
const std::vector<std::string>& tparams = token.params;
|
||||||
|
if (token.type != Token::SCALAR ||
|
||||||
|
std::find(tparams.begin(), tparams.end(), Token::PLAIN_SCALAR) != tparams.end()) {
|
||||||
|
tag = "?";
|
||||||
|
} else {
|
||||||
|
tag = "!";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// now split based on what kind of node we should be
|
// now split based on what kind of node we should be
|
||||||
switch(m_scanner.peek().type) {
|
switch(m_scanner.peek().type) {
|
||||||
case Token::SCALAR:
|
case Token::SCALAR:
|
||||||
|
6
src/token.cpp
Normal file
6
src/token.cpp
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
#include "token.h"
|
||||||
|
|
||||||
|
namespace YAML
|
||||||
|
{
|
||||||
|
const std::string Token::PLAIN_SCALAR("pln");
|
||||||
|
}
|
@@ -59,6 +59,8 @@ namespace YAML
|
|||||||
TAG,
|
TAG,
|
||||||
SCALAR
|
SCALAR
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const std::string PLAIN_SCALAR;
|
||||||
|
|
||||||
// data
|
// data
|
||||||
Token(TYPE type_, const Mark& mark_): status(VALID), type(type_), mark(mark_), data(0) {}
|
Token(TYPE type_, const Mark& mark_): status(VALID), type(type_), mark(mark_), data(0) {}
|
||||||
|
@@ -373,6 +373,31 @@ namespace Test
|
|||||||
desiredOutput = "---\n- !<!foo>\n []\n- !<!bar>\n {}";
|
desiredOutput = "---\n- !<!foo>\n []\n- !<!bar>\n {}";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ByKindTagWithScalar(YAML::Emitter& out, std::string& desiredOutput)
|
||||||
|
{
|
||||||
|
out << YAML::BeginSeq;
|
||||||
|
out << YAML::DoubleQuoted << "12";
|
||||||
|
out << "12";
|
||||||
|
out << YAML::TagByKind << "12";
|
||||||
|
out << YAML::EndSeq;
|
||||||
|
|
||||||
|
desiredOutput = "---\n- \"12\"\n- 12\n- ! 12";
|
||||||
|
}
|
||||||
|
|
||||||
|
void LocalTagWithScalar(YAML::Emitter& out, std::string& desiredOutput)
|
||||||
|
{
|
||||||
|
out << YAML::LocalTag("foo") << "bar";
|
||||||
|
|
||||||
|
desiredOutput = "--- !foo bar";
|
||||||
|
}
|
||||||
|
|
||||||
|
void BadLocalTag(YAML::Emitter& out, std::string& desiredError)
|
||||||
|
{
|
||||||
|
out << YAML::LocalTag("e!far") << "bar";
|
||||||
|
|
||||||
|
desiredError = "invalid tag";
|
||||||
|
}
|
||||||
|
|
||||||
void ComplexDoc(YAML::Emitter& out, std::string& desiredOutput)
|
void ComplexDoc(YAML::Emitter& out, std::string& desiredOutput)
|
||||||
{
|
{
|
||||||
out << YAML::BeginMap;
|
out << YAML::BeginMap;
|
||||||
@@ -789,6 +814,8 @@ namespace Test
|
|||||||
RunEmitterTest(&Emitter::VerbatimTagWithEmptySeq, "verbatim tag with empty seq", passed, total);
|
RunEmitterTest(&Emitter::VerbatimTagWithEmptySeq, "verbatim tag with empty seq", passed, total);
|
||||||
RunEmitterTest(&Emitter::VerbatimTagWithEmptyMap, "verbatim tag with empty map", 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::VerbatimTagWithEmptySeqAndMap, "verbatim tag with empty seq and map", passed, total);
|
||||||
|
RunEmitterTest(&Emitter::ByKindTagWithScalar, "by-kind tag with scalar", passed, total);
|
||||||
|
RunEmitterTest(&Emitter::LocalTagWithScalar, "local tag with scalar", 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);
|
||||||
@@ -815,6 +842,7 @@ namespace Test
|
|||||||
RunEmitterErrorTest(&Emitter::MissingValue, "missing value", passed, total);
|
RunEmitterErrorTest(&Emitter::MissingValue, "missing value", passed, total);
|
||||||
RunEmitterErrorTest(&Emitter::UnexpectedKey, "unexpected key", passed, total);
|
RunEmitterErrorTest(&Emitter::UnexpectedKey, "unexpected key", passed, total);
|
||||||
RunEmitterErrorTest(&Emitter::UnexpectedValue, "unexpected value", passed, total);
|
RunEmitterErrorTest(&Emitter::UnexpectedValue, "unexpected value", passed, total);
|
||||||
|
RunEmitterErrorTest(&Emitter::BadLocalTag, "bad local tag", passed, total);
|
||||||
|
|
||||||
std::cout << "Emitter tests: " << passed << "/" << total << " passed\n";
|
std::cout << "Emitter tests: " << passed << "/" << total << " passed\n";
|
||||||
return passed == total;
|
return passed == total;
|
||||||
|
@@ -706,6 +706,106 @@ namespace Test
|
|||||||
return false;
|
return false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PrepareNodeForTagExam(YAML::Node& doc, const std::string& input)
|
||||||
|
{
|
||||||
|
std::stringstream stream(input);
|
||||||
|
YAML::Parser parser(stream);
|
||||||
|
parser.GetNextDocument(doc);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct TagMismatch: public std::exception {
|
||||||
|
TagMismatch(const std::string& actualTag, const std::string& expectedTag) {
|
||||||
|
std::stringstream output;
|
||||||
|
output << "Tag has value \"" << actualTag << "\" but \"" << expectedTag << "\" was expected";
|
||||||
|
what_ = output.str();
|
||||||
|
}
|
||||||
|
virtual ~TagMismatch() throw() {}
|
||||||
|
virtual const char *what() const throw() { return what_.c_str(); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string what_;
|
||||||
|
};
|
||||||
|
|
||||||
|
bool ExpectedTagValue(YAML::Node& node, const char* tag)
|
||||||
|
{
|
||||||
|
if(node.GetTag() == tag)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
throw TagMismatch(node.GetTag(), tag);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DefaultPlainScalarTag()
|
||||||
|
{
|
||||||
|
YAML::Node node;
|
||||||
|
PrepareNodeForTagExam(node, "--- 12");
|
||||||
|
|
||||||
|
return ExpectedTagValue(node, "?");
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DefaultSingleQuotedScalarTag()
|
||||||
|
{
|
||||||
|
YAML::Node node;
|
||||||
|
PrepareNodeForTagExam(node, "--- '12'");
|
||||||
|
|
||||||
|
return ExpectedTagValue(node, "!");
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ExplicitNonSpecificPlainScalarTag()
|
||||||
|
{
|
||||||
|
YAML::Node node;
|
||||||
|
PrepareNodeForTagExam(node, "--- ! 12");
|
||||||
|
|
||||||
|
return ExpectedTagValue(node, "!");
|
||||||
|
}
|
||||||
|
|
||||||
|
bool BasicLocalTag()
|
||||||
|
{
|
||||||
|
YAML::Node node;
|
||||||
|
PrepareNodeForTagExam(node, "--- !foo 12");
|
||||||
|
|
||||||
|
return ExpectedTagValue(node, "!foo");
|
||||||
|
}
|
||||||
|
|
||||||
|
bool VerbatimLocalTag()
|
||||||
|
{
|
||||||
|
YAML::Node node;
|
||||||
|
PrepareNodeForTagExam(node, "--- !<!foo> 12");
|
||||||
|
|
||||||
|
return ExpectedTagValue(node, "!foo");
|
||||||
|
}
|
||||||
|
|
||||||
|
bool StandardShortcutTag()
|
||||||
|
{
|
||||||
|
YAML::Node node;
|
||||||
|
PrepareNodeForTagExam(node, "--- !!int 12");
|
||||||
|
|
||||||
|
return ExpectedTagValue(node, "tag:yaml.org,2002:int");
|
||||||
|
}
|
||||||
|
|
||||||
|
bool VerbatimURITag()
|
||||||
|
{
|
||||||
|
YAML::Node node;
|
||||||
|
PrepareNodeForTagExam(node, "--- !<tag:yaml.org,2002:int> 12");
|
||||||
|
|
||||||
|
return ExpectedTagValue(node, "tag:yaml.org,2002:int");
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DefaultSequenceTag()
|
||||||
|
{
|
||||||
|
YAML::Node node;
|
||||||
|
PrepareNodeForTagExam(node, "--- [12]");
|
||||||
|
|
||||||
|
return ExpectedTagValue(node, "?");
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ExplicitNonSpecificSequenceTag()
|
||||||
|
{
|
||||||
|
YAML::Node node;
|
||||||
|
PrepareNodeForTagExam(node, "--- ! [12]");
|
||||||
|
|
||||||
|
return ExpectedTagValue(node, "!");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
@@ -746,7 +846,10 @@ namespace Test
|
|||||||
ok = test();
|
ok = test();
|
||||||
} catch(const YAML::Exception& e) {
|
} catch(const YAML::Exception& e) {
|
||||||
ok = false;
|
ok = false;
|
||||||
error = e.msg;
|
error = e.what();
|
||||||
|
} catch(const Parser::TagMismatch& e) {
|
||||||
|
ok = false;
|
||||||
|
error = e.what();
|
||||||
}
|
}
|
||||||
if(ok) {
|
if(ok) {
|
||||||
passed++;
|
passed++;
|
||||||
@@ -969,6 +1072,16 @@ namespace Test
|
|||||||
RunParserTest(&Parser::Bases, "bases", passed, total);
|
RunParserTest(&Parser::Bases, "bases", passed, total);
|
||||||
RunParserTest(&Parser::KeyNotFound, "key not found", passed, total);
|
RunParserTest(&Parser::KeyNotFound, "key not found", passed, total);
|
||||||
RunParserTest(&Parser::DuplicateKey, "duplicate key", passed, total);
|
RunParserTest(&Parser::DuplicateKey, "duplicate key", passed, total);
|
||||||
|
RunParserTest(&Parser::DefaultPlainScalarTag, "default plain scalar tag", passed, total);
|
||||||
|
RunParserTest(&Parser::DefaultSingleQuotedScalarTag, "default single-quoted scalar tag", passed, total);
|
||||||
|
RunParserTest(&Parser::ExplicitNonSpecificPlainScalarTag, "explicit, non-specific plain scalar tag", passed, total);
|
||||||
|
RunParserTest(&Parser::BasicLocalTag, "basic local tag", passed, total);
|
||||||
|
RunParserTest(&Parser::VerbatimLocalTag, "verbatim local tag", passed, total);
|
||||||
|
RunParserTest(&Parser::StandardShortcutTag, "standard shortcut tag", passed, total);
|
||||||
|
RunParserTest(&Parser::VerbatimURITag, "verbatim URI tag", passed, total);
|
||||||
|
RunParserTest(&Parser::DefaultPlainScalarTag, "default plain scalar tag", passed, total);
|
||||||
|
RunParserTest(&Parser::DefaultSequenceTag, "default sequence tag", passed, total);
|
||||||
|
RunParserTest(&Parser::ExplicitNonSpecificSequenceTag, "explicit, non-specific sequence tag", 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);
|
||||||
|
Reference in New Issue
Block a user