Merged aliases branch into trunk, changes r100:150

This commit is contained in:
jbeder
2009-05-22 21:48:05 +00:00
parent 7297387015
commit 5abf31b991
13 changed files with 308 additions and 18 deletions

View File

@@ -38,6 +38,8 @@ namespace YAML
const std::string CHAR_IN_ANCHOR = "illegal character found while scanning anchor";
const std::string ZERO_INDENT_IN_BLOCK = "cannot set zero indentation for a block scalar";
const std::string CHAR_IN_BLOCK = "unexpected character in block scalar";
const std::string AMBIGUOUS_ANCHOR = "cannot assign the same alias to multiple nodes";
const std::string UNKNOWN_ANCHOR = "the referenced anchor is not defined";
const std::string INVALID_SCALAR = "invalid scalar";
const std::string KEY_NOT_FOUND = "key not found";

View File

@@ -66,6 +66,11 @@ namespace YAML
const Node& operator [] (unsigned u) const;
const Node& operator [] (int i) const;
// for anchors/aliases
const Node *Identity() const { return m_pIdentity; }
bool IsAlias() const { return m_alias; }
bool IsReferenced() const { return m_referenced; }
// insertion
friend std::ostream& operator << (std::ostream& out, const Node& node);
@@ -89,6 +94,8 @@ namespace YAML
std::string m_anchor, m_tag;
Content *m_pContent;
bool m_alias;
const Node *m_pIdentity;
mutable bool m_referenced;
};
// templated things we need to keep inline in the header

View File

@@ -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
View 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
View 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;
};
}

View File

@@ -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

View File

@@ -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

View File

@@ -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();
}
}

View File

@@ -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;
};
}

View File

@@ -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;

View File

@@ -16,6 +16,7 @@ namespace Test
files.push_back("tests/mixed.yaml");
files.push_back("tests/scalars.yaml");
files.push_back("tests/directives.yaml");
files.push_back("tests/aliased.yaml");
bool passed = true;
for(unsigned i=0;i<files.size();i++) {

View File

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

View File

@@ -167,6 +167,10 @@
<Filter
Name="Representation"
>
<File
RelativePath=".\src\alias.cpp"
>
</File>
<File
RelativePath=".\src\content.cpp"
>
@@ -257,6 +261,10 @@
<Filter
Name="Representation"
>
<File
RelativePath=".\include\alias.h"
>
</File>
<File
RelativePath=".\src\content.h"
>