mirror of
https://github.com/jbeder/yaml-cpp.git
synced 2025-09-09 12:41:17 +00:00
Merged aliases branch into trunk, changes r100:150
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
set(FILES content.cpp iterator.cpp node.cpp parserstate.cpp
|
||||
set(FILES alias.cpp content.cpp iterator.cpp node.cpp parserstate.cpp
|
||||
scalar.cpp scanscalar.cpp sequence.cpp stream.cpp
|
||||
exp.cpp map.cpp parser.cpp regex.cpp scanner.cpp
|
||||
scantoken.cpp simplekey.cpp)
|
||||
|
125
src/alias.cpp
Normal file
125
src/alias.cpp
Normal file
@@ -0,0 +1,125 @@
|
||||
#include "crt.h"
|
||||
#include "alias.h"
|
||||
#include <iostream>
|
||||
|
||||
namespace YAML
|
||||
{
|
||||
Alias::Alias(Content* pNodeContent)
|
||||
: m_pRef(pNodeContent)
|
||||
{
|
||||
}
|
||||
|
||||
void Alias::Parse(Scanner *pScanner, const ParserState& state)
|
||||
{
|
||||
}
|
||||
|
||||
void Alias::Write(std::ostream& out, int indent, bool startedLine, bool onlyOneCharOnLine)
|
||||
{
|
||||
out << "\n";
|
||||
}
|
||||
|
||||
bool Alias::GetBegin(std::vector <Node *>::const_iterator& i) const
|
||||
{
|
||||
return m_pRef->GetBegin(i);
|
||||
}
|
||||
|
||||
bool Alias::GetBegin(std::map <Node *, Node *, ltnode>::const_iterator& i) const
|
||||
{
|
||||
return m_pRef->GetBegin(i);
|
||||
}
|
||||
|
||||
bool Alias::GetEnd(std::vector <Node *>::const_iterator& i) const
|
||||
{
|
||||
return m_pRef->GetEnd(i);
|
||||
}
|
||||
|
||||
bool Alias::GetEnd(std::map <Node *, Node *, ltnode>::const_iterator& i) const
|
||||
{
|
||||
return m_pRef->GetEnd(i);
|
||||
}
|
||||
|
||||
Node* Alias::GetNode(unsigned n) const
|
||||
{
|
||||
return m_pRef->GetNode(n);
|
||||
}
|
||||
|
||||
unsigned Alias::GetSize() const
|
||||
{
|
||||
return m_pRef->GetSize();
|
||||
}
|
||||
|
||||
bool Alias::IsScalar() const
|
||||
{
|
||||
return m_pRef->IsScalar();
|
||||
}
|
||||
|
||||
bool Alias::IsMap() const
|
||||
{
|
||||
return m_pRef->IsMap();
|
||||
}
|
||||
|
||||
bool Alias::IsSequence() const
|
||||
{
|
||||
return m_pRef->IsSequence();
|
||||
}
|
||||
|
||||
bool Alias::Read(std::string& v) const
|
||||
{
|
||||
return m_pRef->Read(v);
|
||||
}
|
||||
|
||||
bool Alias::Read(int& v) const
|
||||
{
|
||||
return m_pRef->Read(v);
|
||||
}
|
||||
|
||||
bool Alias::Read(unsigned& v) const
|
||||
{
|
||||
return m_pRef->Read(v);
|
||||
}
|
||||
|
||||
bool Alias::Read(long& v) const
|
||||
{
|
||||
return m_pRef->Read(v);
|
||||
}
|
||||
|
||||
bool Alias::Read(float& v) const
|
||||
{
|
||||
return m_pRef->Read(v);
|
||||
}
|
||||
|
||||
bool Alias::Read(double& v) const
|
||||
{
|
||||
return m_pRef->Read(v);
|
||||
}
|
||||
|
||||
bool Alias::Read(char& v) const
|
||||
{
|
||||
return m_pRef->Read(v);
|
||||
}
|
||||
|
||||
bool Alias::Read(bool& v) const
|
||||
{
|
||||
return m_pRef->Read(v);
|
||||
}
|
||||
|
||||
int Alias::Compare(Content *pContent)
|
||||
{
|
||||
return m_pRef->Compare(pContent);
|
||||
}
|
||||
|
||||
int Alias::Compare(Scalar *pScalar)
|
||||
{
|
||||
return m_pRef->Compare(pScalar);
|
||||
}
|
||||
|
||||
int Alias::Compare(Sequence *pSequence)
|
||||
{
|
||||
return m_pRef->Compare(pSequence);
|
||||
}
|
||||
|
||||
int Alias::Compare(Map *pMap)
|
||||
{
|
||||
return m_pRef->Compare(pMap);
|
||||
}
|
||||
}
|
42
src/alias.h
Normal file
42
src/alias.h
Normal file
@@ -0,0 +1,42 @@
|
||||
#pragma once
|
||||
|
||||
#include "content.h"
|
||||
|
||||
namespace YAML
|
||||
{
|
||||
class Alias : public Content
|
||||
{
|
||||
public:
|
||||
Alias(Content *pNodeContent);
|
||||
|
||||
virtual void Parse(Scanner* pScanner, const ParserState& state);
|
||||
virtual void Write(std::ostream& out, int indent, bool startedLine, bool onlyOneCharOnLine);
|
||||
|
||||
virtual bool GetBegin(std::vector <Node *>::const_iterator&) const;
|
||||
virtual bool GetBegin(std::map <Node *, Node *, ltnode>::const_iterator&) const;
|
||||
virtual bool GetEnd(std::vector <Node *>::const_iterator&) const;
|
||||
virtual bool GetEnd(std::map <Node *, Node *, ltnode>::const_iterator&) const;
|
||||
virtual Node* GetNode(unsigned) const;
|
||||
virtual unsigned GetSize() const;
|
||||
virtual bool IsScalar() const;
|
||||
virtual bool IsMap() const;
|
||||
virtual bool IsSequence() const;
|
||||
|
||||
virtual bool Read(std::string&) const;
|
||||
virtual bool Read(int&) const;
|
||||
virtual bool Read(unsigned&) const;
|
||||
virtual bool Read(long&) const;
|
||||
virtual bool Read(float&) const;
|
||||
virtual bool Read(double&) const;
|
||||
virtual bool Read(char&) const;
|
||||
virtual bool Read(bool&) const;
|
||||
|
||||
virtual int Compare(Content *);
|
||||
virtual int Compare(Scalar *);
|
||||
virtual int Compare(Sequence *);
|
||||
virtual int Compare(Map *);
|
||||
|
||||
private:
|
||||
Content* m_pRef;
|
||||
};
|
||||
}
|
70
src/node.cpp
70
src/node.cpp
@@ -7,7 +7,9 @@
|
||||
#include "scalar.h"
|
||||
#include "sequence.h"
|
||||
#include "map.h"
|
||||
#include "alias.h"
|
||||
#include "iterpriv.h"
|
||||
#include <iostream>
|
||||
|
||||
namespace YAML
|
||||
{
|
||||
@@ -17,7 +19,7 @@ namespace YAML
|
||||
return *pNode1 < *pNode2;
|
||||
}
|
||||
|
||||
Node::Node(): m_pContent(0), m_alias(false)
|
||||
Node::Node(): m_pContent(0), m_alias(false), m_pIdentity(this), m_referenced(true)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -31,6 +33,9 @@ namespace YAML
|
||||
delete m_pContent;
|
||||
m_pContent = 0;
|
||||
m_alias = false;
|
||||
m_referenced = false;
|
||||
m_anchor.clear();
|
||||
m_tag.clear();
|
||||
}
|
||||
|
||||
void Node::Parse(Scanner *pScanner, const ParserState& state)
|
||||
@@ -47,30 +52,50 @@ namespace YAML
|
||||
|
||||
ParseHeader(pScanner, state);
|
||||
|
||||
// is this an alias? if so, it can have no content
|
||||
if(m_alias)
|
||||
// is this an alias? if so, its contents are an alias to
|
||||
// a previously defined anchor
|
||||
if(m_alias) {
|
||||
// the scanner throws an exception if it doesn't know this anchor name
|
||||
const Node *pReferencedNode = pScanner->Retrieve(m_anchor);
|
||||
m_pIdentity = pReferencedNode;
|
||||
|
||||
// mark the referenced node for the sake of the client code
|
||||
pReferencedNode->m_referenced = true;
|
||||
|
||||
// use of an Alias object keeps the referenced content from
|
||||
// being deleted twice
|
||||
Content *pAliasedContent = pReferencedNode->m_pContent;
|
||||
if(pAliasedContent)
|
||||
m_pContent = new Alias(pAliasedContent);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// now split based on what kind of node we should be
|
||||
switch(pScanner->peek().type) {
|
||||
case TT_SCALAR:
|
||||
m_pContent = new Scalar;
|
||||
m_pContent->Parse(pScanner, state);
|
||||
break;
|
||||
case TT_FLOW_SEQ_START:
|
||||
case TT_BLOCK_SEQ_START:
|
||||
case TT_BLOCK_ENTRY:
|
||||
m_pContent = new Sequence;
|
||||
m_pContent->Parse(pScanner, state);
|
||||
break;
|
||||
case TT_FLOW_MAP_START:
|
||||
case TT_BLOCK_MAP_START:
|
||||
m_pContent = new Map;
|
||||
m_pContent->Parse(pScanner, state);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// Have to save anchor before parsing to allow for aliases as
|
||||
// contained node (recursive structure)
|
||||
if(!m_anchor.empty())
|
||||
pScanner->Save(m_anchor, this);
|
||||
|
||||
if(m_pContent)
|
||||
m_pContent->Parse(pScanner, state);
|
||||
}
|
||||
|
||||
// ParseHeader
|
||||
@@ -129,33 +154,46 @@ namespace YAML
|
||||
|
||||
void Node::Write(std::ostream& out, int indent, bool startedLine, bool onlyOneCharOnLine) const
|
||||
{
|
||||
// If using an anchor or tag for the whole document, document start
|
||||
// must be explicit
|
||||
bool indicateDocStart = (indent == 0);
|
||||
|
||||
// write anchor/alias
|
||||
if(m_anchor != "") {
|
||||
if (indicateDocStart) {
|
||||
out << "--- ";
|
||||
indicateDocStart = false;
|
||||
}
|
||||
|
||||
if(m_alias)
|
||||
out << std::string("*");
|
||||
out << "*";
|
||||
else
|
||||
out << std::string("&");
|
||||
out << m_anchor << std::string(" ");
|
||||
out << "&";
|
||||
out << m_anchor << " ";
|
||||
startedLine = true;
|
||||
onlyOneCharOnLine = false;
|
||||
}
|
||||
|
||||
// write tag
|
||||
if(m_tag != "") {
|
||||
if (indicateDocStart) {
|
||||
out << "--- ";
|
||||
indicateDocStart = false;
|
||||
}
|
||||
|
||||
// put the tag in the "proper" brackets
|
||||
if(m_tag.substr(0, 2) == "!<" && m_tag.substr(m_tag.size() - 1) == ">")
|
||||
out << m_tag;
|
||||
if(m_tag.substr(0, 2) == std::string("!<") && m_tag.substr(m_tag.size() - 1) == std::string(">"))
|
||||
out << m_tag << " ";
|
||||
else
|
||||
out << std::string("!<") << m_tag << std::string("> ");
|
||||
out << "!<" << m_tag << "> ";
|
||||
startedLine = true;
|
||||
onlyOneCharOnLine = false;
|
||||
}
|
||||
|
||||
if(!m_pContent) {
|
||||
out << std::string("\n");
|
||||
} else {
|
||||
if(!m_pContent)
|
||||
out << "\n";
|
||||
else
|
||||
m_pContent->Write(out, indent, startedLine, onlyOneCharOnLine);
|
||||
}
|
||||
}
|
||||
|
||||
CONTENT_TYPE Node::GetType() const
|
||||
|
@@ -55,6 +55,9 @@ namespace YAML
|
||||
// and finally eat any doc ends we see
|
||||
while(!m_pScanner->empty() && m_pScanner->peek().type == TT_DOC_END)
|
||||
m_pScanner->pop();
|
||||
|
||||
// clear anchors from the scanner, which are no longer relevant
|
||||
m_pScanner->ClearAnchors();
|
||||
}
|
||||
|
||||
// ParseDirectives
|
||||
|
@@ -29,8 +29,13 @@ namespace YAML
|
||||
void Scanner::pop()
|
||||
{
|
||||
EnsureTokensInQueue();
|
||||
if(!m_tokens.empty())
|
||||
if(!m_tokens.empty()) {
|
||||
// Saved anchors shouldn't survive popping the document end marker
|
||||
if (m_tokens.front().type == TT_DOC_END) {
|
||||
ClearAnchors();
|
||||
}
|
||||
m_tokens.pop();
|
||||
}
|
||||
}
|
||||
|
||||
// peek
|
||||
@@ -217,6 +222,7 @@ namespace YAML
|
||||
m_startedStream = true;
|
||||
m_simpleKeyAllowed = true;
|
||||
m_indents.push(-1);
|
||||
m_anchors.clear();
|
||||
}
|
||||
|
||||
// EndStream
|
||||
@@ -273,4 +279,47 @@ namespace YAML
|
||||
m_tokens.push(Token(TT_BLOCK_END, INPUT.line, INPUT.column));
|
||||
}
|
||||
}
|
||||
|
||||
// Save
|
||||
// . Saves a pointer to the Node object referenced by a particular anchor
|
||||
// name.
|
||||
void Scanner::Save(const std::string& anchor, Node* value)
|
||||
{
|
||||
m_anchors[anchor] = value;
|
||||
}
|
||||
|
||||
// Retrieve
|
||||
// . Retrieves a pointer previously saved for an anchor name.
|
||||
// . Throws an exception if the anchor has not been defined.
|
||||
const Node *Scanner::Retrieve(const std::string& anchor) const
|
||||
{
|
||||
typedef std::map<std::string, const Node *> map;
|
||||
|
||||
map::const_iterator itNode = m_anchors.find(anchor);
|
||||
|
||||
if(m_anchors.end() == itNode)
|
||||
ThrowParserException(ErrorMsg::UNKNOWN_ANCHOR);
|
||||
|
||||
return itNode->second;
|
||||
}
|
||||
|
||||
// ThrowParserException
|
||||
// . Throws a ParserException with the current token location
|
||||
// (if available).
|
||||
// . Does not parse any more tokens.
|
||||
void Scanner::ThrowParserException(const std::string& msg) const
|
||||
{
|
||||
int line = -1, column = -1;
|
||||
if(!m_tokens.empty()) {
|
||||
const Token& token = m_tokens.front();
|
||||
line = token.line;
|
||||
column = token.column;
|
||||
}
|
||||
throw ParserException(line, column, msg);
|
||||
}
|
||||
|
||||
void Scanner::ClearAnchors()
|
||||
{
|
||||
m_anchors.clear();
|
||||
}
|
||||
}
|
||||
|
@@ -5,11 +5,14 @@
|
||||
#include <queue>
|
||||
#include <stack>
|
||||
#include <set>
|
||||
#include <map>
|
||||
#include "stream.h"
|
||||
#include "token.h"
|
||||
|
||||
namespace YAML
|
||||
{
|
||||
class Node;
|
||||
|
||||
class Scanner
|
||||
{
|
||||
public:
|
||||
@@ -21,6 +24,11 @@ namespace YAML
|
||||
void pop();
|
||||
Token& peek();
|
||||
|
||||
// anchor management
|
||||
void Save(const std::string& anchor, Node* value);
|
||||
const Node *Retrieve(const std::string& anchor) const;
|
||||
void ClearAnchors();
|
||||
|
||||
private:
|
||||
// scanning
|
||||
void EnsureTokensInQueue();
|
||||
@@ -35,6 +43,7 @@ namespace YAML
|
||||
void InsertSimpleKey();
|
||||
bool VerifySimpleKey(bool force = false);
|
||||
void VerifyAllSimpleKeys();
|
||||
void ThrowParserException(const std::string& msg) const;
|
||||
|
||||
bool IsWhitespaceToBeEaten(char ch);
|
||||
|
||||
@@ -81,5 +90,6 @@ namespace YAML
|
||||
bool m_isLastKeyValid;
|
||||
std::stack <SimpleKey> m_simpleKeys;
|
||||
std::stack <int> m_indents;
|
||||
std::map <std::string, const Node *> m_anchors;
|
||||
};
|
||||
}
|
||||
|
@@ -55,6 +55,7 @@ namespace YAML
|
||||
std::string Stream::get(int n)
|
||||
{
|
||||
std::string ret;
|
||||
ret.reserve(n);
|
||||
for(int i=0;i<n;i++)
|
||||
ret += get();
|
||||
return ret;
|
||||
|
Reference in New Issue
Block a user